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