inet_pton.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1996-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #if defined(LIBC_SCCS) && !defined(lint)
00021 static char rcsid[] =
00022         "$Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp $";
00023 #endif /* LIBC_SCCS and not lint */
00024 
00025 #include <config.h>
00026 
00027 #include <errno.h>
00028 #include <string.h>
00029 
00030 #include <isc/net.h>
00031 
00032 /*% INT16 Size */
00033 #define NS_INT16SZ       2
00034 /*% IPv4 Address Size */
00035 #define NS_INADDRSZ      4
00036 /*% IPv6 Address Size */
00037 #define NS_IN6ADDRSZ    16
00038 
00039 /*
00040  * WARNING: Don't even consider trying to compile this on a system where
00041  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
00042  */
00043 
00044 static int inet_pton4(const char *src, unsigned char *dst);
00045 static int inet_pton6(const char *src, unsigned char *dst);
00046 
00047 /*%
00048  *      convert from presentation format (which usually means ASCII printable)
00049  *      to network format (which is usually some kind of binary format).
00050  * \return
00051  *      1 if the address was valid for the specified address family
00052  *      0 if the address wasn't valid (`dst' is untouched in this case)
00053  *      -1 if some other error occurred (`dst' is untouched in this case, too)
00054  * \author
00055  *      Paul Vixie, 1996.
00056  */
00057 int
00058 isc_net_pton(int af, const char *src, void *dst) {
00059         switch (af) {
00060         case AF_INET:
00061                 return (inet_pton4(src, dst));
00062         case AF_INET6:
00063                 return (inet_pton6(src, dst));
00064         default:
00065                 errno = EAFNOSUPPORT;
00066                 return (-1);
00067         }
00068         /* NOTREACHED */
00069 }
00070 
00071 /*!\fn static int inet_pton4(const char *src, unsigned char *dst)
00072  * \brief
00073  *      like inet_aton() but without all the hexadecimal and shorthand.
00074  * \return
00075  *      1 if `src' is a valid dotted quad, else 0.
00076  * \note
00077  *      does not touch `dst' unless it's returning 1.
00078  * \author
00079  *      Paul Vixie, 1996.
00080  */
00081 static int
00082 inet_pton4(const char *src, unsigned char *dst) {
00083         static const char digits[] = "0123456789";
00084         int saw_digit, octets, ch;
00085         unsigned char tmp[NS_INADDRSZ], *tp;
00086 
00087         saw_digit = 0;
00088         octets = 0;
00089         *(tp = tmp) = 0;
00090         while ((ch = *src++) != '\0') {
00091                 const char *pch;
00092 
00093                 if ((pch = strchr(digits, ch)) != NULL) {
00094                         unsigned int new = *tp * 10;
00095 
00096                         new += (int)(pch - digits);
00097                         if (saw_digit && *tp == 0)
00098                                 return (0);
00099                         if (new > 255)
00100                                 return (0);
00101                         *tp = new;
00102                         if (!saw_digit) {
00103                                 if (++octets > 4)
00104                                         return (0);
00105                                 saw_digit = 1;
00106                         }
00107                 } else if (ch == '.' && saw_digit) {
00108                         if (octets == 4)
00109                                 return (0);
00110                         *++tp = 0;
00111                         saw_digit = 0;
00112                 } else
00113                         return (0);
00114         }
00115         if (octets < 4)
00116                 return (0);
00117         memmove(dst, tmp, NS_INADDRSZ);
00118         return (1);
00119 }
00120 
00121 /*%
00122  *      convert presentation level address to network order binary form.
00123  * \return
00124  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
00125  * \note
00126  *      (1) does not touch `dst' unless it's returning 1.
00127  * \note
00128  *      (2) :: in a full address is silently ignored.
00129  * \author
00130  *      inspired by Mark Andrews.
00131  * \author
00132  *      Paul Vixie, 1996.
00133  */
00134 static int
00135 inet_pton6(const char *src, unsigned char *dst) {
00136         static const char xdigits_l[] = "0123456789abcdef",
00137                           xdigits_u[] = "0123456789ABCDEF";
00138         unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
00139         const char *xdigits, *curtok;
00140         int ch, seen_xdigits;
00141         unsigned int val;
00142 
00143         memset((tp = tmp), '\0', NS_IN6ADDRSZ);
00144         endp = tp + NS_IN6ADDRSZ;
00145         colonp = NULL;
00146         /* Leading :: requires some special handling. */
00147         if (*src == ':')
00148                 if (*++src != ':')
00149                         return (0);
00150         curtok = src;
00151         seen_xdigits = 0;
00152         val = 0;
00153         while ((ch = *src++) != '\0') {
00154                 const char *pch;
00155 
00156                 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
00157                         pch = strchr((xdigits = xdigits_u), ch);
00158                 if (pch != NULL) {
00159                         val <<= 4;
00160                         val |= (pch - xdigits);
00161                         if (++seen_xdigits > 4)
00162                                 return (0);
00163                         continue;
00164                 }
00165                 if (ch == ':') {
00166                         curtok = src;
00167                         if (!seen_xdigits) {
00168                                 if (colonp)
00169                                         return (0);
00170                                 colonp = tp;
00171                                 continue;
00172                         }
00173                         if (tp + NS_INT16SZ > endp)
00174                                 return (0);
00175                         *tp++ = (unsigned char) (val >> 8) & 0xff;
00176                         *tp++ = (unsigned char) val & 0xff;
00177                         seen_xdigits = 0;
00178                         val = 0;
00179                         continue;
00180                 }
00181                 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
00182                     inet_pton4(curtok, tp) > 0) {
00183                         tp += NS_INADDRSZ;
00184                         seen_xdigits = 0;
00185                         break;  /* '\0' was seen by inet_pton4(). */
00186                 }
00187                 return (0);
00188         }
00189         if (seen_xdigits) {
00190                 if (tp + NS_INT16SZ > endp)
00191                         return (0);
00192                 *tp++ = (unsigned char) (val >> 8) & 0xff;
00193                 *tp++ = (unsigned char) val & 0xff;
00194         }
00195         if (colonp != NULL) {
00196                 /*
00197                  * Since some memmove()'s erroneously fail to handle
00198                  * overlapping regions, we'll do the shift by hand.
00199                  */
00200                 const int n = (int)(tp - colonp);
00201                 int i;
00202 
00203                 if (tp == endp)
00204                         return (0);
00205                 for (i = 1; i <= n; i++) {
00206                         endp[- i] = colonp[n - i];
00207                         colonp[n - i] = 0;
00208                 }
00209                 tp = endp;
00210         }
00211         if (tp != endp)
00212                 return (0);
00213         memmove(dst, tmp, NS_IN6ADDRSZ);
00214         return (1);
00215 }

Generated on Tue Apr 28 17:41:04 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha