tizen 2.4 release
[external/c-ares.git] / ares_parse_ns_reply.c
1 /* Copyright 1998 by the Massachusetts Institute of Technology.
2  *
3  * Permission to use, copy, modify, and distribute this
4  * software and its documentation for any purpose and without
5  * fee is hereby granted, provided that the above copyright
6  * notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting
8  * documentation, and that the name of M.I.T. not be used in
9  * advertising or publicity pertaining to distribution of the
10  * software without specific, written prior permission.
11  * M.I.T. makes no representations about the suitability of
12  * this software for any purpose.  It is provided "as is"
13  * without express or implied warranty.
14  */
15
16 /*
17  * ares_parse_ns_reply created by Vlad Dinulescu <vlad.dinulescu@avira.com>
18  *      on behalf of AVIRA Gmbh - http://www.avira.com
19  */
20
21 #include "ares_setup.h"
22
23 #ifdef HAVE_NETINET_IN_H
24 #  include <netinet/in.h>
25 #endif
26 #ifdef HAVE_NETDB_H
27 #  include <netdb.h>
28 #endif
29 #ifdef HAVE_ARPA_INET_H
30 #  include <arpa/inet.h>
31 #endif
32 #ifdef HAVE_ARPA_NAMESER_H
33 #  include <arpa/nameser.h>
34 #else
35 #  include "nameser.h"
36 #endif
37 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
38 #  include <arpa/nameser_compat.h>
39 #endif
40
41 #include "ares.h"
42 #include "ares_dns.h"
43 #include "ares_private.h"
44
45 int ares_parse_ns_reply( const unsigned char* abuf, int alen,
46                          struct hostent** host )
47 {
48   unsigned int qdcount, ancount;
49   int status, i, rr_type, rr_class, rr_len;
50   int nameservers_num;
51   long len;
52   const unsigned char *aptr;
53   char* hostname, *rr_name, *rr_data, **nameservers;
54   struct hostent *hostent;
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, &hostname, &len);
72   if ( status != ARES_SUCCESS )
73     return status;
74   if ( aptr + len + QFIXEDSZ > abuf + alen )
75   {
76     free( hostname );
77     return ARES_EBADRESP;
78   }
79   aptr += len + QFIXEDSZ;
80
81   /* Allocate nameservers array; ancount gives an upper bound */
82   nameservers = malloc( ( ancount + 1 ) * sizeof( char * ) );
83   if ( !nameservers )
84   {
85     free( hostname );
86     return ARES_ENOMEM;
87   }
88   nameservers_num = 0;
89
90   /* Examine each answer resource record (RR) in turn. */
91   for ( i = 0; i < ( int ) ancount; i++ )
92   {
93     /* Decode the RR up to the data field. */
94     status = ares__expand_name_for_response( aptr, abuf, alen, &rr_name, &len );
95     if ( status != ARES_SUCCESS )
96       break;
97     aptr += len;
98     if ( aptr + RRFIXEDSZ > abuf + alen )
99     {
100       status = ARES_EBADRESP;
101       free(rr_name);
102       break;
103     }
104     rr_type = DNS_RR_TYPE( aptr );
105     rr_class = DNS_RR_CLASS( aptr );
106     rr_len = DNS_RR_LEN( aptr );
107     aptr += RRFIXEDSZ;
108     if (aptr + rr_len > abuf + alen)
109       {
110         free(rr_name);
111         status = ARES_EBADRESP;
112         break;
113       }
114
115     if ( rr_class == C_IN && rr_type == T_NS )
116     {
117       /* Decode the RR data and add it to the nameservers list */
118       status = ares__expand_name_for_response( aptr, abuf, alen, &rr_data,
119                                                &len);
120       if ( status != ARES_SUCCESS )
121       {
122         free(rr_name);
123         break;
124       }
125
126       nameservers[nameservers_num] = malloc(strlen(rr_data)+1);
127
128       if (nameservers[nameservers_num]==NULL)
129       {
130         free(rr_name);
131         free(rr_data);
132         status=ARES_ENOMEM;
133         break;
134       }
135       strcpy(nameservers[nameservers_num],rr_data);
136       free(rr_data);
137
138       nameservers_num++;
139     }
140
141     free( rr_name );
142
143     aptr += rr_len;
144     if ( aptr > abuf + alen )
145     {
146       status = ARES_EBADRESP;
147       break;
148     }
149   }
150
151   if ( status == ARES_SUCCESS && nameservers_num == 0 )
152   {
153     status = ARES_ENODATA;
154   }
155   if ( status == ARES_SUCCESS )
156   {
157     /* We got our answer.  Allocate memory to build the host entry. */
158     nameservers[nameservers_num] = NULL;
159     hostent = malloc( sizeof( struct hostent ) );
160     if ( hostent )
161     {
162       hostent->h_addr_list = malloc( 1 * sizeof( char * ) );
163       if ( hostent->h_addr_list )
164       {
165         /* Fill in the hostent and return successfully. */
166         hostent->h_name = hostname;
167         hostent->h_aliases = nameservers;
168         hostent->h_addrtype = AF_INET;
169         hostent->h_length = sizeof( struct in_addr );
170         hostent->h_addr_list[0] = NULL;
171         *host = hostent;
172         return ARES_SUCCESS;
173       }
174       free( hostent );
175     }
176     status = ARES_ENOMEM;
177   }
178   for ( i = 0; i < nameservers_num; i++ )
179     free( nameservers[i] );
180   free( nameservers );
181   free( hostname );
182   return status;
183 }