blob: 976a5311a24d7947aeee4642556f0824761ff089 [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001
2/* Copyright 1998 by the Massachusetts Institute of Technology.
3 *
4 * Permission to use, copy, modify, and distribute this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation, and that the name of M.I.T. not be used in
10 * advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission.
12 * M.I.T. makes no representations about the suitability of
13 * this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
15 */
16
17#include "ares_setup.h"
18
19#ifdef HAVE_NETINET_IN_H
20# include <netinet/in.h>
21#endif
22#ifdef HAVE_NETDB_H
23# include <netdb.h>
24#endif
25#ifdef HAVE_ARPA_NAMESER_H
26# include <arpa/nameser.h>
27#else
28# include "nameser.h"
29#endif
30#ifdef HAVE_ARPA_NAMESER_COMPAT_H
31# include <arpa/nameser_compat.h>
32#endif
33
34#ifdef HAVE_STRINGS_H
35# include <strings.h>
36#endif
37
38#include "ares.h"
39#include "ares_dns.h"
40#include "ares_nowarn.h"
41#include "ares_private.h"
42
43int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
44 int addrlen, int family, struct hostent **host)
45{
46 unsigned int qdcount, ancount;
47 int status, i, rr_type, rr_class, rr_len;
48 long len;
49 const unsigned char *aptr;
50 char *ptrname, *hostname, *rr_name, *rr_data;
51 struct hostent *hostent;
52 int aliascnt = 0;
53 int alias_alloc = 8;
54 char ** aliases;
55
56 /* Set *host to NULL for all failure cases. */
57 *host = NULL;
58
59 /* Give up if abuf doesn't have room for a header. */
60 if (alen < HFIXEDSZ)
61 return ARES_EBADRESP;
62
63 /* Fetch the question and answer count from the header. */
64 qdcount = DNS_HEADER_QDCOUNT(abuf);
65 ancount = DNS_HEADER_ANCOUNT(abuf);
66 if (qdcount != 1)
67 return ARES_EBADRESP;
68
69 /* Expand the name from the question, and skip past the question. */
70 aptr = abuf + HFIXEDSZ;
71 status = ares__expand_name_for_response(aptr, abuf, alen, &ptrname, &len);
72 if (status != ARES_SUCCESS)
73 return status;
74 if (aptr + len + QFIXEDSZ > abuf + alen)
75 {
76 ares_free(ptrname);
77 return ARES_EBADRESP;
78 }
79 aptr += len + QFIXEDSZ;
80
81 /* Examine each answer resource record (RR) in turn. */
82 hostname = NULL;
83 aliases = ares_malloc(alias_alloc * sizeof(char *));
84 if (!aliases)
85 {
86 ares_free(ptrname);
87 return ARES_ENOMEM;
88 }
89 for (i = 0; i < (int)ancount; i++)
90 {
91 /* Decode the RR up to the data field. */
92 status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
93 if (status != ARES_SUCCESS)
94 break;
95 aptr += len;
96 if (aptr + RRFIXEDSZ > abuf + alen)
97 {
98 ares_free(rr_name);
99 status = ARES_EBADRESP;
100 break;
101 }
102 rr_type = DNS_RR_TYPE(aptr);
103 rr_class = DNS_RR_CLASS(aptr);
104 rr_len = DNS_RR_LEN(aptr);
105 aptr += RRFIXEDSZ;
106 if (aptr + rr_len > abuf + alen)
107 {
108 ares_free(rr_name);
109 status = ARES_EBADRESP;
110 break;
111 }
112
113 if (rr_class == C_IN && rr_type == T_PTR
114 && strcasecmp(rr_name, ptrname) == 0)
115 {
116 /* Decode the RR data and set hostname to it. */
117 status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
118 &len);
119 if (status != ARES_SUCCESS)
120 {
121 ares_free(rr_name);
122 break;
123 }
124 if (hostname)
125 ares_free(hostname);
126 hostname = rr_data;
127 aliases[aliascnt] = ares_malloc((strlen(rr_data)+1) * sizeof(char));
128 if (!aliases[aliascnt])
129 {
130 ares_free(rr_name);
131 status = ARES_ENOMEM;
132 break;
133 }
134 strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1);
135 aliascnt++;
136 if (aliascnt >= alias_alloc) {
137 char **ptr;
138 alias_alloc *= 2;
139 ptr = ares_realloc(aliases, alias_alloc * sizeof(char *));
140 if(!ptr) {
141 ares_free(rr_name);
142 status = ARES_ENOMEM;
143 break;
144 }
145 aliases = ptr;
146 }
147 }
148
149 if (rr_class == C_IN && rr_type == T_CNAME)
150 {
151 /* Decode the RR data and replace ptrname with it. */
152 status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
153 &len);
154 if (status != ARES_SUCCESS)
155 {
156 ares_free(rr_name);
157 break;
158 }
159 ares_free(ptrname);
160 ptrname = rr_data;
161 }
162
163 ares_free(rr_name);
164 aptr += rr_len;
165 if (aptr > abuf + alen)
166 { /* LCOV_EXCL_START: already checked above */
167 status = ARES_EBADRESP;
168 break;
169 } /* LCOV_EXCL_STOP */
170 }
171
172 if (status == ARES_SUCCESS && !hostname)
173 status = ARES_ENODATA;
174 if (status == ARES_SUCCESS)
175 {
176 /* We got our answer. Allocate memory to build the host entry. */
177 hostent = ares_malloc(sizeof(struct hostent));
178 if (hostent)
179 {
180 hostent->h_addr_list = ares_malloc(2 * sizeof(char *));
181 if (hostent->h_addr_list)
182 {
183 hostent->h_addr_list[0] = ares_malloc(addrlen);
184 if (hostent->h_addr_list[0])
185 {
186 hostent->h_aliases = ares_malloc((aliascnt+1) * sizeof (char *));
187 if (hostent->h_aliases)
188 {
189 /* Fill in the hostent and return successfully. */
190 hostent->h_name = hostname;
191 for (i=0 ; i<aliascnt ; i++)
192 hostent->h_aliases[i] = aliases[i];
193 hostent->h_aliases[aliascnt] = NULL;
194 hostent->h_addrtype = aresx_sitoss(family);
195 hostent->h_length = aresx_sitoss(addrlen);
196 memcpy(hostent->h_addr_list[0], addr, addrlen);
197 hostent->h_addr_list[1] = NULL;
198 *host = hostent;
199 ares_free(aliases);
200 ares_free(ptrname);
201 return ARES_SUCCESS;
202 }
203 ares_free(hostent->h_addr_list[0]);
204 }
205 ares_free(hostent->h_addr_list);
206 }
207 ares_free(hostent);
208 }
209 status = ARES_ENOMEM;
210 }
211 for (i=0 ; i<aliascnt ; i++)
212 if (aliases[i])
213 ares_free(aliases[i]);
214 ares_free(aliases);
215 if (hostname)
216 ares_free(hostname);
217 ares_free(ptrname);
218 return status;
219}