(root)/
glibc-2.38/
resolv/
tst-bug18665-tcp.c
       1  /* Test __libc_res_nsend buffer mismanagement, basic TCP coverage.
       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 <errno.h>
      20  #include <netdb.h>
      21  #include <resolv.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  #include <support/check.h>
      26  #include <support/check_nss.h>
      27  #include <support/resolv_test.h>
      28  #include <support/xthread.h>
      29  #include <support/xmemstream.h>
      30  
      31  static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
      32  
      33  static int initial_address_count = 1;
      34  static int subsequent_address_count = 2000;
      35  static int response_number = 0;
      36  
      37  static void
      38  response (const struct resolv_response_context *ctx,
      39            struct resolv_response_builder *b,
      40            const char *qname, uint16_t qclass, uint16_t qtype)
      41  {
      42    TEST_VERIFY_EXIT (qname != NULL);
      43  
      44    /* If not using TCP, just force its use.  */
      45    if (!ctx->tcp)
      46      {
      47        struct resolv_response_flags flags = {.tc = true};
      48        resolv_response_init (b, flags);
      49        resolv_response_add_question (b, qname, qclass, qtype);
      50        return;
      51      }
      52  
      53    struct resolv_response_flags flags = {};
      54    resolv_response_init (b, flags);
      55    resolv_response_add_question (b, qname, qclass, qtype);
      56  
      57    resolv_response_section (b, ns_s_an);
      58  
      59    /* The number of addresses (in the additional section) for the name
      60       server record (in the authoritative section).  */
      61    int address_count;
      62    xpthread_mutex_lock (&lock);
      63    ++response_number;
      64    if (response_number == 1)
      65      address_count = initial_address_count;
      66    else if (response_number == 2)
      67      {
      68        address_count = 0;
      69        resolv_response_drop (b);
      70        resolv_response_close (b);
      71      }
      72    else
      73      address_count = subsequent_address_count;
      74    xpthread_mutex_unlock (&lock);
      75  
      76    /* Only add the address record to the answer section if we requested
      77       any name server addresses.  */
      78    if (address_count > 0)
      79      {
      80        resolv_response_open_record (b, qname, qclass, qtype, 0);
      81        switch (qtype)
      82          {
      83          case T_A:
      84            {
      85              char ipv4[4] = {10, response_number >> 8, response_number, 0};
      86              ipv4[3] = 2 * ctx->tcp + 4 * ctx->server_index;
      87              resolv_response_add_data (b, &ipv4, sizeof (ipv4));
      88            }
      89            break;
      90          case T_AAAA:
      91            {
      92              char ipv6[16]
      93                = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0,
      94                   response_number >> 8, response_number, 0, 0};
      95              ipv6[15] = 2 * ctx->tcp + 4 * ctx->server_index;
      96              resolv_response_add_data (b, &ipv6, sizeof (ipv6));
      97            }
      98            break;
      99          default:
     100            support_record_failure ();
     101            printf ("error: unexpected QTYPE: %s/%u/%u\n",
     102                    qname, qclass, qtype);
     103          }
     104        resolv_response_close_record (b);
     105  
     106        /* Add the name server record.  */
     107        resolv_response_section (b, ns_s_ns);
     108        resolv_response_open_record (b, "example", C_IN, T_NS, 0);
     109        resolv_response_add_name (b, "ns.example");
     110        resolv_response_close_record (b);
     111  
     112        /* Increase the response size with name server addresses.  These
     113           addresses are not copied out of nss_dns, and thus do not
     114           trigger getaddrinfo retries with a larger buffer, making
     115           testing more predictable.  */
     116        resolv_response_section (b, ns_s_ar);
     117        for (int i = 1; i <= address_count; ++i)
     118          {
     119            resolv_response_open_record (b, "ns.example", qclass, qtype, 0);
     120            switch (qtype)
     121              {
     122              case T_A:
     123                {
     124                  char ipv4[4] = {response_number, i >> 8, i, 0};
     125                  ipv4[3] = 2 * ctx->tcp + 4 * ctx->server_index;
     126                  resolv_response_add_data (b, &ipv4, sizeof (ipv4));
     127                }
     128                break;
     129              case T_AAAA:
     130                {
     131                  char ipv6[16]
     132                    = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0,
     133                       response_number >> 8, response_number,
     134                       i >> 8, i, 0, 0};
     135                  ipv6[15] = 2 * ctx->tcp + 4 * ctx->server_index;
     136                  resolv_response_add_data (b, &ipv6, sizeof (ipv6));
     137                }
     138                break;
     139              default:
     140                support_record_failure ();
     141                printf ("error: unexpected QTYPE: %s/%u/%u\n",
     142                        qname, qclass, qtype);
     143              }
     144            resolv_response_close_record (b);
     145          }
     146      }
     147  }
     148  
     149  static char *
     150  expected_result (unsigned port, unsigned response_number)
     151  {
     152    struct xmemstream mem;
     153    xopen_memstream (&mem);
     154    /* We fail the second TCP query to the first server by closing the
     155       connection immediately, without returning any data.  This should
     156       cause failover to the second server.  */
     157    int server_index = 1;
     158    fprintf (mem.out, "address: STREAM/TCP 10.%u.%u.%u %u\n",
     159             (response_number >> 8) & 0xff, response_number & 0xff,
     160             2 + 4 * server_index, port);
     161    fprintf (mem.out, "address: STREAM/TCP 2001:db8::%x:%x %u\n",
     162             (response_number + 1) & 0xffff,
     163             2 + 4 * server_index, port);
     164    xfclose_memstream (&mem);
     165    return mem.buffer;
     166  }
     167  
     168  static void
     169  test_different_sizes (void)
     170  {
     171    struct addrinfo hints =
     172      {
     173        .ai_family = AF_UNSPEC,
     174        .ai_socktype = SOCK_STREAM,
     175        .ai_protocol = IPPROTO_TCP,
     176      };
     177    struct addrinfo *ai;
     178    char *expected;
     179    int ret;
     180  
     181    /* This magic number produces a response size close to 2048
     182       bytes.  */
     183    initial_address_count = 124;
     184    response_number = 0;
     185  
     186    ret = getaddrinfo ("www.example", "80", &hints, &ai);
     187    expected = expected_result (80, 3);
     188    check_addrinfo ("www.example:80", ai, ret, expected);
     189    if (ret == 0)
     190      freeaddrinfo (ai);
     191    free (expected);
     192  
     193    response_number = 0;
     194    ret = getaddrinfo ("www123.example", "80", &hints, &ai);
     195    if (ret == 0)
     196      freeaddrinfo (ai);
     197  
     198    response_number = 0;
     199    ret = getaddrinfo ("www1234.example", "80", &hints, &ai);
     200    if (ret == 0)
     201      freeaddrinfo (ai);
     202  
     203    response_number = 0;
     204    ret = getaddrinfo ("www12345.example", "80", &hints, &ai);
     205    if (ret == 0)
     206      freeaddrinfo (ai);
     207  }
     208  
     209  static int
     210  do_test (void)
     211  {
     212    struct resolv_test *obj = resolv_test_start
     213      ((struct resolv_redirect_config)
     214       {
     215         .response_callback = response
     216       });
     217  
     218    test_different_sizes ();
     219  
     220    _res.options |= RES_SNGLKUP;
     221    test_different_sizes ();
     222  
     223    _res.options |= RES_SNGLKUPREOP;
     224    test_different_sizes ();
     225  
     226    resolv_test_end (obj);
     227    return 0;
     228  }
     229  
     230  #include <support/test-driver.c>