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