source: rtems-libbsd/freebsd-userspace/lib/libc/inet/inet_net_pton.c @ 7b1b5b8

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 7b1b5b8 was 7b1b5b8, checked in by Joel Sherrill <joel.sherrill@…>, on 09/06/12 at 15:35:02

Revert patches moving include of port_local.h to top of file

This was covering up rtems-bsd-config.h.in undefining P. These
files can remain closer to the FreeBSD originals.

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