(root)/
glibc-2.38/
resolv/
tst-resolv-qtypes.c
       1  /* Exercise low-level query functions with different QTYPEs.
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <resolv.h>
      20  #include <string.h>
      21  #include <support/check.h>
      22  #include <support/check_nss.h>
      23  #include <support/resolv_test.h>
      24  #include <support/support.h>
      25  #include <support/test-driver.h>
      26  #include <support/xmemstream.h>
      27  
      28  /* If true, the response function will send the actual response packet
      29     over TCP instead of UDP.  */
      30  static volatile bool force_tcp;
      31  
      32  /* Send back a fake resource record matching the QTYPE.  */
      33  static void
      34  response (const struct resolv_response_context *ctx,
      35            struct resolv_response_builder *b,
      36            const char *qname, uint16_t qclass, uint16_t qtype)
      37  {
      38    if (force_tcp && ctx->tcp)
      39      {
      40        resolv_response_init (b, (struct resolv_response_flags) { .tc = 1 });
      41        resolv_response_add_question (b, qname, qclass, qtype);
      42        return;
      43      }
      44  
      45    resolv_response_init (b, (struct resolv_response_flags) { });
      46    resolv_response_add_question (b, qname, qclass, qtype);
      47    resolv_response_section (b, ns_s_an);
      48    resolv_response_open_record (b, qname, qclass, qtype, 0);
      49    resolv_response_add_data (b, &qtype, sizeof (qtype));
      50    resolv_response_close_record (b);
      51  }
      52  
      53  static const char domain[] = "www.example.com";
      54  
      55  static int
      56  wrap_res_query (int type, unsigned char *answer, int answer_length)
      57  {
      58    return res_query (domain, C_IN, type, answer, answer_length);
      59  }
      60  
      61  static int
      62  wrap_res_search (int type, unsigned char *answer, int answer_length)
      63  {
      64    return res_query (domain, C_IN, type, answer, answer_length);
      65  }
      66  
      67  static int
      68  wrap_res_querydomain (int type, unsigned char *answer, int answer_length)
      69  {
      70    return res_querydomain ("www", "example.com", C_IN, type,
      71                             answer, answer_length);
      72  }
      73  
      74  static int
      75  wrap_res_send (int type, unsigned char *answer, int answer_length)
      76  {
      77    unsigned char buf[512];
      78    int ret = res_mkquery (QUERY, domain, C_IN, type,
      79                           (const unsigned char *) "", 0, NULL,
      80                           buf, sizeof (buf));
      81    if (type < 0 || type >= 65536)
      82      {
      83        /* res_mkquery fails for out-of-range record types.  */
      84        TEST_VERIFY_EXIT (ret == -1);
      85        return -1;
      86      }
      87    TEST_VERIFY_EXIT (ret > 12);  /* DNS header length.  */
      88    return res_send (buf, ret, answer, answer_length);
      89  }
      90  
      91  static int
      92  wrap_res_nquery (int type, unsigned char *answer, int answer_length)
      93  {
      94    return res_nquery (&_res, domain, C_IN, type, answer, answer_length);
      95  }
      96  
      97  static int
      98  wrap_res_nsearch (int type, unsigned char *answer, int answer_length)
      99  {
     100    return res_nquery (&_res, domain, C_IN, type, answer, answer_length);
     101  }
     102  
     103  static int
     104  wrap_res_nquerydomain (int type, unsigned char *answer, int answer_length)
     105  {
     106    return res_nquerydomain (&_res, "www", "example.com", C_IN, type,
     107                             answer, answer_length);
     108  }
     109  
     110  static int
     111  wrap_res_nsend (int type, unsigned char *answer, int answer_length)
     112  {
     113    unsigned char buf[512];
     114    int ret = res_nmkquery (&_res, QUERY, domain, C_IN, type,
     115                           (const unsigned char *) "", 0, NULL,
     116                           buf, sizeof (buf));
     117    if (type < 0 || type >= 65536)
     118      {
     119        /* res_mkquery fails for out-of-range record types.  */
     120        TEST_VERIFY_EXIT (ret == -1);
     121        return -1;
     122      }
     123    TEST_VERIFY_EXIT (ret > 12);  /* DNS header length.  */
     124    return res_nsend (&_res, buf, ret, answer, answer_length);
     125  }
     126  
     127  static void
     128  test_function (const char *fname,
     129                 int (*func) (int type,
     130                              unsigned char *answer, int answer_length))
     131  {
     132    unsigned char buf[512];
     133    for (int tcp = 0; tcp < 2; ++tcp)
     134      {
     135        force_tcp = tcp;
     136        for (unsigned int type = 1; type <= 65535; ++type)
     137          {
     138            if (test_verbose)
     139              printf ("info: sending QTYPE %d with %s (tcp=%d)\n",
     140                      type, fname, tcp);
     141            int ret = func (type, buf, sizeof (buf));
     142            if (ret != 47)
     143              FAIL_EXIT1 ("%s tcp=%d qtype=%d return value %d",
     144                          fname,tcp, type, ret);
     145            /* One question, one answer record.  */
     146            TEST_VERIFY (memcmp (buf + 4, "\0\1\0\1\0\0\0\0", 8) == 0);
     147            /* Question section.  */
     148            static const char qname[] = "\3www\7example\3com";
     149            size_t qname_length = sizeof (qname);
     150            TEST_VERIFY (memcmp (buf + 12, qname, qname_length) == 0);
     151            /* RDATA part of answer.  */
     152            uint16_t type16 = type;
     153            TEST_VERIFY (memcmp (buf + ret - 2, &type16, sizeof (type16)) == 0);
     154          }
     155      }
     156  
     157    TEST_VERIFY (func (-1, buf, sizeof (buf) == -1));
     158    TEST_VERIFY (func (65536, buf, sizeof (buf) == -1));
     159  }
     160  
     161  static int
     162  do_test (void)
     163  {
     164    struct resolv_redirect_config config =
     165      {
     166        .response_callback = response,
     167      };
     168    struct resolv_test *obj = resolv_test_start (config);
     169  
     170    test_function ("res_query", &wrap_res_query);
     171    test_function ("res_search", &wrap_res_search);
     172    test_function ("res_querydomain", &wrap_res_querydomain);
     173    test_function ("res_send", &wrap_res_send);
     174  
     175    test_function ("res_nquery", &wrap_res_nquery);
     176    test_function ("res_nsearch", &wrap_res_nsearch);
     177    test_function ("res_nquerydomain", &wrap_res_nquerydomain);
     178    test_function ("res_nsend", &wrap_res_nsend);
     179  
     180    resolv_test_end (obj);
     181    return 0;
     182  }
     183  
     184  #define TIMEOUT 300
     185  #include <support/test-driver.c>