1 /* Test reverse DNS lookup.
2 Copyright (C) 2022-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
19 #include <arpa/inet.h>
26 #include <support/check.h>
27 #include <support/check_nss.h>
28 #include <support/next_to_fault.h>
29 #include <support/resolv_test.h>
30 #include <support/support.h>
32 #include "tst-resolv-maybe_insert_sig.h"
36 ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa.
37 CNAMES|ADDRESSES.2.0.192.in-addr-arpa.
39 For the IPv4 reverse lookup, the address count is in the lower
42 CNAMES is the length of the CNAME chain, ADDRESSES is the number of
43 addresses in the response. The special value 15 means that there
44 are no addresses, and the RCODE is NXDOMAIN. */
46 response (const struct resolv_response_context
*ctx
,
47 struct resolv_response_builder
*b
,
48 const char *qname
, uint16_t qclass
, uint16_t qtype
)
50 TEST_COMPARE (qclass
, C_IN
);
51 TEST_COMPARE (qtype
, T_PTR
);
53 unsigned int addresses
, cnames
, bits
;
55 if (strstr (qname
, "ip6.arpa") != NULL
56 && sscanf (qname
, "%x.%x.%ms", &addresses
, &cnames
, &tail
) == 3)
57 TEST_COMPARE_STRING (tail
, "\
58 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
59 else if (sscanf (qname
, "%u.%ms", &bits
, &tail
) == 2)
61 TEST_COMPARE_STRING (tail
, "2.0.192.in-addr.arpa");
62 addresses
= bits
& 0x0f;
66 FAIL_EXIT1 ("invalid QNAME: %s", qname
);
72 /* Special case: Use no addresses with NXDOMAIN response. */
73 rcode
= ns_r_nxdomain
;
79 struct resolv_response_flags flags
= { .rcode
= rcode
};
80 resolv_response_init (b
, flags
);
81 resolv_response_add_question (b
, qname
, qclass
, qtype
);
82 resolv_response_section (b
, ns_s_an
);
83 maybe_insert_sig (b
, qname
);
85 /* Provide the requested number of CNAME records. */
86 char *previous_name
= (char *) qname
;
87 for (int unique
= 0; unique
< cnames
; ++unique
)
89 resolv_response_open_record (b
, previous_name
, qclass
, T_CNAME
, 60);
90 char *new_name
= xasprintf ("%d.alias.example", unique
);
91 resolv_response_add_name (b
, new_name
);
92 resolv_response_close_record (b
);
94 maybe_insert_sig (b
, qname
);
96 if (previous_name
!= qname
)
98 previous_name
= new_name
;
101 for (int unique
= 0; unique
< addresses
; ++unique
)
103 resolv_response_open_record (b
, previous_name
, qclass
, T_PTR
, 60);
104 char *ptr
= xasprintf ("unique-%d.cnames-%u.addresses-%u.example",
105 unique
, cnames
, addresses
);
106 resolv_response_add_name (b
, ptr
);
108 resolv_response_close_record (b
);
111 if (previous_name
!= qname
)
112 free (previous_name
);
115 /* Used to check that gethostbyaddr_r does not write past the buffer
117 static struct support_next_to_fault ntf
;
119 /* Perform a gethostbyaddr call and check the result. */
121 check_gethostbyaddr (const char *address
, const char *expected
)
123 unsigned char bytes
[16];
124 unsigned int byteslen
;
126 if (strchr (address
, ':') != NULL
)
136 TEST_COMPARE (inet_pton (family
, address
, bytes
), 1);
138 struct hostent
*e
= gethostbyaddr (bytes
, byteslen
, family
);
139 check_hostent (address
, e
, expected
);
144 /* Try gethostbyaddr_r with increasing sizes until success. First
145 compute a reasonable minimum buffer size, to avoid many pointless
147 size_t minimum_size
= strlen (e
->h_name
);
148 for (int i
= 0; e
->h_addr_list
[i
] != NULL
; ++i
)
149 minimum_size
+= e
->h_length
+ sizeof (char *);
150 for (int i
= 0; e
->h_aliases
[i
] != NULL
; ++i
)
151 minimum_size
+= strlen (e
->h_aliases
[i
]) + 1 + sizeof (char *);
153 /* Gradually increase the size until success. */
154 for (size_t size
= minimum_size
; size
< ntf
.length
; ++size
)
156 struct hostent result
;
158 int ret
= gethostbyaddr_r (bytes
, byteslen
, family
, &result
,
159 ntf
.buffer
+ ntf
.length
- size
, size
,
162 /* Retry with larger size. */
163 TEST_COMPARE (herrno
, NETDB_INTERNAL
);
166 TEST_VERIFY (size
> minimum_size
);
167 check_hostent (address
, e
, expected
);
171 FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret
);
174 FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address
);
177 /* Perform a getnameinfo call and check the result. */
179 check_getnameinfo (const char *address
, const char *expected
)
181 struct sockaddr_in sin
= { };
182 struct sockaddr_in6 sin6
= { };
185 if (strchr (address
, ':') != NULL
)
187 sin6
.sin6_family
= AF_INET6
;
188 TEST_COMPARE (inet_pton (AF_INET6
, address
, &sin6
.sin6_addr
), 1);
189 sin6
.sin6_port
= htons (80);
191 salen
= sizeof (sin6
);
195 sin
.sin_family
= AF_INET
;
196 TEST_COMPARE (inet_pton (AF_INET
, address
, &sin
.sin_addr
), 1);
197 sin
.sin_port
= htons (80);
199 salen
= sizeof (sin
);
204 int ret
= getnameinfo (sa
, salen
, host
,
205 sizeof (host
), service
, sizeof (service
),
206 NI_NAMEREQD
| NI_NUMERICSERV
);
210 TEST_COMPARE_STRING (host
, expected
);
211 TEST_COMPARE_STRING (service
, "80");
214 TEST_COMPARE_STRING (strerror (errno
), expected
);
217 TEST_COMPARE_STRING (gai_strerror (ret
), expected
);
224 /* Some reasonably upper bound for the maximum response size. */
225 ntf
= support_next_to_fault_allocate (4096);
227 struct resolv_test
*obj
= resolv_test_start
228 ((struct resolv_redirect_config
)
230 .response_callback
= response
233 for (int do_insert_sig
= 0; do_insert_sig
< 2; ++do_insert_sig
)
235 insert_sig
= do_insert_sig
;
237 /* No PTR record, RCODE=0. */
238 check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n");
239 check_getnameinfo ("192.0.2.0", "Name or service not known");
240 check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n");
241 check_getnameinfo ("192.0.2.16", "Name or service not known");
242 check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n");
243 check_getnameinfo ("192.0.2.32", "Name or service not known");
244 check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n");
245 check_getnameinfo ("2001:db8::", "Name or service not known");
246 check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n");
247 check_getnameinfo ("2001:db8::10", "Name or service not known");
248 check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n");
249 check_getnameinfo ("2001:db8::20", "Name or service not known");
251 /* No PTR record, NXDOMAIN. */
252 check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n");
253 check_getnameinfo ("192.0.2.15", "Name or service not known");
254 check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n");
255 check_getnameinfo ("192.0.2.31", "Name or service not known");
256 check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n");
257 check_getnameinfo ("192.0.2.47", "Name or service not known");
258 check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n");
259 check_getnameinfo ("2001:db8::f", "Name or service not known");
260 check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n");
261 check_getnameinfo ("2001:db8::1f", "Name or service not known");
262 check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n");
263 check_getnameinfo ("2001:db8::2f", "Name or service not known");
265 /* Actual response data. Only the first PTR record is returned. */
266 check_gethostbyaddr ("192.0.2.1",
267 "name: unique-0.cnames-0.addresses-1.example\n"
268 "address: 192.0.2.1\n");
269 check_getnameinfo ("192.0.2.1",
270 "unique-0.cnames-0.addresses-1.example");
271 check_gethostbyaddr ("192.0.2.17",
272 "name: unique-0.cnames-1.addresses-1.example\n"
273 "address: 192.0.2.17\n");
274 check_getnameinfo ("192.0.2.17",
275 "unique-0.cnames-1.addresses-1.example");
276 check_gethostbyaddr ("192.0.2.18",
277 "name: unique-0.cnames-1.addresses-2.example\n"
278 "address: 192.0.2.18\n");
279 check_getnameinfo ("192.0.2.18",
280 "unique-0.cnames-1.addresses-2.example");
281 check_gethostbyaddr ("192.0.2.33",
282 "name: unique-0.cnames-2.addresses-1.example\n"
283 "address: 192.0.2.33\n");
284 check_getnameinfo ("192.0.2.33",
285 "unique-0.cnames-2.addresses-1.example");
286 check_gethostbyaddr ("192.0.2.34",
287 "name: unique-0.cnames-2.addresses-2.example\n"
288 "address: 192.0.2.34\n");
289 check_getnameinfo ("192.0.2.34",
290 "unique-0.cnames-2.addresses-2.example");
292 /* Same for IPv6 addresses. */
293 check_gethostbyaddr ("2001:db8::1",
294 "name: unique-0.cnames-0.addresses-1.example\n"
295 "address: 2001:db8::1\n");
296 check_getnameinfo ("2001:db8::1",
297 "unique-0.cnames-0.addresses-1.example");
298 check_gethostbyaddr ("2001:db8::11",
299 "name: unique-0.cnames-1.addresses-1.example\n"
300 "address: 2001:db8::11\n");
301 check_getnameinfo ("2001:db8::11",
302 "unique-0.cnames-1.addresses-1.example");
303 check_gethostbyaddr ("2001:db8::12",
304 "name: unique-0.cnames-1.addresses-2.example\n"
305 "address: 2001:db8::12\n");
306 check_getnameinfo ("2001:db8::12",
307 "unique-0.cnames-1.addresses-2.example");
308 check_gethostbyaddr ("2001:db8::21",
309 "name: unique-0.cnames-2.addresses-1.example\n"
310 "address: 2001:db8::21\n");
311 check_getnameinfo ("2001:db8::21",
312 "unique-0.cnames-2.addresses-1.example");
313 check_gethostbyaddr ("2001:db8::22",
314 "name: unique-0.cnames-2.addresses-2.example\n"
315 "address: 2001:db8::22\n");
316 check_getnameinfo ("2001:db8::22",
317 "unique-0.cnames-2.addresses-2.example");
320 resolv_test_end (obj
);
322 support_next_to_fault_free (&ntf
);
326 #include <support/test-driver.c>