1
2 /* Copyright 1998 by the Massachusetts Institute of Technology.
3 * Copyright 2005 Dominick Meglio
4 * Copyright (C) 2019 by Andrew Selivanov
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 #ifdef HAVE_ARPA_NAMESER_H
31 # include <arpa/nameser.h>
32 #else
33 # include "nameser.h"
34 #endif
35 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
36 # include <arpa/nameser_compat.h>
37 #endif
38
39 #ifdef HAVE_STRINGS_H
40 # include <strings.h>
41 #endif
42
43 #ifdef HAVE_LIMITS_H
44 # include <limits.h>
45 #endif
46
47 #include "ares.h"
48 #include "ares_dns.h"
49 #include "ares_inet_net_pton.h"
50 #include "ares_private.h"
51
ares_parse_aaaa_reply(const unsigned char * abuf,int alen,struct hostent ** host,struct ares_addr6ttl * addrttls,int * naddrttls)52 int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
53 struct hostent **host, struct ares_addr6ttl *addrttls,
54 int *naddrttls)
55 {
56 struct ares_addrinfo ai;
57 struct ares_addrinfo_node *next;
58 struct ares_addrinfo_cname *next_cname;
59 char **aliases = NULL;
60 char *question_hostname = NULL;
61 struct hostent *hostent = NULL;
62 struct ares_in6_addr *addrs = NULL;
63 int naliases = 0, naddrs = 0, alias = 0, i;
64 int cname_ttl = INT_MAX;
65 int status;
66
67 memset(&ai, 0, sizeof(ai));
68
69 status = ares__parse_into_addrinfo2(abuf, alen, &question_hostname, &ai);
70 if (status != ARES_SUCCESS)
71 {
72 ares_free(question_hostname);
73
74 if (naddrttls)
75 {
76 *naddrttls = 0;
77 }
78
79 return status;
80 }
81
82 hostent = ares_malloc(sizeof(struct hostent));
83 if (!hostent)
84 {
85 goto enomem;
86 }
87
88 next = ai.nodes;
89 while (next)
90 {
91 if(next->ai_family == AF_INET6)
92 {
93 ++naddrs;
94 }
95 next = next->ai_next;
96 }
97
98 next_cname = ai.cnames;
99 while (next_cname)
100 {
101 if(next_cname->alias)
102 ++naliases;
103 next_cname = next_cname->next;
104 }
105
106 aliases = ares_malloc((naliases + 1) * sizeof(char *));
107 if (!aliases)
108 {
109 goto enomem;
110 }
111
112 if (naliases)
113 {
114 next_cname = ai.cnames;
115 while (next_cname)
116 {
117 if(next_cname->alias)
118 aliases[alias++] = strdup(next_cname->alias);
119 if(next_cname->ttl < cname_ttl)
120 cname_ttl = next_cname->ttl;
121 next_cname = next_cname->next;
122 }
123 }
124
125 aliases[alias] = NULL;
126
127 hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
128 if (!hostent->h_addr_list)
129 {
130 goto enomem;
131 }
132
133 for (i = 0; i < naddrs + 1; ++i)
134 {
135 hostent->h_addr_list[i] = NULL;
136 }
137
138 if (ai.cnames)
139 {
140 hostent->h_name = strdup(ai.cnames->name);
141 ares_free(question_hostname);
142 }
143 else
144 {
145 hostent->h_name = question_hostname;
146 }
147
148 hostent->h_aliases = aliases;
149 hostent->h_addrtype = AF_INET6;
150 hostent->h_length = sizeof(struct ares_in6_addr);
151
152 if (naddrs)
153 {
154 addrs = ares_malloc(naddrs * sizeof(struct ares_in6_addr));
155 if (!addrs)
156 {
157 goto enomem;
158 }
159
160 i = 0;
161 next = ai.nodes;
162 while (next)
163 {
164 if(next->ai_family == AF_INET6)
165 {
166 hostent->h_addr_list[i] = (char*)&addrs[i];
167 memcpy(hostent->h_addr_list[i],
168 &(CARES_INADDR_CAST(struct sockaddr_in6 *, next->ai_addr)->sin6_addr),
169 sizeof(struct ares_in6_addr));
170 if (naddrttls && i < *naddrttls)
171 {
172 if(next->ai_ttl > cname_ttl)
173 addrttls[i].ttl = cname_ttl;
174 else
175 addrttls[i].ttl = next->ai_ttl;
176
177 memcpy(&addrttls[i].ip6addr,
178 &(CARES_INADDR_CAST(struct sockaddr_in6 *, next->ai_addr)->sin6_addr),
179 sizeof(struct ares_in6_addr));
180 }
181 ++i;
182 }
183 next = next->ai_next;
184 }
185
186 if (i == 0)
187 {
188 ares_free(addrs);
189 }
190 }
191
192 if (host)
193 {
194 *host = hostent;
195 }
196 else
197 {
198 ares_free_hostent(hostent);
199 }
200
201 if (naddrttls)
202 {
203 /* Truncated to at most *naddrttls entries */
204 *naddrttls = (naddrs > *naddrttls)?*naddrttls:naddrs;
205 }
206
207 ares__freeaddrinfo_cnames(ai.cnames);
208 ares__freeaddrinfo_nodes(ai.nodes);
209 return ARES_SUCCESS;
210
211 enomem:
212 ares_free(aliases);
213 ares_free(hostent);
214 ares__freeaddrinfo_cnames(ai.cnames);
215 ares__freeaddrinfo_nodes(ai.nodes);
216 ares_free(question_hostname);
217 return ARES_ENOMEM;
218 }
219