(root)/
glibc-2.38/
resolv/
tst-resolv-noaaaa.c
       1  /* Test the RES_NOAAAA resolver option.
       2     Copyright (C) 2022-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 <stdlib.h>
      23  #include <support/check.h>
      24  #include <support/check_nss.h>
      25  #include <support/resolv_test.h>
      26  #include <support/support.h>
      27  
      28  /* Used to keep track of the number of queries.  */
      29  static volatile unsigned int queries;
      30  
      31  static void
      32  response (const struct resolv_response_context *ctx,
      33            struct resolv_response_builder *b,
      34            const char *qname, uint16_t qclass, uint16_t qtype)
      35  {
      36    /* Each test should only send one query.  */
      37    ++queries;
      38    TEST_COMPARE (queries, 1);
      39  
      40    /* AAAA queries are supposed to be disabled.  */
      41    TEST_VERIFY (qtype != T_AAAA);
      42    TEST_COMPARE (qclass, C_IN);
      43  
      44    /* The only other query type besides A is PTR.  */
      45    if (qtype != T_A)
      46      TEST_COMPARE (qtype, T_PTR);
      47  
      48    int an, ns, ar;
      49    char *tail;
      50    if (sscanf (qname, "an%d.ns%d.ar%d.%ms", &an, &ns, &ar, &tail) != 4)
      51      FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
      52    TEST_COMPARE_STRING (tail, "example");
      53    free (tail);
      54  
      55    if (an < 0 || ns < 0 || ar < 0)
      56      {
      57        struct resolv_response_flags flags = { .rcode = NXDOMAIN, };
      58        resolv_response_init (b, flags);
      59        resolv_response_add_question (b, qname, qclass, qtype);
      60        return;
      61      }
      62  
      63    struct resolv_response_flags flags = {};
      64    resolv_response_init (b, flags);
      65    resolv_response_add_question (b, qname, qclass, qtype);
      66  
      67    resolv_response_section (b, ns_s_an);
      68    for (int i = 0; i < an; ++i)
      69      {
      70        resolv_response_open_record (b, qname, qclass, qtype, 60);
      71        switch (qtype)
      72          {
      73          case T_A:
      74            {
      75              char ipv4[4] = {192, 0, 2, i + 1};
      76              resolv_response_add_data (b, &ipv4, sizeof (ipv4));
      77            }
      78            break;
      79  
      80          case T_PTR:
      81            {
      82              char *name = xasprintf ("ptr-%d", i);
      83              resolv_response_add_name (b, name);
      84              free (name);
      85            }
      86            break;
      87          }
      88        resolv_response_close_record (b);
      89      }
      90  
      91    resolv_response_section (b, ns_s_ns);
      92    for (int i = 0; i < ns; ++i)
      93      {
      94        resolv_response_open_record (b, qname, qclass, T_NS, 60);
      95        char *name = xasprintf ("ns%d.example.net", i);
      96        resolv_response_add_name (b, name);
      97        free (name);
      98        resolv_response_close_record (b);
      99      }
     100  
     101    resolv_response_section (b, ns_s_ar);
     102    int addr = 1;
     103    for (int i = 0; i < ns; ++i)
     104      {
     105        char *name = xasprintf ("ns%d.example.net", i);
     106        for (int j = 0; j < ar; ++j)
     107          {
     108            resolv_response_open_record (b, name, qclass, T_A, 60);
     109            char ipv4[4] = {192, 0, 2, addr};
     110            resolv_response_add_data (b, &ipv4, sizeof (ipv4));
     111            resolv_response_close_record (b);
     112  
     113            resolv_response_open_record (b, name, qclass, T_AAAA, 60);
     114            char ipv6[16]
     115              = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, addr};
     116            resolv_response_add_data (b, &ipv6, sizeof (ipv6));
     117            resolv_response_close_record (b);
     118  
     119            ++addr;
     120          }
     121        free (name);
     122      }
     123  }
     124  
     125  /* Number of modes.  Lowest bit encodes *n* function vs implicit _res
     126     argument.  The mode numbers themselves are arbitrary.  */
     127  enum { mode_count = 8 };
     128  
     129  /* res_send-like modes do not perform error translation.  */
     130  enum { first_send_mode = 6 };
     131  
     132  static int
     133  libresolv_query (unsigned int mode, const char *qname, uint16_t qtype,
     134                   unsigned char *buf, size_t buflen)
     135  {
     136    int saved_errno = errno;
     137  
     138    TEST_VERIFY_EXIT (mode < mode_count);
     139  
     140    switch (mode)
     141      {
     142      case 0:
     143        return res_query (qname, C_IN, qtype, buf, buflen);
     144      case 1:
     145        return res_nquery (&_res, qname, C_IN, qtype, buf, buflen);
     146      case 2:
     147        return res_search (qname, C_IN, qtype, buf, buflen);
     148      case 3:
     149        return res_nsearch (&_res, qname, C_IN, qtype, buf, buflen);
     150      case 4:
     151        return res_querydomain (qname, "", C_IN, qtype, buf, buflen);
     152      case 5:
     153        return res_nquerydomain (&_res, qname, "", C_IN, qtype, buf, buflen);
     154      case 6:
     155        {
     156          unsigned char querybuf[512];
     157          int ret = res_mkquery (QUERY, qname, C_IN, qtype,
     158                                 NULL, 0, NULL, querybuf, sizeof (querybuf));
     159          TEST_VERIFY_EXIT (ret > 0);
     160          errno = saved_errno;
     161          return res_send (querybuf, ret, buf, buflen);
     162        }
     163      case 7:
     164        {
     165          unsigned char querybuf[512];
     166          int ret = res_nmkquery (&_res, QUERY, qname, C_IN, qtype,
     167                                  NULL, 0, NULL, querybuf, sizeof (querybuf));
     168          TEST_VERIFY_EXIT (ret > 0);
     169          errno = saved_errno;
     170          return res_nsend (&_res, querybuf, ret, buf, buflen);
     171        }
     172      }
     173    __builtin_unreachable ();
     174  }
     175  
     176  static int
     177  do_test (void)
     178  {
     179    struct resolv_test *obj = resolv_test_start
     180      ((struct resolv_redirect_config)
     181       {
     182         .response_callback = response
     183       });
     184  
     185    _res.options |= RES_NOAAAA;
     186  
     187    check_hostent ("an1.ns2.ar1.example",
     188                   gethostbyname ("an1.ns2.ar1.example"),
     189                   "name: an1.ns2.ar1.example\n"
     190                   "address: 192.0.2.1\n");
     191    queries = 0;
     192    check_hostent ("an0.ns2.ar1.example",
     193                   gethostbyname ("an0.ns2.ar1.example"),
     194                   "error: NO_ADDRESS\n");
     195    queries = 0;
     196    check_hostent ("an-1.ns2.ar1.example",
     197                   gethostbyname ("an-1.ns2.ar1.example"),
     198                   "error: HOST_NOT_FOUND\n");
     199    queries = 0;
     200  
     201    check_hostent ("an1.ns2.ar1.example AF_INET",
     202                   gethostbyname2 ("an1.ns2.ar1.example", AF_INET),
     203                   "name: an1.ns2.ar1.example\n"
     204                   "address: 192.0.2.1\n");
     205    queries = 0;
     206    check_hostent ("an0.ns2.ar1.example AF_INET",
     207                   gethostbyname2 ("an0.ns2.ar1.example", AF_INET),
     208                   "error: NO_ADDRESS\n");
     209    queries = 0;
     210    check_hostent ("an-1.ns2.ar1.example AF_INET",
     211                   gethostbyname2 ("an-1.ns2.ar1.example", AF_INET),
     212                   "error: HOST_NOT_FOUND\n");
     213    queries = 0;
     214  
     215    check_hostent ("an1.ns2.ar1.example AF_INET6",
     216                   gethostbyname2 ("an1.ns2.ar1.example", AF_INET6),
     217                   "error: NO_ADDRESS\n");
     218    queries = 0;
     219    check_hostent ("an0.ns2.ar1.example AF_INET6",
     220                   gethostbyname2 ("an0.ns2.ar1.example", AF_INET6),
     221                   "error: NO_ADDRESS\n");
     222    queries = 0;
     223    check_hostent ("an-1.ns2.ar1.example AF_INET6",
     224                   gethostbyname2 ("an-1.ns2.ar1.example", AF_INET6),
     225                   "error: HOST_NOT_FOUND\n");
     226    queries = 0;
     227  
     228    /* Multiple addresses.  */
     229    check_hostent ("an2.ns0.ar0.example",
     230                   gethostbyname ("an2.ns0.ar0.example"),
     231                   "name: an2.ns0.ar0.example\n"
     232                   "address: 192.0.2.1\n"
     233                   "address: 192.0.2.2\n");
     234    queries = 0;
     235    check_hostent ("an2.ns0.ar0.example AF_INET6",
     236                   gethostbyname2 ("an2.ns0.ar0.example", AF_INET6),
     237                   "error: NO_ADDRESS\n");
     238    queries = 0;
     239  
     240    /* getaddrinfo checks with one address.  */
     241    struct addrinfo *ai;
     242    int ret;
     243    ret = getaddrinfo ("an1.ns2.ar1.example", "80",
     244                       &(struct addrinfo)
     245                       {
     246                         .ai_family = AF_INET,
     247                         .ai_socktype = SOCK_STREAM,
     248                       }, &ai);
     249    check_addrinfo ("an1.ns2.ar1.example (AF_INET)", ai, ret,
     250                    "address: STREAM/TCP 192.0.2.1 80\n");
     251    freeaddrinfo (ai);
     252    queries = 0;
     253    ret = getaddrinfo ("an1.ns2.ar1.example", "80",
     254                       &(struct addrinfo)
     255                       {
     256                         .ai_family = AF_INET6,
     257                         .ai_socktype = SOCK_STREAM,
     258                       }, &ai);
     259    check_addrinfo ("an1.ns2.ar1.example (AF_INET6)", ai, ret,
     260                    "error: No address associated with hostname\n");
     261    queries = 0;
     262    ret = getaddrinfo ("an1.ns2.ar1.example", "80",
     263                       &(struct addrinfo)
     264                       {
     265                         .ai_family = AF_UNSPEC,
     266                         .ai_socktype = SOCK_STREAM,
     267                       }, &ai);
     268    check_addrinfo ("an1.ns2.ar1.example (AF_UNSPEC)", ai, ret,
     269                    "address: STREAM/TCP 192.0.2.1 80\n");
     270    freeaddrinfo (ai);
     271    queries = 0;
     272  
     273    /* getaddrinfo checks with three addresses.  */
     274    ret = getaddrinfo ("an3.ns2.ar1.example", "80",
     275                       &(struct addrinfo)
     276                       {
     277                         .ai_family = AF_INET,
     278                         .ai_socktype = SOCK_STREAM,
     279                       }, &ai);
     280    check_addrinfo ("an3.ns2.ar1.example (AF_INET)", ai, ret,
     281                    "address: STREAM/TCP 192.0.2.1 80\n"
     282                    "address: STREAM/TCP 192.0.2.2 80\n"
     283                    "address: STREAM/TCP 192.0.2.3 80\n");
     284    freeaddrinfo (ai);
     285    queries = 0;
     286    ret = getaddrinfo ("an3.ns2.ar1.example", "80",
     287                       &(struct addrinfo)
     288                       {
     289                         .ai_family = AF_INET6,
     290                         .ai_socktype = SOCK_STREAM,
     291                       }, &ai);
     292    check_addrinfo ("an3.ns2.ar1.example (AF_INET6)", ai, ret,
     293                    "error: No address associated with hostname\n");
     294    queries = 0;
     295    ret = getaddrinfo ("an3.ns2.ar1.example", "80",
     296                       &(struct addrinfo)
     297                       {
     298                         .ai_family = AF_UNSPEC,
     299                         .ai_socktype = SOCK_STREAM,
     300                       }, &ai);
     301    check_addrinfo ("an3.ns2.ar1.example (AF_UNSPEC)", ai, ret,
     302                    "address: STREAM/TCP 192.0.2.1 80\n"
     303                    "address: STREAM/TCP 192.0.2.2 80\n"
     304                    "address: STREAM/TCP 192.0.2.3 80\n");
     305    freeaddrinfo (ai);
     306    queries = 0;
     307  
     308    /* getaddrinfo checks with no address.  */
     309    ret = getaddrinfo ("an0.ns2.ar1.example", "80",
     310                       &(struct addrinfo)
     311                       {
     312                         .ai_family = AF_INET,
     313                         .ai_socktype = SOCK_STREAM,
     314                       }, &ai);
     315    check_addrinfo ("an0.ns2.ar1.example (AF_INET)", ai, ret,
     316                    "error: No address associated with hostname\n");
     317    queries = 0;
     318    ret = getaddrinfo ("an0.ns2.ar1.example", "80",
     319                       &(struct addrinfo)
     320                       {
     321                         .ai_family = AF_INET6,
     322                         .ai_socktype = SOCK_STREAM,
     323                       }, &ai);
     324    check_addrinfo ("an0.ns2.ar1.example (AF_INET6)", ai, ret,
     325                    "error: No address associated with hostname\n");
     326    queries = 0;
     327    ret = getaddrinfo ("an0.ns2.ar1.example", "80",
     328                       &(struct addrinfo)
     329                       {
     330                         .ai_family = AF_UNSPEC,
     331                         .ai_socktype = SOCK_STREAM,
     332                       }, &ai);
     333    check_addrinfo ("an-1.ns2.ar1.example (AF_UNSPEC)", ai, ret,
     334                    "error: No address associated with hostname\n");
     335    queries = 0;
     336  
     337    /* getaddrinfo checks with NXDOMAIN.  */
     338    ret = getaddrinfo ("an-1.ns2.ar1.example", "80",
     339                       &(struct addrinfo)
     340                       {
     341                         .ai_family = AF_INET,
     342                         .ai_socktype = SOCK_STREAM,
     343                       }, &ai);
     344    check_addrinfo ("an-1.ns2.ar1.example (AF_INET)", ai, ret,
     345                    "error: Name or service not known\n");
     346    queries = 0;
     347    ret = getaddrinfo ("an-1.ns2.ar1.example", "80",
     348                       &(struct addrinfo)
     349                       {
     350                         .ai_family = AF_INET6,
     351                         .ai_socktype = SOCK_STREAM,
     352                       }, &ai);
     353    check_addrinfo ("an-1.ns2.ar1.example (AF_INET6)", ai, ret,
     354                    "error: Name or service not known\n");
     355    queries = 0;
     356    ret = getaddrinfo ("an-1.ns2.ar1.example", "80",
     357                       &(struct addrinfo)
     358                       {
     359                         .ai_family = AF_UNSPEC,
     360                         .ai_socktype = SOCK_STREAM,
     361                       }, &ai);
     362    check_addrinfo ("an-1.ns2.ar1.example (AF_UNSPEC)", ai, ret,
     363                    "error: Name or service not known\n");
     364    queries = 0;
     365  
     366    for (unsigned int mode = 0; mode < mode_count; ++mode)
     367      {
     368        unsigned char *buf;
     369        int ret;
     370  
     371        /* Response for A.  */
     372        buf = malloc (512);
     373        ret = libresolv_query (mode, "an1.ns2.ar1.example", T_A, buf, 512);
     374        TEST_VERIFY_EXIT (ret > 0);
     375        check_dns_packet ("an1.ns2.ar1.example A", buf, ret,
     376                          "name: an1.ns2.ar1.example\n"
     377                          "address: 192.0.2.1\n");
     378        free (buf);
     379        queries = 0;
     380  
     381        /* NODATA response for A.  */
     382        buf = malloc (512);
     383        errno = 0;
     384        ret = libresolv_query (mode, "an0.ns2.ar1.example", T_A, buf, 512);
     385        if (mode < first_send_mode)
     386          {
     387            TEST_COMPARE (ret, -1);
     388            TEST_COMPARE (errno, 0);
     389            TEST_COMPARE (h_errno, NO_ADDRESS);
     390          }
     391        else
     392          {
     393            TEST_VERIFY_EXIT (ret > 0);
     394            TEST_COMPARE (((HEADER *)buf)->rcode, 0);
     395            check_dns_packet ("an1.ns2.ar1.example A", buf, ret,
     396                              "name: an0.ns2.ar1.example\n");
     397          }
     398        free (buf);
     399        queries = 0;
     400  
     401        /* NXDOMAIN response for A.  */
     402        buf = malloc (512);
     403        errno = 0;
     404        ret = libresolv_query (mode, "an-1.ns2.ar1.example", T_A, buf, 512);
     405        if (mode < first_send_mode)
     406          {
     407            TEST_COMPARE (ret, -1);
     408            TEST_COMPARE (errno, 0);
     409            TEST_COMPARE (h_errno, HOST_NOT_FOUND);
     410          }
     411        else
     412          {
     413            TEST_VERIFY_EXIT (ret > 0);
     414            TEST_COMPARE (((HEADER *)buf)->rcode, NXDOMAIN);
     415            check_dns_packet ("an1.ns2.ar1.example A", buf, ret,
     416                              "name: an-1.ns2.ar1.example\n");
     417          }
     418        free (buf);
     419        queries = 0;
     420  
     421        /* Response for PTR.  */
     422        buf = malloc (512);
     423        ret = libresolv_query (mode, "an1.ns2.ar1.example", T_PTR, buf, 512);
     424        TEST_VERIFY_EXIT (ret > 0);
     425        check_dns_packet ("an1.ns2.ar1.example PTR", buf, ret,
     426                          "name: an1.ns2.ar1.example\n"
     427                          "data: an1.ns2.ar1.example PTR ptr-0\n");
     428        free (buf);
     429        queries = 0;
     430  
     431        /* NODATA response for PTR.  */
     432        buf = malloc (512);
     433        errno = 0;
     434        ret = libresolv_query (mode, "an0.ns2.ar1.example", T_PTR, buf, 512);
     435        if (mode < first_send_mode)
     436          {
     437            TEST_COMPARE (ret, -1);
     438            TEST_COMPARE (errno, 0);
     439            TEST_COMPARE (h_errno, NO_ADDRESS);
     440          }
     441        else
     442          {
     443            TEST_VERIFY_EXIT (ret > 0);
     444            TEST_COMPARE (((HEADER *)buf)->rcode, 0);
     445            check_dns_packet ("an1.ns2.ar1.example PTR", buf, ret,
     446                              "name: an0.ns2.ar1.example\n");
     447          }
     448        free (buf);
     449        queries = 0;
     450  
     451        /* NXDOMAIN response for PTR.  */
     452        buf = malloc (512);
     453        errno = 0;
     454        ret = libresolv_query (mode, "an-1.ns2.ar1.example", T_PTR, buf, 512);
     455        if (mode < first_send_mode)
     456          {
     457            TEST_COMPARE (ret, -1);
     458            TEST_COMPARE (errno, 0);
     459            TEST_COMPARE (h_errno, HOST_NOT_FOUND);
     460          }
     461        else
     462          {
     463            TEST_VERIFY_EXIT (ret > 0);
     464            TEST_COMPARE (((HEADER *)buf)->rcode, NXDOMAIN);
     465            check_dns_packet ("an1.ns2.ar1.example PTR", buf, ret,
     466                              "name: an-1.ns2.ar1.example\n");
     467          }
     468        free (buf);
     469        queries = 0;
     470  
     471        /* NODATA response for AAAA.  */
     472        buf = malloc (512);
     473        errno = 0;
     474        ret = libresolv_query (mode, "an1.ns2.ar1.example", T_AAAA, buf, 512);
     475        if (mode < first_send_mode)
     476          {
     477            TEST_COMPARE (ret, -1);
     478            TEST_COMPARE (errno, 0);
     479            TEST_COMPARE (h_errno, NO_ADDRESS);
     480          }
     481        else
     482          {
     483            TEST_VERIFY_EXIT (ret > 0);
     484            TEST_COMPARE (((HEADER *)buf)->rcode, 0);
     485            check_dns_packet ("an1.ns2.ar1.example A", buf, ret,
     486                              "name: an1.ns2.ar1.example\n");
     487          }
     488        free (buf);
     489        queries = 0;
     490  
     491        /* NODATA response for AAAA (original is already NODATA).  */
     492        buf = malloc (512);
     493        errno = 0;
     494        ret = libresolv_query (mode, "an0.ns2.ar1.example", T_AAAA, buf, 512);
     495        if (mode < first_send_mode)
     496          {
     497            TEST_COMPARE (ret, -1);
     498            TEST_COMPARE (errno, 0);
     499            TEST_COMPARE (h_errno, NO_ADDRESS);
     500          }
     501        else
     502          {
     503            TEST_VERIFY_EXIT (ret > 0);
     504            TEST_COMPARE (((HEADER *)buf)->rcode, 0);
     505            check_dns_packet ("an0.ns2.ar1.example A", buf, ret,
     506                              "name: an0.ns2.ar1.example\n");
     507          }
     508        free (buf);
     509        queries = 0;
     510  
     511        /* NXDOMAIN response.  */
     512        buf = malloc (512);
     513        errno = 0;
     514        ret = libresolv_query (mode, "an-1.ns2.ar1.example", T_AAAA, buf, 512);
     515        if (mode < first_send_mode)
     516          {
     517            TEST_COMPARE (ret, -1);
     518            TEST_COMPARE (errno, 0);
     519            TEST_COMPARE (h_errno, HOST_NOT_FOUND);
     520          }
     521        else
     522          {
     523            TEST_VERIFY_EXIT (ret > 0);
     524            TEST_COMPARE (((HEADER *)buf)->rcode, NXDOMAIN);
     525            check_dns_packet ("an-1.ns2.ar1.example A", buf, ret,
     526                              "name: an-1.ns2.ar1.example\n");
     527          }
     528        free (buf);
     529        queries = 0;
     530      }
     531  
     532    resolv_test_end (obj);
     533  
     534    return 0;
     535  }
     536  
     537  #include <support/test-driver.c>