1 /* Copyright 1998 by the Massachusetts Institute of Technology.
2 * Copyright 2005 Dominick Meglio
3 * Copyright (C) 2019 by Andrew Selivanov
4 * Copyright (C) 2021 by Brad House
5 *
6 * Permission to use, copy, modify, and distribute this
7 * software and its documentation for any purpose and without
8 * fee is hereby granted, provided that the above copyright
9 * notice appear in all copies and that both that copyright
10 * notice and this permission notice appear in supporting
11 * documentation, and that the name of M.I.T. not be used in
12 * advertising or publicity pertaining to distribution of the
13 * software without specific, written prior permission.
14 * M.I.T. makes no representations about the suitability of
15 * this software for any purpose. It is provided "as is"
16 * without express or implied warranty.
17 */
18
19 #include "ares_setup.h"
20
21 #ifdef HAVE_NETINET_IN_H
22 # include <netinet/in.h>
23 #endif
24 #ifdef HAVE_NETDB_H
25 # include <netdb.h>
26 #endif
27 #ifdef HAVE_ARPA_INET_H
28 # include <arpa/inet.h>
29 #endif
30
31 #include "ares_nameser.h"
32
33 #ifdef HAVE_STRINGS_H
34 # include <strings.h>
35 #endif
36
37 #ifdef HAVE_LIMITS_H
38 # include <limits.h>
39 #endif
40
41 #include "ares.h"
42 #include "ares_dns.h"
43 #include "ares_inet_net_pton.h"
44 #include "ares_private.h"
45
ares__addrinfo2hostent(const struct ares_addrinfo * ai,int family,struct hostent ** host)46 int ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family,
47 struct hostent **host)
48 {
49 struct ares_addrinfo_node *next;
50 struct ares_addrinfo_cname *next_cname;
51 char **aliases = NULL;
52 char *addrs = NULL;
53 int naliases = 0, naddrs = 0, alias = 0, i;
54
55 if (ai == NULL || host == NULL)
56 return ARES_EBADQUERY;
57
58 *host = ares_malloc(sizeof(**host));
59 if (!(*host))
60 {
61 goto enomem;
62 }
63 memset(*host, 0, sizeof(**host));
64
65 /* Use the first node of the response as the family, since hostent can only
66 * represent one family. We assume getaddrinfo() returned a sorted list if
67 * the user requested AF_UNSPEC. */
68 if (family == AF_UNSPEC && ai->nodes)
69 family = ai->nodes->ai_family;
70
71 next = ai->nodes;
72 while (next)
73 {
74 if(next->ai_family == family)
75 {
76 ++naddrs;
77 }
78 next = next->ai_next;
79 }
80
81 next_cname = ai->cnames;
82 while (next_cname)
83 {
84 if(next_cname->alias)
85 ++naliases;
86 next_cname = next_cname->next;
87 }
88
89 aliases = ares_malloc((naliases + 1) * sizeof(char *));
90 if (!aliases)
91 {
92 goto enomem;
93 }
94 (*host)->h_aliases = aliases;
95 memset(aliases, 0, (naliases + 1) * sizeof(char *));
96
97 if (naliases)
98 {
99 next_cname = ai->cnames;
100 while (next_cname)
101 {
102 if(next_cname->alias) {
103 aliases[alias] = ares_strdup(next_cname->alias);
104 if (!aliases[alias]) {
105 goto enomem;
106 }
107 alias++;
108 }
109 next_cname = next_cname->next;
110 }
111 }
112
113
114 (*host)->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
115 if (!(*host)->h_addr_list)
116 {
117 goto enomem;
118 }
119
120 memset((*host)->h_addr_list, 0, (naddrs + 1) * sizeof(char *));
121
122 if (ai->cnames)
123 {
124 (*host)->h_name = ares_strdup(ai->cnames->name);
125 if ((*host)->h_name == NULL && ai->cnames->name)
126 {
127 goto enomem;
128 }
129 }
130 else
131 {
132 (*host)->h_name = ares_strdup(ai->name);
133 if ((*host)->h_name == NULL && ai->name)
134 {
135 goto enomem;
136 }
137 }
138
139 (*host)->h_addrtype = family;
140 (*host)->h_length = (family == AF_INET)?
141 sizeof(struct in_addr):sizeof(struct ares_in6_addr);
142
143 if (naddrs)
144 {
145 addrs = ares_malloc(naddrs * (*host)->h_length);
146 if (!addrs)
147 {
148 goto enomem;
149 }
150
151 i = 0;
152 next = ai->nodes;
153 while (next)
154 {
155 if(next->ai_family == family)
156 {
157 (*host)->h_addr_list[i] = addrs + (i * (*host)->h_length);
158 if (family == AF_INET6)
159 {
160 memcpy((*host)->h_addr_list[i],
161 &(CARES_INADDR_CAST(struct sockaddr_in6 *, next->ai_addr)->sin6_addr),
162 (*host)->h_length);
163 }
164 else
165 {
166 memcpy((*host)->h_addr_list[i],
167 &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr),
168 (*host)->h_length);
169 }
170 ++i;
171 }
172 next = next->ai_next;
173 }
174
175 if (i == 0)
176 {
177 ares_free(addrs);
178 }
179 }
180
181 if (naddrs == 0 && naliases == 0)
182 {
183 ares_free_hostent(*host);
184 *host = NULL;
185 return ARES_ENODATA;
186 }
187
188 return ARES_SUCCESS;
189
190 enomem:
191 ares_free_hostent(*host);
192 *host = NULL;
193 return ARES_ENOMEM;
194 }
195
196
ares__addrinfo2addrttl(const struct ares_addrinfo * ai,int family,int req_naddrttls,struct ares_addrttl * addrttls,struct ares_addr6ttl * addr6ttls,int * naddrttls)197 int ares__addrinfo2addrttl(const struct ares_addrinfo *ai, int family,
198 int req_naddrttls, struct ares_addrttl *addrttls,
199 struct ares_addr6ttl *addr6ttls, int *naddrttls)
200 {
201 struct ares_addrinfo_node *next;
202 struct ares_addrinfo_cname *next_cname;
203 int cname_ttl = INT_MAX;
204
205 if (family != AF_INET && family != AF_INET6)
206 return ARES_EBADQUERY;
207
208 if (ai == NULL || naddrttls == NULL)
209 return ARES_EBADQUERY;
210
211 if (family == AF_INET && addrttls == NULL)
212 return ARES_EBADQUERY;
213
214 if (family == AF_INET6 && addr6ttls == NULL)
215 return ARES_EBADQUERY;
216
217 if (req_naddrttls == 0)
218 return ARES_EBADQUERY;
219
220 *naddrttls = 0;
221
222 next_cname = ai->cnames;
223 while (next_cname)
224 {
225 if(next_cname->ttl < cname_ttl)
226 cname_ttl = next_cname->ttl;
227 next_cname = next_cname->next;
228 }
229
230 next = ai->nodes;
231 while (next)
232 {
233 if(next->ai_family == family)
234 {
235 if (*naddrttls < req_naddrttls)
236 {
237 if (family == AF_INET6)
238 {
239 if(next->ai_ttl > cname_ttl)
240 addr6ttls[*naddrttls].ttl = cname_ttl;
241 else
242 addr6ttls[*naddrttls].ttl = next->ai_ttl;
243
244 memcpy(&addr6ttls[*naddrttls].ip6addr,
245 &(CARES_INADDR_CAST(struct sockaddr_in6 *, next->ai_addr)->sin6_addr),
246 sizeof(struct ares_in6_addr));
247 }
248 else
249 {
250 if(next->ai_ttl > cname_ttl)
251 addrttls[*naddrttls].ttl = cname_ttl;
252 else
253 addrttls[*naddrttls].ttl = next->ai_ttl;
254 memcpy(&addrttls[*naddrttls].ipaddr,
255 &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr),
256 sizeof(struct in_addr));
257 }
258 (*naddrttls)++;
259 }
260 }
261 next = next->ai_next;
262 }
263
264 return ARES_SUCCESS;
265 }
266
267