inet_ntop.c: s/socklen_t/ares_socklen_t
[platform/upstream/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
109     if ( rr_class == C_IN && rr_type == T_NS )
110     {
111       /* Decode the RR data and add it to the nameservers list */
112       status = ares__expand_name_for_response( aptr, abuf, alen, &rr_data,
113                                                &len);
114       if ( status != ARES_SUCCESS )
115       {
116         free(rr_name);
117         break;
118       }
119
120       nameservers[nameservers_num] = malloc(strlen(rr_data)+1);
121
122       if (nameservers[nameservers_num]==NULL)
123       {
124         free(rr_name);
125         free(rr_data);
126         status=ARES_ENOMEM;
127         break;
128       }
129       strcpy(nameservers[nameservers_num],rr_data);
130       free(rr_data);
131
132       nameservers_num++;
133     }
134
135     free( rr_name );
136
137     aptr += rr_len;
138     if ( aptr > abuf + alen )
139     {
140       status = ARES_EBADRESP;
141       break;
142     }
143   }
144
145   if ( status == ARES_SUCCESS && nameservers_num == 0 )
146   {
147     status = ARES_ENODATA;
148   }
149   if ( status == ARES_SUCCESS )
150   {
151     /* We got our answer.  Allocate memory to build the host entry. */
152     nameservers[nameservers_num] = NULL;
153     hostent = malloc( sizeof( struct hostent ) );
154     if ( hostent )
155     {
156       hostent->h_addr_list = malloc( 1 * sizeof( char * ) );
157       if ( hostent->h_addr_list )
158       {
159         /* Fill in the hostent and return successfully. */
160         hostent->h_name = hostname;
161         hostent->h_aliases = nameservers;
162         hostent->h_addrtype = AF_INET;
163         hostent->h_length = sizeof( struct in_addr );
164         hostent->h_addr_list[0] = NULL;
165         *host = hostent;
166         return ARES_SUCCESS;
167       }
168       free( hostent );
169     }
170     status = ARES_ENOMEM;
171   }
172   for ( i = 0; i < nameservers_num; i++ )
173     free( nameservers[i] );
174   free( nameservers );
175   free( hostname );
176   return status;
177 }