Blame resolv/tst-ns_name.c

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