Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
      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 ISC DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  */
     17 
     18 #include <stdio.h>
     19 #include <string.h>
     20 #include <stdint.h>
     21 
     22 #include "uv.h"
     23 #include "uv-common.h"
     24 
     25 #define UV__INET_ADDRSTRLEN         16
     26 #define UV__INET6_ADDRSTRLEN        46
     27 
     28 
     29 static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
     30 static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
     31 static int inet_pton4(const char *src, unsigned char *dst);
     32 static int inet_pton6(const char *src, unsigned char *dst);
     33 
     34 
     35 int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
     36   switch (af) {
     37   case AF_INET:
     38     return (inet_ntop4(src, dst, size));
     39   case AF_INET6:
     40     return (inet_ntop6(src, dst, size));
     41   default:
     42     return UV_EAFNOSUPPORT;
     43   }
     44   /* NOTREACHED */
     45 }
     46 
     47 
     48 static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
     49   static const char fmt[] = "%u.%u.%u.%u";
     50   char tmp[UV__INET_ADDRSTRLEN];
     51   int l;
     52 
     53   l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
     54   if (l <= 0 || (size_t) l >= size) {
     55     return UV_ENOSPC;
     56   }
     57   uv__strscpy(dst, tmp, size);
     58   return 0;
     59 }
     60 
     61 
     62 static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
     63   /*
     64    * Note that int32_t and int16_t need only be "at least" large enough
     65    * to contain a value of the specified size.  On some systems, like
     66    * Crays, there is no such thing as an integer variable with 16 bits.
     67    * Keep this in mind if you think this function should have been coded
     68    * to use pointer overlays.  All the world's not a VAX.
     69    */
     70   char tmp[UV__INET6_ADDRSTRLEN], *tp;
     71   struct { int base, len; } best, cur;
     72   unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
     73   int i;
     74 
     75   /*
     76    * Preprocess:
     77    *  Copy the input (bytewise) array into a wordwise array.
     78    *  Find the longest run of 0x00's in src[] for :: shorthanding.
     79    */
     80   memset(words, '\0', sizeof words);
     81   for (i = 0; i < (int) sizeof(struct in6_addr); i++)
     82     words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
     83   best.base = -1;
     84   best.len = 0;
     85   cur.base = -1;
     86   cur.len = 0;
     87   for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
     88     if (words[i] == 0) {
     89       if (cur.base == -1)
     90         cur.base = i, cur.len = 1;
     91       else
     92         cur.len++;
     93     } else {
     94       if (cur.base != -1) {
     95         if (best.base == -1 || cur.len > best.len)
     96           best = cur;
     97         cur.base = -1;
     98       }
     99     }
    100   }
    101   if (cur.base != -1) {
    102     if (best.base == -1 || cur.len > best.len)
    103       best = cur;
    104   }
    105   if (best.base != -1 && best.len < 2)
    106     best.base = -1;
    107 
    108   /*
    109    * Format the result.
    110    */
    111   tp = tmp;
    112   for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
    113     /* Are we inside the best run of 0x00's? */
    114     if (best.base != -1 && i >= best.base &&
    115         i < (best.base + best.len)) {
    116       if (i == best.base)
    117         *tp++ = ':';
    118       continue;
    119     }
    120     /* Are we following an initial run of 0x00s or any real hex? */
    121     if (i != 0)
    122       *tp++ = ':';
    123     /* Is this address an encapsulated IPv4? */
    124     if (i == 6 && best.base == 0 && (best.len == 6 ||
    125         (best.len == 7 && words[7] != 0x0001) ||
    126         (best.len == 5 && words[5] == 0xffff))) {
    127       int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
    128       if (err)
    129         return err;
    130       tp += strlen(tp);
    131       break;
    132     }
    133     tp += snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]);
    134   }
    135   /* Was it a trailing run of 0x00's? */
    136   if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
    137     *tp++ = ':';
    138   *tp++ = '\0';
    139   if ((size_t) (tp - tmp) > size)
    140     return UV_ENOSPC;
    141   uv__strscpy(dst, tmp, size);
    142   return 0;
    143 }
    144 
    145 
    146 int uv_inet_pton(int af, const char* src, void* dst) {
    147   if (src == NULL || dst == NULL)
    148     return UV_EINVAL;
    149 
    150   switch (af) {
    151   case AF_INET:
    152     return (inet_pton4(src, dst));
    153   case AF_INET6: {
    154     int len;
    155     char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
    156     s = (char*) src;
    157     p = strchr(src, '%');
    158     if (p != NULL) {
    159       s = tmp;
    160       len = p - src;
    161       if (len > UV__INET6_ADDRSTRLEN-1)
    162         return UV_EINVAL;
    163       memcpy(s, src, len);
    164       s[len] = '\0';
    165     }
    166     return inet_pton6(s, dst);
    167   }
    168   default:
    169     return UV_EAFNOSUPPORT;
    170   }
    171   /* NOTREACHED */
    172 }
    173 
    174 
    175 static int inet_pton4(const char *src, unsigned char *dst) {
    176   static const char digits[] = "0123456789";
    177   int saw_digit, octets, ch;
    178   unsigned char tmp[sizeof(struct in_addr)], *tp;
    179 
    180   saw_digit = 0;
    181   octets = 0;
    182   *(tp = tmp) = 0;
    183   while ((ch = *src++) != '\0') {
    184     const char *pch;
    185 
    186     if ((pch = strchr(digits, ch)) != NULL) {
    187       unsigned int nw = *tp * 10 + (pch - digits);
    188 
    189       if (saw_digit && *tp == 0)
    190         return UV_EINVAL;
    191       if (nw > 255)
    192         return UV_EINVAL;
    193       *tp = nw;
    194       if (!saw_digit) {
    195         if (++octets > 4)
    196           return UV_EINVAL;
    197         saw_digit = 1;
    198       }
    199     } else if (ch == '.' && saw_digit) {
    200       if (octets == 4)
    201         return UV_EINVAL;
    202       *++tp = 0;
    203       saw_digit = 0;
    204     } else
    205       return UV_EINVAL;
    206   }
    207   if (octets < 4)
    208     return UV_EINVAL;
    209   memcpy(dst, tmp, sizeof(struct in_addr));
    210   return 0;
    211 }
    212 
    213 
    214 static int inet_pton6(const char *src, unsigned char *dst) {
    215   static const char xdigits_l[] = "0123456789abcdef",
    216                     xdigits_u[] = "0123456789ABCDEF";
    217   unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
    218   const char *xdigits, *curtok;
    219   int ch, seen_xdigits;
    220   unsigned int val;
    221 
    222   memset((tp = tmp), '\0', sizeof tmp);
    223   endp = tp + sizeof tmp;
    224   colonp = NULL;
    225   /* Leading :: requires some special handling. */
    226   if (*src == ':')
    227     if (*++src != ':')
    228       return UV_EINVAL;
    229   curtok = src;
    230   seen_xdigits = 0;
    231   val = 0;
    232   while ((ch = *src++) != '\0') {
    233     const char *pch;
    234 
    235     if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
    236       pch = strchr((xdigits = xdigits_u), ch);
    237     if (pch != NULL) {
    238       val <<= 4;
    239       val |= (pch - xdigits);
    240       if (++seen_xdigits > 4)
    241         return UV_EINVAL;
    242       continue;
    243     }
    244     if (ch == ':') {
    245       curtok = src;
    246       if (!seen_xdigits) {
    247         if (colonp)
    248           return UV_EINVAL;
    249         colonp = tp;
    250         continue;
    251       } else if (*src == '\0') {
    252         return UV_EINVAL;
    253       }
    254       if (tp + sizeof(uint16_t) > endp)
    255         return UV_EINVAL;
    256       *tp++ = (unsigned char) (val >> 8) & 0xff;
    257       *tp++ = (unsigned char) val & 0xff;
    258       seen_xdigits = 0;
    259       val = 0;
    260       continue;
    261     }
    262     if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
    263       int err = inet_pton4(curtok, tp);
    264       if (err == 0) {
    265         tp += sizeof(struct in_addr);
    266         seen_xdigits = 0;
    267         break;  /*%< '\\0' was seen by inet_pton4(). */
    268       }
    269     }
    270     return UV_EINVAL;
    271   }
    272   if (seen_xdigits) {
    273     if (tp + sizeof(uint16_t) > endp)
    274       return UV_EINVAL;
    275     *tp++ = (unsigned char) (val >> 8) & 0xff;
    276     *tp++ = (unsigned char) val & 0xff;
    277   }
    278   if (colonp != NULL) {
    279     /*
    280      * Since some memmove()'s erroneously fail to handle
    281      * overlapping regions, we'll do the shift by hand.
    282      */
    283     const int n = tp - colonp;
    284     int i;
    285 
    286     if (tp == endp)
    287       return UV_EINVAL;
    288     for (i = 1; i <= n; i++) {
    289       endp[- i] = colonp[n - i];
    290       colonp[n - i] = 0;
    291     }
    292     tp = endp;
    293   }
    294   if (tp != endp)
    295     return UV_EINVAL;
    296   memcpy(dst, tmp, sizeof tmp);
    297   return 0;
    298 }
    299