[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.9

1.9     ! maya        1: /*     $NetBSD: inet_cidr_pton.c,v 1.8 2012/03/20 17:08:13 matt 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.9     ! maya       25: __RCSID("$NetBSD: inet_cidr_pton.c,v 1.8 2012/03/20 17:08:13 matt 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>
1.7       christos   43: #include <stddef.h>
1.1       christos   44: #include <stdlib.h>
                     45:
                     46: #include "port_after.h"
                     47:
1.2       christos   48: #ifdef __weak_alias
                     49: __weak_alias(inet_cidr_pton,_inet_cidr_pton)
                     50: #endif
                     51:
1.8       matt       52: static int     inet_cidr_pton_ipv4(const char *src, u_char *dst,
                     53:                                         int *bits, int ipv6);
                     54: static int     inet_cidr_pton_ipv6(const char *src, u_char *dst, int *bits);
1.1       christos   55:
                     56: static int     getbits(const char *, int ipv6);
                     57:
1.3       christos   58: /*%
1.1       christos   59:  * int
                     60:  * inet_cidr_pton(af, src, dst, *bits)
                     61:  *     convert network address from presentation to network format.
                     62:  *     accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
                     63:  *     "dst" is assumed large enough for its "af".  "bits" is set to the
                     64:  *     /CIDR prefix length, which can have defaults (like /32 for IPv4).
                     65:  * return:
                     66:  *     -1 if an error occurred (inspect errno; ENOENT means bad format).
                     67:  *     0 if successful conversion occurred.
                     68:  * note:
                     69:  *     192.5.5.1/28 has a nonzero host part, which means it isn't a network
                     70:  *     as called for by inet_net_pton() but it can be a host address with
                     71:  *     an included netmask.
                     72:  * author:
                     73:  *     Paul Vixie (ISC), October 1998
                     74:  */
                     75: int
                     76: inet_cidr_pton(int af, const char *src, void *dst, int *bits) {
                     77:        switch (af) {
                     78:        case AF_INET:
                     79:                return (inet_cidr_pton_ipv4(src, dst, bits, 0));
                     80:        case AF_INET6:
                     81:                return (inet_cidr_pton_ipv6(src, dst, bits));
                     82:        default:
                     83:                errno = EAFNOSUPPORT;
                     84:                return (-1);
                     85:        }
                     86: }
                     87:
                     88: static const char digits[] = "0123456789";
                     89:
                     90: static int
                     91: inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
                     92:        const u_char *odst = dst;
1.7       christos   93:        int ch, bits;
                     94:        ptrdiff_t n, tmp;
1.1       christos   95:        size_t size = 4;
                     96:
                     97:        /* Get the mantissa. */
                     98:        while (ch = *src++, (isascii(ch) && isdigit(ch))) {
                     99:                tmp = 0;
                    100:                do {
                    101:                        n = strchr(digits, ch) - digits;
                    102:                        INSIST(n >= 0 && n <= 9);
                    103:                        tmp *= 10;
                    104:                        tmp += n;
                    105:                        if (tmp > 255)
                    106:                                goto enoent;
                    107:                } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
                    108:                if (size-- == 0U)
                    109:                        goto emsgsize;
                    110:                *dst++ = (u_char) tmp;
                    111:                if (ch == '\0' || ch == '/')
                    112:                        break;
                    113:                if (ch != '.')
                    114:                        goto enoent;
                    115:        }
                    116:
                    117:        /* Get the prefix length if any. */
                    118:        bits = -1;
                    119:        if (ch == '/' && dst > odst) {
                    120:                bits = getbits(src, ipv6);
                    121:                if (bits == -2)
                    122:                        goto enoent;
                    123:        } else if (ch != '\0')
                    124:                goto enoent;
                    125:
                    126:        /* Prefix length can default to /32 only if all four octets spec'd. */
                    127:        if (bits == -1) {
                    128:                if (dst - odst == 4)
                    129:                        bits = ipv6 ? 128 : 32;
                    130:                else
                    131:                        goto enoent;
                    132:        }
                    133:
                    134:        /* If nothing was written to the destination, we found no address. */
                    135:        if (dst == odst)
                    136:                goto enoent;
                    137:
                    138:        /* If prefix length overspecifies mantissa, life is bad. */
                    139:        if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst))
                    140:                goto enoent;
                    141:
                    142:        /* Extend address to four octets. */
                    143:        while (size-- > 0U)
                    144:                *dst++ = 0;
                    145:
                    146:        *pbits = bits;
                    147:        return (0);
                    148:
                    149:  enoent:
                    150:        errno = ENOENT;
                    151:        return (-1);
                    152:
                    153:  emsgsize:
                    154:        errno = EMSGSIZE;
                    155:        return (-1);
                    156: }
                    157:
                    158: static int
                    159: inet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) {
                    160:        static const char xdigits_l[] = "0123456789abcdef",
                    161:                          xdigits_u[] = "0123456789ABCDEF";
                    162:        u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
                    163:        const char *xdigits, *curtok;
                    164:        int ch, saw_xdigit;
                    165:        u_int val;
                    166:        int bits;
                    167:
                    168:        memset((tp = tmp), '\0', NS_IN6ADDRSZ);
                    169:        endp = tp + NS_IN6ADDRSZ;
                    170:        colonp = NULL;
                    171:        /* Leading :: requires some special handling. */
                    172:        if (*src == ':')
                    173:                if (*++src != ':')
                    174:                        return (0);
                    175:        curtok = src;
                    176:        saw_xdigit = 0;
                    177:        val = 0;
                    178:        bits = -1;
                    179:        while ((ch = *src++) != '\0') {
                    180:                const char *pch;
                    181:
                    182:                if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
                    183:                        pch = strchr((xdigits = xdigits_u), ch);
                    184:                if (pch != NULL) {
                    185:                        val <<= 4;
1.7       christos  186:                        val |= (int)(pch - xdigits);
1.1       christos  187:                        if (val > 0xffff)
                    188:                                return (0);
                    189:                        saw_xdigit = 1;
                    190:                        continue;
                    191:                }
                    192:                if (ch == ':') {
                    193:                        curtok = src;
                    194:                        if (!saw_xdigit) {
                    195:                                if (colonp)
                    196:                                        return (0);
                    197:                                colonp = tp;
                    198:                                continue;
                    199:                        } else if (*src == '\0') {
                    200:                                return (0);
                    201:                        }
                    202:                        if (tp + NS_INT16SZ > endp)
                    203:                                return (0);
                    204:                        *tp++ = (u_char) (val >> 8) & 0xff;
                    205:                        *tp++ = (u_char) val & 0xff;
                    206:                        saw_xdigit = 0;
                    207:                        val = 0;
                    208:                        continue;
                    209:                }
                    210:                if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
                    211:                    inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) {
                    212:                        tp += NS_INADDRSZ;
                    213:                        saw_xdigit = 0;
1.3       christos  214:                        break;  /*%< '\\0' was seen by inet_pton4(). */
1.1       christos  215:                }
                    216:                if (ch == '/') {
                    217:                        bits = getbits(src, 1);
                    218:                        if (bits == -2)
                    219:                                goto enoent;
                    220:                        break;
                    221:                }
                    222:                goto enoent;
                    223:        }
                    224:        if (saw_xdigit) {
                    225:                if (tp + NS_INT16SZ > endp)
                    226:                        goto emsgsize;
                    227:                *tp++ = (u_char) (val >> 8) & 0xff;
                    228:                *tp++ = (u_char) val & 0xff;
                    229:        }
                    230:        if (colonp != NULL) {
                    231:                /*
                    232:                 * Since some memmove()'s erroneously fail to handle
                    233:                 * overlapping regions, we'll do the shift by hand.
                    234:                 */
1.7       christos  235:                const ptrdiff_t n = tp - colonp;
1.1       christos  236:                int i;
                    237:
                    238:                if (tp == endp)
                    239:                        goto enoent;
                    240:                for (i = 1; i <= n; i++) {
                    241:                        endp[- i] = colonp[n - i];
                    242:                        colonp[n - i] = 0;
                    243:                }
                    244:                tp = endp;
                    245:        }
                    246:
                    247:        memcpy(dst, tmp, NS_IN6ADDRSZ);
                    248:
                    249:        *pbits = bits;
                    250:        return (0);
                    251:
                    252:  enoent:
                    253:        errno = ENOENT;
                    254:        return (-1);
                    255:
                    256:  emsgsize:
                    257:        errno = EMSGSIZE;
                    258:        return (-1);
                    259: }
                    260:
                    261: static int
                    262: getbits(const char *src, int ipv6) {
                    263:        int bits = 0;
                    264:        char *cp, ch;
                    265:
1.3       christos  266:        if (*src == '\0')                       /*%< syntax */
1.1       christos  267:                return (-2);
                    268:        do {
                    269:                ch = *src++;
                    270:                cp = strchr(digits, ch);
1.3       christos  271:                if (cp == NULL)                 /*%< syntax */
1.1       christos  272:                        return (-2);
                    273:                bits *= 10;
1.7       christos  274:                bits += (int)(cp - digits);
1.3       christos  275:                if (bits == 0 && *src != '\0')  /*%< no leading zeros */
1.1       christos  276:                        return (-2);
1.3       christos  277:                if (bits > (ipv6 ? 128 : 32))   /*%< range error */
1.1       christos  278:                        return (-2);
                    279:        } while (*src != '\0');
                    280:
                    281:        return (bits);
                    282: }
1.3       christos  283:
                    284: /*! \file */

CVSweb <webmaster@jp.NetBSD.org>