Back to index

glibc  2.9
inet_net_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_net_pton.c,v 1.11 1999/01/08 19:23:44 vixie Exp $";
00020 #endif
00021 
00022 #include <sys/types.h>
00023 #include <sys/socket.h>
00024 #include <netinet/in.h>
00025 #include <arpa/inet.h>
00026 
00027 #include <assert.h>
00028 #include <ctype.h>
00029 #include <errno.h>
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include <stdlib.h>
00033 
00034 #ifdef SPRINTF_CHAR
00035 # define SPRINTF(x) strlen(sprintfx)
00036 #else
00037 # define SPRINTF(x) ((size_t)sprintf x)
00038 #endif
00039 
00040 static int    inet_net_pton_ipv4 (const char *src, u_char *dst,
00041                                 size_t size) __THROW;
00042 
00043 /*
00044  * static int
00045  * inet_net_pton(af, src, dst, size)
00046  *     convert network number from presentation to network format.
00047  *     accepts hex octets, hex strings, decimal octets, and /CIDR.
00048  *     "size" is in bytes and describes "dst".
00049  * return:
00050  *     number of bits, either imputed classfully or specified with /CIDR,
00051  *     or -1 if some failure occurred (check errno).  ENOENT means it was
00052  *     not a valid network specification.
00053  * author:
00054  *     Paul Vixie (ISC), June 1996
00055  */
00056 int
00057 inet_net_pton(af, src, dst, size)
00058        int af;
00059        const char *src;
00060        void *dst;
00061        size_t size;
00062 {
00063        switch (af) {
00064        case AF_INET:
00065               return (inet_net_pton_ipv4(src, dst, size));
00066        default:
00067               __set_errno (EAFNOSUPPORT);
00068               return (-1);
00069        }
00070 }
00071 
00072 /*
00073  * static int
00074  * inet_net_pton_ipv4(src, dst, size)
00075  *     convert IPv4 network number from presentation to network format.
00076  *     accepts hex octets, hex strings, decimal octets, and /CIDR.
00077  *     "size" is in bytes and describes "dst".
00078  * return:
00079  *     number of bits, either imputed classfully or specified with /CIDR,
00080  *     or -1 if some failure occurred (check errno).  ENOENT means it was
00081  *     not an IPv4 network specification.
00082  * note:
00083  *     network byte order assumed.  this means 192.5.5.240/28 has
00084  *     0b11110000 in its fourth octet.
00085  * author:
00086  *     Paul Vixie (ISC), June 1996
00087  */
00088 static int
00089 inet_net_pton_ipv4(src, dst, size)
00090        const char *src;
00091        u_char *dst;
00092        size_t size;
00093 {
00094        static const char xdigits[] = "0123456789abcdef";
00095        int n, ch, tmp, dirty, bits;
00096        const u_char *odst = dst;
00097 
00098        ch = *src++;
00099        if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
00100            && isascii(src[1]) && isxdigit(src[1])) {
00101               /* Hexadecimal: Eat nybble string. */
00102               if (size <= 0)
00103                      goto emsgsize;
00104               dirty = 0;
00105               tmp = 0;      /* To calm down gcc.  */
00106               src++; /* skip x or X. */
00107               while (isxdigit((ch = *src++))) {
00108                      ch = _tolower(ch);
00109                      n = (const char *) __rawmemchr(xdigits, ch) - xdigits;
00110                      assert(n >= 0 && n <= 15);
00111                      if (dirty == 0)
00112                             tmp = n;
00113                      else
00114                             tmp = (tmp << 4) | n;
00115                      if (++dirty == 2) {
00116                             if (size-- <= 0)
00117                                    goto emsgsize;
00118                             *dst++ = (u_char) tmp;
00119                             dirty = 0;
00120                      }
00121               }
00122               if (dirty) {  /* Odd trailing nybble? */
00123                      if (size-- <= 0)
00124                             goto emsgsize;
00125                      *dst++ = (u_char) (tmp << 4);
00126               }
00127        } else if (isascii(ch) && isdigit(ch)) {
00128               /* Decimal: eat dotted digit string. */
00129               for (;;) {
00130                      tmp = 0;
00131                      do {
00132                             n = ((const char *) __rawmemchr(xdigits, ch)
00133                                  - xdigits);
00134                             assert(n >= 0 && n <= 9);
00135                             tmp *= 10;
00136                             tmp += n;
00137                             if (tmp > 255)
00138                                    goto enoent;
00139                      } while (isascii((ch = *src++)) && isdigit(ch));
00140                      if (size-- <= 0)
00141                             goto emsgsize;
00142                      *dst++ = (u_char) tmp;
00143                      if (ch == '\0' || ch == '/')
00144                             break;
00145                      if (ch != '.')
00146                             goto enoent;
00147                      ch = *src++;
00148                      if (!isascii(ch) || !isdigit(ch))
00149                             goto enoent;
00150               }
00151        } else
00152               goto enoent;
00153 
00154        bits = -1;
00155        if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
00156               /* CIDR width specifier.  Nothing can follow it. */
00157               ch = *src++;  /* Skip over the /. */
00158               bits = 0;
00159               do {
00160                      n = (const char *) __rawmemchr(xdigits, ch) - xdigits;
00161                      assert(n >= 0 && n <= 9);
00162                      bits *= 10;
00163                      bits += n;
00164               } while (isascii((ch = *src++)) && isdigit(ch));
00165               if (ch != '\0')
00166                      goto enoent;
00167               if (bits > 32)
00168                      goto emsgsize;
00169        }
00170 
00171        /* Firey death and destruction unless we prefetched EOS. */
00172        if (ch != '\0')
00173               goto enoent;
00174 
00175        /* If nothing was written to the destination, we found no address. */
00176        if (dst == odst)
00177               goto enoent;
00178        /* If no CIDR spec was given, infer width from net class. */
00179        if (bits == -1) {
00180               if (*odst >= 240)    /* Class E */
00181                      bits = 32;
00182               else if (*odst >= 224)      /* Class D */
00183                      bits = 4;
00184               else if (*odst >= 192)      /* Class C */
00185                      bits = 24;
00186               else if (*odst >= 128)      /* Class B */
00187                      bits = 16;
00188               else                 /* Class A */
00189                      bits = 8;
00190               /* If imputed mask is narrower than specified octets, widen. */
00191               if (bits >= 8 && bits < ((dst - odst) * 8))
00192                      bits = (dst - odst) * 8;
00193        }
00194        /* Extend network to cover the actual mask. */
00195        while (bits > ((dst - odst) * 8)) {
00196               if (size-- <= 0)
00197                      goto emsgsize;
00198               *dst++ = '\0';
00199        }
00200        return (bits);
00201 
00202  enoent:
00203        __set_errno (ENOENT);
00204        return (-1);
00205 
00206  emsgsize:
00207        __set_errno (EMSGSIZE);
00208        return (-1);
00209 }