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