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