• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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