/src/c-ares/src/lib/ares_parse_ns_reply.c
Line | Count | Source (jump to first uncovered line) |
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 | | * SPDX-License-Identifier: MIT |
16 | | */ |
17 | | |
18 | | /* |
19 | | * ares_parse_ns_reply created by Vlad Dinulescu <vlad.dinulescu@avira.com> |
20 | | * on behalf of AVIRA Gmbh - http://www.avira.com |
21 | | */ |
22 | | |
23 | | #include "ares_setup.h" |
24 | | |
25 | | #ifdef HAVE_NETINET_IN_H |
26 | | # include <netinet/in.h> |
27 | | #endif |
28 | | #ifdef HAVE_NETDB_H |
29 | | # include <netdb.h> |
30 | | #endif |
31 | | #ifdef HAVE_ARPA_INET_H |
32 | | # include <arpa/inet.h> |
33 | | #endif |
34 | | |
35 | | #include "ares_nameser.h" |
36 | | |
37 | | #include "ares.h" |
38 | | #include "ares_dns.h" |
39 | | #include "ares_private.h" |
40 | | |
41 | | int ares_parse_ns_reply( const unsigned char* abuf, int alen, |
42 | | struct hostent** host ) |
43 | 1.62k | { |
44 | 1.62k | unsigned int qdcount, ancount; |
45 | 1.62k | int status, i, rr_type, rr_class, rr_len; |
46 | 1.62k | int nameservers_num; |
47 | 1.62k | long len; |
48 | 1.62k | const unsigned char *aptr; |
49 | 1.62k | char* hostname, *rr_name, *rr_data, **nameservers; |
50 | 1.62k | struct hostent *hostent; |
51 | | |
52 | | /* Set *host to NULL for all failure cases. */ |
53 | 1.62k | *host = NULL; |
54 | | |
55 | | /* Give up if abuf doesn't have room for a header. */ |
56 | 1.62k | if ( alen < HFIXEDSZ ) |
57 | 6 | return ARES_EBADRESP; |
58 | | |
59 | | /* Fetch the question and answer count from the header. */ |
60 | 1.61k | qdcount = DNS_HEADER_QDCOUNT( abuf ); |
61 | 1.61k | ancount = DNS_HEADER_ANCOUNT( abuf ); |
62 | 1.61k | if ( qdcount != 1 ) |
63 | 18 | return ARES_EBADRESP; |
64 | | |
65 | | /* Expand the name from the question, and skip past the question. */ |
66 | 1.59k | aptr = abuf + HFIXEDSZ; |
67 | 1.59k | status = ares__expand_name_for_response( aptr, abuf, alen, &hostname, &len, 0); |
68 | 1.59k | if ( status != ARES_SUCCESS ) |
69 | 100 | return status; |
70 | 1.49k | if ( aptr + len + QFIXEDSZ > abuf + alen ) |
71 | 63 | { |
72 | 63 | ares_free( hostname ); |
73 | 63 | return ARES_EBADRESP; |
74 | 63 | } |
75 | 1.43k | aptr += len + QFIXEDSZ; |
76 | | |
77 | | /* Allocate nameservers array; ancount gives an upper bound */ |
78 | 1.43k | nameservers = ares_malloc( ( ancount + 1 ) * sizeof( char * ) ); |
79 | 1.43k | if ( !nameservers ) |
80 | 0 | { |
81 | 0 | ares_free( hostname ); |
82 | 0 | return ARES_ENOMEM; |
83 | 0 | } |
84 | 1.43k | nameservers_num = 0; |
85 | | |
86 | | /* Examine each answer resource record (RR) in turn. */ |
87 | 224k | for ( i = 0; i < ( int ) ancount; i++ ) |
88 | 224k | { |
89 | | /* Decode the RR up to the data field. */ |
90 | 224k | status = ares__expand_name_for_response( aptr, abuf, alen, &rr_name, &len, 0); |
91 | 224k | if ( status != ARES_SUCCESS ) |
92 | 871 | break; |
93 | 223k | aptr += len; |
94 | 223k | if ( aptr + RRFIXEDSZ > abuf + alen ) |
95 | 160 | { |
96 | 160 | status = ARES_EBADRESP; |
97 | 160 | ares_free(rr_name); |
98 | 160 | break; |
99 | 160 | } |
100 | 223k | rr_type = DNS_RR_TYPE( aptr ); |
101 | 223k | rr_class = DNS_RR_CLASS( aptr ); |
102 | 223k | rr_len = DNS_RR_LEN( aptr ); |
103 | 223k | aptr += RRFIXEDSZ; |
104 | 223k | if (aptr + rr_len > abuf + alen) |
105 | 20 | { |
106 | 20 | ares_free(rr_name); |
107 | 20 | status = ARES_EBADRESP; |
108 | 20 | break; |
109 | 20 | } |
110 | | |
111 | 223k | if ( rr_class == C_IN && rr_type == T_NS ) |
112 | 37.1k | { |
113 | | /* Decode the RR data and add it to the nameservers list */ |
114 | 37.1k | status = ares__expand_name_for_response( aptr, abuf, alen, &rr_data, |
115 | 37.1k | &len, 1); |
116 | 37.1k | if ( status != ARES_SUCCESS ) |
117 | 20 | { |
118 | 20 | ares_free(rr_name); |
119 | 20 | break; |
120 | 20 | } |
121 | | |
122 | 37.1k | nameservers[nameservers_num] = ares_malloc(strlen(rr_data)+1); |
123 | | |
124 | 37.1k | if (nameservers[nameservers_num]==NULL) |
125 | 0 | { |
126 | 0 | ares_free(rr_name); |
127 | 0 | ares_free(rr_data); |
128 | 0 | status=ARES_ENOMEM; |
129 | 0 | break; |
130 | 0 | } |
131 | 37.1k | strcpy(nameservers[nameservers_num],rr_data); |
132 | 37.1k | ares_free(rr_data); |
133 | | |
134 | 37.1k | nameservers_num++; |
135 | 37.1k | } |
136 | | |
137 | 223k | ares_free( rr_name ); |
138 | | |
139 | 223k | aptr += rr_len; |
140 | 223k | if ( aptr > abuf + alen ) |
141 | 0 | { /* LCOV_EXCL_START: already checked above */ |
142 | 0 | status = ARES_EBADRESP; |
143 | 0 | break; |
144 | 0 | } /* LCOV_EXCL_STOP */ |
145 | 223k | } |
146 | | |
147 | 1.43k | if ( status == ARES_SUCCESS && nameservers_num == 0 ) |
148 | 342 | { |
149 | 342 | status = ARES_ENODATA; |
150 | 342 | } |
151 | 1.43k | if ( status == ARES_SUCCESS ) |
152 | 23 | { |
153 | | /* We got our answer. Allocate memory to build the host entry. */ |
154 | 23 | nameservers[nameservers_num] = NULL; |
155 | 23 | hostent = ares_malloc( sizeof( struct hostent ) ); |
156 | 23 | if ( hostent ) |
157 | 23 | { |
158 | 23 | hostent->h_addr_list = ares_malloc( 1 * sizeof( char * ) ); |
159 | 23 | if ( hostent->h_addr_list ) |
160 | 23 | { |
161 | | /* Fill in the hostent and return successfully. */ |
162 | 23 | hostent->h_name = hostname; |
163 | 23 | hostent->h_aliases = nameservers; |
164 | 23 | hostent->h_addrtype = AF_INET; |
165 | 23 | hostent->h_length = sizeof( struct in_addr ); |
166 | 23 | hostent->h_addr_list[0] = NULL; |
167 | 23 | *host = hostent; |
168 | 23 | return ARES_SUCCESS; |
169 | 23 | } |
170 | 0 | ares_free( hostent ); |
171 | 0 | } |
172 | 0 | status = ARES_ENOMEM; |
173 | 0 | } |
174 | 18.5k | for ( i = 0; i < nameservers_num; i++ ) |
175 | 17.1k | ares_free( nameservers[i] ); |
176 | 1.41k | ares_free( nameservers ); |
177 | 1.41k | ares_free( hostname ); |
178 | 1.41k | return status; |
179 | 1.43k | } |