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. */
35 static enum nss_status
36 (*getcanonname) (const char *name, char *buffer, size_t buflen,
37 char **result, int *errnop, int *h_errnop);
38
39 static void
response(const struct resolv_response_context * ctx,struct resolv_response_builder * b,const char * qname,uint16_t qclass,uint16_t qtype)40 response (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 (qname, "code%d.%ms", &code, &tail) != 2
48 || strcmp (tail, "example") != 0)
49 FAIL_EXIT1 ("error: invalid QNAME: %s\n", qname);
50 free (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, qname, qclass, qtype);
58 resolv_response_section (b, ns_s_an);
59 resolv_response_open_record (b, "www.example", qclass, qtype, 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, qname, qclass, qtype);
66 resolv_response_section (b, ns_s_an);
67 if (qtype == T_AAAA)
68 {
69 resolv_response_open_record (b, "www.example", qclass, qtype, 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, qname, qclass, qtype);
79 resolv_response_section (b, ns_s_an);
80 if (qtype == T_AAAA)
81 {
82 resolv_response_open_record (b, "www.example", qclass, qtype, 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, qname, qclass, qtype);
95 resolv_response_section (b, ns_s_an);
96 resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
97 resolv_response_add_name (b, "www.example");
98 resolv_response_close_record (b);
99 resolv_response_open_record (b, "www.example", qclass, qtype, 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, qname, qclass, qtype);
106 resolv_response_section (b, ns_s_an);
107 resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
108 resolv_response_add_name (b, "www.example");
109 resolv_response_close_record (b);
110 resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
111 resolv_response_add_name (b, "www1.example");
112 resolv_response_close_record (b);
113 resolv_response_open_record (b, "www1.example", qclass, qtype, 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, qname, qclass, qtype);
120 resolv_response_section (b, ns_s_an);
121 resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
122 resolv_response_add_name (b, "www.example");
123 resolv_response_close_record (b);
124 resolv_response_open_record (b, qname, qclass, 46 /* RRSIG */, 0);
125 resolv_response_add_name (b, ".");
126 resolv_response_close_record (b);
127 resolv_response_open_record (b, "www.example", qclass, qtype, 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, qname, qclass, qtype);
136 }
137 else
138 {
139 resolv_response_init
140 (b, (struct resolv_response_flags) {.ancount = 1});
141 resolv_response_add_question (b, qname, qclass, qtype);
142 resolv_response_section (b, ns_s_an);
143 resolv_response_open_record (b, qname, qclass, T_CNAME, 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, "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, qname, qclass, qtype);
159 break;
160 case 104:
161 resolv_response_init (b, (struct resolv_response_flags) {.ancount = 1});
162 resolv_response_add_question (b, qname, qclass, qtype);
163 /* No RR metadata. */
164 resolv_response_add_name (b, "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, qname, qclass, 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, qname, qclass, qtype);
178 /* No RR metadata. */
179 resolv_response_add_name
180 (b, "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, qname, qclass, qtype);
186 /* No RR metadata. */
187 resolv_response_add_name (b, "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, qname, qclass, 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, qname, qclass, qtype);
202 /* No RR metadata. */
203 resolv_response_add_name (b, "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
212 static void
check(int code,const char * expected)213 check (int code, const char *expected)
214 {
215 char qname[200];
216 snprintf (qname, sizeof (qname), "code%d.example", code);
217 char *result;
218 enum nss_status status;
219 {
220 enum { buffer_size = 4096 };
221 char *buffer = xmalloc (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 (buffer);
235 }
236
237 if (status == NSS_STATUS_SUCCESS)
238 {
239 if (expected != NULL)
240 {
241 if (strcmp (result, expected) != 0)
242 {
243 support_record_failure ();
244 printf ("error: getcanonname (%s) failed\n", qname);
245 printf ("error: expected: %s\n", expected);
246 printf ("error: actual: %s\n", result);
247 free (result);
248 return;
249 }
250 }
251 else
252 {
253 support_record_failure ();
254 printf ("error: getcanonname (%s) unexpected success\n", qname);
255 printf ("error: actual: %s\n", result);
256 free (result);
257 return;
258 }
259 free (result);
260 }
261 else
262 {
263 if (expected != NULL)
264 {
265 support_record_failure ();
266 printf ("error: getcanonname (%s) failed\n", qname);
267 printf ("error: expected: %s\n", expected);
268 return;
269 }
270 }
271 }
272
273
274 static int
do_test(void)275 do_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 (nss_dns_handle, 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 (1, "www.example");
295 check (2, "www.example");
296 check (3, "www.example");
297 check (4, "www.example");
298 check (5, "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 (6, NULL);
303
304 for (int i = 102; i <= 107; ++i)
305 check (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