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