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