1
2 /* Copyright 1998 by the Massachusetts Institute of Technology.
3 * Copyright (C) 2019 by Andrew Selivanov
4 *
5 * Permission to use, copy, modify, and distribute this
6 * software and its documentation for any purpose and without
7 * fee is hereby granted, provided that the above copyright
8 * notice appear in all copies and that both that copyright
9 * notice and this permission notice appear in supporting
10 * documentation, and that the name of M.I.T. not be used in
11 * advertising or publicity pertaining to distribution of the
12 * software without specific, written prior permission.
13 * M.I.T. makes no representations about the suitability of
14 * this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
16 */
17
18 #include "ares_setup.h"
19
20 #ifdef HAVE_NETINET_IN_H
21 # include <netinet/in.h>
22 #endif
23 #ifdef HAVE_NETDB_H
24 # include <netdb.h>
25 #endif
26 #ifdef HAVE_ARPA_INET_H
27 # include <arpa/inet.h>
28 #endif
29 #ifdef HAVE_ARPA_NAMESER_H
30 # include <arpa/nameser.h>
31 #else
32 # include "nameser.h"
33 #endif
34 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
35 # include <arpa/nameser_compat.h>
36 #endif
37
38 #ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 #endif
41
42 #ifdef HAVE_LIMITS_H
43 # include <limits.h>
44 #endif
45
46 #include "ares.h"
47 #include "ares_dns.h"
48 #include "ares_private.h"
49
ares_parse_a_reply(const unsigned char * abuf,int alen,struct hostent ** host,struct ares_addrttl * addrttls,int * naddrttls)50 int ares_parse_a_reply(const unsigned char *abuf, int alen,
51 struct hostent **host,
52 struct ares_addrttl *addrttls, int *naddrttls)
53 {
54 struct ares_addrinfo ai;
55 struct ares_addrinfo_node *next;
56 struct ares_addrinfo_cname *next_cname;
57 char **aliases = NULL;
58 char *question_hostname = NULL;
59 struct hostent *hostent = NULL;
60 struct in_addr *addrs = NULL;
61 int naliases = 0, naddrs = 0, alias = 0, i;
62 int cname_ttl = INT_MAX;
63 int status;
64
65 memset(&ai, 0, sizeof(ai));
66
67 status = ares__parse_into_addrinfo2(abuf, alen, &question_hostname, &ai);
68 if (status != ARES_SUCCESS)
69 {
70 ares_free(question_hostname);
71
72 if (naddrttls)
73 {
74 *naddrttls = 0;
75 }
76
77 return status;
78 }
79
80 hostent = ares_malloc(sizeof(struct hostent));
81 if (!hostent)
82 {
83 goto enomem;
84 }
85
86 next = ai.nodes;
87 while (next)
88 {
89 if (next->ai_family == AF_INET)
90 {
91 ++naddrs;
92 }
93 next = next->ai_next;
94 }
95
96 next_cname = ai.cnames;
97 while (next_cname)
98 {
99 if(next_cname->alias)
100 ++naliases;
101 next_cname = next_cname->next;
102 }
103
104 aliases = ares_malloc((naliases + 1) * sizeof(char *));
105 if (!aliases)
106 {
107 goto enomem;
108 }
109
110 if (naliases)
111 {
112 /* Truncated to at most *naddrttls entries */
113 *naddrttls = (naddrs > *naddrttls) ? *naddrttls : naddrs;
114 while (next_cname)
115 {
116 if(next_cname->alias)
117 aliases[alias++] = strdup(next_cname->alias);
118 if(next_cname->ttl < cname_ttl)
119 cname_ttl = next_cname->ttl;
120 next_cname = next_cname->next;
121 }
122 }
123
124 aliases[alias] = NULL;
125
126 hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
127 if (!hostent->h_addr_list)
128 {
129 goto enomem;
130 }
131
132 for (i = 0; i < naddrs + 1; ++i)
133 {
134 hostent->h_addr_list[i] = NULL;
135 }
136
137 if (ai.cnames)
138 {
139 hostent->h_name = strdup(ai.cnames->name);
140 ares_free(question_hostname);
141 }
142 else
143 {
144 hostent->h_name = question_hostname;
145 }
146
147 hostent->h_aliases = aliases;
148 hostent->h_addrtype = AF_INET;
149 hostent->h_length = sizeof(struct in_addr);
150
151 if (naddrs)
152 {
153 addrs = ares_malloc(naddrs * sizeof(struct in_addr));
154 if (!addrs)
155 {
156 goto enomem;
157 }
158
159 i = 0;
160 next = ai.nodes;
161 while (next)
162 {
163 if (next->ai_family == AF_INET)
164 {
165 hostent->h_addr_list[i] = (char *)&addrs[i];
166 memcpy(hostent->h_addr_list[i],
167 &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr),
168 sizeof(struct in_addr));
169 if (naddrttls && i < *naddrttls)
170 {
171 if (next->ai_ttl > cname_ttl)
172 addrttls[i].ttl = cname_ttl;
173 else
174 addrttls[i].ttl = next->ai_ttl;
175
176 memcpy(&addrttls[i].ipaddr,
177 &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr),
178 sizeof(struct in_addr));
179 }
180 ++i;
181 }
182 next = next->ai_next;
183 }
184 if (i == 0)
185 {
186 ares_free(addrs);
187 }
188 }
189
190 if (host)
191 {
192 *host = hostent;
193 }
194 else
195 {
196 ares_free_hostent(hostent);
197 }
198
199 if (naddrttls)
200 {
201 *naddrttls = naddrs;
202 }
203
204 ares__freeaddrinfo_cnames(ai.cnames);
205 ares__freeaddrinfo_nodes(ai.nodes);
206 return ARES_SUCCESS;
207
208 enomem:
209 ares_free(aliases);
210 ares_free(hostent);
211 ares__freeaddrinfo_cnames(ai.cnames);
212 ares__freeaddrinfo_nodes(ai.nodes);
213 ares_free(question_hostname);
214 return ARES_ENOMEM;
215 }
216