Imported Upstream version 1.18.1
[platform/upstream/c-ares.git] / src / lib / 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
33 #include "ares_nameser.h"
34
35 #include "ares.h"
36 #include "ares_dns.h"
37 #include "ares_private.h"
38
39 int ares_parse_ns_reply( const unsigned char* abuf, int alen,
40                          struct hostent** host )
41 {
42   unsigned int qdcount, ancount;
43   int status, i, rr_type, rr_class, rr_len;
44   int nameservers_num;
45   long len;
46   const unsigned char *aptr;
47   char* hostname, *rr_name, *rr_data, **nameservers;
48   struct hostent *hostent;
49
50   /* Set *host to NULL for all failure cases. */
51   *host = NULL;
52
53   /* Give up if abuf doesn't have room for a header. */
54   if ( alen < HFIXEDSZ )
55     return ARES_EBADRESP;
56
57   /* Fetch the question and answer count from the header. */
58   qdcount = DNS_HEADER_QDCOUNT( abuf );
59   ancount = DNS_HEADER_ANCOUNT( abuf );
60   if ( qdcount != 1 )
61     return ARES_EBADRESP;
62
63   /* Expand the name from the question, and skip past the question. */
64   aptr = abuf + HFIXEDSZ;
65   status = ares__expand_name_for_response( aptr, abuf, alen, &hostname, &len, 0);
66   if ( status != ARES_SUCCESS )
67     return status;
68   if ( aptr + len + QFIXEDSZ > abuf + alen )
69   {
70     ares_free( hostname );
71     return ARES_EBADRESP;
72   }
73   aptr += len + QFIXEDSZ;
74
75   /* Allocate nameservers array; ancount gives an upper bound */
76   nameservers = ares_malloc( ( ancount + 1 ) * sizeof( char * ) );
77   if ( !nameservers )
78   {
79     ares_free( hostname );
80     return ARES_ENOMEM;
81   }
82   nameservers_num = 0;
83
84   /* Examine each answer resource record (RR) in turn. */
85   for ( i = 0; i < ( int ) ancount; i++ )
86   {
87     /* Decode the RR up to the data field. */
88     status = ares__expand_name_for_response( aptr, abuf, alen, &rr_name, &len, 0);
89     if ( status != ARES_SUCCESS )
90       break;
91     aptr += len;
92     if ( aptr + RRFIXEDSZ > abuf + alen )
93     {
94       status = ARES_EBADRESP;
95       ares_free(rr_name);
96       break;
97     }
98     rr_type = DNS_RR_TYPE( aptr );
99     rr_class = DNS_RR_CLASS( aptr );
100     rr_len = DNS_RR_LEN( aptr );
101     aptr += RRFIXEDSZ;
102     if (aptr + rr_len > abuf + alen)
103       {
104         ares_free(rr_name);
105         status = ARES_EBADRESP;
106         break;
107       }
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, 1);
114       if ( status != ARES_SUCCESS )
115       {
116         ares_free(rr_name);
117         break;
118       }
119
120       nameservers[nameservers_num] = ares_malloc(strlen(rr_data)+1);
121
122       if (nameservers[nameservers_num]==NULL)
123       {
124         ares_free(rr_name);
125         ares_free(rr_data);
126         status=ARES_ENOMEM;
127         break;
128       }
129       strcpy(nameservers[nameservers_num],rr_data);
130       ares_free(rr_data);
131
132       nameservers_num++;
133     }
134
135     ares_free( rr_name );
136
137     aptr += rr_len;
138     if ( aptr > abuf + alen )
139     {  /* LCOV_EXCL_START: already checked above */
140       status = ARES_EBADRESP;
141       break;
142     }  /* LCOV_EXCL_STOP */
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 = ares_malloc( sizeof( struct hostent ) );
154     if ( hostent )
155     {
156       hostent->h_addr_list = ares_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       ares_free( hostent );
169     }
170     status = ARES_ENOMEM;
171   }
172   for ( i = 0; i < nameservers_num; i++ )
173     ares_free( nameservers[i] );
174   ares_free( nameservers );
175   ares_free( hostname );
176   return status;
177 }