Home | History | Annotate | Download | only in lib
      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  * Original code by Paul Vixie. "curlified" by Gisle Vanem.
     19  */
     20 
     21 #include "curl_setup.h"
     22 
     23 #ifndef HAVE_INET_NTOP
     24 
     25 #ifdef HAVE_SYS_PARAM_H
     26 #include <sys/param.h>
     27 #endif
     28 #ifdef HAVE_NETINET_IN_H
     29 #include <netinet/in.h>
     30 #endif
     31 #ifdef HAVE_ARPA_INET_H
     32 #include <arpa/inet.h>
     33 #endif
     34 
     35 #include "inet_ntop.h"
     36 #include "curl_printf.h"
     37 
     38 #define IN6ADDRSZ       16
     39 #define INADDRSZ         4
     40 #define INT16SZ          2
     41 
     42 /*
     43  * Format an IPv4 address, more or less like inet_ntoa().
     44  *
     45  * Returns `dst' (as a const)
     46  * Note:
     47  *  - uses no statics
     48  *  - takes a unsigned char* not an in_addr as input
     49  */
     50 static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
     51 {
     52   char tmp[sizeof "255.255.255.255"];
     53   size_t len;
     54 
     55   DEBUGASSERT(size >= 16);
     56 
     57   tmp[0] = '\0';
     58   (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
     59                  ((int)((unsigned char)src[0])) & 0xff,
     60                  ((int)((unsigned char)src[1])) & 0xff,
     61                  ((int)((unsigned char)src[2])) & 0xff,
     62                  ((int)((unsigned char)src[3])) & 0xff);
     63 
     64   len = strlen(tmp);
     65   if(len == 0 || len >= size) {
     66     errno = ENOSPC;
     67     return (NULL);
     68   }
     69   strcpy(dst, tmp);
     70   return dst;
     71 }
     72 
     73 #ifdef ENABLE_IPV6
     74 /*
     75  * Convert IPv6 binary address into presentation (printable) format.
     76  */
     77 static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
     78 {
     79   /*
     80    * Note that int32_t and int16_t need only be "at least" large enough
     81    * to contain a value of the specified size.  On some systems, like
     82    * Crays, there is no such thing as an integer variable with 16 bits.
     83    * Keep this in mind if you think this function should have been coded
     84    * to use pointer overlays.  All the world's not a VAX.
     85    */
     86   char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
     87   char *tp;
     88   struct {
     89     long base;
     90     long len;
     91   } best, cur;
     92   unsigned long words[IN6ADDRSZ / INT16SZ];
     93   int i;
     94 
     95   /* Preprocess:
     96    *  Copy the input (bytewise) array into a wordwise array.
     97    *  Find the longest run of 0x00's in src[] for :: shorthanding.
     98    */
     99   memset(words, '\0', sizeof(words));
    100   for(i = 0; i < IN6ADDRSZ; i++)
    101     words[i/2] |= (src[i] << ((1 - (i % 2)) << 3));
    102 
    103   best.base = -1;
    104   cur.base  = -1;
    105   best.len = 0;
    106   cur.len = 0;
    107 
    108   for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
    109     if(words[i] == 0) {
    110       if(cur.base == -1)
    111         cur.base = i, cur.len = 1;
    112       else
    113         cur.len++;
    114     }
    115     else if(cur.base != -1) {
    116       if(best.base == -1 || cur.len > best.len)
    117         best = cur;
    118       cur.base = -1;
    119     }
    120   }
    121   if((cur.base != -1) && (best.base == -1 || cur.len > best.len))
    122     best = cur;
    123   if(best.base != -1 && best.len < 2)
    124     best.base = -1;
    125   /* Format the result. */
    126   tp = tmp;
    127   for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
    128     /* Are we inside the best run of 0x00's? */
    129     if(best.base != -1 && i >= best.base && i < (best.base + best.len)) {
    130       if(i == best.base)
    131         *tp++ = ':';
    132       continue;
    133     }
    134 
    135     /* Are we following an initial run of 0x00s or any real hex?
    136      */
    137     if(i != 0)
    138       *tp++ = ':';
    139 
    140     /* Is this address an encapsulated IPv4?
    141      */
    142     if(i == 6 && best.base == 0 &&
    143         (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
    144       if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) {
    145         errno = ENOSPC;
    146         return (NULL);
    147       }
    148       tp += strlen(tp);
    149       break;
    150     }
    151     tp += snprintf(tp, 5, "%lx", words[i]);
    152   }
    153 
    154   /* Was it a trailing run of 0x00's?
    155    */
    156   if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
    157      *tp++ = ':';
    158   *tp++ = '\0';
    159 
    160   /* Check for overflow, copy, and we're done.
    161    */
    162   if((size_t)(tp - tmp) > size) {
    163     errno = ENOSPC;
    164     return (NULL);
    165   }
    166   strcpy(dst, tmp);
    167   return dst;
    168 }
    169 #endif  /* ENABLE_IPV6 */
    170 
    171 /*
    172  * Convert a network format address to presentation format.
    173  *
    174  * Returns pointer to presentation format address (`buf').
    175  * Returns NULL on error and errno set with the specific
    176  * error, EAFNOSUPPORT or ENOSPC.
    177  *
    178  * On Windows we store the error in the thread errno, not
    179  * in the winsock error code. This is to avoid losing the
    180  * actual last winsock error. So when this function returns
    181  * NULL, check errno not SOCKERRNO.
    182  */
    183 char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
    184 {
    185   switch(af) {
    186   case AF_INET:
    187     return inet_ntop4((const unsigned char *)src, buf, size);
    188 #ifdef ENABLE_IPV6
    189   case AF_INET6:
    190     return inet_ntop6((const unsigned char *)src, buf, size);
    191 #endif
    192   default:
    193     errno = EAFNOSUPPORT;
    194     return NULL;
    195   }
    196 }
    197 #endif  /* HAVE_INET_NTOP */
    198