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