• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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