compat / inet_pton.con commit general improvements (43abf13)
   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 "../git-compat-util.h"
  19
  20#ifndef NS_INT16SZ
  21#define NS_INT16SZ       2
  22#endif
  23
  24#ifndef NS_INADDRSZ
  25#define NS_INADDRSZ      4
  26#endif
  27
  28#ifndef NS_IN6ADDRSZ
  29#define NS_IN6ADDRSZ    16
  30#endif
  31
  32/*
  33 * WARNING: Don't even consider trying to compile this on a system where
  34 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
  35 */
  36
  37static int inet_pton4(const char *src, unsigned char *dst);
  38#ifndef NO_IPV6
  39static int inet_pton6(const char *src, unsigned char *dst);
  40#endif
  41
  42/* int
  43 * inet_pton4(src, dst)
  44 *      like inet_aton() but without all the hexadecimal and shorthand.
  45 * return:
  46 *      1 if `src' is a valid dotted quad, else 0.
  47 * notice:
  48 *      does not touch `dst' unless it's returning 1.
  49 * author:
  50 *      Paul Vixie, 1996.
  51 */
  52static int
  53inet_pton4(const char *src, unsigned char *dst)
  54{
  55        static const char digits[] = "0123456789";
  56        int saw_digit, octets, ch;
  57        unsigned char tmp[NS_INADDRSZ], *tp;
  58
  59        saw_digit = 0;
  60        octets = 0;
  61        *(tp = tmp) = 0;
  62        while ((ch = *src++) != '\0') {
  63                const char *pch;
  64
  65                if ((pch = strchr(digits, ch)) != NULL) {
  66                        unsigned int new = *tp * 10 + (pch - digits);
  67
  68                        if (new > 255)
  69                                return (0);
  70                        *tp = new;
  71                        if (! saw_digit) {
  72                                if (++octets > 4)
  73                                        return (0);
  74                                saw_digit = 1;
  75                        }
  76                } else if (ch == '.' && saw_digit) {
  77                        if (octets == 4)
  78                                return (0);
  79                        *++tp = 0;
  80                        saw_digit = 0;
  81                } else
  82                        return (0);
  83        }
  84        if (octets < 4)
  85                return (0);
  86        memcpy(dst, tmp, NS_INADDRSZ);
  87        return (1);
  88}
  89
  90/* int
  91 * inet_pton6(src, dst)
  92 *      convert presentation level address to network order binary form.
  93 * return:
  94 *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
  95 * notice:
  96 *      (1) does not touch `dst' unless it's returning 1.
  97 *      (2) :: in a full address is silently ignored.
  98 * credit:
  99 *      inspired by Mark Andrews.
 100 * author:
 101 *      Paul Vixie, 1996.
 102 */
 103
 104#ifndef NO_IPV6
 105static int
 106inet_pton6(const char *src, unsigned char *dst)
 107{
 108        static const char xdigits_l[] = "0123456789abcdef",
 109                          xdigits_u[] = "0123456789ABCDEF";
 110        unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
 111        const char *xdigits, *curtok;
 112        int ch, saw_xdigit;
 113        unsigned int val;
 114
 115        memset((tp = tmp), '\0', NS_IN6ADDRSZ);
 116        endp = tp + NS_IN6ADDRSZ;
 117        colonp = NULL;
 118        /* Leading :: requires some special handling. */
 119        if (*src == ':')
 120                if (*++src != ':')
 121                        return (0);
 122        curtok = src;
 123        saw_xdigit = 0;
 124        val = 0;
 125        while ((ch = *src++) != '\0') {
 126                const char *pch;
 127
 128                if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
 129                        pch = strchr((xdigits = xdigits_u), ch);
 130                if (pch != NULL) {
 131                        val <<= 4;
 132                        val |= (pch - xdigits);
 133                        if (val > 0xffff)
 134                                return (0);
 135                        saw_xdigit = 1;
 136                        continue;
 137                }
 138                if (ch == ':') {
 139                        curtok = src;
 140                        if (!saw_xdigit) {
 141                                if (colonp)
 142                                        return (0);
 143                                colonp = tp;
 144                                continue;
 145                        }
 146                        if (tp + NS_INT16SZ > endp)
 147                                return (0);
 148                        *tp++ = (unsigned char) (val >> 8) & 0xff;
 149                        *tp++ = (unsigned char) val & 0xff;
 150                        saw_xdigit = 0;
 151                        val = 0;
 152                        continue;
 153                }
 154                if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
 155                    inet_pton4(curtok, tp) > 0) {
 156                        tp += NS_INADDRSZ;
 157                        saw_xdigit = 0;
 158                        break;  /* '\0' was seen by inet_pton4(). */
 159                }
 160                return (0);
 161        }
 162        if (saw_xdigit) {
 163                if (tp + NS_INT16SZ > endp)
 164                        return (0);
 165                *tp++ = (unsigned char) (val >> 8) & 0xff;
 166                *tp++ = (unsigned char) val & 0xff;
 167        }
 168        if (colonp != NULL) {
 169                /*
 170                 * Since some memmove()'s erroneously fail to handle
 171                 * overlapping regions, we'll do the shift by hand.
 172                 */
 173                const int n = tp - colonp;
 174                int i;
 175
 176                for (i = 1; i <= n; i++) {
 177                        endp[- i] = colonp[n - i];
 178                        colonp[n - i] = 0;
 179                }
 180                tp = endp;
 181        }
 182        if (tp != endp)
 183                return (0);
 184        memcpy(dst, tmp, NS_IN6ADDRSZ);
 185        return (1);
 186}
 187#endif
 188
 189/* int
 190 * isc_net_pton(af, src, dst)
 191 *      convert from presentation format (which usually means ASCII printable)
 192 *      to network format (which is usually some kind of binary format).
 193 * return:
 194 *      1 if the address was valid for the specified address family
 195 *      0 if the address wasn't valid (`dst' is untouched in this case)
 196 *      -1 if some other error occurred (`dst' is untouched in this case, too)
 197 * author:
 198 *      Paul Vixie, 1996.
 199 */
 200int
 201inet_pton(int af, const char *src, void *dst)
 202{
 203        switch (af) {
 204        case AF_INET:
 205                return (inet_pton4(src, dst));
 206#ifndef NO_IPV6
 207        case AF_INET6:
 208                return (inet_pton6(src, dst));
 209#endif
 210        default:
 211                errno = EAFNOSUPPORT;
 212                return (-1);
 213        }
 214        /* NOTREACHED */
 215}