]> git.saurik.com Git - apple/libc.git/blobdiff - net/FreeBSD/inet_net_pton.c
Libc-498.1.5.tar.gz
[apple/libc.git] / net / FreeBSD / inet_net_pton.c
index 6958f17290008ea3eb58c930dc7d500473162372..5c6598b89e3f5f2f9c61751cd0fe49585ae37217 100644 (file)
@@ -1,29 +1,32 @@
 /*
- * Copyright (c) 1996 by Internet Software Consortium.
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static const char orig_rcsid[] = "From Id: inet_net_pton.c,v 1.8 1996/11/21 10:28:12 vixie Exp $";
+static const char rcsid[] = "$Id: inet_net_pton.c,v 1.7.18.1 2005/04/27 05:00:53 sra Exp $";
 #endif
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libc/net/inet_net_pton.c,v 1.9 2003/09/15 23:38:06 fenner Exp $");
+__FBSDID("$FreeBSD: src/lib/libc/inet/inet_net_pton.c,v 1.3 2007/06/03 17:20:26 ume Exp $");
+
+#include "port_before.h"
 
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <arpa/nameser.h>
 #include <arpa/inet.h>
 
 #include <assert.h>
@@ -33,44 +36,15 @@ __FBSDID("$FreeBSD: src/lib/libc/net/inet_net_pton.c,v 1.9 2003/09/15 23:38:06 f
 #include <string.h>
 #include <stdlib.h>
 
+#include "port_after.h"
+
 #ifdef SPRINTF_CHAR
 # define SPRINTF(x) strlen(sprintf/**/x)
 #else
 # define SPRINTF(x) ((size_t)sprintf x)
 #endif
 
-static int     inet_net_pton_ipv4(const char *src, u_char *dst, size_t size);
-
-/*
- * static int
- * inet_net_pton(af, src, dst, size)
- *     convert network number from presentation to network format.
- *     accepts hex octets, hex strings, decimal octets, and /CIDR.
- *     "size" is in bytes and describes "dst".
- * return:
- *     number of bits, either imputed classfully or specified with /CIDR,
- *     or -1 if some failure occurred (check errno).  ENOENT means it was
- *     not a valid network specification.
- * author:
- *     Paul Vixie (ISC), June 1996
- */
-int
-inet_net_pton(af, src, dst, size)
-       int af;
-       const char *src;
-       void *dst;
-       size_t size;
-{
-       switch (af) {
-       case AF_INET:
-               return (inet_net_pton_ipv4(src, dst, size));
-       default:
-               errno = EAFNOSUPPORT;
-               return (-1);
-       }
-}
-
-/*
+/*%
  * static int
  * inet_net_pton_ipv4(src, dst, size)
  *     convert IPv4 network number from presentation to network format.
@@ -82,46 +56,47 @@ inet_net_pton(af, src, dst, size)
  *     not an IPv4 network specification.
  * note:
  *     network byte order assumed.  this means 192.5.5.240/28 has
- *     0x11110000 in its fourth octet.
+ *     0b11110000 in its fourth octet.
  * author:
  *     Paul Vixie (ISC), June 1996
  */
 static int
-inet_net_pton_ipv4(src, dst, size)
-       const char *src;
-       u_char *dst;
-       size_t size;
-{
-       static const char
-               xdigits[] = "0123456789abcdef",
-               digits[] = "0123456789";
-       int n, ch, tmp, dirty, bits;
+inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {
+       static const char xdigits[] = "0123456789abcdef";
+       static const char digits[] = "0123456789";
+       int n, ch, tmp = 0, dirty, bits;
        const u_char *odst = dst;
 
        ch = *src++;
        if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
-           && isascii(src[1]) && isxdigit(src[1])) {
+           && isascii((unsigned char)(src[1]))
+           && isxdigit((unsigned char)(src[1]))) {
                /* Hexadecimal: Eat nybble string. */
-               if (size <= 0)
+               if (size <= 0U)
                        goto emsgsize;
-               *dst = 0, dirty = 0;
-               src++;  /* skip x or X. */
-               while ((ch = *src++) != '\0' &&
-                      isascii(ch) && isxdigit(ch)) {
+               dirty = 0;
+               src++;  /*%< skip x or X. */
+               while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) {
                        if (isupper(ch))
                                ch = tolower(ch);
                        n = strchr(xdigits, ch) - xdigits;
                        assert(n >= 0 && n <= 15);
-                       *dst |= n;
-                       if (!dirty++)
-                               *dst <<= 4;
-                       else if (size-- > 0)
-                               *++dst = 0, dirty = 0;
+                       if (dirty == 0)
+                               tmp = n;
                        else
+                               tmp = (tmp << 4) | n;
+                       if (++dirty == 2) {
+                               if (size-- <= 0U)
+                                       goto emsgsize;
+                               *dst++ = (u_char) tmp;
+                               dirty = 0;
+                       }
+               }
+               if (dirty) {  /*%< Odd trailing nybble? */
+                       if (size-- <= 0U)
                                goto emsgsize;
+                       *dst++ = (u_char) (tmp << 4);
                }
-               if (dirty)
-                       size--;
        } else if (isascii(ch) && isdigit(ch)) {
                /* Decimal: eat dotted digit string. */
                for (;;) {
@@ -135,7 +110,7 @@ inet_net_pton_ipv4(src, dst, size)
                                        goto enoent;
                        } while ((ch = *src++) != '\0' &&
                                 isascii(ch) && isdigit(ch));
-                       if (size-- <= 0)
+                       if (size-- <= 0U)
                                goto emsgsize;
                        *dst++ = (u_char) tmp;
                        if (ch == '\0' || ch == '/')
@@ -150,9 +125,10 @@ inet_net_pton_ipv4(src, dst, size)
                goto enoent;
 
        bits = -1;
-       if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
+       if (ch == '/' && isascii((unsigned char)(src[0])) &&
+           isdigit((unsigned char)(src[0])) && dst > odst) {
                /* CIDR width specifier.  Nothing can follow it. */
-               ch = *src++;    /* Skip over the /. */
+               ch = *src++;    /*%< Skip over the /. */
                bits = 0;
                do {
                        n = strchr(digits, ch) - digits;
@@ -175,23 +151,29 @@ inet_net_pton_ipv4(src, dst, size)
                goto enoent;
        /* If no CIDR spec was given, infer width from net class. */
        if (bits == -1) {
-               if (*odst >= 240)       /* Class E */
+               if (*odst >= 240)       /*%< Class E */
                        bits = 32;
-               else if (*odst >= 224)  /* Class D */
-                       bits = 4;
-               else if (*odst >= 192)  /* Class C */
+               else if (*odst >= 224)  /*%< Class D */
+                       bits = 8;
+               else if (*odst >= 192)  /*%< Class C */
                        bits = 24;
-               else if (*odst >= 128)  /* Class B */
+               else if (*odst >= 128)  /*%< Class B */
                        bits = 16;
-               else                    /* Class A */
+               else                    /*%< Class A */
                        bits = 8;
                /* If imputed mask is narrower than specified octets, widen. */
                if (bits < ((dst - odst) * 8))
                        bits = (dst - odst) * 8;
+               /*
+                * If there are no additional bits specified for a class D
+                * address adjust bits to 4.
+                */
+               if (bits == 8 && *odst == 224)
+                       bits = 4;
        }
        /* Extend network to cover the actual mask. */
        while (bits > ((dst - odst) * 8)) {
-               if (size-- <= 0)
+               if (size-- <= 0U)
                        goto emsgsize;
                *dst++ = '\0';
        }
@@ -206,9 +188,229 @@ inet_net_pton_ipv4(src, dst, size)
        return (-1);
 }
 
+static int
+getbits(const char *src, int *bitsp) {
+       static const char digits[] = "0123456789";
+       int n;
+       int val;
+       char ch;
+
+       val = 0;
+       n = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               pch = strchr(digits, ch);
+               if (pch != NULL) {
+                       if (n++ != 0 && val == 0)       /*%< no leading zeros */
+                               return (0);
+                       val *= 10;
+                       val += (pch - digits);
+                       if (val > 128)                  /*%< range */
+                               return (0);
+                       continue;
+               }
+               return (0);
+       }
+       if (n == 0)
+               return (0);
+       *bitsp = val;
+       return (1);
+}
+
+static int
+getv4(const char *src, u_char *dst, int *bitsp) {
+       static const char digits[] = "0123456789";
+       u_char *odst = dst;
+       int n;
+       u_int val;
+       char ch;
+
+       val = 0;
+       n = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               pch = strchr(digits, ch);
+               if (pch != NULL) {
+                       if (n++ != 0 && val == 0)       /*%< no leading zeros */
+                               return (0);
+                       val *= 10;
+                       val += (pch - digits);
+                       if (val > 255)                  /*%< range */
+                               return (0);
+                       continue;
+               }
+               if (ch == '.' || ch == '/') {
+                       if (dst - odst > 3)             /*%< too many octets? */
+                               return (0);
+                       *dst++ = val;
+                       if (ch == '/')
+                               return (getbits(src, bitsp));
+                       val = 0;
+                       n = 0;
+                       continue;
+               }
+               return (0);
+       }
+       if (n == 0)
+               return (0);
+       if (dst - odst > 3)             /*%< too many octets? */
+               return (0);
+       *dst++ = val;
+       return (1);
+}
+
+static int
+inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) {
+       static const char xdigits_l[] = "0123456789abcdef",
+                         xdigits_u[] = "0123456789ABCDEF";
+       u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+       const char *xdigits, *curtok;
+       int ch, saw_xdigit;
+       u_int val;
+       int digits;
+       int bits;
+       size_t bytes;
+       int words;
+       int ipv4;
+
+       memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+       endp = tp + NS_IN6ADDRSZ;
+       colonp = NULL;
+       /* Leading :: requires some special handling. */
+       if (*src == ':')
+               if (*++src != ':')
+                       goto enoent;
+       curtok = src;
+       saw_xdigit = 0;
+       val = 0;
+       digits = 0;
+       bits = -1;
+       ipv4 = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+                       pch = strchr((xdigits = xdigits_u), ch);
+               if (pch != NULL) {
+                       val <<= 4;
+                       val |= (pch - xdigits);
+                       if (++digits > 4)
+                               goto enoent;
+                       saw_xdigit = 1;
+                       continue;
+               }
+               if (ch == ':') {
+                       curtok = src;
+                       if (!saw_xdigit) {
+                               if (colonp)
+                                       goto enoent;
+                               colonp = tp;
+                               continue;
+                       } else if (*src == '\0')
+                               goto enoent;
+                       if (tp + NS_INT16SZ > endp)
+                               return (0);
+                       *tp++ = (u_char) (val >> 8) & 0xff;
+                       *tp++ = (u_char) val & 0xff;
+                       saw_xdigit = 0;
+                       digits = 0;
+                       val = 0;
+                       continue;
+               }
+               if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+                    getv4(curtok, tp, &bits) > 0) {
+                       tp += NS_INADDRSZ;
+                       saw_xdigit = 0;
+                       ipv4 = 1;
+                       break;  /*%< '\\0' was seen by inet_pton4(). */
+               }
+               if (ch == '/' && getbits(src, &bits) > 0)
+                       break;
+               goto enoent;
+       }
+       if (saw_xdigit) {
+               if (tp + NS_INT16SZ > endp)
+                       goto enoent;
+               *tp++ = (u_char) (val >> 8) & 0xff;
+               *tp++ = (u_char) val & 0xff;
+       }
+       if (bits == -1)
+               bits = 128;
+
+       words = (bits + 15) / 16;
+       if (words < 2)
+               words = 2;
+       if (ipv4)
+               words = 8;
+       endp =  tmp + 2 * words;
+
+       if (colonp != NULL) {
+               /*
+                * Since some memmove()'s erroneously fail to handle
+                * overlapping regions, we'll do the shift by hand.
+                */
+               const int n = tp - colonp;
+               int i;
+
+               if (tp == endp)
+                       goto enoent;
+               for (i = 1; i <= n; i++) {
+                       endp[- i] = colonp[n - i];
+                       colonp[n - i] = 0;
+               }
+               tp = endp;
+       }
+       if (tp != endp)
+               goto enoent;
+
+       bytes = (bits + 7) / 8;
+       if (bytes > size)
+               goto emsgsize;
+       memcpy(dst, tmp, bytes);
+       return (bits);
+
+ enoent:
+       errno = ENOENT;
+       return (-1);
+
+ emsgsize:
+       errno = EMSGSIZE;
+       return (-1);
+}
+
+/*%
+ * int
+ * inet_net_pton(af, src, dst, size)
+ *     convert network number from presentation to network format.
+ *     accepts hex octets, hex strings, decimal octets, and /CIDR.
+ *     "size" is in bytes and describes "dst".
+ * return:
+ *     number of bits, either imputed classfully or specified with /CIDR,
+ *     or -1 if some failure occurred (check errno).  ENOENT means it was
+ *     not a valid network specification.
+ * author:
+ *     Paul Vixie (ISC), June 1996
+ */
+int
+inet_net_pton(int af, const char *src, void *dst, size_t size) {
+       switch (af) {
+       case AF_INET:
+               return (inet_net_pton_ipv4(src, dst, size));
+       case AF_INET6:
+               return (inet_net_pton_ipv6(src, dst, size));
+       default:
+               errno = EAFNOSUPPORT;
+               return (-1);
+       }
+}
+
 /*
  * Weak aliases for applications that use certain private entry points,
  * and fail to include <arpa/inet.h>.
  */
 #undef inet_net_pton
 __weak_reference(__inet_net_pton, inet_net_pton);
+
+/*! \file */