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