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