quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

inet_net_pton.c (11608B)


      1 /*
      2  * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org>
      3  * Copyright (c) 1996,1999 by Internet Software Consortium.
      4  *
      5  * Permission to use, copy, modify, and distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
     10  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
     11  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
     12  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
     13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
     14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     15  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     16  * SOFTWARE.
     17  *
     18  * SPDX-License-Identifier: MIT
     19  */
     20 
     21 #include "ares_private.h"
     22 
     23 #ifdef HAVE_NETINET_IN_H
     24 #  include <netinet/in.h>
     25 #endif
     26 #ifdef HAVE_ARPA_INET_H
     27 #  include <arpa/inet.h>
     28 #endif
     29 
     30 #include "ares_nameser.h"
     31 
     32 #include "ares_ipv6.h"
     33 #include "ares_inet_net_pton.h"
     34 
     35 #ifdef USE_WINSOCK
     36 #  define SOCKERRNO        ((int)WSAGetLastError())
     37 #  define SET_SOCKERRNO(x) (WSASetLastError((int)(x)))
     38 #  undef EMSGSIZE
     39 #  define EMSGSIZE WSAEMSGSIZE
     40 #  undef ENOENT
     41 #  define ENOENT WSA_INVALID_PARAMETER
     42 #  undef EAFNOSUPPORT
     43 #  define EAFNOSUPPORT WSAEAFNOSUPPORT
     44 #else
     45 #  define SOCKERRNO        (errno)
     46 #  define SET_SOCKERRNO(x) (errno = (x))
     47 #endif
     48 
     49 const struct ares_in6_addr ares_in6addr_any = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0,
     50                                                     0, 0, 0, 0, 0, 0, 0 } } };
     51 
     52 /*
     53  * static int
     54  * inet_net_pton_ipv4(src, dst, size)
     55  *      convert IPv4 network number from presentation to network format.
     56  *      accepts hex octets, hex strings, decimal octets, and /CIDR.
     57  *      "size" is in bytes and describes "dst".
     58  * return:
     59  *      number of bits, either imputed classfully or specified with /CIDR,
     60  *      or -1 if some failure occurred (check errno).  ENOENT means it was
     61  *      not an IPv4 network specification.
     62  * note:
     63  *      network byte order assumed.  this means 192.5.5.240/28 has
     64  *      0b11110000 in its fourth octet.
     65  * note:
     66  *      On Windows we store the error in the thread errno, not
     67  *      in the winsock error code. This is to avoid losing the
     68  *      actual last winsock error. So use macro ERRNO to fetch the
     69  *      errno this function sets when returning (-1), not SOCKERRNO.
     70  * author:
     71  *      Paul Vixie (ISC), June 1996
     72  */
     73 static int ares_inet_net_pton_ipv4(const char *src, unsigned char *dst,
     74                                    size_t size)
     75 {
     76   static const char    xdigits[] = "0123456789abcdef";
     77   static const char    digits[]  = "0123456789";
     78   int                  n;
     79   int                  ch;
     80   int                  tmp = 0;
     81   int                  dirty;
     82   int                  bits;
     83   const unsigned char *odst = dst;
     84 
     85   ch = *src++;
     86   if (ch == '0' && (src[0] == 'x' || src[0] == 'X') && ares_isascii(src[1]) &&
     87       ares_isxdigit(src[1])) {
     88     /* Hexadecimal: Eat nybble string. */
     89     if (!size) {
     90       goto emsgsize;
     91     }
     92     dirty = 0;
     93     src++; /* skip x or X. */
     94     while ((ch = *src++) != '\0' && ares_isascii(ch) && ares_isxdigit(ch)) {
     95       if (ares_isupper(ch)) {
     96         ch = ares_tolower((unsigned char)ch);
     97       }
     98       n = (int)(strchr(xdigits, ch) - xdigits);
     99       if (dirty == 0) {
    100         tmp = n;
    101       } else {
    102         tmp = (tmp << 4) | n;
    103       }
    104       if (++dirty == 2) {
    105         if (!size--) {
    106           goto emsgsize;
    107         }
    108         *dst++ = (unsigned char)tmp;
    109         dirty  = 0;
    110       }
    111     }
    112     if (dirty) { /* Odd trailing nybble? */
    113       if (!size--) {
    114         goto emsgsize;
    115       }
    116       *dst++ = (unsigned char)(tmp << 4);
    117     }
    118   } else if (ares_isascii(ch) && ares_isdigit(ch)) {
    119     /* Decimal: eat dotted digit string. */
    120     for (;;) {
    121       tmp = 0;
    122       do {
    123         n    = (int)(strchr(digits, ch) - digits);
    124         tmp *= 10;
    125         tmp += n;
    126         if (tmp > 255) {
    127           goto enoent;
    128         }
    129       } while ((ch = *src++) != '\0' && ares_isascii(ch) && ares_isdigit(ch));
    130       if (!size--) {
    131         goto emsgsize;
    132       }
    133       *dst++ = (unsigned char)tmp;
    134       if (ch == '\0' || ch == '/') {
    135         break;
    136       }
    137       if (ch != '.') {
    138         goto enoent;
    139       }
    140       ch = *src++;
    141       if (!ares_isascii(ch) || !ares_isdigit(ch)) {
    142         goto enoent;
    143       }
    144     }
    145   } else {
    146     goto enoent;
    147   }
    148 
    149   bits = -1;
    150   if (ch == '/' && ares_isascii(src[0]) && ares_isdigit(src[0]) && dst > odst) {
    151     /* CIDR width specifier.  Nothing can follow it. */
    152     ch   = *src++; /* Skip over the /. */
    153     bits = 0;
    154     do {
    155       n     = (int)(strchr(digits, ch) - digits);
    156       bits *= 10;
    157       bits += n;
    158       if (bits > 32) {
    159         goto enoent;
    160       }
    161     } while ((ch = *src++) != '\0' && ares_isascii(ch) && ares_isdigit(ch));
    162     if (ch != '\0') {
    163       goto enoent;
    164     }
    165   }
    166 
    167   /* Firey death and destruction unless we prefetched EOS. */
    168   if (ch != '\0') {
    169     goto enoent;
    170   }
    171 
    172   /* If nothing was written to the destination, we found no address. */
    173   if (dst == odst) {
    174     goto enoent; /* LCOV_EXCL_LINE: all valid paths above increment dst */
    175   }
    176   /* If no CIDR spec was given, infer width from net class. */
    177   if (bits == -1) {
    178     if (*odst >= 240) {        /* Class E */
    179       bits = 32;
    180     } else if (*odst >= 224) { /* Class D */
    181       bits = 8;
    182     } else if (*odst >= 192) { /* Class C */
    183       bits = 24;
    184     } else if (*odst >= 128) { /* Class B */
    185       bits = 16;
    186     } else {                   /* Class A */
    187       bits = 8;
    188     }
    189     /* If imputed mask is narrower than specified octets, widen. */
    190     if (bits < ((dst - odst) * 8)) {
    191       bits = (int)(dst - odst) * 8;
    192     }
    193     /*
    194      * If there are no additional bits specified for a class D
    195      * address adjust bits to 4.
    196      */
    197     if (bits == 8 && *odst == 224) {
    198       bits = 4;
    199     }
    200   }
    201   /* Extend network to cover the actual mask. */
    202   while (bits > ((dst - odst) * 8)) {
    203     if (!size--) {
    204       goto emsgsize;
    205     }
    206     *dst++ = '\0';
    207   }
    208   return bits;
    209 
    210 enoent:
    211   SET_SOCKERRNO(ENOENT);
    212   return -1;
    213 
    214 emsgsize:
    215   SET_SOCKERRNO(EMSGSIZE);
    216   return -1;
    217 }
    218 
    219 static int getbits(const char *src, size_t *bitsp)
    220 {
    221   static const char digits[] = "0123456789";
    222   size_t            n;
    223   size_t            val;
    224   char              ch;
    225 
    226   val = 0;
    227   n   = 0;
    228   while ((ch = *src++) != '\0') {
    229     const char *pch;
    230 
    231     pch = strchr(digits, ch);
    232     if (pch != NULL) {
    233       if (n++ != 0 && val == 0) { /* no leading zeros */
    234         return 0;
    235       }
    236       val *= 10;
    237       val += (size_t)(pch - digits);
    238       if (val > 128) { /* range */
    239         return 0;
    240       }
    241       continue;
    242     }
    243     return 0;
    244   }
    245   if (n == 0) {
    246     return 0;
    247   }
    248   *bitsp = val;
    249   return 1;
    250 }
    251 
    252 static int ares_inet_pton6(const char *src, unsigned char *dst)
    253 {
    254   static const char xdigits_l[] = "0123456789abcdef";
    255   static const char xdigits_u[] = "0123456789ABCDEF";
    256   unsigned char     tmp[NS_IN6ADDRSZ];
    257   unsigned char    *tp;
    258   unsigned char    *endp;
    259   unsigned char    *colonp;
    260   const char       *xdigits;
    261   const char       *curtok;
    262   int               ch;
    263   int               saw_xdigit;
    264   int               count_xdigit;
    265   unsigned int      val;
    266 
    267   memset((tp = tmp), '\0', NS_IN6ADDRSZ);
    268   endp   = tp + NS_IN6ADDRSZ;
    269   colonp = NULL;
    270   /* Leading :: requires some special handling. */
    271   if (*src == ':') {
    272     if (*++src != ':') {
    273       goto enoent;
    274     }
    275   }
    276   curtok     = src;
    277   saw_xdigit = count_xdigit = 0;
    278   val                       = 0;
    279   while ((ch = *src++) != '\0') {
    280     const char *pch;
    281 
    282     if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) {
    283       pch = strchr((xdigits = xdigits_u), ch);
    284     }
    285     if (pch != NULL) {
    286       if (count_xdigit >= 4) {
    287         goto enoent;
    288       }
    289       val <<= 4;
    290       val  |= (unsigned int)(pch - xdigits);
    291       if (val > 0xffff) {
    292         goto enoent;
    293       }
    294       saw_xdigit = 1;
    295       count_xdigit++;
    296       continue;
    297     }
    298     if (ch == ':') {
    299       curtok = src;
    300       if (!saw_xdigit) {
    301         if (colonp) {
    302           goto enoent;
    303         }
    304         colonp = tp;
    305         continue;
    306       } else if (*src == '\0') {
    307         goto enoent;
    308       }
    309       if (tp + NS_INT16SZ > endp) {
    310         goto enoent;
    311       }
    312       *tp++        = (unsigned char)(val >> 8) & 0xff;
    313       *tp++        = (unsigned char)val & 0xff;
    314       saw_xdigit   = 0;
    315       count_xdigit = 0;
    316       val          = 0;
    317       continue;
    318     }
    319     if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
    320         ares_inet_net_pton_ipv4(curtok, tp, NS_INADDRSZ) > 0) {
    321       tp         += NS_INADDRSZ;
    322       saw_xdigit  = 0;
    323       break; /* '\0' was seen by inet_pton4(). */
    324     }
    325     goto enoent;
    326   }
    327   if (saw_xdigit) {
    328     if (tp + NS_INT16SZ > endp) {
    329       goto enoent;
    330     }
    331     *tp++ = (unsigned char)(val >> 8) & 0xff;
    332     *tp++ = (unsigned char)val & 0xff;
    333   }
    334   if (colonp != NULL) {
    335     /*
    336      * Since some memmove()'s erroneously fail to handle
    337      * overlapping regions, we'll do the shift by hand.
    338      */
    339     const int n = (int)(tp - colonp);
    340     int       i;
    341 
    342     if (tp == endp) {
    343       goto enoent;
    344     }
    345     for (i = 1; i <= n; i++) {
    346       endp[-i]      = colonp[n - i];
    347       colonp[n - i] = 0;
    348     }
    349     tp = endp;
    350   }
    351   if (tp != endp) {
    352     goto enoent;
    353   }
    354 
    355   memcpy(dst, tmp, NS_IN6ADDRSZ);
    356   return 1;
    357 
    358 enoent:
    359   SET_SOCKERRNO(ENOENT);
    360   return -1;
    361 }
    362 
    363 static int ares_inet_net_pton_ipv6(const char *src, unsigned char *dst,
    364                                    size_t size)
    365 {
    366   struct ares_in6_addr in6;
    367   int                  ret;
    368   size_t               bits;
    369   size_t               bytes;
    370   char                 buf[INET6_ADDRSTRLEN + sizeof("/128")];
    371   char                *sep;
    372 
    373   if (ares_strlen(src) >= sizeof buf) {
    374     SET_SOCKERRNO(EMSGSIZE);
    375     return -1;
    376   }
    377   ares_strcpy(buf, src, sizeof buf);
    378 
    379   sep = strchr(buf, '/');
    380   if (sep != NULL) {
    381     *sep++ = '\0';
    382   }
    383 
    384   ret = ares_inet_pton6(buf, (unsigned char *)&in6);
    385   if (ret != 1) {
    386     return -1;
    387   }
    388 
    389   if (sep == NULL) {
    390     bits = 128;
    391   } else {
    392     if (!getbits(sep, &bits)) {
    393       SET_SOCKERRNO(ENOENT);
    394       return -1;
    395     }
    396   }
    397 
    398   bytes = (bits + 7) / 8;
    399   if (bytes > size) {
    400     SET_SOCKERRNO(EMSGSIZE);
    401     return -1;
    402   }
    403   memcpy(dst, &in6, bytes);
    404   return (int)bits;
    405 }
    406 
    407 /*
    408  * int
    409  * inet_net_pton(af, src, dst, size)
    410  *      convert network number from presentation to network format.
    411  *      accepts hex octets, hex strings, decimal octets, and /CIDR.
    412  *      "size" is in bytes and describes "dst".
    413  * return:
    414  *      number of bits, either imputed classfully or specified with /CIDR,
    415  *      or -1 if some failure occurred (check errno).  ENOENT means it was
    416  *      not a valid network specification.
    417  * author:
    418  *      Paul Vixie (ISC), June 1996
    419  *
    420  */
    421 int ares_inet_net_pton(int af, const char *src, void *dst, size_t size)
    422 {
    423   switch (af) {
    424     case AF_INET:
    425       return ares_inet_net_pton_ipv4(src, dst, size);
    426     case AF_INET6:
    427       return ares_inet_net_pton_ipv6(src, dst, size);
    428     default:
    429       return -1;
    430   }
    431 }
    432 
    433 int ares_inet_pton(int af, const char *src, void *dst)
    434 {
    435   int    result;
    436   size_t size;
    437 
    438   if (af == AF_INET) {
    439     size = sizeof(struct in_addr);
    440   } else if (af == AF_INET6) {
    441     size = sizeof(struct ares_in6_addr);
    442   } else {
    443     SET_SOCKERRNO(EAFNOSUPPORT);
    444     return -1;
    445   }
    446   result = ares_inet_net_pton(af, src, dst, size);
    447   if (result == -1 && SOCKERRNO == ENOENT) {
    448     return 0;
    449   }
    450   return (result > -1) ? 1 : -1;
    451 }