[BACK]Return to inet_cidr_pton.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / inet

Annotation of src/lib/libc/inet/inet_cidr_pton.c, Revision 1.5

1.5     ! christos    1: /*     $NetBSD: inet_cidr_pton.c,v 1.4 2007/03/30 20:23:03 ghen Exp $  */
1.1       christos    2:
                      3: /*
                      4:  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
                      5:  * Copyright (c) 1998,1999 by Internet Software Consortium.
                      6:  *
                      7:  * Permission to use, copy, modify, and distribute this software for any
                      8:  * purpose with or without fee is hereby granted, provided that the above
                      9:  * copyright notice and this permission notice appear in all copies.
                     10:  *
                     11:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
                     12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     13:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
                     14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
                     17:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     18:  */
                     19:
1.2       christos   20: #include <sys/cdefs.h>
1.1       christos   21: #if defined(LIBC_SCCS) && !defined(lint)
1.2       christos   22: #if 0
1.5     ! christos   23: static const char rcsid[] = "Id: inet_cidr_pton.c,v 1.6 2005/04/27 04:56:19 sra Exp";
1.2       christos   24: #else
1.5     ! christos   25: __RCSID("$NetBSD: inet_cidr_pton.c,v 1.4 2007/03/30 20:23:03 ghen Exp $");
1.2       christos   26: #endif
1.1       christos   27: #endif
                     28:
                     29: #include "port_before.h"
                     30:
1.2       christos   31: #include "namespace.h"
1.1       christos   32: #include <sys/types.h>
                     33: #include <sys/socket.h>
                     34: #include <netinet/in.h>
                     35: #include <arpa/nameser.h>
                     36: #include <arpa/inet.h>
                     37:
                     38: #include <isc/assertions.h>
                     39: #include <ctype.h>
                     40: #include <errno.h>
                     41: #include <stdio.h>
                     42: #include <string.h>
                     43: #include <stdlib.h>
                     44:
                     45: #include "port_after.h"
                     46:
                     47: #ifdef SPRINTF_CHAR
                     48: # define SPRINTF(x) strlen(sprintf/**/x)
                     49: #else
                     50: # define SPRINTF(x) ((size_t)sprintf x)
                     51: #endif
                     52:
1.2       christos   53: #ifdef __weak_alias
                     54: __weak_alias(inet_cidr_pton,_inet_cidr_pton)
                     55: #endif
                     56:
1.1       christos   57: static int     inet_cidr_pton_ipv4 __P((const char *src, u_char *dst,
                     58:                                         int *bits, int ipv6));
                     59: static int     inet_cidr_pton_ipv6 __P((const char *src, u_char *dst,
                     60:                                         int *bits));
                     61:
                     62: static int     getbits(const char *, int ipv6);
                     63:
1.3       christos   64: /*%
1.1       christos   65:  * int
                     66:  * inet_cidr_pton(af, src, dst, *bits)
                     67:  *     convert network address from presentation to network format.
                     68:  *     accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
                     69:  *     "dst" is assumed large enough for its "af".  "bits" is set to the
                     70:  *     /CIDR prefix length, which can have defaults (like /32 for IPv4).
                     71:  * return:
                     72:  *     -1 if an error occurred (inspect errno; ENOENT means bad format).
                     73:  *     0 if successful conversion occurred.
                     74:  * note:
                     75:  *     192.5.5.1/28 has a nonzero host part, which means it isn't a network
                     76:  *     as called for by inet_net_pton() but it can be a host address with
                     77:  *     an included netmask.
                     78:  * author:
                     79:  *     Paul Vixie (ISC), October 1998
                     80:  */
                     81: int
                     82: inet_cidr_pton(int af, const char *src, void *dst, int *bits) {
                     83:        switch (af) {
                     84:        case AF_INET:
                     85:                return (inet_cidr_pton_ipv4(src, dst, bits, 0));
                     86:        case AF_INET6:
                     87:                return (inet_cidr_pton_ipv6(src, dst, bits));
                     88:        default:
                     89:                errno = EAFNOSUPPORT;
                     90:                return (-1);
                     91:        }
                     92: }
                     93:
                     94: static const char digits[] = "0123456789";
                     95:
                     96: static int
                     97: inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
                     98:        const u_char *odst = dst;
                     99:        int n, ch, tmp, bits;
                    100:        size_t size = 4;
                    101:
                    102:        /* Get the mantissa. */
                    103:        while (ch = *src++, (isascii(ch) && isdigit(ch))) {
                    104:                tmp = 0;
                    105:                do {
                    106:                        n = strchr(digits, ch) - digits;
                    107:                        INSIST(n >= 0 && n <= 9);
                    108:                        tmp *= 10;
                    109:                        tmp += n;
                    110:                        if (tmp > 255)
                    111:                                goto enoent;
                    112:                } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
                    113:                if (size-- == 0U)
                    114:                        goto emsgsize;
                    115:                *dst++ = (u_char) tmp;
                    116:                if (ch == '\0' || ch == '/')
                    117:                        break;
                    118:                if (ch != '.')
                    119:                        goto enoent;
                    120:        }
                    121:
                    122:        /* Get the prefix length if any. */
                    123:        bits = -1;
                    124:        if (ch == '/' && dst > odst) {
                    125:                bits = getbits(src, ipv6);
                    126:                if (bits == -2)
                    127:                        goto enoent;
                    128:        } else if (ch != '\0')
                    129:                goto enoent;
                    130:
                    131:        /* Prefix length can default to /32 only if all four octets spec'd. */
                    132:        if (bits == -1) {
                    133:                if (dst - odst == 4)
                    134:                        bits = ipv6 ? 128 : 32;
                    135:                else
                    136:                        goto enoent;
                    137:        }
                    138:
                    139:        /* If nothing was written to the destination, we found no address. */
                    140:        if (dst == odst)
                    141:                goto enoent;
                    142:
                    143:        /* If prefix length overspecifies mantissa, life is bad. */
                    144:        if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst))
                    145:                goto enoent;
                    146:
                    147:        /* Extend address to four octets. */
                    148:        while (size-- > 0U)
                    149:                *dst++ = 0;
                    150:
                    151:        *pbits = bits;
                    152:        return (0);
                    153:
                    154:  enoent:
                    155:        errno = ENOENT;
                    156:        return (-1);
                    157:
                    158:  emsgsize:
                    159:        errno = EMSGSIZE;
                    160:        return (-1);
                    161: }
                    162:
                    163: static int
                    164: inet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) {
                    165:        static const char xdigits_l[] = "0123456789abcdef",
                    166:                          xdigits_u[] = "0123456789ABCDEF";
                    167:        u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
                    168:        const char *xdigits, *curtok;
                    169:        int ch, saw_xdigit;
                    170:        u_int val;
                    171:        int bits;
                    172:
                    173:        memset((tp = tmp), '\0', NS_IN6ADDRSZ);
                    174:        endp = tp + NS_IN6ADDRSZ;
                    175:        colonp = NULL;
                    176:        /* Leading :: requires some special handling. */
                    177:        if (*src == ':')
                    178:                if (*++src != ':')
                    179:                        return (0);
                    180:        curtok = src;
                    181:        saw_xdigit = 0;
                    182:        val = 0;
                    183:        bits = -1;
                    184:        while ((ch = *src++) != '\0') {
                    185:                const char *pch;
                    186:
                    187:                if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
                    188:                        pch = strchr((xdigits = xdigits_u), ch);
                    189:                if (pch != NULL) {
                    190:                        val <<= 4;
                    191:                        val |= (pch - xdigits);
                    192:                        if (val > 0xffff)
                    193:                                return (0);
                    194:                        saw_xdigit = 1;
                    195:                        continue;
                    196:                }
                    197:                if (ch == ':') {
                    198:                        curtok = src;
                    199:                        if (!saw_xdigit) {
                    200:                                if (colonp)
                    201:                                        return (0);
                    202:                                colonp = tp;
                    203:                                continue;
                    204:                        } else if (*src == '\0') {
                    205:                                return (0);
                    206:                        }
                    207:                        if (tp + NS_INT16SZ > endp)
                    208:                                return (0);
                    209:                        *tp++ = (u_char) (val >> 8) & 0xff;
                    210:                        *tp++ = (u_char) val & 0xff;
                    211:                        saw_xdigit = 0;
                    212:                        val = 0;
                    213:                        continue;
                    214:                }
                    215:                if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
                    216:                    inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) {
                    217:                        tp += NS_INADDRSZ;
                    218:                        saw_xdigit = 0;
1.3       christos  219:                        break;  /*%< '\\0' was seen by inet_pton4(). */
1.1       christos  220:                }
                    221:                if (ch == '/') {
                    222:                        bits = getbits(src, 1);
                    223:                        if (bits == -2)
                    224:                                goto enoent;
                    225:                        break;
                    226:                }
                    227:                goto enoent;
                    228:        }
                    229:        if (saw_xdigit) {
                    230:                if (tp + NS_INT16SZ > endp)
                    231:                        goto emsgsize;
                    232:                *tp++ = (u_char) (val >> 8) & 0xff;
                    233:                *tp++ = (u_char) val & 0xff;
                    234:        }
                    235:        if (colonp != NULL) {
                    236:                /*
                    237:                 * Since some memmove()'s erroneously fail to handle
                    238:                 * overlapping regions, we'll do the shift by hand.
                    239:                 */
                    240:                const int n = tp - colonp;
                    241:                int i;
                    242:
                    243:                if (tp == endp)
                    244:                        goto enoent;
                    245:                for (i = 1; i <= n; i++) {
                    246:                        endp[- i] = colonp[n - i];
                    247:                        colonp[n - i] = 0;
                    248:                }
                    249:                tp = endp;
                    250:        }
                    251:
                    252:        memcpy(dst, tmp, NS_IN6ADDRSZ);
                    253:
                    254:        *pbits = bits;
                    255:        return (0);
                    256:
                    257:  enoent:
                    258:        errno = ENOENT;
                    259:        return (-1);
                    260:
                    261:  emsgsize:
                    262:        errno = EMSGSIZE;
                    263:        return (-1);
                    264: }
                    265:
                    266: static int
                    267: getbits(const char *src, int ipv6) {
                    268:        int bits = 0;
                    269:        char *cp, ch;
                    270:
1.3       christos  271:        if (*src == '\0')                       /*%< syntax */
1.1       christos  272:                return (-2);
                    273:        do {
                    274:                ch = *src++;
                    275:                cp = strchr(digits, ch);
1.3       christos  276:                if (cp == NULL)                 /*%< syntax */
1.1       christos  277:                        return (-2);
                    278:                bits *= 10;
                    279:                bits += cp - digits;
1.3       christos  280:                if (bits == 0 && *src != '\0')  /*%< no leading zeros */
1.1       christos  281:                        return (-2);
1.3       christos  282:                if (bits > (ipv6 ? 128 : 32))   /*%< range error */
1.1       christos  283:                        return (-2);
                    284:        } while (*src != '\0');
                    285:
                    286:        return (bits);
                    287: }
1.3       christos  288:
                    289: /*! \file */

CVSweb <webmaster@jp.NetBSD.org>