1 /*        $NetBSD: inet_pton.c,v 1.8 2012/03/13 21:13:38 christos Exp $         */
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 <sys/cdefs.h>
21 #if defined(LIBC_SCCS) && !defined(lint)
22 #if 0
23 static const char rcsid[] = "Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp";
24 #else
25 __RCSID("$NetBSD: inet_pton.c,v 1.8 2012/03/13 21:13:38 christos Exp $");
26 #endif
27 #endif /* LIBC_SCCS and not lint */
28 
29 #include "port_before.h"
30 
31 #include "namespace.h"
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <arpa/nameser.h>
38 #include <stddef.h>
39 #include <string.h>
40 #include <assert.h>
41 #include <ctype.h>
42 #include <errno.h>
43 
44 #include "port_after.h"
45 
46 #ifdef __weak_alias
47 __weak_alias(inet_pton,_inet_pton)
48 #endif
49 
50 /*%
51  * WARNING: Don't even consider trying to compile this on a system where
52  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
53  */
54 
55 static int          inet_pton4(const char *src, u_char *dst, int pton);
56 static int          inet_pton6(const char *src, u_char *dst);
57 
58 /* int
59  * inet_pton(af, src, dst)
60  *        convert from presentation format (which usually means ASCII printable)
61  *        to network format (which is usually some kind of binary format).
62  * return:
63  *        1 if the address was valid for the specified address family
64  *        0 if the address wasn't valid (`dst' is untouched in this case)
65  *        -1 if some other error occurred (`dst' is untouched in this case, too)
66  * author:
67  *        Paul Vixie, 1996.
68  */
69 int
inet_pton(int af,const char * src,void * dst)70 inet_pton(int af, const char *src, void *dst)
71 {
72 
73           _DIAGASSERT(src != NULL);
74           _DIAGASSERT(dst != NULL);
75 
76           switch (af) {
77           case AF_INET:
78                     return (inet_pton4(src, dst, 1));
79           case AF_INET6:
80                     return (inet_pton6(src, dst));
81           default:
82                     errno = EAFNOSUPPORT;
83                     return (-1);
84           }
85           /* NOTREACHED */
86 }
87 
88 /* int
89  * inet_pton4(src, dst, pton)
90  *        when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
91  *        when last arg is 1: inet_pton(). decimal dotted-quad only.
92  * return:
93  *        1 if `src' is a valid input, else 0.
94  * notice:
95  *        does not touch `dst' unless it's returning 1.
96  * author:
97  *        Paul Vixie, 1996.
98  */
99 static int
inet_pton4(const char * src,u_char * dst,int pton)100 inet_pton4(const char *src, u_char *dst, int pton)
101 {
102           u_int32_t val;
103           u_int digit, base;
104           ptrdiff_t n;
105           unsigned char c;
106           u_int parts[4];
107           u_int *pp = parts;
108 
109           _DIAGASSERT(src != NULL);
110           _DIAGASSERT(dst != NULL);
111 
112           c = *src;
113           for (;;) {
114                     /*
115                      * Collect number up to ``.''.
116                      * Values are specified as for C:
117                      * 0x=hex, 0=octal, isdigit=decimal.
118                      */
119                     if (!isdigit(c))
120                               return (0);
121                     val = 0; base = 10;
122                     if (c == '0') {
123                               c = *++src;
124                               if (c == 'x' || c == 'X')
125                                         base = 16, c = *++src;
126                               else if (isdigit(c) && c != '9')
127                                         base = 8;
128                     }
129                     /* inet_pton() takes decimal only */
130                     if (pton && base != 10)
131                               return (0);
132                     for (;;) {
133                               if (isdigit(c)) {
134                                         digit = c - '0';
135                                         if (digit >= base)
136                                                   break;
137                                         val = (val * base) + digit;
138                                         c = *++src;
139                               } else if (base == 16 && isxdigit(c)) {
140                                         digit = c + 10 - (islower(c) ? 'a' : 'A');
141                                         if (digit >= 16)
142                                                   break;
143                                         val = (val << 4) | digit;
144                                         c = *++src;
145                               } else
146                                         break;
147                     }
148                     if (c == '.') {
149                               /*
150                                * Internet format:
151                                *        a.b.c.d
152                                *        a.b.c     (with c treated as 16 bits)
153                                *        a.b       (with b treated as 24 bits)
154                                *        a         (with a treated as 32 bits)
155                                */
156                               if (pp >= parts + 3)
157                                         return (0);
158                               *pp++ = val;
159                               c = *++src;
160                     } else
161                               break;
162           }
163           /*
164            * Check for trailing characters.
165            */
166           if (c != '\0' && !isspace(c))
167                     return (0);
168           /*
169            * Concoct the address according to
170            * the number of parts specified.
171            */
172           n = pp - parts + 1;
173           /* inet_pton() takes dotted-quad only.  it does not take shorthand. */
174           if (pton && n != 4)
175                     return (0);
176           switch (n) {
177 
178           case 0:
179                     return (0);                   /* initial nondigit */
180 
181           case 1:                                 /* a -- 32 bits */
182                     break;
183 
184           case 2:                                 /* a.b -- 8.24 bits */
185                     if (parts[0] > 0xff || val > 0xffffff)
186                               return (0);
187                     val |= parts[0] << 24;
188                     break;
189 
190           case 3:                                 /* a.b.c -- 8.8.16 bits */
191                     if ((parts[0] | parts[1]) > 0xff || val > 0xffff)
192                               return (0);
193                     val |= (parts[0] << 24) | (parts[1] << 16);
194                     break;
195 
196           case 4:                                 /* a.b.c.d -- 8.8.8.8 bits */
197                     if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
198                               return (0);
199                     val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
200                     break;
201           }
202           if (dst) {
203                     val = htonl(val);
204                     memcpy(dst, &val, NS_INADDRSZ);
205           }
206           return (1);
207 }
208 
209 /* int
210  * inet_pton6(src, dst)
211  *        convert presentation level address to network order binary form.
212  * return:
213  *        1 if `src' is a valid [RFC1884 2.2] address, else 0.
214  * notice:
215  *        (1) does not touch `dst' unless it's returning 1.
216  *        (2) :: in a full address is silently ignored.
217  * credit:
218  *        inspired by Mark Andrews.
219  * author:
220  *        Paul Vixie, 1996.
221  */
222 static int
inet_pton6(const char * src,u_char * dst)223 inet_pton6(const char *src, u_char *dst)
224 {
225           static const char xdigits_l[] = "0123456789abcdef",
226                                 xdigits_u[] = "0123456789ABCDEF";
227           u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
228           const char *xdigits, *curtok;
229           int ch, seen_xdigits;
230           u_int val;
231 
232           _DIAGASSERT(src != NULL);
233           _DIAGASSERT(dst != NULL);
234 
235           memset((tp = tmp), '\0', NS_IN6ADDRSZ);
236           endp = tp + NS_IN6ADDRSZ;
237           colonp = NULL;
238           /* Leading :: requires some special handling. */
239           if (*src == ':')
240                     if (*++src != ':')
241                               return (0);
242           curtok = src;
243           seen_xdigits = 0;
244           val = 0;
245           while ((ch = *src++) != '\0') {
246                     const char *pch;
247 
248                     if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
249                               pch = strchr((xdigits = xdigits_u), ch);
250                     if (pch != NULL) {
251                               val <<= 4;
252                               val |= (int)(pch - xdigits);
253                               if (++seen_xdigits > 4)
254                                         return (0);
255                               continue;
256                     }
257                     if (ch == ':') {
258                               curtok = src;
259                               if (!seen_xdigits) {
260                                         if (colonp)
261                                                   return (0);
262                                         colonp = tp;
263                                         continue;
264                               } else if (*src == '\0')
265                                         return (0);
266                               if (tp + NS_INT16SZ > endp)
267                                         return (0);
268                               *tp++ = (u_char) (val >> 8) & 0xff;
269                               *tp++ = (u_char) val & 0xff;
270                               seen_xdigits = 0;
271                               val = 0;
272                               continue;
273                     }
274                     if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
275                         inet_pton4(curtok, tp, 1) > 0) {
276                               tp += NS_INADDRSZ;
277                               seen_xdigits = 0;
278                               break;    /*%< '\\0' was seen by inet_pton4(). */
279                     }
280                     return (0);
281           }
282           if (seen_xdigits) {
283                     if (tp + NS_INT16SZ > endp)
284                               return (0);
285                     *tp++ = (u_char) (val >> 8) & 0xff;
286                     *tp++ = (u_char) val & 0xff;
287           }
288           if (colonp != NULL) {
289                     /*
290                      * Since some memmove()'s erroneously fail to handle
291                      * overlapping regions, we'll do the shift by hand.
292                      */
293                     const ptrdiff_t n = tp - colonp;
294                     int i;
295 
296                     if (tp == endp)
297                               return (0);
298                     for (i = 1; i <= n; i++) {
299                               endp[- i] = colonp[n - i];
300                               colonp[n - i] = 0;
301                     }
302                     tp = endp;
303           }
304           if (tp != endp)
305                     return (0);
306           memcpy(dst, tmp, NS_IN6ADDRSZ);
307           return (1);
308 }
309 
310 /*! \file */
311