Blame resolv/tst-ns_name.c

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