inet_ntop.c 5.75 KB
Newer Older
Denis Bilenko's avatar
Denis Bilenko committed
1 2 3
/*
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
 * Copyright (c) 1996-1999 by Internet Software Consortium.
4 5 6 7 8
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
Denis Bilenko's avatar
Denis Bilenko committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
 */

#include "ares_setup.h"

#ifdef HAVE_NETINET_IN_H
#  include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#  include <arpa/inet.h>
#endif
#ifdef HAVE_ARPA_NAMESER_H
#  include <arpa/nameser.h>
#else
#  include "nameser.h"
#endif
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
#  include <arpa/nameser_compat.h>
#endif

#include "ares.h"
#include "ares_ipv6.h"

#ifndef HAVE_INET_NTOP

/*
 * WARNING: Don't even consider trying to compile this on a system where
 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
 */

static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size);
static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size);

/* char *
 * inet_ntop(af, src, dst, size)
 *     convert a network format address to presentation format.
 * return:
 *     pointer to presentation format address (`dst'), or NULL (see errno).
 * note:
Denis Bilenko's avatar
Denis Bilenko committed
54 55 56
 *     On Windows we store the error in the thread errno, not
 *     in the winsock error code. This is to avoid loosing the
 *     actual last winsock error. So use macro ERRNO to fetch the
57
 *     errno this function sets when returning NULL, not SOCKERRNO.
58 59 60 61
 * author:
 *     Paul Vixie, 1996.
 */
const char *
Omer Katz's avatar
Omer Katz committed
62
ares_inet_ntop(int af, const void *src, char *dst, ares_socklen_t size)
63
{
Denis Bilenko's avatar
Denis Bilenko committed
64 65
  switch (af) {
  case AF_INET:
Omer Katz's avatar
Omer Katz committed
66
    return (inet_ntop4(src, dst, (size_t)size));
Denis Bilenko's avatar
Denis Bilenko committed
67
  case AF_INET6:
Omer Katz's avatar
Omer Katz committed
68
    return (inet_ntop6(src, dst, (size_t)size));
Denis Bilenko's avatar
Denis Bilenko committed
69 70 71 72
  default:
    SET_ERRNO(EAFNOSUPPORT);
    return (NULL);
  }
73 74 75 76 77
  /* NOTREACHED */
}

/* const char *
 * inet_ntop4(src, dst, size)
Denis Bilenko's avatar
Denis Bilenko committed
78
 *     format an IPv4 address
79 80 81 82 83 84 85 86 87 88 89 90
 * return:
 *     `dst' (as a const)
 * notes:
 *     (1) uses no statics
 *     (2) takes a unsigned char* not an in_addr as input
 * author:
 *     Paul Vixie, 1996.
 */
static const char *
inet_ntop4(const unsigned char *src, char *dst, size_t size)
{
  static const char fmt[] = "%u.%u.%u.%u";
Denis Bilenko's avatar
Denis Bilenko committed
91
  char tmp[sizeof("255.255.255.255")];
92

Denis Bilenko's avatar
Denis Bilenko committed
93 94 95 96 97 98
  if ((size_t)sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) >= size) {
    SET_ERRNO(ENOSPC);
    return (NULL);
  }
  strcpy(dst, tmp);
  return (dst);
99 100 101 102
}

/* const char *
 * inet_ntop6(src, dst, size)
Denis Bilenko's avatar
Denis Bilenko committed
103
 *     convert IPv6 binary address into presentation (printable) format
104
 * author:
Denis Bilenko's avatar
Denis Bilenko committed
105
 *     Paul Vixie, 1996.
106 107 108 109 110 111 112 113 114 115 116 117 118
 */
static const char *
inet_ntop6(const unsigned char *src, char *dst, size_t size)
{
  /*
   * Note that int32_t and int16_t need only be "at least" large enough
   * to contain a value of the specified size.  On some systems, like
   * Crays, there is no such thing as an integer variable with 16 bits.
   * Keep this in mind if you think this function should have been coded
   * to use pointer overlays.  All the world's not a VAX.
   */
  char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
  char *tp;
Denis Bilenko's avatar
Denis Bilenko committed
119 120
  struct { int base, len; } best, cur;
  unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
121 122 123 124 125 126 127 128 129
  int i;

  /*
   * Preprocess:
   *  Copy the input (bytewise) array into a wordwise array.
   *  Find the longest run of 0x00's in src[] for :: shorthanding.
   */
  memset(words, '\0', sizeof(words));
  for (i = 0; i < NS_IN6ADDRSZ; i++)
Denis Bilenko's avatar
Denis Bilenko committed
130
    words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
131 132
  best.base = -1;
  best.len = 0;
Denis Bilenko's avatar
Denis Bilenko committed
133
  cur.base = -1;
134
  cur.len = 0;
Denis Bilenko's avatar
Denis Bilenko committed
135 136 137 138
  for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
    if (words[i] == 0) {
      if (cur.base == -1)
        cur.base = i, cur.len = 1;
139
      else
Denis Bilenko's avatar
Denis Bilenko committed
140 141 142 143 144 145 146
        cur.len++;
    } else {
      if (cur.base != -1) {
        if (best.base == -1 || cur.len > best.len)
          best = cur;
        cur.base = -1;
      }
147
    }
Denis Bilenko's avatar
Denis Bilenko committed
148 149 150 151 152
  }
  if (cur.base != -1) {
    if (best.base == -1 || cur.len > best.len)
      best = cur;
  }
153 154 155 156 157 158 159
  if (best.base != -1 && best.len < 2)
    best.base = -1;

  /*
   * Format the result.
   */
  tp = tmp;
Denis Bilenko's avatar
Denis Bilenko committed
160 161 162 163 164
  for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
    /* Are we inside the best run of 0x00's? */
    if (best.base != -1 && i >= best.base &&
        i < (best.base + best.len)) {
      if (i == best.base)
165
        *tp++ = ':';
Denis Bilenko's avatar
Denis Bilenko committed
166
      continue;
167
    }
Denis Bilenko's avatar
Denis Bilenko committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181
    /* Are we following an initial run of 0x00s or any real hex? */
    if (i != 0)
      *tp++ = ':';
    /* Is this address an encapsulated IPv4? */
    if (i == 6 && best.base == 0 && (best.len == 6 ||
        (best.len == 7 && words[7] != 0x0001) ||
        (best.len == 5 && words[5] == 0xffff))) {
      if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp)))
        return (NULL);
      tp += strlen(tp);
      break;
    }
    tp += sprintf(tp, "%x", words[i]);
  }
182
  /* Was it a trailing run of 0x00's? */
Jason Madden's avatar
Jason Madden committed
183
  if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ))
184 185 186 187 188 189
    *tp++ = ':';
  *tp++ = '\0';

  /*
   * Check for overflow, copy, and we're done.
   */
Denis Bilenko's avatar
Denis Bilenko committed
190 191 192 193
  if ((size_t)(tp - tmp) > size) {
    SET_ERRNO(ENOSPC);
    return (NULL);
  }
194 195 196
  strcpy(dst, tmp);
  return (dst);
}
Omer Katz's avatar
Omer Katz committed
197 198 199 200 201 202 203 204 205 206 207

#else /* HAVE_INET_NTOP */

const char *
ares_inet_ntop(int af, const void *src, char *dst, ares_socklen_t size)
{
  /* just relay this to the underlying function */
  return inet_ntop(af, src, dst, size);
}

#endif /* HAVE_INET_NTOP */