Prefer https to http for gnu.org and fsf.org URLs
[platform/upstream/glibc.git] / resolv / tst-ns_name.c
1 /* Test ns_name-related functions.
2    Copyright (C) 2017-2019 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 /* This test program processes the tst-ns_name.data file.  */
20
21 #include <ctype.h>
22 #include <resolv.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <support/check.h>
28 #include <support/support.h>
29 #include <support/xstdio.h>
30
31 /* A byte buffer and its length.  */
32 struct buffer
33 {
34   unsigned char *data;
35   size_t length;
36 };
37
38 /* Convert a base64-encoded string to its binary representation.  */
39 static bool
40 base64_to_buffer (const char *base64, struct buffer *result)
41 {
42   /* "-" denotes an empty input.  */
43   if (strcmp (base64, "-") == 0)
44     {
45       result->data = xmalloc (1);
46       result->length = 0;
47       return true;
48     }
49
50   size_t size = strlen (base64);
51   unsigned char *data = xmalloc (size);
52   int ret = b64_pton (base64, data, size);
53   if (ret < 0 || ret > size)
54     return false;
55   result->data = xrealloc (data, ret);
56   result->length = ret;
57   return true;
58 }
59
60 /* A test case for ns_name_unpack and ns_name_ntop.  */
61 struct test_case
62 {
63   char *path;
64   size_t lineno;
65   struct buffer input;
66   size_t input_offset;
67   int unpack_result;
68   struct buffer unpack_output;
69   int ntop_result;
70   char *ntop_text;
71 };
72
73 /* Deallocate the buffers associated with the test case.  */
74 static void
75 free_test_case (struct test_case *t)
76 {
77   free (t->path);
78   free (t->input.data);
79   free (t->unpack_output.data);
80   free (t->ntop_text);
81 }
82
83 /* Extract the test case information from a test file line.  */
84 static bool
85 parse_test_case (const char *path, size_t lineno, const char *line,
86                  struct test_case *result)
87 {
88   memset (result, 0, sizeof (*result));
89   result->path = xstrdup (path);
90   result->lineno = lineno;
91   result->ntop_result = -1;
92   char *input = NULL;
93   char *unpack_output = NULL;
94   int ret = sscanf (line, "%ms %zu %d %ms %d %ms",
95                     &input, &result->input_offset,
96                     &result->unpack_result, &unpack_output,
97                     &result->ntop_result, &result->ntop_text);
98   if (ret < 3)
99     {
100       printf ("%s:%zu: error: missing input fields\n", path, lineno);
101       free (input);
102       return false;
103     }
104   if (!base64_to_buffer (input, &result->input))
105     {
106       printf ("%s:%zu: error: malformed base64 input data\n", path, lineno);
107       free (input);
108       free (unpack_output);
109       free (result->ntop_text);
110       return false;
111     }
112   free (input);
113
114   if (unpack_output == NULL)
115     result->unpack_output = (struct buffer) { NULL, 0 };
116   else if (!base64_to_buffer (unpack_output, &result->unpack_output))
117     {
118       printf ("%s:%zu: error: malformed base64 unpack data\n", path, lineno);
119       free (result->input.data);
120       free (unpack_output);
121       free (result->ntop_text);
122       return false;
123     }
124   free (unpack_output);
125
126   /* At this point, all allocated buffers have been transferred to
127      *result.  */
128
129   if (result->input_offset > result->input.length)
130     {
131       printf ("%s:%zu: error: input offset %zu exceeds buffer size %zu\n",
132               path, lineno, result->input_offset, result->input.length);
133       free_test_case (result);
134       return false;
135     }
136   if (result->unpack_result < -1)
137     {
138       printf ("%s:%zu: error: invalid unpack result %d\n",
139               path, lineno, result->unpack_result);
140       free_test_case (result);
141       return false;
142     }
143   if (result->ntop_result < -1)
144     {
145       printf ("%s:%zu: error: invalid ntop result %d\n",
146               path, lineno, result->ntop_result);
147       free_test_case (result);
148       return false;
149     }
150
151   bool fields_consistent;
152   switch (ret)
153     {
154     case 3:
155       fields_consistent = result->unpack_result == -1;
156       break;
157     case 5:
158       fields_consistent = result->unpack_result != -1
159         && result->ntop_result == -1;
160       break;
161     case 6:
162       fields_consistent = result->unpack_result != -1
163         && result->ntop_result != -1;
164       break;
165     default:
166       fields_consistent = false;
167     }
168   if (!fields_consistent)
169     {
170       printf ("%s:%zu: error: wrong number of fields: %d\n",
171               path, lineno, ret);
172       free_test_case (result);
173       return false;
174     }
175   return true;
176 }
177
178 /* Format the buffer as a hexadecimal string and write it to standard
179    output.  */
180 static void
181 print_hex (const char *label, struct buffer buffer)
182 {
183   printf ("  %s ", label);
184   unsigned char *p = buffer.data;
185   unsigned char *end = p + buffer.length;
186   while (p < end)
187     {
188       printf ("%02X", *p & 0xFF);
189       ++p;
190     }
191   putchar ('\n');
192 }
193
194 /* Run the test case specified in *T.  */
195 static void
196 run_test_case (struct test_case *t)
197 {
198   /* Test ns_name_unpack.  */
199   unsigned char *unpacked = xmalloc (NS_MAXCDNAME);
200   int consumed = ns_name_unpack
201     (t->input.data, t->input.data + t->input.length,
202      t->input.data + t->input_offset,
203      unpacked, NS_MAXCDNAME);
204   if (consumed != t->unpack_result)
205     {
206       support_record_failure ();
207       printf ("%s:%zu: error: wrong result from ns_name_unpack\n"
208               "  expected: %d\n"
209               "  actual:   %d\n",
210               t->path, t->lineno, t->unpack_result, consumed);
211       return;
212     }
213   if (consumed != -1)
214     {
215       if (memcmp (unpacked, t->unpack_output.data,
216                   t->unpack_output.length) != 0)
217         {
218           support_record_failure ();
219           printf ("%s:%zu: error: wrong data from ns_name_unpack\n",
220                   t->path, t->lineno);
221           print_hex ("expected:", t->unpack_output);
222           print_hex ("actual:  ",
223                      (struct buffer) { unpacked, t->unpack_output.length });
224           return;
225         }
226
227       /* Test ns_name_ntop.  */
228       char *text = xmalloc (NS_MAXDNAME);
229       int ret = ns_name_ntop (unpacked, text, NS_MAXDNAME);
230       if (ret != t->ntop_result)
231         {
232           support_record_failure ();
233           printf ("%s:%zu: error: wrong result from ns_name_top\n"
234                   "  expected: %d\n"
235                   "  actual:   %d\n",
236                   t->path, t->lineno, t->ntop_result, ret);
237           return;
238         }
239       if (ret != -1)
240         {
241           if (strcmp (text, t->ntop_text) != 0)
242             {
243               support_record_failure ();
244               printf ("%s:%zu: error: wrong data from ns_name_ntop\n",
245                       t->path, t->lineno);
246               printf ("  expected: \"%s\"\n", t->ntop_text);
247               printf ("  actual:   \"%s\"\n", text);
248               return;
249             }
250
251           /* Test ns_name_pton.  Unpacking does not check the
252              NS_MAXCDNAME limit, but packing does, so we need to
253              adjust the expected result.  */
254           int expected;
255           if (t->unpack_output.length > NS_MAXCDNAME)
256             expected = -1;
257           else if (strcmp (text, ".") == 0)
258             /* The root domain is fully qualified.  */
259             expected = 1;
260           else
261             /* The domain name is never fully qualified.  */
262             expected = 0;
263           unsigned char *repacked = xmalloc (NS_MAXCDNAME);
264           ret = ns_name_pton (text, repacked, NS_MAXCDNAME);
265           if (ret != expected)
266             {
267               support_record_failure ();
268               printf ("%s:%zu: error: wrong result from ns_name_pton\n"
269                       "  expected: %d\n"
270                       "  actual:   %d\n",
271                       t->path, t->lineno, expected, ret);
272               return;
273             }
274           if (ret >= 0
275               && memcmp (repacked, unpacked, t->unpack_output.length) != 0)
276             {
277               support_record_failure ();
278               printf ("%s:%zu: error: wrong data from ns_name_pton\n",
279                       t->path, t->lineno);
280               print_hex ("expected:", t->unpack_output);
281               print_hex ("actual:  ",
282                          (struct buffer) { repacked, t->unpack_output.length });
283               return;
284             }
285
286           /* Test ns_name_compress, no compression case.  */
287           if (t->unpack_output.length > NS_MAXCDNAME)
288             expected = -1;
289           else
290             expected = t->unpack_output.length;
291           memset (repacked, '$', NS_MAXCDNAME);
292           {
293             enum { ptr_count = 5 };
294             const unsigned char *dnptrs[ptr_count] = { repacked, };
295             ret = ns_name_compress (text, repacked, NS_MAXCDNAME,
296                                     dnptrs, dnptrs + ptr_count);
297             if (ret != expected)
298               {
299                 support_record_failure ();
300                 printf ("%s:%zu: error: wrong result from ns_name_compress\n"
301                         "  expected: %d\n"
302                         "  actual:   %d\n",
303                         t->path, t->lineno, expected, ret);
304                 return;
305               }
306             if (ret < 0)
307               {
308                 TEST_VERIFY (dnptrs[0] == repacked);
309                 TEST_VERIFY (dnptrs[1] == NULL);
310               }
311             else
312               {
313                 if (memcmp (repacked, unpacked, t->unpack_output.length) != 0)
314                   {
315                     support_record_failure ();
316                     printf ("%s:%zu: error: wrong data from ns_name_compress\n",
317                             t->path, t->lineno);
318                     print_hex ("expected:", t->unpack_output);
319                     print_hex ("actual:  ", (struct buffer) { repacked, ret });
320                     return;
321                   }
322                 TEST_VERIFY (dnptrs[0] == repacked);
323                 if (unpacked[0] == '\0')
324                   /* The root domain is not a compression target.  */
325                   TEST_VERIFY (dnptrs[1] == NULL);
326                 else
327                   {
328                     TEST_VERIFY (dnptrs[1] == repacked);
329                     TEST_VERIFY (dnptrs[2] == NULL);
330                   }
331               }
332           }
333
334           /* Test ns_name_compress, full compression case.  Skip this
335              test for invalid names and the root domain.  */
336           if (expected >= 0 && unpacked[0] != '\0')
337             {
338               /* The destination buffer needs additional room for the
339                  offset, the initial name, and the compression
340                  reference.  */
341               enum { name_offset = 259 };
342               size_t target_offset = name_offset + t->unpack_output.length;
343               size_t repacked_size = target_offset + 2;
344               repacked = xrealloc (repacked, repacked_size);
345               memset (repacked, '@', repacked_size);
346               memcpy (repacked + name_offset,
347                       t->unpack_output.data, t->unpack_output.length);
348               enum { ptr_count = 5 };
349               const unsigned char *dnptrs[ptr_count]
350                 = { repacked, repacked + name_offset, };
351               ret = ns_name_compress
352                 (text, repacked + target_offset, NS_MAXCDNAME,
353                  dnptrs, dnptrs + ptr_count);
354               if (ret != 2)
355                 {
356                   support_record_failure ();
357                   printf ("%s:%zu: error: wrong result from ns_name_compress"
358                           " (2)\n"
359                           "  expected: 2\n"
360                           "  actual:   %d\n",
361                           t->path, t->lineno, ret);
362                   return;
363                 }
364               if (memcmp (repacked + target_offset, "\xc1\x03", 2) != 0)
365                 {
366                   support_record_failure ();
367                   printf ("%s:%zu: error: wrong data from ns_name_compress"
368                           " (2)\n"
369                           "  expected: C103\n",
370                           t->path, t->lineno);
371                   print_hex ("actual:  ",
372                              (struct buffer) { repacked + target_offset, ret });
373                   return;
374                 }
375               TEST_VERIFY (dnptrs[0] == repacked);
376               TEST_VERIFY (dnptrs[1] == repacked + name_offset);
377               TEST_VERIFY (dnptrs[2] == NULL);
378             }
379
380           free (repacked);
381         }
382       free (text);
383     }
384   free (unpacked);
385 }
386
387 /* Open the file at PATH, parse the test cases contained in it, and
388    run them.  */
389 static void
390 run_test_file (const char *path)
391 {
392   FILE *fp = xfopen (path, "re");
393   char *line = NULL;
394   size_t line_allocated = 0;
395   size_t lineno = 0;
396
397   while (true)
398     {
399       ssize_t ret = getline (&line, &line_allocated, fp);
400       if (ret < 0)
401         {
402           if (ferror (fp))
403             {
404               printf ("%s: error reading file: %m\n", path);
405               exit (1);
406             }
407           TEST_VERIFY (feof (fp));
408           break;
409         }
410
411       ++lineno;
412       char *p = line;
413       while (isspace (*p))
414         ++p;
415       if (*p == '\0' || *p == '#')
416         continue;
417
418       struct test_case test_case;
419       if (!parse_test_case (path, lineno, line, &test_case))
420         {
421           support_record_failure ();
422           continue;
423         }
424       run_test_case (&test_case);
425       free_test_case (&test_case);
426     }
427   free (line);
428   xfclose (fp);
429 }
430
431 static int
432 do_test (void)
433 {
434   run_test_file ("tst-ns_name.data");
435   return 0;
436 }
437
438 #include <support/test-driver.c>