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