inet_net_pton.c (11608B)
1 /* 2 * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org> 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 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 * SPDX-License-Identifier: MIT 19 */ 20 21 #include "ares_private.h" 22 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 30 #include "ares_nameser.h" 31 32 #include "ares_ipv6.h" 33 #include "ares_inet_net_pton.h" 34 35 #ifdef USE_WINSOCK 36 # define SOCKERRNO ((int)WSAGetLastError()) 37 # define SET_SOCKERRNO(x) (WSASetLastError((int)(x))) 38 # undef EMSGSIZE 39 # define EMSGSIZE WSAEMSGSIZE 40 # undef ENOENT 41 # define ENOENT WSA_INVALID_PARAMETER 42 # undef EAFNOSUPPORT 43 # define EAFNOSUPPORT WSAEAFNOSUPPORT 44 #else 45 # define SOCKERRNO (errno) 46 # define SET_SOCKERRNO(x) (errno = (x)) 47 #endif 48 49 const struct ares_in6_addr ares_in6addr_any = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 50 0, 0, 0, 0, 0, 0, 0 } } }; 51 52 /* 53 * static int 54 * inet_net_pton_ipv4(src, dst, size) 55 * convert IPv4 network number from presentation to network format. 56 * accepts hex octets, hex strings, decimal octets, and /CIDR. 57 * "size" is in bytes and describes "dst". 58 * return: 59 * number of bits, either imputed classfully or specified with /CIDR, 60 * or -1 if some failure occurred (check errno). ENOENT means it was 61 * not an IPv4 network specification. 62 * note: 63 * network byte order assumed. this means 192.5.5.240/28 has 64 * 0b11110000 in its fourth octet. 65 * note: 66 * On Windows we store the error in the thread errno, not 67 * in the winsock error code. This is to avoid losing the 68 * actual last winsock error. So use macro ERRNO to fetch the 69 * errno this function sets when returning (-1), not SOCKERRNO. 70 * author: 71 * Paul Vixie (ISC), June 1996 72 */ 73 static int ares_inet_net_pton_ipv4(const char *src, unsigned char *dst, 74 size_t size) 75 { 76 static const char xdigits[] = "0123456789abcdef"; 77 static const char digits[] = "0123456789"; 78 int n; 79 int ch; 80 int tmp = 0; 81 int dirty; 82 int bits; 83 const unsigned char *odst = dst; 84 85 ch = *src++; 86 if (ch == '0' && (src[0] == 'x' || src[0] == 'X') && ares_isascii(src[1]) && 87 ares_isxdigit(src[1])) { 88 /* Hexadecimal: Eat nybble string. */ 89 if (!size) { 90 goto emsgsize; 91 } 92 dirty = 0; 93 src++; /* skip x or X. */ 94 while ((ch = *src++) != '\0' && ares_isascii(ch) && ares_isxdigit(ch)) { 95 if (ares_isupper(ch)) { 96 ch = ares_tolower((unsigned char)ch); 97 } 98 n = (int)(strchr(xdigits, ch) - xdigits); 99 if (dirty == 0) { 100 tmp = n; 101 } else { 102 tmp = (tmp << 4) | n; 103 } 104 if (++dirty == 2) { 105 if (!size--) { 106 goto emsgsize; 107 } 108 *dst++ = (unsigned char)tmp; 109 dirty = 0; 110 } 111 } 112 if (dirty) { /* Odd trailing nybble? */ 113 if (!size--) { 114 goto emsgsize; 115 } 116 *dst++ = (unsigned char)(tmp << 4); 117 } 118 } else if (ares_isascii(ch) && ares_isdigit(ch)) { 119 /* Decimal: eat dotted digit string. */ 120 for (;;) { 121 tmp = 0; 122 do { 123 n = (int)(strchr(digits, ch) - digits); 124 tmp *= 10; 125 tmp += n; 126 if (tmp > 255) { 127 goto enoent; 128 } 129 } while ((ch = *src++) != '\0' && ares_isascii(ch) && ares_isdigit(ch)); 130 if (!size--) { 131 goto emsgsize; 132 } 133 *dst++ = (unsigned char)tmp; 134 if (ch == '\0' || ch == '/') { 135 break; 136 } 137 if (ch != '.') { 138 goto enoent; 139 } 140 ch = *src++; 141 if (!ares_isascii(ch) || !ares_isdigit(ch)) { 142 goto enoent; 143 } 144 } 145 } else { 146 goto enoent; 147 } 148 149 bits = -1; 150 if (ch == '/' && ares_isascii(src[0]) && ares_isdigit(src[0]) && dst > odst) { 151 /* CIDR width specifier. Nothing can follow it. */ 152 ch = *src++; /* Skip over the /. */ 153 bits = 0; 154 do { 155 n = (int)(strchr(digits, ch) - digits); 156 bits *= 10; 157 bits += n; 158 if (bits > 32) { 159 goto enoent; 160 } 161 } while ((ch = *src++) != '\0' && ares_isascii(ch) && ares_isdigit(ch)); 162 if (ch != '\0') { 163 goto enoent; 164 } 165 } 166 167 /* Firey death and destruction unless we prefetched EOS. */ 168 if (ch != '\0') { 169 goto enoent; 170 } 171 172 /* If nothing was written to the destination, we found no address. */ 173 if (dst == odst) { 174 goto enoent; /* LCOV_EXCL_LINE: all valid paths above increment dst */ 175 } 176 /* If no CIDR spec was given, infer width from net class. */ 177 if (bits == -1) { 178 if (*odst >= 240) { /* Class E */ 179 bits = 32; 180 } else if (*odst >= 224) { /* Class D */ 181 bits = 8; 182 } else if (*odst >= 192) { /* Class C */ 183 bits = 24; 184 } else if (*odst >= 128) { /* Class B */ 185 bits = 16; 186 } else { /* Class A */ 187 bits = 8; 188 } 189 /* If imputed mask is narrower than specified octets, widen. */ 190 if (bits < ((dst - odst) * 8)) { 191 bits = (int)(dst - odst) * 8; 192 } 193 /* 194 * If there are no additional bits specified for a class D 195 * address adjust bits to 4. 196 */ 197 if (bits == 8 && *odst == 224) { 198 bits = 4; 199 } 200 } 201 /* Extend network to cover the actual mask. */ 202 while (bits > ((dst - odst) * 8)) { 203 if (!size--) { 204 goto emsgsize; 205 } 206 *dst++ = '\0'; 207 } 208 return bits; 209 210 enoent: 211 SET_SOCKERRNO(ENOENT); 212 return -1; 213 214 emsgsize: 215 SET_SOCKERRNO(EMSGSIZE); 216 return -1; 217 } 218 219 static int getbits(const char *src, size_t *bitsp) 220 { 221 static const char digits[] = "0123456789"; 222 size_t n; 223 size_t val; 224 char ch; 225 226 val = 0; 227 n = 0; 228 while ((ch = *src++) != '\0') { 229 const char *pch; 230 231 pch = strchr(digits, ch); 232 if (pch != NULL) { 233 if (n++ != 0 && val == 0) { /* no leading zeros */ 234 return 0; 235 } 236 val *= 10; 237 val += (size_t)(pch - digits); 238 if (val > 128) { /* range */ 239 return 0; 240 } 241 continue; 242 } 243 return 0; 244 } 245 if (n == 0) { 246 return 0; 247 } 248 *bitsp = val; 249 return 1; 250 } 251 252 static int ares_inet_pton6(const char *src, unsigned char *dst) 253 { 254 static const char xdigits_l[] = "0123456789abcdef"; 255 static const char xdigits_u[] = "0123456789ABCDEF"; 256 unsigned char tmp[NS_IN6ADDRSZ]; 257 unsigned char *tp; 258 unsigned char *endp; 259 unsigned char *colonp; 260 const char *xdigits; 261 const char *curtok; 262 int ch; 263 int saw_xdigit; 264 int count_xdigit; 265 unsigned int val; 266 267 memset((tp = tmp), '\0', NS_IN6ADDRSZ); 268 endp = tp + NS_IN6ADDRSZ; 269 colonp = NULL; 270 /* Leading :: requires some special handling. */ 271 if (*src == ':') { 272 if (*++src != ':') { 273 goto enoent; 274 } 275 } 276 curtok = src; 277 saw_xdigit = count_xdigit = 0; 278 val = 0; 279 while ((ch = *src++) != '\0') { 280 const char *pch; 281 282 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) { 283 pch = strchr((xdigits = xdigits_u), ch); 284 } 285 if (pch != NULL) { 286 if (count_xdigit >= 4) { 287 goto enoent; 288 } 289 val <<= 4; 290 val |= (unsigned int)(pch - xdigits); 291 if (val > 0xffff) { 292 goto enoent; 293 } 294 saw_xdigit = 1; 295 count_xdigit++; 296 continue; 297 } 298 if (ch == ':') { 299 curtok = src; 300 if (!saw_xdigit) { 301 if (colonp) { 302 goto enoent; 303 } 304 colonp = tp; 305 continue; 306 } else if (*src == '\0') { 307 goto enoent; 308 } 309 if (tp + NS_INT16SZ > endp) { 310 goto enoent; 311 } 312 *tp++ = (unsigned char)(val >> 8) & 0xff; 313 *tp++ = (unsigned char)val & 0xff; 314 saw_xdigit = 0; 315 count_xdigit = 0; 316 val = 0; 317 continue; 318 } 319 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && 320 ares_inet_net_pton_ipv4(curtok, tp, NS_INADDRSZ) > 0) { 321 tp += NS_INADDRSZ; 322 saw_xdigit = 0; 323 break; /* '\0' was seen by inet_pton4(). */ 324 } 325 goto enoent; 326 } 327 if (saw_xdigit) { 328 if (tp + NS_INT16SZ > endp) { 329 goto enoent; 330 } 331 *tp++ = (unsigned char)(val >> 8) & 0xff; 332 *tp++ = (unsigned char)val & 0xff; 333 } 334 if (colonp != NULL) { 335 /* 336 * Since some memmove()'s erroneously fail to handle 337 * overlapping regions, we'll do the shift by hand. 338 */ 339 const int n = (int)(tp - colonp); 340 int i; 341 342 if (tp == endp) { 343 goto enoent; 344 } 345 for (i = 1; i <= n; i++) { 346 endp[-i] = colonp[n - i]; 347 colonp[n - i] = 0; 348 } 349 tp = endp; 350 } 351 if (tp != endp) { 352 goto enoent; 353 } 354 355 memcpy(dst, tmp, NS_IN6ADDRSZ); 356 return 1; 357 358 enoent: 359 SET_SOCKERRNO(ENOENT); 360 return -1; 361 } 362 363 static int ares_inet_net_pton_ipv6(const char *src, unsigned char *dst, 364 size_t size) 365 { 366 struct ares_in6_addr in6; 367 int ret; 368 size_t bits; 369 size_t bytes; 370 char buf[INET6_ADDRSTRLEN + sizeof("/128")]; 371 char *sep; 372 373 if (ares_strlen(src) >= sizeof buf) { 374 SET_SOCKERRNO(EMSGSIZE); 375 return -1; 376 } 377 ares_strcpy(buf, src, sizeof buf); 378 379 sep = strchr(buf, '/'); 380 if (sep != NULL) { 381 *sep++ = '\0'; 382 } 383 384 ret = ares_inet_pton6(buf, (unsigned char *)&in6); 385 if (ret != 1) { 386 return -1; 387 } 388 389 if (sep == NULL) { 390 bits = 128; 391 } else { 392 if (!getbits(sep, &bits)) { 393 SET_SOCKERRNO(ENOENT); 394 return -1; 395 } 396 } 397 398 bytes = (bits + 7) / 8; 399 if (bytes > size) { 400 SET_SOCKERRNO(EMSGSIZE); 401 return -1; 402 } 403 memcpy(dst, &in6, bytes); 404 return (int)bits; 405 } 406 407 /* 408 * int 409 * inet_net_pton(af, src, dst, size) 410 * convert network number from presentation to network format. 411 * accepts hex octets, hex strings, decimal octets, and /CIDR. 412 * "size" is in bytes and describes "dst". 413 * return: 414 * number of bits, either imputed classfully or specified with /CIDR, 415 * or -1 if some failure occurred (check errno). ENOENT means it was 416 * not a valid network specification. 417 * author: 418 * Paul Vixie (ISC), June 1996 419 * 420 */ 421 int ares_inet_net_pton(int af, const char *src, void *dst, size_t size) 422 { 423 switch (af) { 424 case AF_INET: 425 return ares_inet_net_pton_ipv4(src, dst, size); 426 case AF_INET6: 427 return ares_inet_net_pton_ipv6(src, dst, size); 428 default: 429 return -1; 430 } 431 } 432 433 int ares_inet_pton(int af, const char *src, void *dst) 434 { 435 int result; 436 size_t size; 437 438 if (af == AF_INET) { 439 size = sizeof(struct in_addr); 440 } else if (af == AF_INET6) { 441 size = sizeof(struct ares_in6_addr); 442 } else { 443 SET_SOCKERRNO(EAFNOSUPPORT); 444 return -1; 445 } 446 result = ares_inet_net_pton(af, src, dst, size); 447 if (result == -1 && SOCKERRNO == ENOENT) { 448 return 0; 449 } 450 return (result > -1) ? 1 : -1; 451 }