mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-30 10:45:40 +03:00 
			
		
		
		
	* All files with FSF copyright notices: Update copyright dates using scripts/update-copyrights. * locale/programs/charmap-kw.h: Regenerated. * locale/programs/locfile-kw.h: Likewise.
		
			
				
	
	
		
			439 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			439 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Test ns_name-related functions.
 | |
|    Copyright (C) 2017-2018 Free Software Foundation, Inc.
 | |
|    This file is part of the GNU C Library.
 | |
| 
 | |
|    The GNU C Library is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU Lesser General Public
 | |
|    License as published by the Free Software Foundation; either
 | |
|    version 2.1 of the License, or (at your option) any later version.
 | |
| 
 | |
|    The GNU C Library is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    Lesser General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU Lesser General Public
 | |
|    License along with the GNU C Library; if not, see
 | |
|    <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| /* This test program processes the tst-ns_name.data file.  */
 | |
| 
 | |
| #include <ctype.h>
 | |
| #include <resolv.h>
 | |
| #include <stdbool.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <support/check.h>
 | |
| #include <support/support.h>
 | |
| #include <support/xstdio.h>
 | |
| 
 | |
| /* A byte buffer and its length.  */
 | |
| struct buffer
 | |
| {
 | |
|   unsigned char *data;
 | |
|   size_t length;
 | |
| };
 | |
| 
 | |
| /* Convert a base64-encoded string to its binary representation.  */
 | |
| static bool
 | |
| base64_to_buffer (const char *base64, struct buffer *result)
 | |
| {
 | |
|   /* "-" denotes an empty input.  */
 | |
|   if (strcmp (base64, "-") == 0)
 | |
|     {
 | |
|       result->data = xmalloc (1);
 | |
|       result->length = 0;
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|   size_t size = strlen (base64);
 | |
|   unsigned char *data = xmalloc (size);
 | |
|   int ret = b64_pton (base64, data, size);
 | |
|   if (ret < 0 || ret > size)
 | |
|     return false;
 | |
|   result->data = xrealloc (data, ret);
 | |
|   result->length = ret;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| /* A test case for ns_name_unpack and ns_name_ntop.  */
 | |
| struct test_case
 | |
| {
 | |
|   char *path;
 | |
|   size_t lineno;
 | |
|   struct buffer input;
 | |
|   size_t input_offset;
 | |
|   int unpack_result;
 | |
|   struct buffer unpack_output;
 | |
|   int ntop_result;
 | |
|   char *ntop_text;
 | |
| };
 | |
| 
 | |
| /* Deallocate the buffers associated with the test case.  */
 | |
| static void
 | |
| free_test_case (struct test_case *t)
 | |
| {
 | |
|   free (t->path);
 | |
|   free (t->input.data);
 | |
|   free (t->unpack_output.data);
 | |
|   free (t->ntop_text);
 | |
| }
 | |
| 
 | |
| /* Extract the test case information from a test file line.  */
 | |
| static bool
 | |
| parse_test_case (const char *path, size_t lineno, const char *line,
 | |
|                  struct test_case *result)
 | |
| {
 | |
|   memset (result, 0, sizeof (*result));
 | |
|   result->path = xstrdup (path);
 | |
|   result->lineno = lineno;
 | |
|   result->ntop_result = -1;
 | |
|   char *input = NULL;
 | |
|   char *unpack_output = NULL;
 | |
|   int ret = sscanf (line, "%ms %zu %d %ms %d %ms",
 | |
|                     &input, &result->input_offset,
 | |
|                     &result->unpack_result, &unpack_output,
 | |
|                     &result->ntop_result, &result->ntop_text);
 | |
|   if (ret < 3)
 | |
|     {
 | |
|       printf ("%s:%zu: error: missing input fields\n", path, lineno);
 | |
|       free (input);
 | |
|       return false;
 | |
|     }
 | |
|   if (!base64_to_buffer (input, &result->input))
 | |
|     {
 | |
|       printf ("%s:%zu: error: malformed base64 input data\n", path, lineno);
 | |
|       free (input);
 | |
|       free (unpack_output);
 | |
|       free (result->ntop_text);
 | |
|       return false;
 | |
|     }
 | |
|   free (input);
 | |
| 
 | |
|   if (unpack_output == NULL)
 | |
|     result->unpack_output = (struct buffer) { NULL, 0 };
 | |
|   else if (!base64_to_buffer (unpack_output, &result->unpack_output))
 | |
|     {
 | |
|       printf ("%s:%zu: error: malformed base64 unpack data\n", path, lineno);
 | |
|       free (result->input.data);
 | |
|       free (unpack_output);
 | |
|       free (result->ntop_text);
 | |
|       return false;
 | |
|     }
 | |
|   free (unpack_output);
 | |
| 
 | |
|   /* At this point, all allocated buffers have been transferred to
 | |
|      *result.  */
 | |
| 
 | |
|   if (result->input_offset > result->input.length)
 | |
|     {
 | |
|       printf ("%s:%zu: error: input offset %zu exceeds buffer size %zu\n",
 | |
|               path, lineno, result->input_offset, result->input.length);
 | |
|       free_test_case (result);
 | |
|       return false;
 | |
|     }
 | |
|   if (result->unpack_result < -1)
 | |
|     {
 | |
|       printf ("%s:%zu: error: invalid unpack result %d\n",
 | |
|               path, lineno, result->unpack_result);
 | |
|       free_test_case (result);
 | |
|       return false;
 | |
|     }
 | |
|   if (result->ntop_result < -1)
 | |
|     {
 | |
|       printf ("%s:%zu: error: invalid ntop result %d\n",
 | |
|               path, lineno, result->ntop_result);
 | |
|       free_test_case (result);
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|   bool fields_consistent;
 | |
|   switch (ret)
 | |
|     {
 | |
|     case 3:
 | |
|       fields_consistent = result->unpack_result == -1;
 | |
|       break;
 | |
|     case 5:
 | |
|       fields_consistent = result->unpack_result != -1
 | |
|         && result->ntop_result == -1;
 | |
|       break;
 | |
|     case 6:
 | |
|       fields_consistent = result->unpack_result != -1
 | |
|         && result->ntop_result != -1;
 | |
|       break;
 | |
|     default:
 | |
|       fields_consistent = false;
 | |
|     }
 | |
|   if (!fields_consistent)
 | |
|     {
 | |
|       printf ("%s:%zu: error: wrong number of fields: %d\n",
 | |
|               path, lineno, ret);
 | |
|       free_test_case (result);
 | |
|       return false;
 | |
|     }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| /* Format the buffer as a hexadecimal string and write it to standard
 | |
|    output.  */
 | |
| static void
 | |
| print_hex (const char *label, struct buffer buffer)
 | |
| {
 | |
|   printf ("  %s ", label);
 | |
|   unsigned char *p = buffer.data;
 | |
|   unsigned char *end = p + buffer.length;
 | |
|   while (p < end)
 | |
|     {
 | |
|       printf ("%02X", *p & 0xFF);
 | |
|       ++p;
 | |
|     }
 | |
|   putchar ('\n');
 | |
| }
 | |
| 
 | |
| /* Run the test case specified in *T.  */
 | |
| static void
 | |
| run_test_case (struct test_case *t)
 | |
| {
 | |
|   /* Test ns_name_unpack.  */
 | |
|   unsigned char *unpacked = xmalloc (NS_MAXCDNAME);
 | |
|   int consumed = ns_name_unpack
 | |
|     (t->input.data, t->input.data + t->input.length,
 | |
|      t->input.data + t->input_offset,
 | |
|      unpacked, NS_MAXCDNAME);
 | |
|   if (consumed != t->unpack_result)
 | |
|     {
 | |
|       support_record_failure ();
 | |
|       printf ("%s:%zu: error: wrong result from ns_name_unpack\n"
 | |
|               "  expected: %d\n"
 | |
|               "  actual:   %d\n",
 | |
|               t->path, t->lineno, t->unpack_result, consumed);
 | |
|       return;
 | |
|     }
 | |
|   if (consumed != -1)
 | |
|     {
 | |
|       if (memcmp (unpacked, t->unpack_output.data,
 | |
|                   t->unpack_output.length) != 0)
 | |
|         {
 | |
|           support_record_failure ();
 | |
|           printf ("%s:%zu: error: wrong data from ns_name_unpack\n",
 | |
|                   t->path, t->lineno);
 | |
|           print_hex ("expected:", t->unpack_output);
 | |
|           print_hex ("actual:  ",
 | |
|                      (struct buffer) { unpacked, t->unpack_output.length });
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|       /* Test ns_name_ntop.  */
 | |
|       char *text = xmalloc (NS_MAXDNAME);
 | |
|       int ret = ns_name_ntop (unpacked, text, NS_MAXDNAME);
 | |
|       if (ret != t->ntop_result)
 | |
|         {
 | |
|           support_record_failure ();
 | |
|           printf ("%s:%zu: error: wrong result from ns_name_top\n"
 | |
|                   "  expected: %d\n"
 | |
|                   "  actual:   %d\n",
 | |
|                   t->path, t->lineno, t->ntop_result, ret);
 | |
|           return;
 | |
|         }
 | |
|       if (ret != -1)
 | |
|         {
 | |
|           if (strcmp (text, t->ntop_text) != 0)
 | |
|             {
 | |
|               support_record_failure ();
 | |
|               printf ("%s:%zu: error: wrong data from ns_name_ntop\n",
 | |
|                       t->path, t->lineno);
 | |
|               printf ("  expected: \"%s\"\n", t->ntop_text);
 | |
|               printf ("  actual:   \"%s\"\n", text);
 | |
|               return;
 | |
|             }
 | |
| 
 | |
|           /* Test ns_name_pton.  Unpacking does not check the
 | |
|              NS_MAXCDNAME limit, but packing does, so we need to
 | |
|              adjust the expected result.  */
 | |
|           int expected;
 | |
|           if (t->unpack_output.length > NS_MAXCDNAME)
 | |
|             expected = -1;
 | |
|           else if (strcmp (text, ".") == 0)
 | |
|             /* The root domain is fully qualified.  */
 | |
|             expected = 1;
 | |
|           else
 | |
|             /* The domain name is never fully qualified.  */
 | |
|             expected = 0;
 | |
|           unsigned char *repacked = xmalloc (NS_MAXCDNAME);
 | |
|           ret = ns_name_pton (text, repacked, NS_MAXCDNAME);
 | |
|           if (ret != expected)
 | |
|             {
 | |
|               support_record_failure ();
 | |
|               printf ("%s:%zu: error: wrong result from ns_name_pton\n"
 | |
|                       "  expected: %d\n"
 | |
|                       "  actual:   %d\n",
 | |
|                       t->path, t->lineno, expected, ret);
 | |
|               return;
 | |
|             }
 | |
|           if (ret >= 0
 | |
|               && memcmp (repacked, unpacked, t->unpack_output.length) != 0)
 | |
|             {
 | |
|               support_record_failure ();
 | |
|               printf ("%s:%zu: error: wrong data from ns_name_pton\n",
 | |
|                       t->path, t->lineno);
 | |
|               print_hex ("expected:", t->unpack_output);
 | |
|               print_hex ("actual:  ",
 | |
|                          (struct buffer) { repacked, t->unpack_output.length });
 | |
|               return;
 | |
|             }
 | |
| 
 | |
|           /* Test ns_name_compress, no compression case.  */
 | |
|           if (t->unpack_output.length > NS_MAXCDNAME)
 | |
|             expected = -1;
 | |
|           else
 | |
|             expected = t->unpack_output.length;
 | |
|           memset (repacked, '$', NS_MAXCDNAME);
 | |
|           {
 | |
|             enum { ptr_count = 5 };
 | |
|             const unsigned char *dnptrs[ptr_count] = { repacked, };
 | |
|             ret = ns_name_compress (text, repacked, NS_MAXCDNAME,
 | |
|                                     dnptrs, dnptrs + ptr_count);
 | |
|             if (ret != expected)
 | |
|               {
 | |
|                 support_record_failure ();
 | |
|                 printf ("%s:%zu: error: wrong result from ns_name_compress\n"
 | |
|                         "  expected: %d\n"
 | |
|                         "  actual:   %d\n",
 | |
|                         t->path, t->lineno, expected, ret);
 | |
|                 return;
 | |
|               }
 | |
|             if (ret < 0)
 | |
|               {
 | |
|                 TEST_VERIFY (dnptrs[0] == repacked);
 | |
|                 TEST_VERIFY (dnptrs[1] == NULL);
 | |
|               }
 | |
|             else
 | |
|               {
 | |
|                 if (memcmp (repacked, unpacked, t->unpack_output.length) != 0)
 | |
|                   {
 | |
|                     support_record_failure ();
 | |
|                     printf ("%s:%zu: error: wrong data from ns_name_compress\n",
 | |
|                             t->path, t->lineno);
 | |
|                     print_hex ("expected:", t->unpack_output);
 | |
|                     print_hex ("actual:  ", (struct buffer) { repacked, ret });
 | |
|                     return;
 | |
|                   }
 | |
|                 TEST_VERIFY (dnptrs[0] == repacked);
 | |
|                 if (unpacked[0] == '\0')
 | |
|                   /* The root domain is not a compression target.  */
 | |
|                   TEST_VERIFY (dnptrs[1] == NULL);
 | |
|                 else
 | |
|                   {
 | |
|                     TEST_VERIFY (dnptrs[1] == repacked);
 | |
|                     TEST_VERIFY (dnptrs[2] == NULL);
 | |
|                   }
 | |
|               }
 | |
|           }
 | |
| 
 | |
|           /* Test ns_name_compress, full compression case.  Skip this
 | |
|              test for invalid names and the root domain.  */
 | |
|           if (expected >= 0 && unpacked[0] != '\0')
 | |
|             {
 | |
|               /* The destination buffer needs additional room for the
 | |
|                  offset, the initial name, and the compression
 | |
|                  reference.  */
 | |
|               enum { name_offset = 259 };
 | |
|               size_t target_offset = name_offset + t->unpack_output.length;
 | |
|               size_t repacked_size = target_offset + 2;
 | |
|               repacked = xrealloc (repacked, repacked_size);
 | |
|               memset (repacked, '@', repacked_size);
 | |
|               memcpy (repacked + name_offset,
 | |
|                       t->unpack_output.data, t->unpack_output.length);
 | |
|               enum { ptr_count = 5 };
 | |
|               const unsigned char *dnptrs[ptr_count]
 | |
|                 = { repacked, repacked + name_offset, };
 | |
|               ret = ns_name_compress
 | |
|                 (text, repacked + target_offset, NS_MAXCDNAME,
 | |
|                  dnptrs, dnptrs + ptr_count);
 | |
|               if (ret != 2)
 | |
|                 {
 | |
|                   support_record_failure ();
 | |
|                   printf ("%s:%zu: error: wrong result from ns_name_compress"
 | |
|                           " (2)\n"
 | |
|                           "  expected: 2\n"
 | |
|                           "  actual:   %d\n",
 | |
|                           t->path, t->lineno, ret);
 | |
|                   return;
 | |
|                 }
 | |
|               if (memcmp (repacked + target_offset, "\xc1\x03", 2) != 0)
 | |
|                 {
 | |
|                   support_record_failure ();
 | |
|                   printf ("%s:%zu: error: wrong data from ns_name_compress"
 | |
|                           " (2)\n"
 | |
|                           "  expected: C103\n",
 | |
|                           t->path, t->lineno);
 | |
|                   print_hex ("actual:  ",
 | |
|                              (struct buffer) { repacked + target_offset, ret });
 | |
|                   return;
 | |
|                 }
 | |
|               TEST_VERIFY (dnptrs[0] == repacked);
 | |
|               TEST_VERIFY (dnptrs[1] == repacked + name_offset);
 | |
|               TEST_VERIFY (dnptrs[2] == NULL);
 | |
|             }
 | |
| 
 | |
|           free (repacked);
 | |
|         }
 | |
|       free (text);
 | |
|     }
 | |
|   free (unpacked);
 | |
| }
 | |
| 
 | |
| /* Open the file at PATH, parse the test cases contained in it, and
 | |
|    run them.  */
 | |
| static void
 | |
| run_test_file (const char *path)
 | |
| {
 | |
|   FILE *fp = xfopen (path, "re");
 | |
|   char *line = NULL;
 | |
|   size_t line_allocated = 0;
 | |
|   size_t lineno = 0;
 | |
| 
 | |
|   while (true)
 | |
|     {
 | |
|       ssize_t ret = getline (&line, &line_allocated, fp);
 | |
|       if (ret < 0)
 | |
|         {
 | |
|           if (ferror (fp))
 | |
|             {
 | |
|               printf ("%s: error reading file: %m\n", path);
 | |
|               exit (1);
 | |
|             }
 | |
|           TEST_VERIFY (feof (fp));
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|       ++lineno;
 | |
|       char *p = line;
 | |
|       while (isspace (*p))
 | |
|         ++p;
 | |
|       if (*p == '\0' || *p == '#')
 | |
|         continue;
 | |
| 
 | |
|       struct test_case test_case;
 | |
|       if (!parse_test_case (path, lineno, line, &test_case))
 | |
|         {
 | |
|           support_record_failure ();
 | |
|           continue;
 | |
|         }
 | |
|       run_test_case (&test_case);
 | |
|       free_test_case (&test_case);
 | |
|     }
 | |
|   free (line);
 | |
|   xfclose (fp);
 | |
| }
 | |
| 
 | |
| static int
 | |
| do_test (void)
 | |
| {
 | |
|   run_test_file ("tst-ns_name.data");
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #include <support/test-driver.c>
 |