1
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_SYS_SOCKET_H
20 # include <sys/socket.h>
21 #endif
22 #ifdef HAVE_NETINET_IN_H
23 # include <netinet/in.h>
24 #endif
25 #ifdef HAVE_NETDB_H
26 # include <netdb.h>
27 #endif
28 #ifdef HAVE_ARPA_NAMESER_H
29 # include <arpa/nameser.h>
30 #else
31 # include "nameser.h"
32 #endif
33 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
34 # include <arpa/nameser_compat.h>
35 #endif
36
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif
40
41 #include <stdlib.h>
42 #include <string.h>
43 #include "ares.h"
44 #include "ares_dns.h"
45 #include "ares_private.h"
46
ares_parse_ptr_reply(const unsigned char * abuf,int alen,const void * addr,int addrlen,int family,struct hostent ** host)47 int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
48 int addrlen, int family, struct hostent **host)
49 {
50 unsigned int qdcount, ancount;
51 int status, i, rr_type, rr_class, rr_len;
52 long len;
53 const unsigned char *aptr;
54 char *ptrname, *hostname, *rr_name, *rr_data;
55 struct hostent *hostent;
56 int aliascnt = 0;
57 int alias_alloc = 8;
58 char ** aliases;
59
60 /* Set *host to NULL for all failure cases. */
61 *host = NULL;
62
63 /* Give up if abuf doesn't have room for a header. */
64 if (alen < HFIXEDSZ)
65 return ARES_EBADRESP;
66
67 /* Fetch the question and answer count from the header. */
68 qdcount = DNS_HEADER_QDCOUNT(abuf);
69 ancount = DNS_HEADER_ANCOUNT(abuf);
70 if (qdcount != 1)
71 return ARES_EBADRESP;
72
73 /* Expand the name from the question, and skip past the question. */
74 aptr = abuf + HFIXEDSZ;
75 status = ares__expand_name_for_response(aptr, abuf, alen, &ptrname, &len);
76 if (status != ARES_SUCCESS)
77 return status;
78 if (aptr + len + QFIXEDSZ > abuf + alen)
79 {
80 free(ptrname);
81 return ARES_EBADRESP;
82 }
83 aptr += len + QFIXEDSZ;
84
85 /* Examine each answer resource record (RR) in turn. */
86 hostname = NULL;
87 aliases = malloc(alias_alloc * sizeof(char *));
88 if (!aliases)
89 {
90 free(ptrname);
91 return ARES_ENOMEM;
92 }
93 for (i = 0; i < (int)ancount; i++)
94 {
95 /* Decode the RR up to the data field. */
96 status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
97 if (status != ARES_SUCCESS)
98 break;
99 aptr += len;
100 if (aptr + RRFIXEDSZ > abuf + alen)
101 {
102 free(rr_name);
103 status = ARES_EBADRESP;
104 break;
105 }
106 rr_type = DNS_RR_TYPE(aptr);
107 rr_class = DNS_RR_CLASS(aptr);
108 rr_len = DNS_RR_LEN(aptr);
109 aptr += RRFIXEDSZ;
110
111 if (rr_class == C_IN && rr_type == T_PTR
112 && strcasecmp(rr_name, ptrname) == 0)
113 {
114 /* Decode the RR data and set hostname to it. */
115 status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
116 &len);
117 if (status != ARES_SUCCESS)
118 {
119 free(rr_name);
120 break;
121 }
122 if (hostname)
123 free(hostname);
124 hostname = rr_data;
125 aliases[aliascnt] = malloc((strlen(rr_data)+1) * sizeof(char));
126 if (!aliases[aliascnt])
127 {
128 free(rr_name);
129 status = ARES_ENOMEM;
130 break;
131 }
132 strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1);
133 aliascnt++;
134 if (aliascnt >= alias_alloc) {
135 char **ptr;
136 alias_alloc *= 2;
137 ptr = realloc(aliases, alias_alloc * sizeof(char *));
138 if(!ptr) {
139 free(rr_name);
140 status = ARES_ENOMEM;
141 break;
142 }
143 aliases = ptr;
144 }
145 }
146
147 if (rr_class == C_IN && rr_type == T_CNAME)
148 {
149 /* Decode the RR data and replace ptrname with it. */
150 status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
151 &len);
152 if (status != ARES_SUCCESS)
153 {
154 free(rr_name);
155 break;
156 }
157 free(ptrname);
158 ptrname = rr_data;
159 }
160
161 free(rr_name);
162 aptr += rr_len;
163 if (aptr > abuf + alen)
164 {
165 status = ARES_EBADRESP;
166 break;
167 }
168 }
169
170 if (status == ARES_SUCCESS && !hostname)
171 status = ARES_ENODATA;
172 if (status == ARES_SUCCESS)
173 {
174 /* We got our answer. Allocate memory to build the host entry. */
175 hostent = malloc(sizeof(struct hostent));
176 if (hostent)
177 {
178 hostent->h_addr_list = malloc(2 * sizeof(char *));
179 if (hostent->h_addr_list)
180 {
181 hostent->h_addr_list[0] = malloc(addrlen);
182 if (hostent->h_addr_list[0])
183 {
184 hostent->h_aliases = malloc((aliascnt+1) * sizeof (char *));
185 if (hostent->h_aliases)
186 {
187 /* Fill in the hostent and return successfully. */
188 hostent->h_name = hostname;
189 for (i=0 ; i<aliascnt ; i++)
190 hostent->h_aliases[i] = aliases[i];
191 hostent->h_aliases[aliascnt] = NULL;
192 hostent->h_addrtype = family;
193 hostent->h_length = addrlen;
194 memcpy(hostent->h_addr_list[0], addr, addrlen);
195 hostent->h_addr_list[1] = NULL;
196 *host = hostent;
197 free(aliases);
198 free(ptrname);
199 return ARES_SUCCESS;
200 }
201 free(hostent->h_addr_list[0]);
202 }
203 free(hostent->h_addr_list);
204 }
205 free(hostent);
206 }
207 status = ARES_ENOMEM;
208 }
209 for (i=0 ; i<aliascnt ; i++)
210 if (aliases[i])
211 free(aliases[i]);
212 free(aliases);
213 if (hostname)
214 free(hostname);
215 free(ptrname);
216 return status;
217 }
218