1 /* MIT License
2 *
3 * Copyright (c) 1998 Massachusetts Institute of Technology
4 * Copyright (c) 2005 Dominick Meglio
5 * Copyright (c) 2019 Andrew Selivanov
6 * Copyright (c) 2021 Brad House
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * SPDX-License-Identifier: MIT
28 */
29
30 #include "ares_private.h"
31
32 #ifdef HAVE_NETINET_IN_H
33 # include <netinet/in.h>
34 #endif
35 #ifdef HAVE_NETDB_H
36 # include <netdb.h>
37 #endif
38 #ifdef HAVE_ARPA_INET_H
39 # include <arpa/inet.h>
40 #endif
41
42 #ifdef HAVE_STRINGS_H
43 # include <strings.h>
44 #endif
45
46 #ifdef HAVE_LIMITS_H
47 # include <limits.h>
48 #endif
49
hostent_nalias(const struct hostent * host)50 static size_t hostent_nalias(const struct hostent *host)
51 {
52 size_t i;
53 for (i=0; host->h_aliases != NULL && host->h_aliases[i] != NULL; i++)
54 ;
55
56 return i;
57 }
58
ai_nalias(const struct ares_addrinfo * ai)59 static size_t ai_nalias(const struct ares_addrinfo *ai)
60 {
61 const struct ares_addrinfo_cname *cname;
62 size_t i = 0;
63
64 for (cname = ai->cnames; cname != NULL; cname=cname->next) {
65 i++;
66 }
67
68 return i;
69 }
70
hostent_naddr(const struct hostent * host)71 static size_t hostent_naddr(const struct hostent *host)
72 {
73 size_t i;
74 for (i=0; host->h_addr_list != NULL && host->h_addr_list[i] != NULL; i++)
75 ;
76
77 return i;
78 }
79
ai_naddr(const struct ares_addrinfo * ai,int af)80 static size_t ai_naddr(const struct ares_addrinfo *ai, int af)
81 {
82 const struct ares_addrinfo_node *node;
83 size_t i = 0;
84
85 for (node = ai->nodes; node != NULL; node=node->ai_next) {
86 if (af != AF_UNSPEC && af != node->ai_family)
87 continue;
88 i++;
89 }
90
91 return i;
92 }
93
ares_addrinfo2hostent(const struct ares_addrinfo * ai,int family,struct hostent ** host)94 ares_status_t ares_addrinfo2hostent(const struct ares_addrinfo *ai, int family,
95 struct hostent **host)
96 {
97 struct ares_addrinfo_node *next;
98 char **aliases = NULL;
99 char **addrs = NULL;
100 size_t naliases = 0;
101 size_t naddrs = 0;
102 size_t i;
103 size_t ealiases = 0;
104 size_t eaddrs = 0;
105
106 if (ai == NULL || host == NULL) {
107 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
108 }
109
110 /* Use either the host set in the passed in hosts to be filled in, or the
111 * first node of the response as the family, since hostent can only
112 * represent one family. We assume getaddrinfo() returned a sorted list if
113 * the user requested AF_UNSPEC. */
114 if (family == AF_UNSPEC) {
115 if (*host != NULL && (*host)->h_addrtype != AF_UNSPEC) {
116 family = (*host)->h_addrtype;
117 } else if (ai->nodes != NULL) {
118 family = ai->nodes->ai_family;
119 }
120 }
121
122 if (family != AF_INET && family != AF_INET6) {
123 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
124 }
125
126 if (*host == NULL) {
127 *host = ares_malloc_zero(sizeof(**host));
128 if (!(*host)) {
129 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
130 }
131 }
132
133 (*host)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family;
134 if (family == AF_INET) {
135 (*host)->h_length = sizeof(struct in_addr);
136 } else if (family == AF_INET6) {
137 (*host)->h_length = sizeof(struct ares_in6_addr);
138 }
139
140 if ((*host)->h_name == NULL) {
141 if (ai->cnames) {
142 (*host)->h_name = ares_strdup(ai->cnames->name);
143 if ((*host)->h_name == NULL && ai->cnames->name) {
144 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
145 }
146 } else {
147 (*host)->h_name = ares_strdup(ai->name);
148 if ((*host)->h_name == NULL && ai->name) {
149 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
150 }
151 }
152 }
153
154 naliases = ai_nalias(ai);
155 ealiases = hostent_nalias(*host);
156 aliases = ares_realloc_zero((*host)->h_aliases,
157 ealiases * sizeof(char *),
158 (naliases + ealiases + 1) * sizeof(char *));
159 if (!aliases) {
160 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
161 }
162 (*host)->h_aliases = aliases;
163
164 if (naliases) {
165 const struct ares_addrinfo_cname *cname;
166 i = ealiases;
167 for (cname = ai->cnames; cname != NULL; cname = cname->next) {
168 if (cname->alias == NULL) {
169 continue;
170 }
171 (*host)->h_aliases[i] = ares_strdup(cname->alias);
172 if ((*host)->h_aliases[i] == NULL) {
173 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
174 }
175 i++;
176 }
177 }
178
179 naddrs = ai_naddr(ai, family);
180 eaddrs = hostent_naddr(*host);
181 addrs = ares_realloc_zero((*host)->h_addr_list, eaddrs * sizeof(char *),
182 (naddrs + eaddrs + 1) * sizeof(char *));
183 if (addrs == NULL) {
184 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
185 }
186 (*host)->h_addr_list = addrs;
187
188 if (naddrs) {
189 i = eaddrs;
190 for (next = ai->nodes; next != NULL; next = next->ai_next) {
191 if (next->ai_family != family) {
192 continue;
193 }
194 (*host)->h_addr_list[i] = ares_malloc_zero((size_t)(*host)->h_length);
195 if ((*host)->h_addr_list[i] == NULL) {
196 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
197 }
198 if (family == AF_INET6) {
199 memcpy((*host)->h_addr_list[i],
200 &(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr)
201 ->sin6_addr),
202 (size_t)(*host)->h_length);
203 }
204 if (family == AF_INET) {
205 memcpy((*host)->h_addr_list[i],
206 &(CARES_INADDR_CAST(const struct sockaddr_in *, next->ai_addr)
207 ->sin_addr),
208 (size_t)(*host)->h_length);
209 }
210 i++;
211 }
212 }
213
214 if (naddrs + eaddrs == 0 && naliases + ealiases == 0) {
215 ares_free_hostent(*host);
216 *host = NULL;
217 return ARES_ENODATA;
218 }
219
220 return ARES_SUCCESS;
221
222 /* LCOV_EXCL_START: OutOfMemory */
223 enomem:
224 ares_free_hostent(*host);
225 *host = NULL;
226 return ARES_ENOMEM;
227 /* LCOV_EXCL_STOP */
228 }
229
ares_addrinfo2addrttl(const struct ares_addrinfo * ai,int family,size_t req_naddrttls,struct ares_addrttl * addrttls,struct ares_addr6ttl * addr6ttls,size_t * naddrttls)230 ares_status_t ares_addrinfo2addrttl(const struct ares_addrinfo *ai, int family,
231 size_t req_naddrttls,
232 struct ares_addrttl *addrttls,
233 struct ares_addr6ttl *addr6ttls,
234 size_t *naddrttls)
235 {
236 struct ares_addrinfo_node *next;
237 struct ares_addrinfo_cname *next_cname;
238 int cname_ttl = INT_MAX;
239
240 if (family != AF_INET && family != AF_INET6) {
241 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
242 }
243
244 if (ai == NULL || naddrttls == NULL) {
245 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
246 }
247
248 if (family == AF_INET && addrttls == NULL) {
249 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
250 }
251
252 if (family == AF_INET6 && addr6ttls == NULL) {
253 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
254 }
255
256 if (req_naddrttls == 0) {
257 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
258 }
259
260 *naddrttls = 0;
261
262 next_cname = ai->cnames;
263 while (next_cname) {
264 if (next_cname->ttl < cname_ttl) {
265 cname_ttl = next_cname->ttl;
266 }
267 next_cname = next_cname->next;
268 }
269
270 for (next = ai->nodes; next != NULL; next = next->ai_next) {
271 if (next->ai_family != family) {
272 continue;
273 }
274
275 if (*naddrttls >= req_naddrttls) {
276 break;
277 }
278
279 if (family == AF_INET6) {
280 if (next->ai_ttl > cname_ttl) {
281 addr6ttls[*naddrttls].ttl = cname_ttl;
282 } else {
283 addr6ttls[*naddrttls].ttl = next->ai_ttl;
284 }
285
286 memcpy(&addr6ttls[*naddrttls].ip6addr,
287 &(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr)
288 ->sin6_addr),
289 sizeof(struct ares_in6_addr));
290 } else {
291 if (next->ai_ttl > cname_ttl) {
292 addrttls[*naddrttls].ttl = cname_ttl;
293 } else {
294 addrttls[*naddrttls].ttl = next->ai_ttl;
295 }
296 memcpy(&addrttls[*naddrttls].ipaddr,
297 &(CARES_INADDR_CAST(const struct sockaddr_in *, next->ai_addr)
298 ->sin_addr),
299 sizeof(struct in_addr));
300 }
301 (*naddrttls)++;
302 }
303
304 return ARES_SUCCESS;
305 }
306