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