Blame resolv/tst-resolv-canonname.c

Packit 6c4009
/* Test _nss_dns_getcanonname_r corner cases.
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
#include <dlfcn.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <gnu/lib-names.h>
Packit 6c4009
#include <netdb.h>
Packit 6c4009
#include <nss.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/resolv_test.h>
Packit 6c4009
#include <support/support.h>
Packit 6c4009
Packit 6c4009
/* _nss_dns_getcanonname_r is not called during regular operation
Packit 6c4009
   because nss_dns directly provides a canonical name, so we have to
Packit 6c4009
   test it directly.  The function pointer is initialized by do_test
Packit 6c4009
   below.  */
Packit 6c4009
static enum nss_status
Packit 6c4009
(*getcanonname) (const char *name, char *buffer, size_t buflen,
Packit 6c4009
                 char **result, int *errnop, int *h_errnop);
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
response (const struct resolv_response_context *ctx,
Packit 6c4009
          struct resolv_response_builder *b,
Packit 6c4009
          const char *qname, uint16_t qclass, uint16_t qtype)
Packit 6c4009
{
Packit 6c4009
  int code;
Packit 6c4009
  {
Packit 6c4009
    char *tail;
Packit 6c4009
    if (sscanf (qname, "code%d.%ms", &code, &tail) != 2
Packit 6c4009
        || strcmp (tail, "example") != 0)
Packit 6c4009
      FAIL_EXIT1 ("error: invalid QNAME: %s\n", qname);
Packit 6c4009
    free (tail);
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  switch (code)
Packit 6c4009
    {
Packit 6c4009
    case 1:
Packit 6c4009
      resolv_response_init (b, (struct resolv_response_flags) {});
Packit 6c4009
      resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
      resolv_response_section (b, ns_s_an);
Packit 6c4009
      resolv_response_open_record (b, "www.example", qclass, qtype, 0);
Packit 6c4009
      resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
Packit 6c4009
      resolv_response_close_record (b);
Packit 6c4009
      break;
Packit 6c4009
    case 2:
Packit 6c4009
      resolv_response_init (b, (struct resolv_response_flags) {});
Packit 6c4009
      resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
      resolv_response_section (b, ns_s_an);
Packit 6c4009
      if (qtype == T_AAAA)
Packit 6c4009
        {
Packit 6c4009
          resolv_response_open_record (b, "www.example", qclass, qtype, 0);
Packit 6c4009
          resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
Packit 6c4009
          resolv_response_close_record (b);
Packit 6c4009
          for (int i = 0; i < 30000; ++i)
Packit 6c4009
            resolv_response_add_data (b, "", 1);
Packit 6c4009
        }
Packit 6c4009
      break;
Packit 6c4009
    case 3:
Packit 6c4009
      resolv_response_init (b, (struct resolv_response_flags) {});
Packit 6c4009
      resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
      resolv_response_section (b, ns_s_an);
Packit 6c4009
      if (qtype == T_AAAA)
Packit 6c4009
        {
Packit 6c4009
          resolv_response_open_record (b, "www.example", qclass, qtype, 0);
Packit 6c4009
          resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
Packit 6c4009
          resolv_response_close_record (b);
Packit 6c4009
        }
Packit 6c4009
      else
Packit 6c4009
        {
Packit 6c4009
          for (int i = 0; i < 30000; ++i)
Packit 6c4009
            resolv_response_add_data (b, "", 1);
Packit 6c4009
        }
Packit 6c4009
      break;
Packit 6c4009
    case 4:
Packit 6c4009
      resolv_response_init (b, (struct resolv_response_flags) {});
Packit 6c4009
      resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
      resolv_response_section (b, ns_s_an);
Packit 6c4009
      resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
Packit 6c4009
      resolv_response_add_name (b, "www.example");
Packit 6c4009
      resolv_response_close_record (b);
Packit 6c4009
      resolv_response_open_record (b, "www.example", qclass, qtype, 0);
Packit 6c4009
      resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
Packit 6c4009
      resolv_response_close_record (b);
Packit 6c4009
      break;
Packit 6c4009
    case 5:
Packit 6c4009
      resolv_response_init (b, (struct resolv_response_flags) {});
Packit 6c4009
      resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
      resolv_response_section (b, ns_s_an);
Packit 6c4009
      resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
Packit 6c4009
      resolv_response_add_name (b, "www.example");
Packit 6c4009
      resolv_response_close_record (b);
Packit 6c4009
      resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
Packit 6c4009
      resolv_response_add_name (b, "www1.example");
Packit 6c4009
      resolv_response_close_record (b);
Packit 6c4009
      resolv_response_open_record (b, "www1.example", qclass, qtype, 0);
Packit 6c4009
      resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
Packit 6c4009
      resolv_response_close_record (b);
Packit 6c4009
      break;
Packit 6c4009
    case 6:
Packit 6c4009
      resolv_response_init (b, (struct resolv_response_flags) {});
Packit 6c4009
      resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
      resolv_response_section (b, ns_s_an);
Packit 6c4009
      resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
Packit 6c4009
      resolv_response_add_name (b, "www.example");
Packit 6c4009
      resolv_response_close_record (b);
Packit 6c4009
      resolv_response_open_record (b, qname, qclass, 46 /* RRSIG */, 0);
Packit 6c4009
      resolv_response_add_name (b, ".");
Packit 6c4009
      resolv_response_close_record (b);
Packit 6c4009
      resolv_response_open_record (b, "www.example", qclass, qtype, 0);
Packit 6c4009
      resolv_response_add_data (b, "\xC0\x00\x02\x01", 4);
Packit 6c4009
      resolv_response_close_record (b);
Packit 6c4009
      break;
Packit 6c4009
    case 102:
Packit 6c4009
      if (!ctx->tcp)
Packit 6c4009
        {
Packit 6c4009
          resolv_response_init (b, (struct resolv_response_flags) {.tc = true});
Packit 6c4009
          resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
        }
Packit 6c4009
      else
Packit 6c4009
        {
Packit 6c4009
          resolv_response_init
Packit 6c4009
            (b, (struct resolv_response_flags) {.ancount = 1});
Packit 6c4009
          resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
          resolv_response_section (b, ns_s_an);
Packit 6c4009
          resolv_response_open_record (b, qname, qclass, T_CNAME, 0);
Packit 6c4009
          size_t to_fill = 65535 - resolv_response_length (b)
Packit 6c4009
            - 2 /* length, "n" */ - 2 /* compression reference */
Packit 6c4009
            - 2 /* RR type */;
Packit 6c4009
          for (size_t i = 0; i < to_fill; ++i)
Packit 6c4009
            resolv_response_add_data (b, "", 1);
Packit 6c4009
          resolv_response_close_record (b);
Packit 6c4009
          resolv_response_add_name (b, "n.example");
Packit 6c4009
          uint16_t rrtype = htons (T_CNAME);
Packit 6c4009
          resolv_response_add_data (b, &rrtype, sizeof (rrtype));
Packit 6c4009
        }
Packit 6c4009
      break;
Packit 6c4009
    case 103:
Packit 6c4009
      /* NODATA repsonse.  */
Packit 6c4009
      resolv_response_init (b, (struct resolv_response_flags) {});
Packit 6c4009
      resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
      break;
Packit 6c4009
    case 104:
Packit 6c4009
      resolv_response_init (b, (struct resolv_response_flags) {.ancount = 1});
Packit 6c4009
      resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
      /* No RR metadata.  */
Packit 6c4009
      resolv_response_add_name (b, "www.example");
Packit 6c4009
      break;
Packit 6c4009
    case 105:
Packit 6c4009
      if (qtype == T_A)
Packit 6c4009
        {
Packit 6c4009
          resolv_response_init (b, (struct resolv_response_flags) {});
Packit 6c4009
          resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
          /* No data, trigger AAAA query.  */
Packit 6c4009
        }
Packit 6c4009
      else
Packit 6c4009
        {
Packit 6c4009
          resolv_response_init
Packit 6c4009
            (b, (struct resolv_response_flags) {.ancount = 1});
Packit 6c4009
          resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
          /* No RR metadata.  */
Packit 6c4009
          resolv_response_add_name
Packit 6c4009
            (b, "long-name-exceed-previously-initialized-buffer.example");
Packit 6c4009
        }
Packit 6c4009
      break;
Packit 6c4009
    case 106:
Packit 6c4009
      resolv_response_init (b, (struct resolv_response_flags) {.ancount = 1});
Packit 6c4009
      resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
      /* No RR metadata.  */
Packit 6c4009
      resolv_response_add_name (b, "www.example");
Packit 6c4009
      resolv_response_add_data (b, "\xff\xff", 2);
Packit 6c4009
      break;
Packit 6c4009
    case 107:
Packit 6c4009
      if (qtype == T_A)
Packit 6c4009
        {
Packit 6c4009
          resolv_response_init (b, (struct resolv_response_flags) {});
Packit 6c4009
          resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
          /* No data, trigger AAAA query.  */
Packit 6c4009
        }
Packit 6c4009
      else
Packit 6c4009
        {
Packit 6c4009
          resolv_response_init
Packit 6c4009
            (b, (struct resolv_response_flags) {.ancount = 1});
Packit 6c4009
          resolv_response_add_question (b, qname, qclass, qtype);
Packit 6c4009
          /* No RR metadata.  */
Packit 6c4009
          resolv_response_add_name (b, "www.example");
Packit 6c4009
          resolv_response_add_data (b, "\xff\xff", 2);
Packit 6c4009
        }
Packit 6c4009
      break;
Packit 6c4009
    default:
Packit 6c4009
      FAIL_EXIT1 ("error: invalid QNAME: %s (code %d)\n", qname, code);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
check (int code, const char *expected)
Packit 6c4009
{
Packit 6c4009
  char qname[200];
Packit 6c4009
  snprintf (qname, sizeof (qname), "code%d.example", code);
Packit 6c4009
  char *result;
Packit 6c4009
  enum nss_status status;
Packit 6c4009
  {
Packit 6c4009
    enum { buffer_size = 4096 };
Packit 6c4009
    char *buffer = xmalloc (buffer_size);
Packit 6c4009
    char *temp_result;
Packit 6c4009
    int temp_errno;
Packit 6c4009
    int temp_herrno;
Packit 6c4009
    status = getcanonname
Packit 6c4009
      (qname, buffer, buffer_size, &temp_result, &temp_errno, &temp_herrno);
Packit 6c4009
    if (status == NSS_STATUS_SUCCESS)
Packit 6c4009
      result = xstrdup (temp_result);
Packit 6c4009
    else
Packit 6c4009
      {
Packit 6c4009
        errno = temp_errno;
Packit 6c4009
        h_errno = temp_herrno;
Packit 6c4009
      }
Packit 6c4009
    free (buffer);
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  if (status == NSS_STATUS_SUCCESS)
Packit 6c4009
    {
Packit 6c4009
      if (expected != NULL)
Packit 6c4009
        {
Packit 6c4009
          if (strcmp (result, expected) != 0)
Packit 6c4009
            {
Packit 6c4009
              support_record_failure ();
Packit 6c4009
              printf ("error: getcanonname (%s) failed\n", qname);
Packit 6c4009
              printf ("error:  expected: %s\n", expected);
Packit 6c4009
              printf ("error:  actual:   %s\n", result);
Packit 6c4009
              free (result);
Packit 6c4009
              return;
Packit 6c4009
            }
Packit 6c4009
        }
Packit 6c4009
      else
Packit 6c4009
        {
Packit 6c4009
          support_record_failure ();
Packit 6c4009
          printf ("error: getcanonname (%s) unexpected success\n", qname);
Packit 6c4009
          printf ("error:  actual:   %s\n", result);
Packit 6c4009
          free (result);
Packit 6c4009
          return;
Packit 6c4009
        }
Packit 6c4009
      free (result);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      if (expected != NULL)
Packit 6c4009
        {
Packit 6c4009
          support_record_failure ();
Packit 6c4009
          printf ("error: getcanonname (%s) failed\n", qname);
Packit 6c4009
          printf ("error:  expected: %s\n", expected);
Packit 6c4009
          return;
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  void *nss_dns_handle = dlopen (LIBNSS_DNS_SO, RTLD_LAZY);
Packit 6c4009
  if (nss_dns_handle == NULL)
Packit 6c4009
    FAIL_EXIT1 ("could not dlopen %s: %s", LIBNSS_DNS_SO, dlerror ());
Packit 6c4009
  {
Packit 6c4009
    const char *func = "_nss_dns_getcanonname_r";
Packit 6c4009
    void *ptr = dlsym (nss_dns_handle, func);
Packit 6c4009
    if (ptr == NULL)
Packit 6c4009
      FAIL_EXIT1 ("could not look up %s: %s", func, dlerror ());
Packit 6c4009
    getcanonname = ptr;
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  struct resolv_test *aux = resolv_test_start
Packit 6c4009
    ((struct resolv_redirect_config)
Packit 6c4009
     {
Packit 6c4009
       .response_callback = response,
Packit 6c4009
     });
Packit 6c4009
Packit 6c4009
  check (1, "www.example");
Packit 6c4009
  check (2, "www.example");
Packit 6c4009
  check (3, "www.example");
Packit 6c4009
  check (4, "www.example");
Packit 6c4009
  check (5, "www1.example");
Packit 6c4009
Packit 6c4009
  /* This should really result in "www.example", but the fake RRSIG
Packit 6c4009
     record causes the current implementation to stop parsing.  */
Packit 6c4009
  check (6, NULL);
Packit 6c4009
Packit 6c4009
  for (int i = 102; i <= 107; ++i)
Packit 6c4009
  check (i, NULL);
Packit 6c4009
Packit 6c4009
  resolv_test_end (aux);
Packit 6c4009
Packit 6c4009
  TEST_VERIFY (dlclose (nss_dns_handle) == 0);
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#include <support/test-driver.c>