Blame resolv/tst-resolv-edns.c

Packit Service 82fcde
/* Test EDNS handling in the stub resolver.
Packit Service 82fcde
   Copyright (C) 2016-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
#include <errno.h>
Packit Service 82fcde
#include <netdb.h>
Packit Service 82fcde
#include <resolv.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/resolv_test.h>
Packit Service 82fcde
#include <support/support.h>
Packit Service 82fcde
#include <support/test-driver.h>
Packit Service 82fcde
#include <support/xthread.h>
Packit Service 82fcde
Packit Service 82fcde
/* Data produced by a test query.  */
Packit Service 82fcde
struct response_data
Packit Service 82fcde
{
Packit Service 82fcde
  char *qname;
Packit Service 82fcde
  uint16_t qtype;
Packit Service 82fcde
  struct resolv_edns_info edns;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
/* Global array used by put_response and get_response to record
Packit Service 82fcde
   response data.  The test DNS server returns the index of the array
Packit Service 82fcde
   element which contains the actual response data.  This enables the
Packit Service 82fcde
   test case to return arbitrary amounts of data with the limited
Packit Service 82fcde
   number of bits which fit into an IP addres.
Packit Service 82fcde
Packit Service 82fcde
   The volatile specifier is needed because the test case accesses
Packit Service 82fcde
   these variables from a callback function called from a function
Packit Service 82fcde
   which is marked as __THROW (i.e., a leaf function which actually is
Packit Service 82fcde
   not).  */
Packit Service 82fcde
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Packit Service 82fcde
static struct response_data ** volatile response_data_array;
Packit Service 82fcde
volatile static size_t response_data_count;
Packit Service 82fcde
Packit Service 82fcde
/* Extract information from the query, store it in a struct
Packit Service 82fcde
   response_data object, and return its index in the
Packit Service 82fcde
   response_data_array.  */
Packit Service 82fcde
static unsigned int
Packit Service 82fcde
put_response (const struct resolv_response_context *ctx,
Packit Service 82fcde
                 const char *qname, uint16_t qtype)
Packit Service 82fcde
{
Packit Service 82fcde
  xpthread_mutex_lock (&mutex);
Packit Service 82fcde
  ++response_data_count;
Packit Service 82fcde
  /* We only can represent 2**24 indexes in 10.0.0.0/8.  */
Packit Service 82fcde
  TEST_VERIFY (response_data_count < (1 << 24));
Packit Service 82fcde
  response_data_array = xrealloc
Packit Service 82fcde
    (response_data_array, sizeof (*response_data_array) * response_data_count);
Packit Service 82fcde
  unsigned int index = response_data_count - 1;
Packit Service 82fcde
  struct response_data *data = xmalloc (sizeof (*data));
Packit Service 82fcde
  *data = (struct response_data)
Packit Service 82fcde
    {
Packit Service 82fcde
      .qname = xstrdup (qname),
Packit Service 82fcde
      .qtype = qtype,
Packit Service 82fcde
      .edns = ctx->edns,
Packit Service 82fcde
    };
Packit Service 82fcde
  response_data_array[index] = data;
Packit Service 82fcde
  xpthread_mutex_unlock (&mutex);
Packit Service 82fcde
  return index;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Verify the index into the response_data array and return the data
Packit Service 82fcde
   at it.  */
Packit Service 82fcde
static struct response_data *
Packit Service 82fcde
get_response (unsigned int index)
Packit Service 82fcde
{
Packit Service 82fcde
  xpthread_mutex_lock (&mutex);
Packit Service 82fcde
  TEST_VERIFY_EXIT (index < response_data_count);
Packit Service 82fcde
  struct response_data *result = response_data_array[index];
Packit Service 82fcde
  xpthread_mutex_unlock (&mutex);
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Deallocate all response data.  */
Packit Service 82fcde
static void
Packit Service 82fcde
free_response_data (void)
Packit Service 82fcde
{
Packit Service 82fcde
  xpthread_mutex_lock (&mutex);
Packit Service 82fcde
  size_t count = response_data_count;
Packit Service 82fcde
  struct response_data **array = response_data_array;
Packit Service 82fcde
  for (unsigned int i = 0; i < count; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct response_data *data = array[i];
Packit Service 82fcde
      free (data->qname);
Packit Service 82fcde
      free (data);
Packit Service 82fcde
    }
Packit Service 82fcde
  free (array);
Packit Service 82fcde
  response_data_array = NULL;
Packit Service 82fcde
  response_data_count = 0;
Packit Service 82fcde
  xpthread_mutex_unlock (&mutex);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#define EDNS_PROBE_EXAMPLE "edns-probe.example"
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
response (const struct resolv_response_context *ctx,
Packit Service 82fcde
          struct resolv_response_builder *b,
Packit Service 82fcde
          const char *qname, uint16_t qclass, uint16_t qtype)
Packit Service 82fcde
{
Packit Service 82fcde
  TEST_VERIFY_EXIT (qname != NULL);
Packit Service 82fcde
Packit Service 82fcde
  const char *qname_compare = qname;
Packit Service 82fcde
Packit Service 82fcde
  /* The "formerr." prefix can be used to request a FORMERR response on the
Packit Service 82fcde
     first server.  */
Packit Service 82fcde
  bool send_formerr;
Packit Service 82fcde
  if (strncmp ("formerr.", qname, strlen ("formerr.")) == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      send_formerr = true;
Packit Service 82fcde
      qname_compare = qname + strlen ("formerr.");
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      send_formerr = false;
Packit Service 82fcde
      qname_compare = qname;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* The "tcp." prefix can be used to request TCP fallback.  */
Packit Service 82fcde
  bool force_tcp;
Packit Service 82fcde
  if (strncmp ("tcp.", qname_compare, strlen ("tcp.")) == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      force_tcp = true;
Packit Service 82fcde
      qname_compare += strlen ("tcp.");
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    force_tcp = false;
Packit Service 82fcde
Packit Service 82fcde
  enum {edns_probe} requested_qname;
Packit Service 82fcde
  if (strcmp (qname_compare, EDNS_PROBE_EXAMPLE) == 0)
Packit Service 82fcde
    requested_qname = edns_probe;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      support_record_failure ();
Packit Service 82fcde
      printf ("error: unexpected QNAME: %s (reduced: %s)\n",
Packit Service 82fcde
              qname, qname_compare);
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
  TEST_VERIFY_EXIT (qclass == C_IN);
Packit Service 82fcde
  struct resolv_response_flags flags = { };
Packit Service 82fcde
  flags.tc = force_tcp && !ctx->tcp;
Packit Service 82fcde
  if (!flags.tc && send_formerr && ctx->server_index == 0)
Packit Service 82fcde
    /* Send a FORMERR for the first full response from the first
Packit Service 82fcde
       server.  */
Packit Service 82fcde
    flags.rcode = 1;          /* FORMERR */
Packit Service 82fcde
  resolv_response_init (b, flags);
Packit Service 82fcde
  resolv_response_add_question (b, qname, qclass, qtype);
Packit Service 82fcde
  if (flags.tc || flags.rcode != 0)
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  if (test_verbose)
Packit Service 82fcde
    printf ("info: edns=%d payload_size=%d\n",
Packit Service 82fcde
            ctx->edns.active, ctx->edns.payload_size);
Packit Service 82fcde
Packit Service 82fcde
  /* Encode the response_data object in multiple address records.
Packit Service 82fcde
     Each record carries two bytes of payload data, and an index.  */
Packit Service 82fcde
  resolv_response_section (b, ns_s_an);
Packit Service 82fcde
  switch (requested_qname)
Packit Service 82fcde
    {
Packit Service 82fcde
    case edns_probe:
Packit Service 82fcde
      {
Packit Service 82fcde
        unsigned int index = put_response (ctx, qname, qtype);
Packit Service 82fcde
        switch (qtype)
Packit Service 82fcde
          {
Packit Service 82fcde
          case T_A:
Packit Service 82fcde
            {
Packit Service 82fcde
              uint32_t addr = htonl (0x0a000000 | index);
Packit Service 82fcde
              resolv_response_open_record (b, qname, qclass, qtype, 0);
Packit Service 82fcde
              resolv_response_add_data (b, &addr, sizeof (addr));
Packit Service 82fcde
              resolv_response_close_record (b);
Packit Service 82fcde
            }
Packit Service 82fcde
            break;
Packit Service 82fcde
          case T_AAAA:
Packit Service 82fcde
            {
Packit Service 82fcde
              char addr[16]
Packit Service 82fcde
                = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Packit Service 82fcde
                   index >> 16, index >> 8, index};
Packit Service 82fcde
              resolv_response_open_record (b, qname, qclass, qtype, 0);
Packit Service 82fcde
              resolv_response_add_data (b, &addr, sizeof (addr));
Packit Service 82fcde
              resolv_response_close_record (b);
Packit Service 82fcde
            }
Packit Service 82fcde
          }
Packit Service 82fcde
      }
Packit Service 82fcde
      break;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Update *DATA with data from ADDRESS of SIZE.  Set the corresponding
Packit Service 82fcde
   flag in SHADOW for each byte written.  */
Packit Service 82fcde
static struct response_data *
Packit Service 82fcde
decode_address (const void *address, size_t size)
Packit Service 82fcde
{
Packit Service 82fcde
  switch (size)
Packit Service 82fcde
    {
Packit Service 82fcde
    case 4:
Packit Service 82fcde
      TEST_VERIFY (memcmp (address, "\x0a", 1) == 0);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case 16:
Packit Service 82fcde
      TEST_VERIFY (memcmp (address, "\x20\x01\x0d\xb8", 4) == 0);
Packit Service 82fcde
      break;
Packit Service 82fcde
    default:
Packit Service 82fcde
      FAIL_EXIT1 ("unexpected address size %zu", size);
Packit Service 82fcde
    }
Packit Service 82fcde
  const unsigned char *addr = address;
Packit Service 82fcde
  unsigned int index = addr[size - 3] * 256 * 256
Packit Service 82fcde
    + addr[size - 2] * 256
Packit Service 82fcde
    + addr[size - 1];
Packit Service 82fcde
  return get_response (index);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static struct response_data *
Packit Service 82fcde
decode_hostent (struct hostent *e)
Packit Service 82fcde
{
Packit Service 82fcde
  TEST_VERIFY_EXIT (e != NULL);
Packit Service 82fcde
  TEST_VERIFY_EXIT (e->h_addr_list[0] != NULL);
Packit Service 82fcde
  TEST_VERIFY (e->h_addr_list[1] == NULL);
Packit Service 82fcde
  return decode_address (e->h_addr_list[0], e->h_length);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static struct response_data *
Packit Service 82fcde
decode_addrinfo (struct addrinfo *ai, int family)
Packit Service 82fcde
{
Packit Service 82fcde
  struct response_data *data = NULL;
Packit Service 82fcde
  while (ai != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (ai->ai_family == family)
Packit Service 82fcde
        {
Packit Service 82fcde
          struct response_data *new_data;
Packit Service 82fcde
          switch (family)
Packit Service 82fcde
            {
Packit Service 82fcde
            case AF_INET:
Packit Service 82fcde
              {
Packit Service 82fcde
                struct sockaddr_in *pin = (struct sockaddr_in *) ai->ai_addr;
Packit Service 82fcde
                new_data = decode_address (&pin->sin_addr.s_addr, 4);
Packit Service 82fcde
              }
Packit Service 82fcde
              break;
Packit Service 82fcde
            case AF_INET6:
Packit Service 82fcde
              {
Packit Service 82fcde
                struct sockaddr_in6 *pin = (struct sockaddr_in6 *) ai->ai_addr;
Packit Service 82fcde
                new_data = decode_address (&pin->sin6_addr.s6_addr, 16);
Packit Service 82fcde
              }
Packit Service 82fcde
              break;
Packit Service 82fcde
            default:
Packit Service 82fcde
              FAIL_EXIT1 ("invalid address family %d", ai->ai_family);
Packit Service 82fcde
            }
Packit Service 82fcde
          if (data == NULL)
Packit Service 82fcde
            data = new_data;
Packit Service 82fcde
          else
Packit Service 82fcde
            /* Check pointer equality because this should be the same
Packit Service 82fcde
               response (same index).  */
Packit Service 82fcde
            TEST_VERIFY (data == new_data);
Packit Service 82fcde
        }
Packit Service 82fcde
      ai = ai->ai_next;
Packit Service 82fcde
    }
Packit Service 82fcde
  TEST_VERIFY_EXIT (data != NULL);
Packit Service 82fcde
  return data;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Updated by the main test loop in accordance with what is set in
Packit Service 82fcde
   _res.options.  */
Packit Service 82fcde
static bool use_edns;
Packit Service 82fcde
static bool use_dnssec;
Packit Service 82fcde
Packit Service 82fcde
/* Verify the decoded response data against the flags above.  */
Packit Service 82fcde
static void
Packit Service 82fcde
verify_response_data_payload (struct response_data *data,
Packit Service 82fcde
                              size_t expected_payload)
Packit Service 82fcde
{
Packit Service 82fcde
  bool edns = use_edns || use_dnssec;
Packit Service 82fcde
  TEST_VERIFY (data->edns.active == edns);
Packit Service 82fcde
  if (!edns)
Packit Service 82fcde
    expected_payload = 0;
Packit Service 82fcde
  if (data->edns.payload_size != expected_payload)
Packit Service 82fcde
    {
Packit Service 82fcde
      support_record_failure ();
Packit Service 82fcde
      printf ("error: unexpected payload size %d (edns=%d)\n",
Packit Service 82fcde
              (int) data->edns.payload_size, edns);
Packit Service 82fcde
    }
Packit Service 82fcde
  uint16_t expected_flags = 0;
Packit Service 82fcde
  if (use_dnssec)
Packit Service 82fcde
    expected_flags |= 0x8000;   /* DO flag.  */
Packit Service 82fcde
  if (data->edns.flags != expected_flags)
Packit Service 82fcde
    {
Packit Service 82fcde
      support_record_failure ();
Packit Service 82fcde
      printf ("error: unexpected EDNS flags 0x%04x (edns=%d)\n",
Packit Service 82fcde
              (int) data->edns.flags, edns);
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Same as verify_response_data_payload, but use the default
Packit Service 82fcde
   payload.  */
Packit Service 82fcde
static void
Packit Service 82fcde
verify_response_data (struct response_data *data)
Packit Service 82fcde
{
Packit Service 82fcde
  verify_response_data_payload (data, 1200);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
check_hostent (struct hostent *e)
Packit Service 82fcde
{
Packit Service 82fcde
  TEST_VERIFY_EXIT (e != NULL);
Packit Service 82fcde
  verify_response_data (decode_hostent (e));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
do_ai (int family)
Packit Service 82fcde
{
Packit Service 82fcde
  struct addrinfo hints = { .ai_family = family };
Packit Service 82fcde
  struct addrinfo *ai;
Packit Service 82fcde
  int ret = getaddrinfo (EDNS_PROBE_EXAMPLE, "80", &hints, &ai;;
Packit Service 82fcde
  TEST_VERIFY_EXIT (ret == 0);
Packit Service 82fcde
  switch (family)
Packit Service 82fcde
    {
Packit Service 82fcde
    case AF_INET:
Packit Service 82fcde
    case AF_INET6:
Packit Service 82fcde
      verify_response_data (decode_addrinfo (ai, family));
Packit Service 82fcde
      break;
Packit Service 82fcde
    case AF_UNSPEC:
Packit Service 82fcde
      verify_response_data (decode_addrinfo (ai, AF_INET));
Packit Service 82fcde
      verify_response_data (decode_addrinfo (ai, AF_INET6));
Packit Service 82fcde
      break;
Packit Service 82fcde
    default:
Packit Service 82fcde
      FAIL_EXIT1 ("invalid address family %d", family);
Packit Service 82fcde
    }
Packit Service 82fcde
  freeaddrinfo (ai);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
enum res_op
Packit Service 82fcde
{
Packit Service 82fcde
  res_op_search,
Packit Service 82fcde
  res_op_query,
Packit Service 82fcde
  res_op_querydomain,
Packit Service 82fcde
  res_op_nsearch,
Packit Service 82fcde
  res_op_nquery,
Packit Service 82fcde
  res_op_nquerydomain,
Packit Service 82fcde
Packit Service 82fcde
  res_op_last = res_op_nquerydomain,
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
static const char *
Packit Service 82fcde
res_op_string (enum res_op op)
Packit Service 82fcde
{
Packit Service 82fcde
  switch (op)
Packit Service 82fcde
    {
Packit Service 82fcde
      case res_op_search:
Packit Service 82fcde
        return "res_search";
Packit Service 82fcde
      case res_op_query:
Packit Service 82fcde
        return "res_query";
Packit Service 82fcde
      case res_op_querydomain:
Packit Service 82fcde
        return "res_querydomain";
Packit Service 82fcde
      case res_op_nsearch:
Packit Service 82fcde
        return "res_nsearch";
Packit Service 82fcde
      case res_op_nquery:
Packit Service 82fcde
        return "res_nquery";
Packit Service 82fcde
      case res_op_nquerydomain:
Packit Service 82fcde
        return "res_nquerydomain";
Packit Service 82fcde
    }
Packit Service 82fcde
  FAIL_EXIT1 ("invalid res_op value %d", (int) op);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Call libresolv function OP to look up PROBE_NAME, with an answer
Packit Service 82fcde
   buffer of SIZE bytes.  Check that the advertised UDP buffer size is
Packit Service 82fcde
   in fact EXPECTED_BUFFER_SIZE.  */
Packit Service 82fcde
static void
Packit Service 82fcde
do_res_search (const char *probe_name, enum res_op op, size_t size,
Packit Service 82fcde
               size_t expected_buffer_size)
Packit Service 82fcde
{
Packit Service 82fcde
  if (test_verbose)
Packit Service 82fcde
    printf ("info: testing %s with buffer size %zu\n",
Packit Service 82fcde
            res_op_string (op), size);
Packit Service 82fcde
  unsigned char *buffer = xmalloc (size);
Packit Service 82fcde
  int ret = -1;
Packit Service 82fcde
  switch (op)
Packit Service 82fcde
    {
Packit Service 82fcde
    case res_op_search:
Packit Service 82fcde
      ret = res_search (probe_name, C_IN, T_A, buffer, size);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case res_op_query:
Packit Service 82fcde
      ret = res_query (probe_name, C_IN, T_A, buffer, size);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case res_op_nsearch:
Packit Service 82fcde
      ret = res_nsearch (&_res, probe_name, C_IN, T_A, buffer, size);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case res_op_nquery:
Packit Service 82fcde
      ret = res_nquery (&_res, probe_name, C_IN, T_A, buffer, size);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case res_op_querydomain:
Packit Service 82fcde
    case res_op_nquerydomain:
Packit Service 82fcde
      {
Packit Service 82fcde
        char *example_stripped = xstrdup (probe_name);
Packit Service 82fcde
        char *dot_example = strstr (example_stripped, ".example");
Packit Service 82fcde
        if (dot_example != NULL && strcmp (dot_example, ".example") == 0)
Packit Service 82fcde
          {
Packit Service 82fcde
            /* Truncate the domain name.  */
Packit Service 82fcde
            *dot_example = '\0';
Packit Service 82fcde
            if (op == res_op_querydomain)
Packit Service 82fcde
              ret = res_querydomain
Packit Service 82fcde
              (example_stripped, "example", C_IN, T_A, buffer, size);
Packit Service 82fcde
            else
Packit Service 82fcde
              ret = res_nquerydomain
Packit Service 82fcde
                (&_res, example_stripped, "example", C_IN, T_A, buffer, size);
Packit Service 82fcde
          }
Packit Service 82fcde
        else
Packit Service 82fcde
          FAIL_EXIT1 ("invalid probe name: %s", probe_name);
Packit Service 82fcde
        free (example_stripped);
Packit Service 82fcde
      }
Packit Service 82fcde
      break;
Packit Service 82fcde
    }
Packit Service 82fcde
  TEST_VERIFY_EXIT (ret > 12);
Packit Service 82fcde
  unsigned char *end = buffer + ret;
Packit Service 82fcde
Packit Service 82fcde
  HEADER *hd = (HEADER *) buffer;
Packit Service 82fcde
  TEST_VERIFY (ntohs (hd->qdcount) == 1);
Packit Service 82fcde
  TEST_VERIFY (ntohs (hd->ancount) == 1);
Packit Service 82fcde
  /* Skip over the header.  */
Packit Service 82fcde
  unsigned char *p = buffer + sizeof (*hd);
Packit Service 82fcde
  /* Skip over the question.  */
Packit Service 82fcde
  ret = dn_skipname (p, end);
Packit Service 82fcde
  TEST_VERIFY_EXIT (ret > 0);
Packit Service 82fcde
  p += ret;
Packit Service 82fcde
  TEST_VERIFY_EXIT (end - p >= 4);
Packit Service 82fcde
  p += 4;
Packit Service 82fcde
  /* Skip over the RNAME and the RR header, but stop at the RDATA
Packit Service 82fcde
     length.  */
Packit Service 82fcde
  ret = dn_skipname (p, end);
Packit Service 82fcde
  TEST_VERIFY_EXIT (ret > 0);
Packit Service 82fcde
  p += ret;
Packit Service 82fcde
  TEST_VERIFY_EXIT (end - p >= 2 + 2 + 4 + 2 + 4);
Packit Service 82fcde
  p += 2 + 2 + 4;
Packit Service 82fcde
  /* The IP address should be 4 bytes long.  */
Packit Service 82fcde
  TEST_VERIFY_EXIT (p[0] == 0);
Packit Service 82fcde
  TEST_VERIFY_EXIT (p[1] == 4);
Packit Service 82fcde
  /* Extract the address information.   */
Packit Service 82fcde
  p += 2;
Packit Service 82fcde
  struct response_data *data = decode_address (p, 4);
Packit Service 82fcde
Packit Service 82fcde
  verify_response_data_payload (data, expected_buffer_size);
Packit Service 82fcde
Packit Service 82fcde
  free (buffer);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
run_test (const char *probe_name)
Packit Service 82fcde
{
Packit Service 82fcde
  if (test_verbose)
Packit Service 82fcde
    printf ("\ninfo: * use_edns=%d use_dnssec=%d\n",
Packit Service 82fcde
            use_edns, use_dnssec);
Packit Service 82fcde
  check_hostent (gethostbyname (probe_name));
Packit Service 82fcde
  check_hostent (gethostbyname2 (probe_name, AF_INET));
Packit Service 82fcde
  check_hostent (gethostbyname2 (probe_name, AF_INET6));
Packit Service 82fcde
  do_ai (AF_UNSPEC);
Packit Service 82fcde
  do_ai (AF_INET);
Packit Service 82fcde
  do_ai (AF_INET6);
Packit Service 82fcde
Packit Service 82fcde
  for (int op = 0; op <= res_op_last; ++op)
Packit Service 82fcde
    {
Packit Service 82fcde
      do_res_search (probe_name, op, 301, 512);
Packit Service 82fcde
      do_res_search (probe_name, op, 511, 512);
Packit Service 82fcde
      do_res_search (probe_name, op, 512, 512);
Packit Service 82fcde
      do_res_search (probe_name, op, 513, 513);
Packit Service 82fcde
      do_res_search (probe_name, op, 657, 657);
Packit Service 82fcde
      do_res_search (probe_name, op, 1199, 1199);
Packit Service 82fcde
      do_res_search (probe_name, op, 1200, 1200);
Packit Service 82fcde
      do_res_search (probe_name, op, 1201, 1200);
Packit Service 82fcde
      do_res_search (probe_name, op, 65535, 1200);
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
do_test (void)
Packit Service 82fcde
{
Packit Service 82fcde
  for (int do_edns = 0; do_edns < 2; ++do_edns)
Packit Service 82fcde
    for (int do_dnssec = 0; do_dnssec < 2; ++do_dnssec)
Packit Service 82fcde
      for (int do_tcp = 0; do_tcp < 2; ++do_tcp)
Packit Service 82fcde
        for (int do_formerr = 0; do_formerr < 2; ++do_formerr)
Packit Service 82fcde
          {
Packit Service 82fcde
            struct resolv_test *aux = resolv_test_start
Packit Service 82fcde
              ((struct resolv_redirect_config)
Packit Service 82fcde
               {
Packit Service 82fcde
                 .response_callback = response,
Packit Service 82fcde
               });
Packit Service 82fcde
Packit Service 82fcde
            use_edns = do_edns;
Packit Service 82fcde
            if (do_edns)
Packit Service 82fcde
              _res.options |= RES_USE_EDNS0;
Packit Service 82fcde
            use_dnssec = do_dnssec;
Packit Service 82fcde
            if (do_dnssec)
Packit Service 82fcde
              _res.options |= RES_USE_DNSSEC;
Packit Service 82fcde
Packit Service 82fcde
            char *probe_name = xstrdup (EDNS_PROBE_EXAMPLE);
Packit Service 82fcde
            if (do_tcp)
Packit Service 82fcde
              {
Packit Service 82fcde
                char *n = xasprintf ("tcp.%s", probe_name);
Packit Service 82fcde
                free (probe_name);
Packit Service 82fcde
                probe_name = n;
Packit Service 82fcde
              }
Packit Service 82fcde
            if (do_formerr)
Packit Service 82fcde
              {
Packit Service 82fcde
                /* Send a garbage query in an attempt to trigger EDNS
Packit Service 82fcde
                   fallback.  */
Packit Service 82fcde
                char *n = xasprintf ("formerr.%s", probe_name);
Packit Service 82fcde
                gethostbyname (n);
Packit Service 82fcde
                free (n);
Packit Service 82fcde
              }
Packit Service 82fcde
Packit Service 82fcde
            run_test (probe_name);
Packit Service 82fcde
Packit Service 82fcde
            free (probe_name);
Packit Service 82fcde
            resolv_test_end (aux);
Packit Service 82fcde
          }
Packit Service 82fcde
Packit Service 82fcde
  free_response_data ();
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#include <support/test-driver.c>