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