unistd: Improve fortify with clang
[glibc.git] / resolv / tst-resolv-invalid-cname.c
blob69f1c63be1439b7df828b5444890fc727c1a84d4
1 /* Test handling of CNAMEs with non-host domain names (bug 12154).
2 Copyright (C) 2022-2024 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 <errno.h>
20 #include <netdb.h>
21 #include <resolv.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <support/check.h>
25 #include <support/check_nss.h>
26 #include <support/resolv_test.h>
27 #include <support/support.h>
28 #include <support/xmemstream.h>
30 /* Query strings describe the CNAME chain in the response. They have
31 the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are
32 replaced by unsigned decimal numbers. COUNT is the number of CNAME
33 records in the response. BITS has two bits for each CNAME record,
34 describing a special prefix that is added to that CNAME.
36 0: No special leading label.
37 1: Starting with "*.".
38 2: Starting with "-x.".
39 3: Starting with "star.*.".
41 The first CNAME in the response using the two least significant
42 bits.
44 For PTR queries, the QNAME format is different, it is either
45 COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still
46 decimal), or:
48 COUNT.BITS0.BITS1.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.
50 where BITS and COUNT are hexadecimal. */
52 static void
53 response (const struct resolv_response_context *ctx,
54 struct resolv_response_builder *b,
55 const char *qname, uint16_t qclass, uint16_t qtype)
57 TEST_COMPARE (qclass, C_IN);
59 /* The only other query type besides A is PTR. */
60 if (qtype != T_A && qtype != T_AAAA)
61 TEST_COMPARE (qtype, T_PTR);
63 unsigned int bits, bits1, count;
64 char *tail = NULL;
65 if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3)
66 TEST_COMPARE_STRING (tail, "example");
67 else if (strstr (qname, "in-addr.arpa") != NULL
68 && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3)
69 TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa");
70 else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4)
72 TEST_COMPARE_STRING (tail, "\
73 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");
74 bits |= bits1 << 4;
76 else
77 FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
78 free (tail);
80 struct resolv_response_flags flags = {};
81 resolv_response_init (b, flags);
82 resolv_response_add_question (b, qname, qclass, qtype);
83 resolv_response_section (b, ns_s_an);
85 /* Provide the requested number of CNAME records. */
86 char *previous_name = (char *) qname;
87 unsigned int original_bits = bits;
88 for (int unique = 0; unique < count; ++unique)
90 resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
92 static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." };
93 char *new_name = xasprintf ("%sunique%d.example",
94 bits_to_prefix[bits & 3], unique);
95 bits >>= 2;
96 resolv_response_add_name (b, new_name);
97 resolv_response_close_record (b);
99 if (previous_name != qname)
100 free (previous_name);
101 previous_name = new_name;
104 /* Actual answer record. */
105 resolv_response_open_record (b, previous_name, qclass, qtype, 60);
106 switch (qtype)
108 case T_A:
110 char ipv4[4] = {192, 168, count, original_bits};
111 resolv_response_add_data (b, &ipv4, sizeof (ipv4));
113 break;
114 case T_AAAA:
116 char ipv6[16] =
118 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 count, original_bits
121 resolv_response_add_data (b, &ipv6, sizeof (ipv6));
123 break;
125 case T_PTR:
127 char *name = xasprintf ("bits%u.count%u.example",
128 original_bits, count);
129 resolv_response_add_name (b, name);
130 free (name);
132 break;
134 resolv_response_close_record (b);
136 if (previous_name != qname)
137 free (previous_name);
140 /* Controls which name resolution function is invoked. */
141 enum test_mode
143 byname, /* gethostbyname. */
144 byname2, /* gethostbyname2. */
145 gai, /* getaddrinfo without AI_CANONNAME. */
146 gai_canon, /* getaddrinfo with AI_CANONNAME. */
148 test_mode_num /* Number of enum values. */
151 static const char *
152 test_mode_to_string (enum test_mode mode)
154 switch (mode)
156 case byname:
157 return "byname";
158 case byname2:
159 return "byname2";
160 case gai:
161 return "gai";
162 case gai_canon:
163 return "gai_canon";
164 case test_mode_num:
165 break; /* Report error below. */
167 FAIL_EXIT1 ("invalid test_mode: %d", mode);
170 /* Append the name and aliases to OUT. */
171 static void
172 append_names (FILE *out, const char *qname, int bits, int count,
173 enum test_mode mode)
175 /* Largest valid index which has a corresponding zero in bits
176 (meaning a syntactically valid CNAME). */
177 int last_valid_cname = -1;
179 for (int i = 0; i < count; ++i)
180 if ((bits & (3 << (i * 2))) == 0)
181 last_valid_cname = i;
183 if (mode != gai)
185 const char *label;
186 if (mode == gai_canon)
187 label = "canonname";
188 else
189 label = "name";
190 if (last_valid_cname >= 0)
191 fprintf (out, "%s: unique%d.example\n", label, last_valid_cname);
192 else
193 fprintf (out, "%s: %s\n", label, qname);
196 if (mode == byname || mode == byname2)
198 if (last_valid_cname >= 0)
199 fprintf (out, "alias: %s\n", qname);
200 for (int i = 0; i < count; ++i)
202 if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname)
203 fprintf (out, "alias: unique%d.example\n", i);
208 /* Append the address information to OUT. */
209 static void
210 append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode)
212 int last = count * 256 + bits;
213 if (mode == gai || mode == gai_canon)
215 if (af == AF_INET || af == AF_UNSPEC)
216 fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits);
217 if (af == AF_INET6 || af == AF_UNSPEC)
219 if (last == 0)
220 fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n");
221 else
222 fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last);
225 else
227 TEST_VERIFY (af != AF_UNSPEC);
228 if (af == AF_INET)
229 fprintf (out, "address: 192.168.%d.%d\n", count, bits);
230 if (af == AF_INET6)
232 if (last == 0)
233 fprintf (out, "address: 2001:db8::\n");
234 else
235 fprintf (out, "address: 2001:db8::%x\n", last);
240 /* Perform one test using a forward lookup. */
241 static void
242 check_forward (int af, int bits, int count, enum test_mode mode)
244 char *qname = xasprintf ("bits%d.count%d.example", bits, count);
245 char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s",
246 af, bits, count, test_mode_to_string (mode), qname);
248 struct xmemstream expected;
249 xopen_memstream (&expected);
250 if (mode == gai_canon)
251 fprintf (expected.out, "flags: AI_CANONNAME\n");
252 append_names (expected.out, qname, bits, count, mode);
253 append_addresses (expected.out, af, bits, count, mode);
254 xfclose_memstream (&expected);
256 if (mode == gai || mode == gai_canon)
258 struct addrinfo *ai;
259 struct addrinfo hints =
261 .ai_family = af,
262 .ai_socktype = SOCK_STREAM,
264 if (mode == gai_canon)
265 hints.ai_flags |= AI_CANONNAME;
266 int ret = getaddrinfo (qname, "80", &hints, &ai);
267 check_addrinfo (label, ai, ret, expected.buffer);
268 if (ret == 0)
269 freeaddrinfo (ai);
271 else
273 struct hostent *e;
274 if (mode == gai)
276 TEST_COMPARE (af, AF_INET);
277 e = gethostbyname (qname);
279 else
281 if (af != AF_INET)
282 TEST_COMPARE (af, AF_INET6);
283 e = gethostbyname2 (qname, af);
285 check_hostent (label, e, expected.buffer);
288 free (expected.buffer);
289 free (label);
290 free (qname);
293 /* Perform one check using a reverse lookup. */
295 static void
296 check_reverse (int af, int bits, int count)
298 TEST_VERIFY (af == AF_INET || af == AF_INET6);
300 char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count);
301 char *fqdn = xasprintf ("bits%d.count%d.example", bits, count);
303 struct xmemstream expected;
304 xopen_memstream (&expected);
305 fprintf (expected.out, "name: %s\n", fqdn);
306 append_addresses (expected.out, af, bits, count, byname);
307 xfclose_memstream (&expected);
309 char addr[16] = { 0 };
310 socklen_t addrlen;
311 if (af == AF_INET)
313 addr[0] = 192;
314 addr[1] = 168;
315 addr[2] = count;
316 addr[3] = bits;
317 addrlen = 4;
319 else
321 addr[0] = 0x20;
322 addr[1] = 0x01;
323 addr[2] = 0x0d;
324 addr[3] = 0xb8;
325 addr[14] = count;
326 addr[15] = bits;
327 addrlen = 16;
330 struct hostent *e = gethostbyaddr (addr, addrlen, af);
331 check_hostent (label, e, expected.buffer);
333 /* getnameinfo check is different. There is no generic check_*
334 function for it. */
336 struct sockaddr_in sin = { };
337 struct sockaddr_in6 sin6 = { };
338 void *sa;
339 socklen_t salen;
340 if (af == AF_INET)
342 sin.sin_family = AF_INET;
343 memcpy (&sin.sin_addr, addr, addrlen);
344 sin.sin_port = htons (80);
345 sa = &sin;
346 salen = sizeof (sin);
348 else
350 sin6.sin6_family = AF_INET6;
351 memcpy (&sin6.sin6_addr, addr, addrlen);
352 sin6.sin6_port = htons (80);
353 sa = &sin6;
354 salen = sizeof (sin6);
357 char host[64];
358 char service[64];
359 int ret = getnameinfo (sa, salen, host,
360 sizeof (host), service, sizeof (service),
361 NI_NAMEREQD | NI_NUMERICSERV);
362 TEST_COMPARE (ret, 0);
363 TEST_COMPARE_STRING (host, fqdn);
364 TEST_COMPARE_STRING (service, "80");
367 free (expected.buffer);
368 free (fqdn);
369 free (label);
372 static int
373 do_test (void)
375 struct resolv_test *obj = resolv_test_start
376 ((struct resolv_redirect_config)
378 .response_callback = response
381 for (int count = 0; count <= 3; ++count)
382 for (int bits = 0; bits <= 1 << (count * 2); ++bits)
384 if (count > 0 && bits == count)
385 /* The last bits value is only checked if count == 0. */
386 continue;
388 for (enum test_mode mode = 0; mode < test_mode_num; ++mode)
390 check_forward (AF_INET, bits, count, mode);
391 if (mode != byname)
392 check_forward (AF_INET6, bits, count, mode);
393 if (mode == gai || mode == gai_canon)
394 check_forward (AF_UNSPEC, bits, count, mode);
397 check_reverse (AF_INET, bits, count);
398 check_reverse (AF_INET6, bits, count);
401 resolv_test_end (obj);
403 return 0;
406 #include <support/test-driver.c>