3 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
4 * Copyright (c) 1996,1999 by Internet Software Consortium.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include "ares_setup.h"
21 #ifdef HAVE_SYS_SOCKET_H
22 # include <sys/socket.h>
24 #ifdef HAVE_NETINET_IN_H
25 # include <netinet/in.h>
27 #ifdef HAVE_ARPA_INET_H
28 # include <arpa/inet.h>
30 #ifdef HAVE_ARPA_NAMESER_H
31 # include <arpa/nameser.h>
35 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
36 # include <arpa/nameser_compat.h>
46 #include "ares_ipv6.h"
47 #include "inet_net_pton.h"
50 const struct ares_in6_addr ares_in6addr_any = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
53 #if !defined(HAVE_INET_NET_PTON) || !defined(HAVE_INET_NET_PTON_IPV6)
57 * inet_net_pton_ipv4(src, dst, size)
58 * convert IPv4 network number from presentation to network format.
59 * accepts hex octets, hex strings, decimal octets, and /CIDR.
60 * "size" is in bytes and describes "dst".
62 * number of bits, either imputed classfully or specified with /CIDR,
63 * or -1 if some failure occurred (check errno). ENOENT means it was
64 * not an IPv4 network specification.
66 * network byte order assumed. this means 192.5.5.240/28 has
67 * 0b11110000 in its fourth octet.
69 * On Windows we store the error in the thread errno, not
70 * in the winsock error code. This is to avoid loosing the
71 * actual last winsock error. So use macro ERRNO to fetch the
72 * errno this funtion sets when returning (-1), not SOCKERRNO.
74 * Paul Vixie (ISC), June 1996
77 inet_net_pton_ipv4(const char *src, unsigned char *dst, size_t size)
79 static const char xdigits[] = "0123456789abcdef";
80 static const char digits[] = "0123456789";
81 int n, ch, tmp = 0, dirty, bits;
82 const unsigned char *odst = dst;
85 if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
86 && ISXDIGIT(src[1])) {
87 /* Hexadecimal: Eat nybble string. */
91 src++; /* skip x or X. */
92 while ((ch = *src++) != '\0' && ISXDIGIT(ch)) {
95 n = (int)(strchr(xdigits, ch) - xdigits);
103 *dst++ = (unsigned char) tmp;
107 if (dirty) { /* Odd trailing nybble? */
110 *dst++ = (unsigned char) (tmp << 4);
112 } else if (ISDIGIT(ch)) {
113 /* Decimal: eat dotted digit string. */
117 n = (int)(strchr(digits, ch) - digits);
122 } while ((ch = *src++) != '\0' &&
126 *dst++ = (unsigned char) tmp;
127 if (ch == '\0' || ch == '/')
140 ISDIGIT(src[0]) && dst > odst) {
141 /* CIDR width specifier. Nothing can follow it. */
142 ch = *src++; /* Skip over the /. */
145 n = (int)(strchr(digits, ch) - digits);
148 } while ((ch = *src++) != '\0' && ISDIGIT(ch));
155 /* Firey death and destruction unless we prefetched EOS. */
159 /* If nothing was written to the destination, we found no address. */
162 /* If no CIDR spec was given, infer width from net class. */
164 if (*odst >= 240) /* Class E */
166 else if (*odst >= 224) /* Class D */
168 else if (*odst >= 192) /* Class C */
170 else if (*odst >= 128) /* Class B */
174 /* If imputed mask is narrower than specified octets, widen. */
175 if (bits < ((dst - odst) * 8))
176 bits = (int)(dst - odst) * 8;
178 * If there are no additional bits specified for a class D
179 * address adjust bits to 4.
181 if (bits == 8 && *odst == 224)
184 /* Extend network to cover the actual mask. */
185 while (bits > ((dst - odst) * 8)) {
202 getbits(const char *src, int *bitsp)
204 static const char digits[] = "0123456789";
211 while ((ch = *src++) != '\0') {
214 pch = strchr(digits, ch);
216 if (n++ != 0 && val == 0) /* no leading zeros */
219 val += (pch - digits);
220 if (val > 128) /* range */
233 getv4(const char *src, unsigned char *dst, int *bitsp)
235 static const char digits[] = "0123456789";
236 unsigned char *odst = dst;
243 while ((ch = *src++) != '\0') {
246 pch = strchr(digits, ch);
248 if (n++ != 0 && val == 0) /* no leading zeros */
251 val += (pch - digits);
252 if (val > 255) /* range */
256 if (ch == '.' || ch == '/') {
257 if (dst - odst > 3) /* too many octets? */
259 *dst++ = (unsigned char)val;
261 return (getbits(src, bitsp));
270 if (dst - odst > 3) /* too many octets? */
272 *dst++ = (unsigned char)val;
277 inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size)
279 static const char xdigits_l[] = "0123456789abcdef",
280 xdigits_u[] = "0123456789ABCDEF";
281 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
282 const char *xdigits, *curtok;
291 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
292 endp = tp + NS_IN6ADDRSZ;
294 /* Leading :: requires some special handling. */
304 while ((ch = *src++) != '\0') {
307 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
308 pch = strchr((xdigits = xdigits_u), ch);
311 val |= (pch - xdigits);
324 } else if (*src == '\0')
326 if (tp + NS_INT16SZ > endp)
328 *tp++ = (unsigned char)((val >> 8) & 0xff);
329 *tp++ = (unsigned char)(val & 0xff);
335 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
336 getv4(curtok, tp, &bits) > 0) {
340 break; /* '\0' was seen by inet_pton4(). */
342 if (ch == '/' && getbits(src, &bits) > 0)
347 if (tp + NS_INT16SZ > endp)
349 *tp++ = (unsigned char)((val >> 8) & 0xff);
350 *tp++ = (unsigned char)(val & 0xff);
355 words = (bits + 15) / 16;
360 endp = tmp + 2 * words;
362 if (colonp != NULL) {
364 * Since some memmove()'s erroneously fail to handle
365 * overlapping regions, we'll do the shift by hand.
367 const int n = (int)(tp - colonp);
372 for (i = 1; i <= n; i++) {
373 endp[- i] = colonp[n - i];
381 bytes = (bits + 7) / 8;
384 memcpy(dst, tmp, bytes);
398 * inet_net_pton(af, src, dst, size)
399 * convert network number from presentation to network format.
400 * accepts hex octets, hex strings, decimal octets, and /CIDR.
401 * "size" is in bytes and describes "dst".
403 * number of bits, either imputed classfully or specified with /CIDR,
404 * or -1 if some failure occurred (check errno). ENOENT means it was
405 * not a valid network specification.
407 * On Windows we store the error in the thread errno, not
408 * in the winsock error code. This is to avoid loosing the
409 * actual last winsock error. So use macro ERRNO to fetch the
410 * errno this funtion sets when returning (-1), not SOCKERRNO.
412 * Paul Vixie (ISC), June 1996
415 ares_inet_net_pton(int af, const char *src, void *dst, size_t size)
419 return (inet_net_pton_ipv4(src, dst, size));
421 return (inet_net_pton_ipv6(src, dst, size));
423 SET_ERRNO(EAFNOSUPPORT);
430 #ifndef HAVE_INET_PTON
431 int ares_inet_pton(int af, const char *src, void *dst)
437 size = sizeof(struct in_addr);
438 else if (af == AF_INET6)
439 size = sizeof(struct ares_in6_addr);
442 SET_ERRNO(EAFNOSUPPORT);
445 result = ares_inet_net_pton(af, src, dst, size);
446 if (result == -1 && ERRNO == ENOENT)
448 return (result > -1 ? 1 : -1);