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