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