e71c993f8de691348fc2fe9dd7655d3a45fc8d75
[platform/upstream/c-ares.git] / src / lib / ares_parse_a_reply.c
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
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 }