• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * SPDX-License-Identifier: MIT
18  */
19 
20 #include "ares_private.h"
21 
22 #ifdef HAVE_NETINET_IN_H
23 #  include <netinet/in.h>
24 #endif
25 #ifdef HAVE_ARPA_INET_H
26 #  include <arpa/inet.h>
27 #endif
28 
29 #include "ares_nameser.h"
30 #include "ares_ipv6.h"
31 
32 #ifdef USE_WINSOCK
33 #  define SOCKERRNO        ((int)WSAGetLastError())
34 #  define SET_SOCKERRNO(x) (WSASetLastError((int)(x)))
35 #  undef EMSGSIZE
36 #  define EMSGSIZE WSAEMSGSIZE
37 #  undef ENOENT
38 #  define ENOENT WSA_INVALID_PARAMETER
39 #  undef EAFNOSUPPORT
40 #  define EAFNOSUPPORT WSAEAFNOSUPPORT
41 #  undef ENOSPC
42 #  define ENOSPC WSA_INVALID_PARAMETER
43 #else
44 #  define SOCKERRNO        (errno)
45 #  define SET_SOCKERRNO(x) (errno = (x))
46 #endif
47 
48 /*
49  * WARNING: Don't even consider trying to compile this on a system where
50  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
51  */
52 
53 static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size);
54 static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size);
55 
56 /* char *
57  * inet_ntop(af, src, dst, size)
58  *     convert a network format address to presentation format.
59  * return:
60  *     pointer to presentation format address (`dst'), or NULL (see errno).
61  * author:
62  *     Paul Vixie, 1996.
63  */
ares_inet_ntop(int af,const void * src,char * dst,ares_socklen_t size)64 const char        *ares_inet_ntop(int af, const void *src, char *dst,
65                                   ares_socklen_t size)
66 {
67   switch (af) {
68     case AF_INET:
69       return inet_ntop4(src, dst, (size_t)size);
70     case AF_INET6:
71       return inet_ntop6(src, dst, (size_t)size);
72     default:
73       break;
74   }
75   SET_SOCKERRNO(EAFNOSUPPORT);
76   return NULL;
77 }
78 
79 /* const char *
80  * inet_ntop4(src, dst, size)
81  *     format an IPv4 address
82  * return:
83  *     `dst' (as a const)
84  * notes:
85  *     (1) uses no statics
86  *     (2) takes a unsigned char* not an in_addr as input
87  * author:
88  *     Paul Vixie, 1996.
89  */
inet_ntop4(const unsigned char * src,char * dst,size_t size)90 static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
91 {
92   static const char fmt[] = "%u.%u.%u.%u";
93   char              tmp[sizeof("255.255.255.255")];
94 
95   if (size < sizeof(tmp)) {
96     SET_SOCKERRNO(ENOSPC);
97     return NULL;
98   }
99 
100   if ((size_t)snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]) >=
101       size) {
102     SET_SOCKERRNO(ENOSPC);
103     return NULL;
104   }
105   ares_strcpy(dst, tmp, size);
106   return dst;
107 }
108 
109 /* const char *
110  * inet_ntop6(src, dst, size)
111  *     convert IPv6 binary address into presentation (printable) format
112  * author:
113  *     Paul Vixie, 1996.
114  */
inet_ntop6(const unsigned char * src,char * dst,size_t size)115 static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
116 {
117   /*
118    * Note that int32_t and int16_t need only be "at least" large enough
119    * to contain a value of the specified size.  On some systems, like
120    * Crays, there is no such thing as an integer variable with 16 bits.
121    * Keep this in mind if you think this function should have been coded
122    * to use pointer overlays.  All the world's not a VAX.
123    */
124   char  tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
125   char *tp;
126 
127   struct {
128     ares_ssize_t base;
129     size_t       len;
130   } best, cur;
131 
132   unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
133   size_t       i;
134 
135   /*
136    * Preprocess:
137    *  Copy the input (bytewise) array into a wordwise array.
138    *  Find the longest run of 0x00's in src[] for :: shorthanding.
139    */
140   memset(words, '\0', sizeof(words));
141   for (i = 0; i < NS_IN6ADDRSZ; i++) {
142     words[i / 2] |= (unsigned int)(src[i] << ((1 - (i % 2)) << 3));
143   }
144   best.base = -1;
145   best.len  = 0;
146   cur.base  = -1;
147   cur.len   = 0;
148   for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
149     if (words[i] == 0) {
150       if (cur.base == -1) {
151         cur.base = (ares_ssize_t)i;
152         cur.len  = 1;
153       } else {
154         cur.len++;
155       }
156     } else {
157       if (cur.base != -1) {
158         if (best.base == -1 || cur.len > best.len) {
159           best = cur;
160         }
161         cur.base = -1;
162       }
163     }
164   }
165   if (cur.base != -1) {
166     if (best.base == -1 || cur.len > best.len) {
167       best = cur;
168     }
169   }
170   if (best.base != -1 && best.len < 2) {
171     best.base = -1;
172   }
173 
174   /*
175    * Format the result.
176    */
177   tp = tmp;
178   for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
179     /* Are we inside the best run of 0x00's? */
180     if (best.base != -1 && i >= (size_t)best.base &&
181         i < ((size_t)best.base + best.len)) {
182       if (i == (size_t)best.base) {
183         *tp++ = ':';
184       }
185       continue;
186     }
187     /* Are we following an initial run of 0x00s or any real hex? */
188     if (i != 0) {
189       *tp++ = ':';
190     }
191     /* Is this address an encapsulated IPv4? */
192     if (i == 6 && best.base == 0 &&
193         (best.len == 6 || (best.len == 7 && words[7] != 0x0001) ||
194          (best.len == 5 && words[5] == 0xffff))) {
195       if (!inet_ntop4(src + 12, tp, sizeof(tmp) - (size_t)(tp - tmp))) {
196         return (NULL);
197       }
198       tp += ares_strlen(tp);
199       break;
200     }
201     tp += snprintf(tp, sizeof(tmp) - (size_t)(tp - tmp), "%x", words[i]);
202   }
203   /* Was it a trailing run of 0x00's? */
204   if (best.base != -1 &&
205       ((size_t)best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) {
206     *tp++ = ':';
207   }
208   *tp++ = '\0';
209 
210   /*
211    * Check for overflow, copy, and we're done.
212    */
213   if ((size_t)(tp - tmp) > size) {
214     SET_SOCKERRNO(ENOSPC);
215     return NULL;
216   }
217   ares_strcpy(dst, tmp, size);
218   return dst;
219 }
220