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