1 | /* Test getnetbyname and getnetbyaddr. |
2 | Copyright (C) 2016-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <netdb.h> |
20 | #include <stdlib.h> |
21 | #include <string.h> |
22 | #include <support/check.h> |
23 | #include <support/check_nss.h> |
24 | #include <support/resolv_test.h> |
25 | #include <support/support.h> |
26 | #include <support/xmemstream.h> |
27 | |
28 | static void |
29 | send_ptr (struct resolv_response_builder *b, |
30 | const char *qname, uint16_t qclass, uint16_t qtype, |
31 | const char *alias) |
32 | { |
33 | resolv_response_init (b, (struct resolv_response_flags) {}); |
34 | resolv_response_add_question (b, name: qname, class: qclass, type: qtype); |
35 | resolv_response_section (b, ns_s_an); |
36 | resolv_response_open_record (b, name: qname, class: qclass, T_PTR, ttl: 0); |
37 | resolv_response_add_name (b, name: alias); |
38 | resolv_response_close_record (b); |
39 | } |
40 | |
41 | static void |
42 | handle_code (const struct resolv_response_context *ctx, |
43 | struct resolv_response_builder *b, |
44 | const char *qname, uint16_t qclass, uint16_t qtype, |
45 | int code) |
46 | { |
47 | switch (code) |
48 | { |
49 | case 1: |
50 | send_ptr (b, qname, qclass, qtype, alias: "1.in-addr.arpa" ); |
51 | break; |
52 | case 2: |
53 | send_ptr (b, qname, qclass, qtype, alias: "2.1.in-addr.arpa" ); |
54 | break; |
55 | case 3: |
56 | send_ptr (b, qname, qclass, qtype, alias: "3.2.1.in-addr.arpa" ); |
57 | break; |
58 | case 4: |
59 | send_ptr (b, qname, qclass, qtype, alias: "4.3.2.1.in-addr.arpa" ); |
60 | break; |
61 | case 5: |
62 | /* Test multiple PTR records. */ |
63 | resolv_response_init (b, (struct resolv_response_flags) {}); |
64 | resolv_response_add_question (b, name: qname, class: qclass, type: qtype); |
65 | resolv_response_section (b, ns_s_an); |
66 | resolv_response_open_record (b, name: qname, class: qclass, T_PTR, ttl: 0); |
67 | resolv_response_add_name (b, name: "127.in-addr.arpa" ); |
68 | resolv_response_close_record (b); |
69 | resolv_response_open_record (b, name: qname, class: qclass, T_PTR, ttl: 0); |
70 | resolv_response_add_name (b, name: "0.in-addr.arpa" ); |
71 | resolv_response_close_record (b); |
72 | break; |
73 | case 6: |
74 | /* Test skipping of RRSIG record. */ |
75 | resolv_response_init (b, (struct resolv_response_flags) { }); |
76 | resolv_response_add_question (b, name: qname, class: qclass, type: qtype); |
77 | resolv_response_section (b, ns_s_an); |
78 | |
79 | resolv_response_open_record (b, name: qname, class: qclass, T_PTR, ttl: 0); |
80 | resolv_response_add_name (b, name: "127.in-addr.arpa" ); |
81 | resolv_response_close_record (b); |
82 | |
83 | resolv_response_open_record (b, name: qname, class: qclass, type: 46 /* RRSIG */, ttl: 0); |
84 | { |
85 | char buf[500]; |
86 | memset (s: buf, c: 0x3f, n: sizeof (buf)); |
87 | resolv_response_add_data (b, buf, sizeof (buf)); |
88 | } |
89 | resolv_response_close_record (b); |
90 | |
91 | resolv_response_open_record (b, name: qname, class: qclass, T_PTR, ttl: 0); |
92 | resolv_response_add_name (b, name: "0.in-addr.arpa" ); |
93 | resolv_response_close_record (b); |
94 | break; |
95 | case 7: |
96 | /* Test CNAME handling. */ |
97 | resolv_response_init (b, (struct resolv_response_flags) { }); |
98 | resolv_response_add_question (b, name: qname, class: qclass, type: qtype); |
99 | resolv_response_section (b, ns_s_an); |
100 | resolv_response_open_record (b, name: qname, class: qclass, T_CNAME, ttl: 0); |
101 | resolv_response_add_name (b, name: "cname.example" ); |
102 | resolv_response_close_record (b); |
103 | resolv_response_open_record (b, name: "cname.example" , class: qclass, T_PTR, ttl: 0); |
104 | resolv_response_add_name (b, name: "4.3.2.1.in-addr.arpa" ); |
105 | resolv_response_close_record (b); |
106 | break; |
107 | |
108 | case 100: |
109 | resolv_response_init (b, (struct resolv_response_flags) { .rcode = 0, }); |
110 | resolv_response_add_question (b, name: qname, class: qclass, type: qtype); |
111 | break; |
112 | case 101: |
113 | resolv_response_init (b, (struct resolv_response_flags) |
114 | { .rcode = NXDOMAIN, }); |
115 | resolv_response_add_question (b, name: qname, class: qclass, type: qtype); |
116 | break; |
117 | case 102: |
118 | resolv_response_init (b, (struct resolv_response_flags) {.rcode = SERVFAIL}); |
119 | resolv_response_add_question (b, name: qname, class: qclass, type: qtype); |
120 | break; |
121 | case 103: |
122 | /* Check response length matching. */ |
123 | if (!ctx->tcp) |
124 | { |
125 | resolv_response_init (b, (struct resolv_response_flags) {.tc = true}); |
126 | resolv_response_add_question (b, name: qname, class: qclass, type: qtype); |
127 | } |
128 | else |
129 | { |
130 | resolv_response_init (b, (struct resolv_response_flags) {.ancount = 1}); |
131 | resolv_response_add_question (b, name: qname, class: qclass, type: qtype); |
132 | resolv_response_section (b, ns_s_an); |
133 | resolv_response_open_record (b, name: qname, class: qclass, T_PTR, ttl: 0); |
134 | resolv_response_add_name (b, name: "127.in-addr.arpa" ); |
135 | resolv_response_close_record (b); |
136 | resolv_response_open_record (b, name: qname, class: qclass, T_PTR, ttl: 0); |
137 | resolv_response_add_name (b, name: "example" ); |
138 | resolv_response_close_record (b); |
139 | |
140 | resolv_response_open_record (b, name: qname, class: qclass, T_PTR, ttl: 0); |
141 | size_t to_fill = 65535 - resolv_response_length (b) |
142 | - 2 /* length, "n" */ - 2 /* compression reference */ |
143 | - 2 /* RR type */; |
144 | for (size_t i = 0; i < to_fill; ++i) |
145 | resolv_response_add_data (b, "" , 1); |
146 | resolv_response_close_record (b); |
147 | resolv_response_add_name (b, name: "n.example" ); |
148 | uint16_t rrtype = htons (T_PTR); |
149 | resolv_response_add_data (b, &rrtype, sizeof (rrtype)); |
150 | } |
151 | break; |
152 | case 104: |
153 | send_ptr (b, qname, qclass, qtype, alias: "host.example" ); |
154 | break; |
155 | default: |
156 | FAIL_EXIT1 ("invalid QNAME: %s (code %d)" , qname, code); |
157 | } |
158 | } |
159 | |
160 | static void |
161 | response (const struct resolv_response_context *ctx, |
162 | struct resolv_response_builder *b, |
163 | const char *qname, uint16_t qclass, uint16_t qtype) |
164 | { |
165 | int code; |
166 | if (strstr (haystack: qname, needle: "in-addr.arpa" ) == NULL) |
167 | { |
168 | char *tail; |
169 | if (sscanf (s: qname, format: "code%d.%ms" , &code, &tail) != 2 |
170 | || strcmp (s1: tail, s2: "example" ) != 0) |
171 | FAIL_EXIT1 ("invalid QNAME: %s" , qname); |
172 | free (ptr: tail); |
173 | handle_code (ctx, b, qname, qclass, qtype, code); |
174 | } |
175 | else |
176 | { |
177 | /* Reverse lookup. */ |
178 | int components[4]; |
179 | char *tail; |
180 | if (sscanf (s: qname, format: "%d.%d.%d.%d.%ms" , |
181 | components, components + 1, components + 2, components + 3, |
182 | &tail) != 5 |
183 | || strcmp (s1: tail, s2: "in-addr.arpa" ) != 0) |
184 | FAIL_EXIT1 ("invalid QNAME: %s" , qname); |
185 | free (ptr: tail); |
186 | handle_code (ctx, b, qname, qclass, qtype, code: components[3]); |
187 | } |
188 | } |
189 | |
190 | static void |
191 | check_reverse (int code, const char *expected) |
192 | { |
193 | char *query = xasprintf (format: "code=%d" , code); |
194 | check_netent (query_description: query, getnetbyaddr (net: code, AF_INET), expected); |
195 | free (ptr: query); |
196 | } |
197 | |
198 | /* Test for CVE-2016-3075. */ |
199 | static void |
200 | check_long_name (void) |
201 | { |
202 | struct xmemstream mem; |
203 | xopen_memstream (stream: &mem); |
204 | |
205 | char label[65]; |
206 | memset (s: label, c: 'x', n: 63); |
207 | label[63] = '.'; |
208 | label[64] = '\0'; |
209 | for (unsigned i = 0; i < 64 * 1024 * 1024 / strlen (s: label); ++i) |
210 | fprintf (stream: mem.out, format: "%s" , label); |
211 | |
212 | xfclose_memstream (stream: &mem); |
213 | |
214 | check_netent (query_description: "long name" , getnetbyname (name: mem.buffer), |
215 | expected: "error: NO_RECOVERY\n" ); |
216 | |
217 | free (ptr: mem.buffer); |
218 | } |
219 | |
220 | static int |
221 | do_test (void) |
222 | { |
223 | struct resolv_test *obj = resolv_test_start |
224 | ((struct resolv_redirect_config) |
225 | { |
226 | .response_callback = response |
227 | }); |
228 | |
229 | /* Lookup by name, success cases. */ |
230 | check_netent (query_description: "code1.example" , getnetbyname (name: "code1.example" ), |
231 | expected: "alias: 1.in-addr.arpa\n" |
232 | "net: 0x00000001\n" ); |
233 | check_netent (query_description: "code2.example" , getnetbyname (name: "code2.example" ), |
234 | expected: "alias: 2.1.in-addr.arpa\n" |
235 | "net: 0x00000102\n" ); |
236 | check_netent (query_description: "code3.example" , getnetbyname (name: "code3.example" ), |
237 | expected: "alias: 3.2.1.in-addr.arpa\n" |
238 | "net: 0x00010203\n" ); |
239 | check_netent (query_description: "code4.example" , getnetbyname (name: "code4.example" ), |
240 | expected: "alias: 4.3.2.1.in-addr.arpa\n" |
241 | "net: 0x01020304\n" ); |
242 | check_netent (query_description: "code5.example" , getnetbyname (name: "code5.example" ), |
243 | expected: "alias: 127.in-addr.arpa\n" |
244 | "alias: 0.in-addr.arpa\n" |
245 | "net: 0x0000007f\n" ); |
246 | check_netent (query_description: "code6.example" , getnetbyname (name: "code6.example" ), |
247 | expected: "alias: 127.in-addr.arpa\n" |
248 | "alias: 0.in-addr.arpa\n" |
249 | "net: 0x0000007f\n" ); |
250 | check_netent (query_description: "code7.example" , getnetbyname (name: "code7.example" ), |
251 | expected: "alias: 4.3.2.1.in-addr.arpa\n" |
252 | "net: 0x01020304\n" ); |
253 | |
254 | /* Lookup by name, failure cases. */ |
255 | check_netent (query_description: "code100.example" , getnetbyname (name: "code100.example" ), |
256 | expected: "error: NO_ADDRESS\n" ); |
257 | check_netent (query_description: "code101.example" , getnetbyname (name: "code101.example" ), |
258 | expected: "error: HOST_NOT_FOUND\n" ); |
259 | check_netent (query_description: "code102.example" , getnetbyname (name: "code102.example" ), |
260 | expected: "error: TRY_AGAIN\n" ); |
261 | check_netent (query_description: "code103.example" , getnetbyname (name: "code103.example" ), |
262 | expected: "error: NO_RECOVERY\n" ); |
263 | /* Test bug #17630. */ |
264 | check_netent (query_description: "code104.example" , getnetbyname (name: "code104.example" ), |
265 | expected: "error: TRY_AGAIN\n" ); |
266 | |
267 | /* Lookup by address, success cases. */ |
268 | check_reverse (code: 1, |
269 | expected: "name: 1.in-addr.arpa\n" |
270 | "net: 0x00000001\n" ); |
271 | check_reverse (code: 2, |
272 | expected: "name: 2.1.in-addr.arpa\n" |
273 | "net: 0x00000002\n" ); |
274 | check_reverse (code: 3, |
275 | expected: "name: 3.2.1.in-addr.arpa\n" |
276 | "net: 0x00000003\n" ); |
277 | check_reverse (code: 4, |
278 | expected: "name: 4.3.2.1.in-addr.arpa\n" |
279 | "net: 0x00000004\n" ); |
280 | check_reverse (code: 5, |
281 | expected: "name: 127.in-addr.arpa\n" |
282 | "alias: 0.in-addr.arpa\n" |
283 | "net: 0x00000005\n" ); |
284 | check_reverse (code: 6, |
285 | expected: "name: 127.in-addr.arpa\n" |
286 | "alias: 0.in-addr.arpa\n" |
287 | "net: 0x00000006\n" ); |
288 | check_reverse (code: 7, |
289 | expected: "name: 4.3.2.1.in-addr.arpa\n" |
290 | "net: 0x00000007\n" ); |
291 | |
292 | /* Lookup by address, failure cases. */ |
293 | check_reverse (code: 100, |
294 | expected: "error: NO_ADDRESS\n" ); |
295 | check_reverse (code: 101, |
296 | expected: "error: HOST_NOT_FOUND\n" ); |
297 | check_reverse (code: 102, |
298 | expected: "error: TRY_AGAIN\n" ); |
299 | check_reverse (code: 103, |
300 | expected: "error: NO_RECOVERY\n" ); |
301 | |
302 | check_long_name (); |
303 | |
304 | resolv_test_end (obj); |
305 | |
306 | return 0; |
307 | } |
308 | |
309 | #include <support/test-driver.c> |
310 | |