compat / inet_pton.con commit Merge branch 'jc/maint-1.6.0-diff-borrow-carefully' into maint-1.6.1 (3f3e2c2)
   1/*
   2 * Copyright (C) 1996-2001  Internet Software Consortium.
   3 *
   4 * Permission to use, copy, modify, and distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
   9 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  10 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  11 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  13 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  14 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  15 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18#include <errno.h>
  19#include <sys/types.h>
  20#include <sys/socket.h>
  21#include <netinet/in.h>
  22#include <arpa/inet.h>
  23#include <stdio.h>
  24#include <string.h>
  25
  26#ifndef NS_INT16SZ
  27#define NS_INT16SZ       2
  28#endif
  29
  30#ifndef NS_INADDRSZ
  31#define NS_INADDRSZ      4
  32#endif
  33
  34#ifndef NS_IN6ADDRSZ
  35#define NS_IN6ADDRSZ    16
  36#endif
  37
  38/*
  39 * WARNING: Don't even consider trying to compile this on a system where
  40 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
  41 */
  42
  43static int inet_pton4(const char *src, unsigned char *dst);
  44static int inet_pton6(const char *src, unsigned char *dst);
  45
  46/* int
  47 * inet_pton4(src, dst)
  48 *      like inet_aton() but without all the hexadecimal and shorthand.
  49 * return:
  50 *      1 if `src' is a valid dotted quad, else 0.
  51 * notice:
  52 *      does not touch `dst' unless it's returning 1.
  53 * author:
  54 *      Paul Vixie, 1996.
  55 */
  56static int
  57inet_pton4(const char *src, unsigned char *dst)
  58{
  59        static const char digits[] = "0123456789";
  60        int saw_digit, octets, ch;
  61        unsigned char tmp[NS_INADDRSZ], *tp;
  62
  63        saw_digit = 0;
  64        octets = 0;
  65        *(tp = tmp) = 0;
  66        while ((ch = *src++) != '\0') {
  67                const char *pch;
  68
  69                if ((pch = strchr(digits, ch)) != NULL) {
  70                        unsigned int new = *tp * 10 + (pch - digits);
  71
  72                        if (new > 255)
  73                                return (0);
  74                        *tp = new;
  75                        if (! saw_digit) {
  76                                if (++octets > 4)
  77                                        return (0);
  78                                saw_digit = 1;
  79                        }
  80                } else if (ch == '.' && saw_digit) {
  81                        if (octets == 4)
  82                                return (0);
  83                        *++tp = 0;
  84                        saw_digit = 0;
  85                } else
  86                        return (0);
  87        }
  88        if (octets < 4)
  89                return (0);
  90        memcpy(dst, tmp, NS_INADDRSZ);
  91        return (1);
  92}
  93
  94/* int
  95 * inet_pton6(src, dst)
  96 *      convert presentation level address to network order binary form.
  97 * return:
  98 *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
  99 * notice:
 100 *      (1) does not touch `dst' unless it's returning 1.
 101 *      (2) :: in a full address is silently ignored.
 102 * credit:
 103 *      inspired by Mark Andrews.
 104 * author:
 105 *      Paul Vixie, 1996.
 106 */
 107
 108#ifndef NO_IPV6
 109static int
 110inet_pton6(const char *src, unsigned char *dst)
 111{
 112        static const char xdigits_l[] = "0123456789abcdef",
 113                          xdigits_u[] = "0123456789ABCDEF";
 114        unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
 115        const char *xdigits, *curtok;
 116        int ch, saw_xdigit;
 117        unsigned int val;
 118
 119        memset((tp = tmp), '\0', NS_IN6ADDRSZ);
 120        endp = tp + NS_IN6ADDRSZ;
 121        colonp = NULL;
 122        /* Leading :: requires some special handling. */
 123        if (*src == ':')
 124                if (*++src != ':')
 125                        return (0);
 126        curtok = src;
 127        saw_xdigit = 0;
 128        val = 0;
 129        while ((ch = *src++) != '\0') {
 130                const char *pch;
 131
 132                if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
 133                        pch = strchr((xdigits = xdigits_u), ch);
 134                if (pch != NULL) {
 135                        val <<= 4;
 136                        val |= (pch - xdigits);
 137                        if (val > 0xffff)
 138                                return (0);
 139                        saw_xdigit = 1;
 140                        continue;
 141                }
 142                if (ch == ':') {
 143                        curtok = src;
 144                        if (!saw_xdigit) {
 145                                if (colonp)
 146                                        return (0);
 147                                colonp = tp;
 148                                continue;
 149                        }
 150                        if (tp + NS_INT16SZ > endp)
 151                                return (0);
 152                        *tp++ = (unsigned char) (val >> 8) & 0xff;
 153                        *tp++ = (unsigned char) val & 0xff;
 154                        saw_xdigit = 0;
 155                        val = 0;
 156                        continue;
 157                }
 158                if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
 159                    inet_pton4(curtok, tp) > 0) {
 160                        tp += NS_INADDRSZ;
 161                        saw_xdigit = 0;
 162                        break;  /* '\0' was seen by inet_pton4(). */
 163                }
 164                return (0);
 165        }
 166        if (saw_xdigit) {
 167                if (tp + NS_INT16SZ > endp)
 168                        return (0);
 169                *tp++ = (unsigned char) (val >> 8) & 0xff;
 170                *tp++ = (unsigned char) val & 0xff;
 171        }
 172        if (colonp != NULL) {
 173                /*
 174                 * Since some memmove()'s erroneously fail to handle
 175                 * overlapping regions, we'll do the shift by hand.
 176                 */
 177                const int n = tp - colonp;
 178                int i;
 179
 180                for (i = 1; i <= n; i++) {
 181                        endp[- i] = colonp[n - i];
 182                        colonp[n - i] = 0;
 183                }
 184                tp = endp;
 185        }
 186        if (tp != endp)
 187                return (0);
 188        memcpy(dst, tmp, NS_IN6ADDRSZ);
 189        return (1);
 190}
 191#endif
 192
 193/* int
 194 * isc_net_pton(af, src, dst)
 195 *      convert from presentation format (which usually means ASCII printable)
 196 *      to network format (which is usually some kind of binary format).
 197 * return:
 198 *      1 if the address was valid for the specified address family
 199 *      0 if the address wasn't valid (`dst' is untouched in this case)
 200 *      -1 if some other error occurred (`dst' is untouched in this case, too)
 201 * author:
 202 *      Paul Vixie, 1996.
 203 */
 204int
 205inet_pton(int af, const char *src, void *dst)
 206{
 207        switch (af) {
 208        case AF_INET:
 209                return (inet_pton4(src, dst));
 210#ifndef NO_IPV6
 211        case AF_INET6:
 212                return (inet_pton6(src, dst));
 213#endif
 214        default:
 215                errno = EAFNOSUPPORT;
 216                return (-1);
 217        }
 218        /* NOTREACHED */
 219}