• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org>
3  * Copyright (c) 1996,1999 by Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
10  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
12  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
15  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
16  * SOFTWARE.
17  *
18  * SPDX-License-Identifier: MIT
19  */
20 
21 #include "ares_setup.h"
22 
23 #ifdef HAVE_NETINET_IN_H
24 #  include <netinet/in.h>
25 #endif
26 #ifdef HAVE_ARPA_INET_H
27 #  include <arpa/inet.h>
28 #endif
29 
30 #include "ares_nameser.h"
31 
32 #include "ares.h"
33 #include "ares_ipv6.h"
34 #include "ares_inet_net_pton.h"
35 #include "ares_private.h"
36 
37 
38 const struct ares_in6_addr ares_in6addr_any = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0,
39                                                     0, 0, 0, 0, 0, 0, 0 } } };
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 losing the
57  *      actual last winsock error. So use macro ERRNO to fetch the
58  *      errno this function sets when returning (-1), not SOCKERRNO.
59  * author:
60  *      Paul Vixie (ISC), June 1996
61  */
ares_inet_net_pton_ipv4(const char * src,unsigned char * dst,size_t size)62 static int ares_inet_net_pton_ipv4(const char *src, unsigned char *dst,
63                                    size_t size)
64 {
65   static const char    xdigits[] = "0123456789abcdef";
66   static const char    digits[]  = "0123456789";
67   int                  n;
68   int                  ch;
69   int                  tmp = 0;
70   int                  dirty;
71   int                  bits;
72   const unsigned char *odst = dst;
73 
74   ch = *src++;
75   if (ch == '0' && (src[0] == 'x' || src[0] == 'X') && ISASCII(src[1]) &&
76       ISXDIGIT(src[1])) {
77     /* Hexadecimal: Eat nybble string. */
78     if (!size) {
79       goto emsgsize;
80     }
81     dirty = 0;
82     src++; /* skip x or X. */
83     while ((ch = *src++) != '\0' && ISASCII(ch) && ISXDIGIT(ch)) {
84       if (ISUPPER(ch)) {
85         ch = tolower(ch);
86       }
87       n = (int)(strchr(xdigits, ch) - xdigits);
88       if (dirty == 0) {
89         tmp = n;
90       } else {
91         tmp = (tmp << 4) | n;
92       }
93       if (++dirty == 2) {
94         if (!size--) {
95           goto emsgsize;
96         }
97         *dst++ = (unsigned char)tmp;
98         dirty  = 0;
99       }
100     }
101     if (dirty) { /* Odd trailing nybble? */
102       if (!size--) {
103         goto emsgsize;
104       }
105       *dst++ = (unsigned char)(tmp << 4);
106     }
107   } else if (ISASCII(ch) && ISDIGIT(ch)) {
108     /* Decimal: eat dotted digit string. */
109     for (;;) {
110       tmp = 0;
111       do {
112         n    = (int)(strchr(digits, ch) - digits);
113         tmp *= 10;
114         tmp += n;
115         if (tmp > 255) {
116           goto enoent;
117         }
118       } while ((ch = *src++) != '\0' && ISASCII(ch) && ISDIGIT(ch));
119       if (!size--) {
120         goto emsgsize;
121       }
122       *dst++ = (unsigned char)tmp;
123       if (ch == '\0' || ch == '/') {
124         break;
125       }
126       if (ch != '.') {
127         goto enoent;
128       }
129       ch = *src++;
130       if (!ISASCII(ch) || !ISDIGIT(ch)) {
131         goto enoent;
132       }
133     }
134   } else {
135     goto enoent;
136   }
137 
138   bits = -1;
139   if (ch == '/' && ISASCII(src[0]) && ISDIGIT(src[0]) && dst > odst) {
140     /* CIDR width specifier.  Nothing can follow it. */
141     ch   = *src++; /* Skip over the /. */
142     bits = 0;
143     do {
144       n     = (int)(strchr(digits, ch) - digits);
145       bits *= 10;
146       bits += n;
147       if (bits > 32) {
148         goto enoent;
149       }
150     } while ((ch = *src++) != '\0' && ISASCII(ch) && ISDIGIT(ch));
151     if (ch != '\0') {
152       goto enoent;
153     }
154   }
155 
156   /* Firey death and destruction unless we prefetched EOS. */
157   if (ch != '\0') {
158     goto enoent;
159   }
160 
161   /* If nothing was written to the destination, we found no address. */
162   if (dst == odst) {
163     goto enoent; /* LCOV_EXCL_LINE: all valid paths above increment dst */
164   }
165   /* If no CIDR spec was given, infer width from net class. */
166   if (bits == -1) {
167     if (*odst >= 240) {        /* Class E */
168       bits = 32;
169     } else if (*odst >= 224) { /* Class D */
170       bits = 8;
171     } else if (*odst >= 192) { /* Class C */
172       bits = 24;
173     } else if (*odst >= 128) { /* Class B */
174       bits = 16;
175     } else {                   /* Class A */
176       bits = 8;
177     }
178     /* If imputed mask is narrower than specified octets, widen. */
179     if (bits < ((dst - odst) * 8)) {
180       bits = (int)(dst - odst) * 8;
181     }
182     /*
183      * If there are no additional bits specified for a class D
184      * address adjust bits to 4.
185      */
186     if (bits == 8 && *odst == 224) {
187       bits = 4;
188     }
189   }
190   /* Extend network to cover the actual mask. */
191   while (bits > ((dst - odst) * 8)) {
192     if (!size--) {
193       goto emsgsize;
194     }
195     *dst++ = '\0';
196   }
197   return bits;
198 
199 enoent:
200   SET_ERRNO(ENOENT);
201   return -1;
202 
203 emsgsize:
204   SET_ERRNO(EMSGSIZE);
205   return -1;
206 }
207 
getbits(const char * src,size_t * bitsp)208 static int getbits(const char *src, size_t *bitsp)
209 {
210   static const char digits[] = "0123456789";
211   size_t            n;
212   size_t            val;
213   char              ch;
214 
215   val = 0;
216   n   = 0;
217   while ((ch = *src++) != '\0') {
218     const char *pch;
219 
220     pch = strchr(digits, ch);
221     if (pch != NULL) {
222       if (n++ != 0 && val == 0) { /* no leading zeros */
223         return 0;
224       }
225       val *= 10;
226       val += (size_t)(pch - digits);
227       if (val > 128) { /* range */
228         return 0;
229       }
230       continue;
231     }
232     return 0;
233   }
234   if (n == 0) {
235     return 0;
236   }
237   *bitsp = val;
238   return 1;
239 }
240 
ares_inet_pton6(const char * src,unsigned char * dst)241 static int ares_inet_pton6(const char *src, unsigned char *dst)
242 {
243   static const char xdigits_l[] = "0123456789abcdef";
244   static const char xdigits_u[] = "0123456789ABCDEF";
245   unsigned char     tmp[NS_IN6ADDRSZ];
246   unsigned char    *tp;
247   unsigned char    *endp;
248   unsigned char    *colonp;
249   const char       *xdigits;
250   const char       *curtok;
251   int               ch;
252   int               saw_xdigit;
253   int               count_xdigit;
254   unsigned int      val;
255 
256   memset((tp = tmp), '\0', NS_IN6ADDRSZ);
257   endp   = tp + NS_IN6ADDRSZ;
258   colonp = NULL;
259   /* Leading :: requires some special handling. */
260   if (*src == ':') {
261     if (*++src != ':') {
262       goto enoent;
263     }
264   }
265   curtok     = src;
266   saw_xdigit = count_xdigit = 0;
267   val                       = 0;
268   while ((ch = *src++) != '\0') {
269     const char *pch;
270 
271     if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) {
272       pch = strchr((xdigits = xdigits_u), ch);
273     }
274     if (pch != NULL) {
275       if (count_xdigit >= 4) {
276         goto enoent;
277       }
278       val <<= 4;
279       val  |= (unsigned int)(pch - xdigits);
280       if (val > 0xffff) {
281         goto enoent;
282       }
283       saw_xdigit = 1;
284       count_xdigit++;
285       continue;
286     }
287     if (ch == ':') {
288       curtok = src;
289       if (!saw_xdigit) {
290         if (colonp) {
291           goto enoent;
292         }
293         colonp = tp;
294         continue;
295       } else if (*src == '\0') {
296         goto enoent;
297       }
298       if (tp + NS_INT16SZ > endp) {
299         goto enoent;
300       }
301       *tp++        = (unsigned char)(val >> 8) & 0xff;
302       *tp++        = (unsigned char)val & 0xff;
303       saw_xdigit   = 0;
304       count_xdigit = 0;
305       val          = 0;
306       continue;
307     }
308     if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
309         ares_inet_net_pton_ipv4(curtok, tp, NS_INADDRSZ) > 0) {
310       tp         += NS_INADDRSZ;
311       saw_xdigit  = 0;
312       break; /* '\0' was seen by inet_pton4(). */
313     }
314     goto enoent;
315   }
316   if (saw_xdigit) {
317     if (tp + NS_INT16SZ > endp) {
318       goto enoent;
319     }
320     *tp++ = (unsigned char)(val >> 8) & 0xff;
321     *tp++ = (unsigned char)val & 0xff;
322   }
323   if (colonp != NULL) {
324     /*
325      * Since some memmove()'s erroneously fail to handle
326      * overlapping regions, we'll do the shift by hand.
327      */
328     const int n = (int)(tp - colonp);
329     int       i;
330 
331     if (tp == endp) {
332       goto enoent;
333     }
334     for (i = 1; i <= n; i++) {
335       endp[-i]      = colonp[n - i];
336       colonp[n - i] = 0;
337     }
338     tp = endp;
339   }
340   if (tp != endp) {
341     goto enoent;
342   }
343 
344   memcpy(dst, tmp, NS_IN6ADDRSZ);
345   return 1;
346 
347 enoent:
348   SET_ERRNO(ENOENT);
349   return -1;
350 }
351 
ares_inet_net_pton_ipv6(const char * src,unsigned char * dst,size_t size)352 static int ares_inet_net_pton_ipv6(const char *src, unsigned char *dst,
353                                    size_t size)
354 {
355   struct ares_in6_addr in6;
356   int                  ret;
357   size_t               bits;
358   size_t               bytes;
359   char                 buf[INET6_ADDRSTRLEN + sizeof("/128")];
360   char                *sep;
361 
362   if (ares_strlen(src) >= sizeof buf) {
363     SET_ERRNO(EMSGSIZE);
364     return -1;
365   }
366   ares_strcpy(buf, src, sizeof buf);
367 
368   sep = strchr(buf, '/');
369   if (sep != NULL) {
370     *sep++ = '\0';
371   }
372 
373   ret = ares_inet_pton6(buf, (unsigned char *)&in6);
374   if (ret != 1) {
375     return -1;
376   }
377 
378   if (sep == NULL) {
379     bits = 128;
380   } else {
381     if (!getbits(sep, &bits)) {
382       SET_ERRNO(ENOENT);
383       return -1;
384     }
385   }
386 
387   bytes = (bits + 7) / 8;
388   if (bytes > size) {
389     SET_ERRNO(EMSGSIZE);
390     return -1;
391   }
392   memcpy(dst, &in6, bytes);
393   return (int)bits;
394 }
395 
396 /*
397  * int
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".
402  * return:
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.
406  * note:
407  *      On Windows we store the error in the thread errno, not
408  *      in the winsock error code. This is to avoid losing the
409  *      actual last winsock error. So use macro ERRNO to fetch the
410  *      errno this function sets when returning (-1), not SOCKERRNO.
411  * author:
412  *      Paul Vixie (ISC), June 1996
413  */
ares_inet_net_pton(int af,const char * src,void * dst,size_t size)414 int ares_inet_net_pton(int af, const char *src, void *dst, size_t size)
415 {
416   switch (af) {
417     case AF_INET:
418       return ares_inet_net_pton_ipv4(src, dst, size);
419     case AF_INET6:
420       return ares_inet_net_pton_ipv6(src, dst, size);
421     default:
422       SET_ERRNO(EAFNOSUPPORT);
423       return -1;
424   }
425 }
426 
ares_inet_pton(int af,const char * src,void * dst)427 int ares_inet_pton(int af, const char *src, void *dst)
428 {
429   int    result;
430   size_t size;
431 
432   if (af == AF_INET) {
433     size = sizeof(struct in_addr);
434   } else if (af == AF_INET6) {
435     size = sizeof(struct ares_in6_addr);
436   } else {
437     SET_ERRNO(EAFNOSUPPORT);
438     return -1;
439   }
440   result = ares_inet_net_pton(af, src, dst, size);
441   if (result == -1 && ERRNO == ENOENT) {
442     return 0;
443   }
444   return (result > -1) ? 1 : -1;
445 }
446