(root)/
glibc-2.38/
resolv/
tst-resolv-ai_idn-common.c
       1  /* Common code for AI_IDN/NI_IDN tests.
       2     Copyright (C) 2018-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  /* Before including this file, TEST_USE_UTF8 must be defined to 1 or
      20     0, depending on whether a UTF-8 locale is used or a Latin-1
      21     locale.  */
      22  
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <support/check.h>
      27  #include <support/check_nss.h>
      28  #include <support/resolv_test.h>
      29  #include <support/support.h>
      30  
      31  /* Name of the shared object for libidn2.  */
      32  #define LIBIDN2_SONAME "libidn2.so.0"
      33  
      34  #if TEST_USE_UTF8
      35  /* UTF-8 encoding of "nämchen" (German for “namelet”).  */
      36  # define NAEMCHEN "n\xC3\xA4mchen"
      37  
      38  /* UTF-8 encoding of "שם" (Hebrew for “name”).  */
      39  # define SHEM "\xD7\xA9\xD7\x9D"
      40  
      41  /* UTF-8 encoding of "buße" (German for “penance”).  This used to be
      42     encoded as "busse" (“busses”) in IDNA2003.  */
      43  # define BUSSE "bu\xC3\x9F""e"
      44  
      45  #else
      46  /* Latin-1 encodings, as far as they are available.  */
      47  
      48  # define NAEMCHEN "n\xE4mchen"
      49  # define BUSSE "bu\xDF""e"
      50  
      51  #endif
      52  
      53  /* IDNA encoding of NAEMCHEN.  */
      54  #define NAEMCHEN_IDNA "xn--nmchen-bua"
      55  
      56  /* IDNA encoding of NAEMCHEN "_zwo".  */
      57  #define NAEMCHEN_ZWO_IDNA "xn--nmchen_zwo-q5a"
      58  
      59  /* IDNA encoding of SHEM.  */
      60  #define SHEM_IDNA "xn--iebx"
      61  
      62  /* IDNA encoding of BUSSE.  */
      63  #define BUSSE_IDNA "xn--bue-6ka"
      64  
      65  /* IDNA encoding of "שם1".  */
      66  #define SHEM1_IDNA "xn--1-qic9a"
      67  
      68  /* Another IDNA name.  */
      69  #define ANDERES_NAEMCHEN "anderes-" NAEMCHEN
      70  #define ANDERES_NAEMCHEN_IDNA "xn--anderes-nmchen-eib"
      71  
      72  /* Controls the kind of test data in a PTR lookup response.  */
      73  enum gni_test
      74    {
      75      gni_non_idn_name,
      76      gni_non_idn_cname_to_non_idn_name,
      77      gni_non_idn_cname_to_idn_name,
      78      gni_idn_name,
      79      gni_idn_shem,
      80      gni_idn_shem1,
      81      gni_idn_cname_to_non_idn_name,
      82      gni_idn_cname_to_idn_name,
      83      gni_invalid_idn_1,
      84      gni_invalid_idn_2,
      85    };
      86  
      87  /* Called from response below.  The LSB (first byte) controls what
      88     goes into the response, see enum gni_test.  */
      89  static void
      90  response_ptr (const struct resolv_response_context *ctx,
      91                struct resolv_response_builder *b, const char *qname)
      92  {
      93    int comp[4] = { 0 };
      94    TEST_COMPARE (sscanf (qname, "%d.%d.%d.%d.in-addr.arpa",
      95                          &comp[0], &comp[1], &comp[2], &comp[3]), 4);
      96    const char *next_name;
      97    switch ((enum gni_test) comp[0])
      98      {
      99      /* First name in response is non-IDN name.  */
     100      case gni_non_idn_name:
     101        resolv_response_open_record (b, qname, C_IN, T_PTR, 0);
     102        resolv_response_add_name (b, "non-idn.example");
     103        resolv_response_close_record (b);
     104        return;
     105      case gni_non_idn_cname_to_non_idn_name:
     106        resolv_response_open_record (b, qname, C_IN, T_CNAME, 0);
     107        next_name = "non-idn-cname.example";
     108        resolv_response_add_name (b, next_name);
     109        resolv_response_close_record (b);
     110        resolv_response_open_record (b, next_name, C_IN, T_PTR, 0);
     111        resolv_response_add_name (b, "non-idn-name.example");
     112        resolv_response_close_record (b);
     113        return;
     114      case gni_non_idn_cname_to_idn_name:
     115        resolv_response_open_record (b, qname, C_IN, T_CNAME, 0);
     116        next_name = "non-idn-cname.example";
     117        resolv_response_add_name (b, next_name);
     118        resolv_response_close_record (b);
     119        resolv_response_open_record (b, next_name, C_IN, T_PTR, 0);
     120        resolv_response_add_name (b, NAEMCHEN_IDNA ".example");
     121        resolv_response_close_record (b);
     122        return;
     123  
     124      /* First name in response is IDN name.  */
     125      case gni_idn_name:
     126        resolv_response_open_record (b, qname, C_IN, T_PTR, 0);
     127        resolv_response_add_name (b, "xn--nmchen-bua.example");
     128        resolv_response_close_record (b);
     129        return;
     130      case gni_idn_shem:
     131        resolv_response_open_record (b, qname, C_IN, T_PTR, 0);
     132        resolv_response_add_name (b, SHEM_IDNA ".example");
     133        resolv_response_close_record (b);
     134        return;
     135      case gni_idn_shem1:
     136        resolv_response_open_record (b, qname, C_IN, T_PTR, 0);
     137        resolv_response_add_name (b, SHEM1_IDNA ".example");
     138        resolv_response_close_record (b);
     139        return;
     140      case gni_idn_cname_to_non_idn_name:
     141        resolv_response_open_record (b, qname, C_IN, T_CNAME, 0);
     142        next_name = NAEMCHEN_IDNA ".example";
     143        resolv_response_add_name (b, next_name);
     144        resolv_response_close_record (b);
     145        resolv_response_open_record (b, next_name, C_IN, T_PTR, 0);
     146        resolv_response_add_name (b, "non-idn-name.example");
     147        resolv_response_close_record (b);
     148        return;
     149      case gni_idn_cname_to_idn_name:
     150        resolv_response_open_record (b, qname, C_IN, T_CNAME, 0);
     151        next_name = NAEMCHEN_IDNA ".example";
     152        resolv_response_add_name (b, next_name);
     153        resolv_response_close_record (b);
     154        resolv_response_open_record (b, next_name, C_IN, T_PTR, 0);
     155        resolv_response_add_name (b, ANDERES_NAEMCHEN_IDNA ".example");
     156        resolv_response_close_record (b);
     157        return;
     158  
     159      /* Invalid IDN encodings.  */
     160      case gni_invalid_idn_1:
     161        resolv_response_open_record (b, qname, C_IN, T_PTR, 0);
     162        resolv_response_add_name (b, "xn---.example");
     163        resolv_response_close_record (b);
     164        return;
     165      case gni_invalid_idn_2:
     166        resolv_response_open_record (b, qname, C_IN, T_PTR, 0);
     167        resolv_response_add_name (b, "xn--x.example");
     168        resolv_response_close_record (b);
     169        return;
     170      }
     171    FAIL_EXIT1 ("invalid PTR query: %s", qname);
     172  }
     173  
     174  /* For PTR responses, see above.  A/AAAA queries can request
     175     additional CNAMEs in the response by include ".cname." and
     176     ".idn-cname." in the query.  The LSB in the address contains the
     177     first byte of the QNAME.  */
     178  static void
     179  response (const struct resolv_response_context *ctx,
     180            struct resolv_response_builder *b,
     181            const char *qname, uint16_t qclass, uint16_t qtype)
     182  {
     183    TEST_VERIFY_EXIT (qclass == C_IN);
     184  
     185    for (const char *p = qname; *p != '\0'; ++p)
     186      if (!(('0' <= *p && *p <= '9')
     187            || ('a' <= *p && *p <= 'z')
     188            || ('A' <= *p && *p <= 'Z')
     189            || *p == '.' || *p == '-' || *p == '_'))
     190        {
     191          /* Non-ASCII query.  Reply with NXDOMAIN.  */
     192          struct resolv_response_flags flags = { .rcode = 3 };
     193          resolv_response_init (b, flags);
     194          resolv_response_add_question (b, qname, qclass, qtype);
     195          return;
     196        }
     197  
     198    struct resolv_response_flags flags = { 0 };
     199    resolv_response_init (b, flags);
     200    resolv_response_add_question (b, qname, qclass, qtype);
     201    resolv_response_section (b, ns_s_an);
     202  
     203    if (qtype == T_PTR)
     204      {
     205        response_ptr (ctx, b, qname);
     206        return;
     207      }
     208  
     209    bool with_cname = strstr (qname, ".cname.") != NULL;
     210    bool with_idn_cname = strstr (qname, ".idn-cname.") != NULL;
     211  
     212    const char *next_name = qname;
     213    if (with_cname)
     214      {
     215        next_name = "non-idn-cname.example";
     216        resolv_response_open_record (b, qname, C_IN, T_CNAME, 0);
     217        resolv_response_add_name (b, next_name);
     218        resolv_response_close_record (b);
     219      }
     220    if (with_idn_cname)
     221      {
     222        const char *previous_name = next_name;
     223        next_name = ANDERES_NAEMCHEN_IDNA ".example";
     224        resolv_response_open_record (b, previous_name, C_IN, T_CNAME, 0);
     225        resolv_response_add_name (b, next_name);
     226        resolv_response_close_record (b);
     227      }
     228  
     229    resolv_response_open_record (b, next_name, C_IN, qtype, 0);
     230    switch (qtype)
     231      {
     232      case T_A:
     233        {
     234          char addr[4] = { 192, 0, 2, qname[0] };
     235          resolv_response_add_data (b, &addr, sizeof (addr));
     236        }
     237        break;
     238      case T_AAAA:
     239        {
     240          char addr[16]
     241            = { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     242                qname[0] };
     243          resolv_response_add_data (b, &addr, sizeof (addr));
     244        }
     245        break;
     246      default:
     247        FAIL_EXIT1 ("invalid qtype: %d", qtype);
     248      }
     249    resolv_response_close_record (b);
     250  }
     251  
     252  /* Check the result of a getaddrinfo call.  */
     253  static void
     254  check_ai (const char *name, int ai_flags, const char *expected)
     255  {
     256    struct addrinfo hints =
     257      {
     258        .ai_flags = ai_flags,
     259        .ai_family = AF_INET,
     260        .ai_socktype = SOCK_STREAM,
     261      };
     262    struct addrinfo *ai;
     263    char *query = xasprintf ("%s:80 AF_INET/0x%x", name, ai_flags);
     264    int ret = getaddrinfo (name, "80", &hints, &ai);
     265    check_addrinfo (query, ai, ret, expected);
     266    if (ret == 0)
     267      freeaddrinfo (ai);
     268    free (query);
     269  }
     270  
     271  /* Run one getnameinfo test.  FLAGS is automatically augmented with
     272     NI_NUMERICSERV.  */
     273  static void
     274  gni_test (enum gni_test code, unsigned int flags, const char *expected)
     275  {
     276    struct sockaddr_in sin =
     277      {
     278        .sin_family = AF_INET,
     279        .sin_port = htons (80),
     280        .sin_addr = { htonl (0xc0000200 | code) }, /* 192.0.2.0/24 network.  */
     281      };
     282    char host[1024];
     283    char service[1024];
     284    int ret = getnameinfo ((const struct sockaddr *) &sin, sizeof (sin),
     285                           host, sizeof (host), service, sizeof (service),
     286                           flags| NI_NUMERICSERV);
     287    if (ret != 0)
     288      {
     289        if (expected == NULL)
     290          TEST_COMPARE (ret, EAI_IDN_ENCODE);
     291        else
     292          {
     293            support_record_failure ();
     294            printf ("error: getnameinfo failed (code %d, flags 0x%x): %s (%d)\n",
     295                    (int) code, flags, gai_strerror (ret), ret);
     296          }
     297      }
     298    else if (ret == 0 && expected == NULL)
     299      {
     300        support_record_failure ();
     301        printf ("error: getnameinfo unexpected success (code %d, flags 0x%x)\n",
     302                (int) code, flags);
     303      }
     304    else if (strcmp (host, expected) != 0 || strcmp (service, "80") != 0)
     305      {
     306        support_record_failure ();
     307        printf ("error: getnameinfo test failure (code %d, flags 0x%x)\n"
     308                "  expected host:    \"%s\"\n"
     309                "  expected service: \"80\"\n"
     310                "  actual host:      \"%s\"\n"
     311                "  actual service:   \"%s\"\n",
     312                (int) code, flags, expected, host, service);
     313      }
     314  }
     315  
     316  /* Tests for getaddrinfo which assume a working libidn2 library.  */
     317  __attribute__ ((unused))
     318  static void
     319  gai_tests_with_libidn2 (void)
     320  {
     321    /* No CNAME.  */
     322    check_ai ("non-idn.example", 0,
     323              "address: STREAM/TCP 192.0.2.110 80\n");
     324    check_ai ("non-idn.example", AI_IDN,
     325              "flags: AI_IDN\n"
     326              "address: STREAM/TCP 192.0.2.110 80\n");
     327    check_ai ("non-idn.example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     328              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     329              "canonname: non-idn.example\n"
     330              "address: STREAM/TCP 192.0.2.110 80\n");
     331  
     332    check_ai (NAEMCHEN ".example", 0,
     333              "error: Name or service not known\n");
     334    check_ai (NAEMCHEN ".example", AI_IDN,
     335              "flags: AI_IDN\n"
     336              "address: STREAM/TCP 192.0.2.120 80\n");
     337    check_ai (NAEMCHEN ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     338              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     339              "canonname: " NAEMCHEN ".example\n"
     340              "address: STREAM/TCP 192.0.2.120 80\n");
     341  
     342  #if TEST_USE_UTF8
     343    check_ai (SHEM ".example", 0,
     344              "error: Name or service not known\n");
     345    check_ai (SHEM ".example", AI_IDN,
     346              "flags: AI_IDN\n"
     347              "address: STREAM/TCP 192.0.2.120 80\n");
     348    check_ai (SHEM ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     349              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     350              "canonname: " SHEM ".example\n"
     351              "address: STREAM/TCP 192.0.2.120 80\n");
     352    check_ai (SHEM ".example", AI_IDN | AI_CANONNAME,
     353              "flags: AI_CANONNAME AI_IDN\n"
     354              "canonname: " SHEM_IDNA ".example\n"
     355              "address: STREAM/TCP 192.0.2.120 80\n");
     356    check_ai (SHEM "1.example", AI_IDN,
     357              "flags: AI_IDN\n"
     358              "address: STREAM/TCP 192.0.2.120 80\n");
     359    check_ai (SHEM "1.example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     360              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     361              "canonname: " SHEM "1.example\n"
     362              "address: STREAM/TCP 192.0.2.120 80\n");
     363    check_ai (SHEM "1.example", AI_IDN | AI_CANONNAME,
     364              "flags: AI_CANONNAME AI_IDN\n"
     365              "canonname: " SHEM1_IDNA ".example\n"
     366              "address: STREAM/TCP 192.0.2.120 80\n");
     367  #endif
     368  
     369    /* Check that non-transitional mode is active.  German sharp S
     370       should not turn into SS.  */
     371    check_ai (BUSSE ".example", 0,
     372              "error: Name or service not known\n");
     373    check_ai (BUSSE ".example", AI_IDN,
     374              "flags: AI_IDN\n"
     375              "address: STREAM/TCP 192.0.2.120 80\n");
     376    check_ai (BUSSE ".example", AI_IDN | AI_CANONNAME,
     377              "flags: AI_CANONNAME AI_IDN\n"
     378              "canonname: " BUSSE_IDNA ".example\n"
     379              "address: STREAM/TCP 192.0.2.120 80\n");
     380    check_ai (BUSSE ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     381              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     382              "canonname: " BUSSE ".example\n"
     383              "address: STREAM/TCP 192.0.2.120 80\n");
     384  
     385    /* Check that Unicode TR 46 mode is active.  Underscores should be
     386       permitted in IDNA components.  */
     387    check_ai (NAEMCHEN "_zwo.example", 0,
     388              "error: Name or service not known\n");
     389    check_ai (NAEMCHEN "_zwo.example", AI_IDN,
     390              "flags: AI_IDN\n"
     391              "address: STREAM/TCP 192.0.2.120 80\n");
     392    check_ai (NAEMCHEN "_zwo.example", AI_IDN | AI_CANONNAME,
     393              "flags: AI_CANONNAME AI_IDN\n"
     394              "canonname: " NAEMCHEN_ZWO_IDNA ".example\n"
     395              "address: STREAM/TCP 192.0.2.120 80\n");
     396    check_ai (NAEMCHEN "_zwo.example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     397              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     398              "canonname: " NAEMCHEN "_zwo.example\n"
     399              "address: STREAM/TCP 192.0.2.120 80\n");
     400  
     401    /* No CNAME, but already IDN-encoded.  */
     402    check_ai (NAEMCHEN_IDNA ".example", 0,
     403              "address: STREAM/TCP 192.0.2.120 80\n");
     404    check_ai (NAEMCHEN_IDNA ".example", AI_IDN,
     405              "flags: AI_IDN\n"
     406              "address: STREAM/TCP 192.0.2.120 80\n");
     407    check_ai (NAEMCHEN_IDNA ".example", AI_IDN | AI_CANONNAME,
     408              "flags: AI_CANONNAME AI_IDN\n"
     409              "canonname: " NAEMCHEN_IDNA ".example\n"
     410              "address: STREAM/TCP 192.0.2.120 80\n");
     411    check_ai (NAEMCHEN_IDNA ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     412              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     413              "canonname: " NAEMCHEN ".example\n"
     414              "address: STREAM/TCP 192.0.2.120 80\n");
     415    check_ai (SHEM_IDNA ".example", 0,
     416              "address: STREAM/TCP 192.0.2.120 80\n");
     417    check_ai (SHEM_IDNA ".example", AI_IDN,
     418              "flags: AI_IDN\n"
     419              "address: STREAM/TCP 192.0.2.120 80\n");
     420    check_ai (SHEM_IDNA ".example", AI_IDN | AI_CANONNAME,
     421              "flags: AI_CANONNAME AI_IDN\n"
     422              "canonname: " SHEM_IDNA ".example\n"
     423              "address: STREAM/TCP 192.0.2.120 80\n");
     424  #if TEST_USE_UTF8
     425    check_ai (SHEM_IDNA ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     426              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     427              "canonname: " SHEM ".example\n"
     428              "address: STREAM/TCP 192.0.2.120 80\n");
     429  #else
     430    check_ai (SHEM_IDNA ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     431              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     432              "canonname: " SHEM_IDNA ".example\n"
     433              "address: STREAM/TCP 192.0.2.120 80\n");
     434  #endif
     435  
     436    /* Invalid IDNA canonical name is returned as-is.  */
     437    check_ai ("xn---.example", AI_CANONNAME | AI_CANONIDN,
     438              "flags: AI_CANONNAME AI_CANONIDN\n"
     439              "canonname: xn---.example\n"
     440              "address: STREAM/TCP 192.0.2.120 80\n");
     441  
     442    /* Non-IDN CNAME.  */
     443    check_ai ("with.cname.example", 0,
     444              "address: STREAM/TCP 192.0.2.119 80\n");
     445    check_ai ("with.cname.example", AI_IDN,
     446              "flags: AI_IDN\n"
     447              "address: STREAM/TCP 192.0.2.119 80\n");
     448    check_ai ("with.cname.example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
     449              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     450              "canonname: non-idn-cname.example\n"
     451              "address: STREAM/TCP 192.0.2.119 80\n");
     452  
     453    check_ai ("with.cname." NAEMCHEN ".example", 0,
     454              "error: Name or service not known\n");
     455    check_ai ("with.cname." NAEMCHEN ".example", AI_IDN,
     456              "flags: AI_IDN\n"
     457              "address: STREAM/TCP 192.0.2.119 80\n");
     458    check_ai ("with.cname." NAEMCHEN ".example", AI_IDN | AI_CANONNAME,
     459              "flags: AI_CANONNAME AI_IDN\n"
     460              "canonname: non-idn-cname.example\n"
     461              "address: STREAM/TCP 192.0.2.119 80\n");
     462    check_ai ("with.cname." NAEMCHEN ".example",
     463              AI_IDN | AI_CANONNAME | AI_CANONIDN,
     464              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     465              "canonname: non-idn-cname.example\n"
     466              "address: STREAM/TCP 192.0.2.119 80\n");
     467  
     468    /* IDN CNAME.  */
     469    check_ai ("With.idn-cname.example", 0,
     470              "address: STREAM/TCP 192.0.2.87 80\n");
     471    check_ai ("With.idn-cname.example", AI_IDN,
     472              "flags: AI_IDN\n"
     473              "address: STREAM/TCP 192.0.2.87 80\n");
     474    check_ai ("With.idn-cname.example", AI_IDN | AI_CANONNAME,
     475              "flags: AI_CANONNAME AI_IDN\n"
     476              "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n"
     477              "address: STREAM/TCP 192.0.2.87 80\n");
     478    check_ai ("With.idn-cname.example",
     479              AI_IDN | AI_CANONNAME | AI_CANONIDN,
     480              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     481              "canonname: " ANDERES_NAEMCHEN ".example\n"
     482              "address: STREAM/TCP 192.0.2.87 80\n");
     483  
     484    check_ai ("With.idn-cname." NAEMCHEN ".example", 0,
     485              "error: Name or service not known\n");
     486    check_ai ("With.idn-cname." NAEMCHEN ".example", AI_IDN,
     487              "flags: AI_IDN\n"
     488              "address: STREAM/TCP 192.0.2.119 80\n");
     489    check_ai ("With.idn-cname." NAEMCHEN ".example", AI_IDN | AI_CANONNAME,
     490              "flags: AI_CANONNAME AI_IDN\n"
     491              "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n"
     492              "address: STREAM/TCP 192.0.2.119 80\n");
     493    check_ai ("With.idn-cname." NAEMCHEN ".example",
     494              AI_IDN | AI_CANONNAME | AI_CANONIDN,
     495              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     496              "canonname: " ANDERES_NAEMCHEN ".example\n"
     497              "address: STREAM/TCP 192.0.2.119 80\n");
     498  
     499    /* Non-IDN to IDN CNAME chain.  */
     500    check_ai ("both.cname.idn-cname.example", 0,
     501              "address: STREAM/TCP 192.0.2.98 80\n");
     502    check_ai ("both.cname.idn-cname.example", AI_IDN,
     503              "flags: AI_IDN\n"
     504              "address: STREAM/TCP 192.0.2.98 80\n");
     505    check_ai ("both.cname.idn-cname.example", AI_IDN | AI_CANONNAME,
     506              "flags: AI_CANONNAME AI_IDN\n"
     507              "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n"
     508              "address: STREAM/TCP 192.0.2.98 80\n");
     509    check_ai ("both.cname.idn-cname.example",
     510              AI_IDN | AI_CANONNAME | AI_CANONIDN,
     511              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     512              "canonname: " ANDERES_NAEMCHEN ".example\n"
     513              "address: STREAM/TCP 192.0.2.98 80\n");
     514  
     515    check_ai ("both.cname.idn-cname." NAEMCHEN ".example", 0,
     516              "error: Name or service not known\n");
     517    check_ai ("both.cname.idn-cname." NAEMCHEN ".example", AI_IDN,
     518              "flags: AI_IDN\n"
     519              "address: STREAM/TCP 192.0.2.98 80\n");
     520    check_ai ("both.cname.idn-cname." NAEMCHEN ".example",
     521              AI_IDN | AI_CANONNAME,
     522              "flags: AI_CANONNAME AI_IDN\n"
     523              "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n"
     524              "address: STREAM/TCP 192.0.2.98 80\n");
     525    check_ai ("both.cname.idn-cname." NAEMCHEN ".example",
     526              AI_IDN | AI_CANONNAME | AI_CANONIDN,
     527              "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
     528              "canonname: " ANDERES_NAEMCHEN ".example\n"
     529              "address: STREAM/TCP 192.0.2.98 80\n");
     530  }
     531  
     532  /* Tests for getnameinfo which assume a working libidn2 library.  */
     533  __attribute__ ((unused))
     534  static void
     535  gni_tests_with_libidn2 (void)
     536  {
     537    gni_test (gni_non_idn_name, 0, "non-idn.example");
     538    gni_test (gni_non_idn_name, NI_IDN, "non-idn.example");
     539    gni_test (gni_non_idn_name, NI_NUMERICHOST, "192.0.2.0");
     540    gni_test (gni_non_idn_name, NI_NUMERICHOST | NI_IDN, "192.0.2.0");
     541  
     542    gni_test (gni_non_idn_cname_to_non_idn_name, 0, "non-idn-name.example");
     543    gni_test (gni_non_idn_cname_to_non_idn_name, NI_IDN, "non-idn-name.example");
     544  
     545    gni_test (gni_non_idn_cname_to_idn_name, 0, NAEMCHEN_IDNA ".example");
     546    gni_test (gni_non_idn_cname_to_idn_name, NI_IDN, NAEMCHEN ".example");
     547  
     548    gni_test (gni_idn_name, 0, NAEMCHEN_IDNA ".example");
     549    gni_test (gni_idn_name, NI_IDN, NAEMCHEN ".example");
     550    gni_test (gni_idn_shem, 0, SHEM_IDNA ".example");
     551    gni_test (gni_idn_shem1, 0, SHEM1_IDNA ".example");
     552  #if TEST_USE_UTF8
     553    gni_test (gni_idn_shem, NI_IDN, SHEM ".example");
     554    gni_test (gni_idn_shem1, NI_IDN, SHEM "1.example");
     555  #else
     556    gni_test (gni_idn_shem, NI_IDN, SHEM_IDNA ".example");
     557    gni_test (gni_idn_shem1, NI_IDN, SHEM1_IDNA ".example");
     558  #endif
     559  
     560    gni_test (gni_idn_cname_to_non_idn_name, 0, "non-idn-name.example");
     561    gni_test (gni_idn_cname_to_non_idn_name, NI_IDN, "non-idn-name.example");
     562  
     563    gni_test (gni_idn_cname_to_idn_name, 0, ANDERES_NAEMCHEN_IDNA ".example");
     564    gni_test (gni_idn_cname_to_idn_name, NI_IDN, ANDERES_NAEMCHEN ".example");
     565  
     566    /* Test encoding errors.  */
     567    gni_test (gni_invalid_idn_1, 0, "xn---.example");
     568    gni_test (gni_invalid_idn_1, NI_IDN, "xn---.example");
     569    gni_test (gni_invalid_idn_2, 0, "xn--x.example");
     570    gni_test (gni_invalid_idn_2, NI_IDN, "xn--x.example");
     571  }