source: rtems-libbsd/freebsd/lib/libc/inet/inet_net_pton.c @ d48955b

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since d48955b was d48955b, checked in by Sebastian Huber <sebastian.huber@…>, on 11/06/13 at 08:02:16

Add and use <machine/rtems-bsd-user-space.h>

  • Property mode set to 100644
File size: 9.5 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
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#if defined(LIBC_SCCS) && !defined(lint)
21static const char rcsid[] = "$Id: inet_net_pton.c,v 1.7.18.2 2008/08/26 04:42:43 marka Exp $";
22#endif
23#include <sys/cdefs.h>
24__FBSDID("$FreeBSD$");
25
26#include "port_before.h"
27
28#include <rtems/bsd/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 */
65static int
66inet_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
193static int
194getbits(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
223static int
224getv4(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
266static int
267inet_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 */
398int
399inet_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 */
Note: See TracBrowser for help on using the repository browser.