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