• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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