linux: Sync Linux 6.6 elf.h
[glibc.git] / resolv / tst-resolv-byaddr.c
blob5e98c0ad026af46ac1722e0cf400281a78c7f087
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>
20 #include <errno.h>
21 #include <netdb.h>
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.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"
34 /* QNAME format:
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
40 bits.
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. */
45 static void
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;
54 char *tail;
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;
63 cnames = bits >> 4;
65 else
66 FAIL_EXIT1 ("invalid QNAME: %s", qname);
67 free (tail);
69 int rcode;
70 if (addresses == 15)
72 /* Special case: Use no addresses with NXDOMAIN response. */
73 rcode = ns_r_nxdomain;
74 addresses = 0;
76 else
77 rcode = 0;
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)
97 free (previous_name);
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);
107 free (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
116 end. */
117 static struct support_next_to_fault ntf;
119 /* Perform a gethostbyaddr call and check the result. */
120 static void
121 check_gethostbyaddr (const char *address, const char *expected)
123 unsigned char bytes[16];
124 unsigned int byteslen;
125 int family;
126 if (strchr (address, ':') != NULL)
128 family = AF_INET6;
129 byteslen = 16;
131 else
133 family = AF_INET;
134 byteslen = 4;
136 TEST_COMPARE (inet_pton (family, address, bytes), 1);
138 struct hostent *e = gethostbyaddr (bytes, byteslen, family);
139 check_hostent (address, e, expected);
141 if (e == NULL)
142 return;
144 /* Try gethostbyaddr_r with increasing sizes until success. First
145 compute a reasonable minimum buffer size, to avoid many pointless
146 attempts. */
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;
157 int herrno;
158 int ret = gethostbyaddr_r (bytes, byteslen, family, &result,
159 ntf.buffer + ntf.length - size, size,
160 &e, &herrno);
161 if (ret == ERANGE)
162 /* Retry with larger size. */
163 TEST_COMPARE (herrno, NETDB_INTERNAL);
164 else if (ret == 0)
166 TEST_VERIFY (size > minimum_size);
167 check_hostent (address, e, expected);
168 return;
170 else
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. */
178 static void
179 check_getnameinfo (const char *address, const char *expected)
181 struct sockaddr_in sin = { };
182 struct sockaddr_in6 sin6 = { };
183 void *sa;
184 socklen_t salen;
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);
190 sa = &sin6;
191 salen = sizeof (sin6);
193 else
195 sin.sin_family = AF_INET;
196 TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1);
197 sin.sin_port = htons (80);
198 sa = &sin;
199 salen = sizeof (sin);
202 char host[64];
203 char service[64];
204 int ret = getnameinfo (sa, salen, host,
205 sizeof (host), service, sizeof (service),
206 NI_NAMEREQD | NI_NUMERICSERV);
207 switch (ret)
209 case 0:
210 TEST_COMPARE_STRING (host, expected);
211 TEST_COMPARE_STRING (service, "80");
212 break;
213 case EAI_SYSTEM:
214 TEST_COMPARE_STRING (strerror (errno), expected);
215 break;
216 default:
217 TEST_COMPARE_STRING (gai_strerror (ret), expected);
221 static int
222 do_test (void)
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);
323 return 0;
326 #include <support/test-driver.c>