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