1/* Test _nss_dns_getcanonname_r corner cases.
2 Copyright (C) 2017-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 <dlfcn.h>
20#include <errno.h>
21#include <gnu/lib-names.h>
22#include <netdb.h>
23#include <nss.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <support/check.h>
28#include <support/resolv_test.h>
29#include <support/support.h>
30
31/* _nss_dns_getcanonname_r is not called during regular operation
32 because nss_dns directly provides a canonical name, so we have to
33 test it directly. The function pointer is initialized by do_test
34 below. */
35static enum nss_status
36(*getcanonname) (const char *name, char *buffer, size_t buflen,
37 char **result, int *errnop, int *h_errnop);
38
39static void
40response (const struct resolv_response_context *ctx,
41 struct resolv_response_builder *b,
42 const char *qname, uint16_t qclass, uint16_t qtype)
43{
44 int code;
45 {
46 char *tail;
47 if (sscanf (s: qname, format: "code%d.%ms", &code, &tail) != 2
48 || strcmp (s1: tail, s2: "example") != 0)
49 FAIL_EXIT1 ("error: invalid QNAME: %s\n", qname);
50 free (ptr: tail);
51 }
52
53 switch (code)
54 {
55 case 1:
56 resolv_response_init (b, (struct resolv_response_flags) {});
57 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
58 resolv_response_section (b, ns_s_an);
59 resolv_response_open_record (b, name: "www.example", class: qclass, type: qtype, ttl: 0);
60 resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
61 resolv_response_close_record (b);
62 break;
63 case 2:
64 resolv_response_init (b, (struct resolv_response_flags) {});
65 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
66 resolv_response_section (b, ns_s_an);
67 if (qtype == T_AAAA)
68 {
69 resolv_response_open_record (b, name: "www.example", class: qclass, type: qtype, ttl: 0);
70 resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
71 resolv_response_close_record (b);
72 for (int i = 0; i < 30000; ++i)
73 resolv_response_add_data (b, "", 1);
74 }
75 break;
76 case 3:
77 resolv_response_init (b, (struct resolv_response_flags) {});
78 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
79 resolv_response_section (b, ns_s_an);
80 if (qtype == T_AAAA)
81 {
82 resolv_response_open_record (b, name: "www.example", class: qclass, type: qtype, ttl: 0);
83 resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
84 resolv_response_close_record (b);
85 }
86 else
87 {
88 for (int i = 0; i < 30000; ++i)
89 resolv_response_add_data (b, "", 1);
90 }
91 break;
92 case 4:
93 resolv_response_init (b, (struct resolv_response_flags) {});
94 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
95 resolv_response_section (b, ns_s_an);
96 resolv_response_open_record (b, name: qname, class: qclass, T_CNAME, ttl: 0);
97 resolv_response_add_name (b, name: "www.example");
98 resolv_response_close_record (b);
99 resolv_response_open_record (b, name: "www.example", class: qclass, type: qtype, ttl: 0);
100 resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
101 resolv_response_close_record (b);
102 break;
103 case 5:
104 resolv_response_init (b, (struct resolv_response_flags) {});
105 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
106 resolv_response_section (b, ns_s_an);
107 resolv_response_open_record (b, name: qname, class: qclass, T_CNAME, ttl: 0);
108 resolv_response_add_name (b, name: "www.example");
109 resolv_response_close_record (b);
110 resolv_response_open_record (b, name: qname, class: qclass, T_CNAME, ttl: 0);
111 resolv_response_add_name (b, name: "www1.example");
112 resolv_response_close_record (b);
113 resolv_response_open_record (b, name: "www1.example", class: qclass, type: qtype, ttl: 0);
114 resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
115 resolv_response_close_record (b);
116 break;
117 case 6:
118 resolv_response_init (b, (struct resolv_response_flags) {});
119 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
120 resolv_response_section (b, ns_s_an);
121 resolv_response_open_record (b, name: qname, class: qclass, T_CNAME, ttl: 0);
122 resolv_response_add_name (b, name: "www.example");
123 resolv_response_close_record (b);
124 resolv_response_open_record (b, name: qname, class: qclass, type: 46 /* RRSIG */, ttl: 0);
125 resolv_response_add_name (b, name: ".");
126 resolv_response_close_record (b);
127 resolv_response_open_record (b, name: "www.example", class: qclass, type: qtype, ttl: 0);
128 resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
129 resolv_response_close_record (b);
130 break;
131 case 102:
132 if (!ctx->tcp)
133 {
134 resolv_response_init (b, (struct resolv_response_flags) {.tc = true});
135 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
136 }
137 else
138 {
139 resolv_response_init
140 (b, (struct resolv_response_flags) {.ancount = 1});
141 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
142 resolv_response_section (b, ns_s_an);
143 resolv_response_open_record (b, name: qname, class: qclass, T_CNAME, ttl: 0);
144 size_t to_fill = 65535 - resolv_response_length (b)
145 - 2 /* length, "n" */ - 2 /* compression reference */
146 - 2 /* RR type */;
147 for (size_t i = 0; i < to_fill; ++i)
148 resolv_response_add_data (b, "", 1);
149 resolv_response_close_record (b);
150 resolv_response_add_name (b, name: "n.example");
151 uint16_t rrtype = htons (T_CNAME);
152 resolv_response_add_data (b, &rrtype, sizeof (rrtype));
153 }
154 break;
155 case 103:
156 /* NODATA repsonse. */
157 resolv_response_init (b, (struct resolv_response_flags) {});
158 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
159 break;
160 case 104:
161 resolv_response_init (b, (struct resolv_response_flags) {.ancount = 1});
162 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
163 /* No RR metadata. */
164 resolv_response_add_name (b, name: "www.example");
165 break;
166 case 105:
167 if (qtype == T_A)
168 {
169 resolv_response_init (b, (struct resolv_response_flags) {});
170 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
171 /* No data, trigger AAAA query. */
172 }
173 else
174 {
175 resolv_response_init
176 (b, (struct resolv_response_flags) {.ancount = 1});
177 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
178 /* No RR metadata. */
179 resolv_response_add_name
180 (b, name: "long-name-exceed-previously-initialized-buffer.example");
181 }
182 break;
183 case 106:
184 resolv_response_init (b, (struct resolv_response_flags) {.ancount = 1});
185 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
186 /* No RR metadata. */
187 resolv_response_add_name (b, name: "www.example");
188 resolv_response_add_data (b, "\xff\xff", 2);
189 break;
190 case 107:
191 if (qtype == T_A)
192 {
193 resolv_response_init (b, (struct resolv_response_flags) {});
194 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
195 /* No data, trigger AAAA query. */
196 }
197 else
198 {
199 resolv_response_init
200 (b, (struct resolv_response_flags) {.ancount = 1});
201 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
202 /* No RR metadata. */
203 resolv_response_add_name (b, name: "www.example");
204 resolv_response_add_data (b, "\xff\xff", 2);
205 }
206 break;
207 default:
208 FAIL_EXIT1 ("error: invalid QNAME: %s (code %d)\n", qname, code);
209 }
210}
211
212static void
213check (int code, const char *expected)
214{
215 char qname[200];
216 snprintf (s: qname, maxlen: sizeof (qname), format: "code%d.example", code);
217 char *result;
218 enum nss_status status;
219 {
220 enum { buffer_size = 4096 };
221 char *buffer = xmalloc (n: buffer_size);
222 char *temp_result;
223 int temp_errno;
224 int temp_herrno;
225 status = getcanonname
226 (qname, buffer, buffer_size, &temp_result, &temp_errno, &temp_herrno);
227 if (status == NSS_STATUS_SUCCESS)
228 result = xstrdup (temp_result);
229 else
230 {
231 errno = temp_errno;
232 h_errno = temp_herrno;
233 }
234 free (ptr: buffer);
235 }
236
237 if (status == NSS_STATUS_SUCCESS)
238 {
239 if (expected != NULL)
240 {
241 if (strcmp (s1: result, s2: expected) != 0)
242 {
243 support_record_failure ();
244 printf (format: "error: getcanonname (%s) failed\n", qname);
245 printf (format: "error: expected: %s\n", expected);
246 printf (format: "error: actual: %s\n", result);
247 free (ptr: result);
248 return;
249 }
250 }
251 else
252 {
253 support_record_failure ();
254 printf (format: "error: getcanonname (%s) unexpected success\n", qname);
255 printf (format: "error: actual: %s\n", result);
256 free (ptr: result);
257 return;
258 }
259 free (ptr: result);
260 }
261 else
262 {
263 if (expected != NULL)
264 {
265 support_record_failure ();
266 printf (format: "error: getcanonname (%s) failed\n", qname);
267 printf (format: "error: expected: %s\n", expected);
268 return;
269 }
270 }
271}
272
273
274static int
275do_test (void)
276{
277 void *nss_dns_handle = dlopen (LIBNSS_DNS_SO, RTLD_LAZY);
278 if (nss_dns_handle == NULL)
279 FAIL_EXIT1 ("could not dlopen %s: %s", LIBNSS_DNS_SO, dlerror ());
280 {
281 const char *func = "_nss_dns_getcanonname_r";
282 void *ptr = dlsym (handle: nss_dns_handle, name: func);
283 if (ptr == NULL)
284 FAIL_EXIT1 ("could not look up %s: %s", func, dlerror ());
285 getcanonname = ptr;
286 }
287
288 struct resolv_test *aux = resolv_test_start
289 ((struct resolv_redirect_config)
290 {
291 .response_callback = response,
292 });
293
294 check (code: 1, expected: "www.example");
295 check (code: 2, expected: "www.example");
296 check (code: 3, expected: "www.example");
297 check (code: 4, expected: "www.example");
298 check (code: 5, expected: "www1.example");
299
300 /* This should really result in "www.example", but the fake RRSIG
301 record causes the current implementation to stop parsing. */
302 check (code: 6, NULL);
303
304 for (int i = 102; i <= 107; ++i)
305 check (code: i, NULL);
306
307 resolv_test_end (aux);
308
309 TEST_VERIFY (dlclose (nss_dns_handle) == 0);
310 return 0;
311}
312
313#include <support/test-driver.c>
314

source code of glibc/resolv/tst-resolv-canonname.c