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