Blame resolv/tst-resolv-edns.c

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