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 next_cname = ai.cnames;
113 while (next_cname)
114 {
115 if(next_cname->alias)
116 aliases[alias++] = strdup(next_cname->alias);
117 if(next_cname->ttl < cname_ttl)
118 cname_ttl = next_cname->ttl;
119 next_cname = next_cname->next;
120 }
121 }
122
123 aliases[alias] = NULL;
124
125 hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
126 if (!hostent->h_addr_list)
127 {
128 goto enomem;
129 }
130
131 for (i = 0; i < naddrs + 1; ++i)
132 {
133 hostent->h_addr_list[i] = NULL;
134 }
135
136 if (ai.cnames)
137 {
138 hostent->h_name = strdup(ai.cnames->name);
139 ares_free(question_hostname);
140 }
141 else
142 {
143 hostent->h_name = question_hostname;
144 }
145
146 hostent->h_aliases = aliases;
147 hostent->h_addrtype = AF_INET;
148 hostent->h_length = sizeof(struct in_addr);
149
150 if (naddrs)
151 {
152 addrs = ares_malloc(naddrs * sizeof(struct in_addr));
153 if (!addrs)
154 {
155 goto enomem;
156 }
157
158 i = 0;
159 next = ai.nodes;
160 while (next)
161 {
162 if (next->ai_family == AF_INET)
163 {
164 hostent->h_addr_list[i] = (char *)&addrs[i];
165 memcpy(hostent->h_addr_list[i],
166 &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr),
167 sizeof(struct in_addr));
168 if (naddrttls && i < *naddrttls)
169 {
170 if (next->ai_ttl > cname_ttl)
171 addrttls[i].ttl = cname_ttl;
172 else
173 addrttls[i].ttl = next->ai_ttl;
174
175 memcpy(&addrttls[i].ipaddr,
176 &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr),
177 sizeof(struct in_addr));
178 }
179 ++i;
180 }
181 next = next->ai_next;
182 }
183 if (i == 0)
184 {
185 ares_free(addrs);
186 }
187 }
188
189 if (host)
190 {
191 *host = hostent;
192 }
193 else
194 {
195 ares_free_hostent(hostent);
196 }
197
198 if (naddrttls)
199 {
200 /* Truncated to at most *naddrttls entries */
201 *naddrttls = (naddrs > *naddrttls)?*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