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