net-snmp 5.7
inet_pton.c
00001 /*      Id: inet_pton.c,v 1.5 2001/04/13 15:24:35 lukem Exp     */
00002 /*      $NetBSD: inet_pton.c,v 1.16 2000/02/07 18:51:02 itojun Exp $    */
00003 
00004 /* Copyright (c) 1996 by Internet Software Consortium.
00005  *
00006  * Permission to use, copy, modify, and distribute this software for any
00007  * purpose with or without fee is hereby granted, provided that the above
00008  * copyright notice and this permission notice appear in all copies.
00009  *
00010  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
00011  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
00012  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
00013  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00014  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00015  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00016  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00017  * SOFTWARE.
00018  */
00019 
00020 #include <net-snmp/net-snmp-config.h>
00021 
00022 #include <ctype.h>
00023 
00024 #if HAVE_ARPA_NAMESER_H
00025 #include <arpa/nameser.h>
00026 #endif
00027 
00028 #include <errno.h>
00029 #include <stdio.h>
00030 #if HAVE_STRING_H
00031 #include <string.h>
00032 #else
00033 #include <strings.h>
00034 #endif
00035 
00036 #include <net-snmp/types.h>
00037 #include "inet_pton.h"
00038 
00039 #ifndef EAFNOSUPPORT
00040 #define EAFNOSUPPORT            WSAEAFNOSUPPORT
00041 #endif
00042 
00043 #ifndef IN6ADDRSZ
00044 #define IN6ADDRSZ       16
00045 #endif
00046 
00047 #ifndef INT16SZ
00048 #define INT16SZ         2
00049 #endif
00050 
00051 #ifndef INADDRSZ
00052 #define INADDRSZ        4
00053 #endif
00054 
00055 /*
00056  * WARNING: Don't even consider trying to compile this on a system where
00057  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
00058  */
00059 
00060 static int      inet_pton4(const char *src, u_char *dst, int pton);
00061 #ifdef NETSNMP_ENABLE_IPV6
00062 static int      inet_pton6(const char *src, u_char *dst);
00063 #endif
00064 
00065 /* int
00066  * inet_pton(af, src, dst)
00067  *      convert from presentation format (which usually means ASCII printable)
00068  *      to network format (which is usually some kind of binary format).
00069  * return:
00070  *      1 if the address was valid for the specified address family
00071  *      0 if the address wasn't valid (`dst' is untouched in this case)
00072  *      -1 if some other error occurred (`dst' is untouched in this case, too)
00073  * author:
00074  *      Paul Vixie, 1996.
00075  */
00076 int
00077 inet_pton(int af, const char *src, void *dst)
00078 {
00079 
00080         switch (af) {
00081         case AF_INET:
00082                 return (inet_pton4(src, dst, 1));
00083 #ifdef NETSNMP_ENABLE_IPV6
00084         case AF_INET6:
00085                 return (inet_pton6(src, dst));
00086 #endif
00087         default:
00088                 errno = EAFNOSUPPORT;
00089                 return (-1);
00090         }
00091         /* NOTREACHED */
00092 }
00093 
00094 /* int
00095  * inet_pton4(src, dst, pton)
00096  *      when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
00097  *      when last arg is 1: inet_pton(). decimal dotted-quad only.
00098  * return:
00099  *      1 if `src' is a valid input, else 0.
00100  * notice:
00101  *      does not touch `dst' unless it's returning 1.
00102  * author:
00103  *      Paul Vixie, 1996.
00104  */
00105 static int
00106 inet_pton4(const char *src, u_char *dst, int pton)
00107 {
00108         u_int val;
00109         u_int digit;
00110         int base, n;
00111         unsigned char c;
00112         u_int parts[4];
00113         register u_int *pp = parts;
00114 
00115         c = *src;
00116         for (;;) {
00117                 /*
00118                  * Collect number up to ``.''.
00119                  * Values are specified as for C:
00120                  * 0x=hex, 0=octal, isdigit=decimal.
00121                  */
00122                 if (!isdigit(c))
00123                         return (0);
00124                 val = 0; base = 10;
00125                 if (c == '0') {
00126                         c = *++src;
00127                         if (c == 'x' || c == 'X')
00128                                 base = 16, c = *++src;
00129                         else if (isdigit(c) && c != '9')
00130                                 base = 8;
00131                 }
00132                 /* inet_pton() takes decimal only */
00133                 if (pton && base != 10)
00134                         return (0);
00135                 for (;;) {
00136                         if (isdigit(c)) {
00137                                 digit = c - '0';
00138                                 if ((int)digit >= base)
00139                                         break;
00140                                 val = (val * base) + digit;
00141                                 c = *++src;
00142                         } else if (base == 16 && isxdigit(c)) {
00143                                 digit = c + 10 - (islower(c) ? 'a' : 'A');
00144                                 if (digit >= 16)
00145                                         break;
00146                                 val = (val << 4) | digit;
00147                                 c = *++src;
00148                         } else
00149                                 break;
00150                 }
00151                 if (c == '.') {
00152                         /*
00153                          * Internet format:
00154                          *      a.b.c.d
00155                          *      a.b.c   (with c treated as 16 bits)
00156                          *      a.b     (with b treated as 24 bits)
00157                          *      a       (with a treated as 32 bits)
00158                          */
00159                         if (pp >= parts + 3)
00160                                 return (0);
00161                         *pp++ = val;
00162                         c = *++src;
00163                 } else
00164                         break;
00165         }
00166         /*
00167          * Check for trailing characters.
00168          */
00169         if (c != '\0' && !isspace(c))
00170                 return (0);
00171         /*
00172          * Concoct the address according to
00173          * the number of parts specified.
00174          */
00175         n = pp - parts + 1;
00176         /* inet_pton() takes dotted-quad only.  it does not take shorthand. */
00177         if (pton && n != 4)
00178                 return (0);
00179         switch (n) {
00180 
00181         case 0:
00182                 return (0);             /* initial nondigit */
00183 
00184         case 1:                         /* a -- 32 bits */
00185                 break;
00186 
00187         case 2:                         /* a.b -- 8.24 bits */
00188                 if (parts[0] > 0xff || val > 0xffffff)
00189                         return (0);
00190                 val |= parts[0] << 24;
00191                 break;
00192 
00193         case 3:                         /* a.b.c -- 8.8.16 bits */
00194                 if ((parts[0] | parts[1]) > 0xff || val > 0xffff)
00195                         return (0);
00196                 val |= (parts[0] << 24) | (parts[1] << 16);
00197                 break;
00198 
00199         case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
00200                 if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
00201                         return (0);
00202                 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
00203                 break;
00204         }
00205         if (dst) {
00206                 val = htonl(val);
00207                 memcpy(dst, &val, INADDRSZ);
00208         }
00209         return (1);
00210 }
00211 
00212 #ifdef NETSNMP_ENABLE_IPV6
00213 /* int
00214  * inet_pton6(src, dst)
00215  *      convert presentation level address to network order binary form.
00216  * return:
00217  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
00218  * notice:
00219  *      (1) does not touch `dst' unless it's returning 1.
00220  *      (2) :: in a full address is silently ignored.
00221  * credit:
00222  *      inspired by Mark Andrews.
00223  * author:
00224  *      Paul Vixie, 1996.
00225  */
00226 static int
00227 inet_pton6(const char *src, u_char *dst)
00228 {
00229         static const char xdigits_l[] = "0123456789abcdef",
00230                           xdigits_u[] = "0123456789ABCDEF";
00231         u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
00232         const char *xdigits, *curtok;
00233         int ch, saw_xdigit;
00234         u_int val;
00235 
00236         memset((tp = tmp), '\0', IN6ADDRSZ);
00237         endp = tp + IN6ADDRSZ;
00238         colonp = NULL;
00239         /* Leading :: requires some special handling. */
00240         if (*src == ':')
00241                 if (*++src != ':')
00242                         return (0);
00243         curtok = src;
00244         saw_xdigit = 0;
00245         val = 0;
00246         while ((ch = *src++) != '\0') {
00247                 const char *pch;
00248 
00249                 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
00250                         pch = strchr((xdigits = xdigits_u), ch);
00251                 if (pch != NULL) {
00252                         val <<= 4;
00253                         val |= (pch - xdigits);
00254                         if (val > 0xffff)
00255                                 return (0);
00256                         saw_xdigit = 1;
00257                         continue;
00258                 }
00259                 if (ch == ':') {
00260                         curtok = src;
00261                         if (!saw_xdigit) {
00262                                 if (colonp)
00263                                         return (0);
00264                                 colonp = tp;
00265                                 continue;
00266                         } else if (*src == '\0')
00267                                 return (0);
00268                         if (tp + INT16SZ > endp)
00269                                 return (0);
00270                         *tp++ = (u_char) (val >> 8) & 0xff;
00271                         *tp++ = (u_char) val & 0xff;
00272                         saw_xdigit = 0;
00273                         val = 0;
00274                         continue;
00275                 }
00276                 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
00277                     inet_pton4(curtok, tp, 1) > 0) {
00278                         tp += INADDRSZ;
00279                         saw_xdigit = 0;
00280                         break;  /* '\0' was seen by inet_pton4(). */
00281                 }
00282                 return (0);
00283         }
00284         if (saw_xdigit) {
00285                 if (tp + INT16SZ > endp)
00286                         return (0);
00287                 *tp++ = (u_char) (val >> 8) & 0xff;
00288                 *tp++ = (u_char) val & 0xff;
00289         }
00290         if (colonp != NULL) {
00291                 /*
00292                  * Since some memmove()'s erroneously fail to handle
00293                  * overlapping regions, we'll do the shift by hand.
00294                  */
00295                 const int n = tp - colonp;
00296                 int i;
00297 
00298                 if (tp == endp)
00299                         return (0);
00300                 for (i = 1; i <= n; i++) {
00301                         endp[- i] = colonp[n - i];
00302                         colonp[n - i] = 0;
00303                 }
00304                 tp = endp;
00305         }
00306         if (tp != endp)
00307                 return (0);
00308         memcpy(dst, tmp, IN6ADDRSZ);
00309         return (1);
00310 }
00311 #endif