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 "ares_setup.h" 19 20 #ifdef HAVE_SYS_SOCKET_H 21 # include <sys/socket.h> 22 #endif 23 #ifdef HAVE_NETINET_IN_H 24 # include <netinet/in.h> 25 #endif 26 #ifdef HAVE_ARPA_INET_H 27 # include <arpa/inet.h> 28 #endif 29 #ifdef HAVE_ARPA_NAMESER_H 30 # include <arpa/nameser.h> 31 #else 32 # include "nameser.h" 33 #endif 34 #ifdef HAVE_ARPA_NAMESER_COMPAT_H 35 # include <arpa/nameser_compat.h> 36 #endif 37 38 #include <ctype.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <stdlib.h> 42 43 #include "ares.h" 44 #include "ares_ipv6.h" 45 #include "inet_ntop.h" 46 47 48 #ifndef HAVE_INET_NTOP 49 50 /* 51 * WARNING: Don't even consider trying to compile this on a system where 52 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 53 */ 54 55 static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size); 56 static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size); 57 58 /* char * 59 * inet_ntop(af, src, dst, size) 60 * convert a network format address to presentation format. 61 * return: 62 * pointer to presentation format address (`dst'), or NULL (see errno). 63 * note: 64 * On Windows we store the error in the thread errno, not 65 * in the winsock error code. This is to avoid loosing the 66 * actual last winsock error. So use macro ERRNO to fetch the 67 * errno this funtion sets when returning NULL, not SOCKERRNO. 68 * author: 69 * Paul Vixie, 1996. 70 */ 71 const char * 72 ares_inet_ntop(int af, const void *src, char *dst, size_t size) 73 { 74 switch (af) { 75 case AF_INET: 76 return (inet_ntop4(src, dst, size)); 77 case AF_INET6: 78 return (inet_ntop6(src, dst, size)); 79 default: 80 SET_ERRNO(EAFNOSUPPORT); 81 return (NULL); 82 } 83 /* NOTREACHED */ 84 } 85 86 /* const char * 87 * inet_ntop4(src, dst, size) 88 * format an IPv4 address 89 * return: 90 * `dst' (as a const) 91 * notes: 92 * (1) uses no statics 93 * (2) takes a unsigned char* not an in_addr as input 94 * author: 95 * Paul Vixie, 1996. 96 */ 97 static const char * 98 inet_ntop4(const unsigned char *src, char *dst, size_t size) 99 { 100 static const char fmt[] = "%u.%u.%u.%u"; 101 char tmp[sizeof("255.255.255.255")]; 102 103 if ((size_t)sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) >= size) { 104 SET_ERRNO(ENOSPC); 105 return (NULL); 106 } 107 strcpy(dst, tmp); 108 return (dst); 109 } 110 111 /* const char * 112 * inet_ntop6(src, dst, size) 113 * convert IPv6 binary address into presentation (printable) format 114 * author: 115 * Paul Vixie, 1996. 116 */ 117 static const char * 118 inet_ntop6(const unsigned char *src, char *dst, size_t size) 119 { 120 /* 121 * Note that int32_t and int16_t need only be "at least" large enough 122 * to contain a value of the specified size. On some systems, like 123 * Crays, there is no such thing as an integer variable with 16 bits. 124 * Keep this in mind if you think this function should have been coded 125 * to use pointer overlays. All the world's not a VAX. 126 */ 127 char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; 128 char *tp; 129 struct { int base, len; } best, cur; 130 unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; 131 int i; 132 133 /* 134 * Preprocess: 135 * Copy the input (bytewise) array into a wordwise array. 136 * Find the longest run of 0x00's in src[] for :: shorthanding. 137 */ 138 memset(words, '\0', sizeof(words)); 139 for (i = 0; i < NS_IN6ADDRSZ; i++) 140 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); 141 best.base = -1; 142 best.len = 0; 143 cur.base = -1; 144 cur.len = 0; 145 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { 146 if (words[i] == 0) { 147 if (cur.base == -1) 148 cur.base = i, cur.len = 1; 149 else 150 cur.len++; 151 } else { 152 if (cur.base != -1) { 153 if (best.base == -1 || cur.len > best.len) 154 best = cur; 155 cur.base = -1; 156 } 157 } 158 } 159 if (cur.base != -1) { 160 if (best.base == -1 || cur.len > best.len) 161 best = cur; 162 } 163 if (best.base != -1 && best.len < 2) 164 best.base = -1; 165 166 /* 167 * Format the result. 168 */ 169 tp = tmp; 170 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { 171 /* Are we inside the best run of 0x00's? */ 172 if (best.base != -1 && i >= best.base && 173 i < (best.base + best.len)) { 174 if (i == best.base) 175 *tp++ = ':'; 176 continue; 177 } 178 /* Are we following an initial run of 0x00s or any real hex? */ 179 if (i != 0) 180 *tp++ = ':'; 181 /* Is this address an encapsulated IPv4? */ 182 if (i == 6 && best.base == 0 && (best.len == 6 || 183 (best.len == 7 && words[7] != 0x0001) || 184 (best.len == 5 && words[5] == 0xffff))) { 185 if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) 186 return (NULL); 187 tp += strlen(tp); 188 break; 189 } 190 tp += sprintf(tp, "%x", words[i]); 191 } 192 /* Was it a trailing run of 0x00's? */ 193 if (best.base != -1 && (best.base + best.len) == 194 (NS_IN6ADDRSZ / NS_INT16SZ)) 195 *tp++ = ':'; 196 *tp++ = '\0'; 197 198 /* 199 * Check for overflow, copy, and we're done. 200 */ 201 if ((size_t)(tp - tmp) > size) { 202 SET_ERRNO(ENOSPC); 203 return (NULL); 204 } 205 strcpy(dst, tmp); 206 return (dst); 207 } 208 #endif 209