Back to index

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