• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ares_parse_ns_reply(const unsigned char * abuf,int alen,struct hostent ** host)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     ares_free( hostname );
77     return ARES_EBADRESP;
78   }
79   aptr += len + QFIXEDSZ;
80 
81   /* Allocate nameservers array; ancount gives an upper bound */
82   nameservers = ares_malloc( ( ancount + 1 ) * sizeof( char * ) );
83   if ( !nameservers )
84   {
85     ares_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       ares_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         ares_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         ares_free(rr_name);
123         break;
124       }
125 
126       nameservers[nameservers_num] = ares_malloc(strlen(rr_data)+1);
127 
128       if (nameservers[nameservers_num]==NULL)
129       {
130         ares_free(rr_name);
131         ares_free(rr_data);
132         status=ARES_ENOMEM;
133         break;
134       }
135       strcpy(nameservers[nameservers_num],rr_data);
136       ares_free(rr_data);
137 
138       nameservers_num++;
139     }
140 
141     ares_free( rr_name );
142 
143     aptr += rr_len;
144     if ( aptr > abuf + alen )
145     {  /* LCOV_EXCL_START: already checked above */
146       status = ARES_EBADRESP;
147       break;
148     }  /* LCOV_EXCL_STOP */
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 = ares_malloc( sizeof( struct hostent ) );
160     if ( hostent )
161     {
162       hostent->h_addr_list = ares_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       ares_free( hostent );
175     }
176     status = ARES_ENOMEM;
177   }
178   for ( i = 0; i < nameservers_num; i++ )
179     ares_free( nameservers[i] );
180   ares_free( nameservers );
181   ares_free( hostname );
182   return status;
183 }
184