1 | /* $OpenBSD: inet_ntop.c,v 1.1 1997/03/13 19:07:32 downsj Exp $ */ 2 | 3 | /* Copyright (c) 1996 by Internet Software Consortium. 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 10 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 11 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 12 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 15 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16 | * SOFTWARE. 17 | */ 18 | #define __P(a) a 19 | 20 | #if defined(LIBC_SCCS) && !defined(lint) 21 | #if 0 22 | static char rcsid[] = "$From: inet_ntop.c,v 8.7 1996/08/05 08:41:18 vixie Exp $"; 23 | #else 24 | static char rcsid[] = "$OpenBSD: inet_ntop.c,v 1.1 1997/03/13 19:07:32 downsj Exp $"; 25 | #endif 26 | #endif /* LIBC_SCCS and not lint */ 27 | 28 | #include <sys/param.h> 29 | #include <sys/types.h> 30 | #include <sys/socket.h> 31 | #include <netinet/in.h> 32 | #include <arpa/inet.h> 33 | #include <arpa/nameser.h> 34 | 35 | #include <string.h> 36 | #include <errno.h> 37 | #include <stdio.h> 38 | 39 | #include "inet6def.h" 40 | 41 | /* 42 | * WARNING: Don't even consider trying to compile this on a system where 43 | * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 44 | */ 45 | 46 | static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size)); 47 | static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size)); 48 | 49 | /* char * 50 | * inet_ntop(af, src, dst, size) 51 | * convert a network format address to presentation format. 52 | * return: 53 | * pointer to presentation format address (`dst'), or NULL (see errno). 54 | * author: 55 | * Paul Vixie, 1996. 56 | */ 57 | const char * 58 | inet_ntop(af, src, dst, size) 59 | int af; 60 | const void *src; 61 | char *dst; 62 | size_t size; 63 | { 64 | switch (af) { 65 | case AF_INET: 66 | return (inet_ntop4(src, dst, size)); 67 | case AF_INET6: 68 | return (inet_ntop6(src, dst, size)); 69 | default: 70 | errno = EAFNOSUPPORT; 71 | return (NULL); 72 | } 73 | /* NOTREACHED */ 74 | } 75 | 76 | /* const char * 77 | * inet_ntop4(src, dst, size) 78 | * format an IPv4 address, more or less like inet_ntoa() 79 | * return: 80 | * `dst' (as a const) 81 | * notes: 82 | * (1) uses no statics 83 | * (2) takes a u_char* not an in_addr as input 84 | * author: 85 | * Paul Vixie, 1996. 86 | */ 87 | static const char * 88 | inet_ntop4(src, dst, size) 89 | const u_char *src; 90 | char *dst; 91 | size_t size; 92 | { 93 | static const char fmt[] = "%u.%u.%u.%u"; 94 | char tmp[sizeof "255.255.255.255"]; 95 | 96 | if (sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) > size) { 97 | errno = ENOSPC; 98 | return (NULL); 99 | } 100 | strcpy(dst, tmp); 101 | return (dst); 102 | } 103 | 104 | /* const char * 105 | * inet_ntop6(src, dst, size) 106 | * convert IPv6 binary address into presentation (printable) format 107 | * author: 108 | * Paul Vixie, 1996. 109 | */ 110 | static const char * 111 | inet_ntop6(src, dst, size) 112 | const u_char *src; 113 | char *dst; 114 | size_t size; 115 | { 116 | /* 117 | * Note that int32_t and int16_t need only be "at least" large enough 118 | * to contain a value of the specified size. On some systems, like 119 | * Crays, there is no such thing as an integer variable with 16 bits. 120 | * Keep this in mind if you think this function should have been coded 121 | * to use pointer overlays. All the world's not a VAX. 122 | */ 123 | char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; 124 | struct { int base, len; } best, cur; 125 | u_int words[IN6ADDRSZ / INT16SZ]; 126 | int i; 127 | 128 | /* 129 | * Preprocess: 130 | * Copy the input (bytewise) array into a wordwise array. 131 | * Find the longest run of 0x00's in src[] for :: shorthanding. 132 | */ 133 | memset(words, '\0', sizeof words); 134 | for (i = 0; i < IN6ADDRSZ; i++) 135 | words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); 136 | best.base = -1; 137 | cur.base = -1; 138 | for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 139 | if (words[i] == 0) { 140 | if (cur.base == -1) 141 | cur.base = i, cur.len = 1; 142 | else 143 | cur.len++; 144 | } else { 145 | if (cur.base != -1) { 146 | if (best.base == -1 || cur.len > best.len) 147 | best = cur; 148 | cur.base = -1; 149 | } 150 | } 151 | } 152 | if (cur.base != -1) { 153 | if (best.base == -1 || cur.len > best.len) 154 | best = cur; 155 | } 156 | if (best.base != -1 && best.len < 2) 157 | best.base = -1; 158 | 159 | /* 160 | * Format the result. 161 | */ 162 | tp = tmp; 163 | for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 164 | /* Are we inside the best run of 0x00's? */ 165 | if (best.base != -1 && i >= best.base && 166 | i < (best.base + best.len)) { 167 | if (i == best.base) 168 | *tp++ = ':'; 169 | continue; 170 | } 171 | /* Are we following an initial run of 0x00s or any real hex? */ 172 | if (i != 0) 173 | *tp++ = ':'; 174 | /* Is this address an encapsulated IPv4? */ 175 | if (i == 6 && best.base == 0 && 176 | (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { 177 | if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) 178 | return (NULL); 179 | tp += strlen(tp); 180 | break; 181 | } 182 | tp += sprintf(tp, "%x", words[i]); 183 | } 184 | /* Was it a trailing run of 0x00's? */ 185 | if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) 186 | *tp++ = ':'; 187 | *tp++ = '\0'; 188 | 189 | /* 190 | * Check for overflow, copy, and we're done. 191 | */ 192 | if ((size_t)(tp - tmp) > size) { 193 | errno = ENOSPC; 194 | return (NULL); 195 | } 196 | strcpy(dst, tmp); 197 | return (dst); 198 | }