(root)/
glibc-2.38/
inet/
tst-inet6_scopeid_pton.c
       1  /* Tests for __inet6_scopeid_pton and IPv6 scopes in getaddrinfo.
       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 <arpa/inet.h>
      20  #include <inttypes.h>
      21  #include <net-internal.h>
      22  #include <net/if.h>
      23  #include <netdb.h>
      24  #include <stdio.h>
      25  #include <stdlib.h>
      26  #include <string.h>
      27  #include <support/check.h>
      28  #include <support/support.h>
      29  #include <support/test-driver.h>
      30  
      31  /* An interface which is known to the system.  */
      32  static const char *interface_name;
      33  static uint32_t interface_index;
      34  
      35  /* Initiale the variables above.  */
      36  static void
      37  setup_interface (void)
      38  {
      39    struct if_nameindex *list = if_nameindex ();
      40    if (list != NULL && list[0].if_index != 0 && list[0].if_name[0] != '\0')
      41      {
      42        interface_name = list[0].if_name;
      43        interface_index = list[0].if_index;
      44      }
      45  }
      46  
      47  /* Convert ADDRESS to struct in6_addr.  */
      48  static struct in6_addr
      49  from_string (const char *address)
      50  {
      51    struct in6_addr addr;
      52    if (inet_pton (AF_INET6, address, &addr) != 1)
      53      FAIL_EXIT1 ("inet_pton (\"%s\")", address);
      54    return addr;
      55  }
      56  
      57  /* Invoke getaddrinfo to parse ADDRESS%SCOPE.  Return true if
      58     getaddrinfo was successful.  */
      59  static bool
      60  call_gai (int family, const char *address, const char *scope,
      61            struct sockaddr_in6 *result)
      62  {
      63    struct addrinfo hints =
      64      {
      65        .ai_family = family,
      66        .ai_flags = AI_NUMERICHOST,
      67        .ai_socktype = SOCK_DGRAM,
      68        .ai_protocol = IPPROTO_UDP,
      69      };
      70    char *fulladdr = xasprintf ("%s%%%s", address, scope);
      71    struct addrinfo *ai = NULL;
      72    int ret = getaddrinfo (fulladdr, NULL, &hints, &ai);
      73    if (ret == EAI_ADDRFAMILY || ret == EAI_NONAME)
      74      {
      75        if (test_verbose > 0)
      76          printf ("info: getaddrinfo (\"%s\"): %s (%d)\n",
      77                  fulladdr, gai_strerror (ret), ret);
      78        free (fulladdr);
      79        return false;
      80      }
      81    if (ret != 0)
      82      FAIL_EXIT1 ("getaddrinfo (\"%s\"): %s (%d)\n",
      83                  fulladdr, gai_strerror (ret), ret);
      84    TEST_VERIFY_EXIT (ai != NULL);
      85    TEST_VERIFY_EXIT (ai->ai_addrlen == sizeof (*result));
      86    TEST_VERIFY (ai->ai_family == AF_INET6);
      87    TEST_VERIFY (ai->ai_next == NULL);
      88    memcpy (result, ai->ai_addr, sizeof (*result));
      89    free (fulladdr);
      90    freeaddrinfo (ai);
      91    return true;
      92  }
      93  
      94  /* Verify that a successful call to getaddrinfo returned the expected
      95     scope data.  */
      96  static void
      97  check_ai (const char *what, const char *addr_string, const char *scope_string,
      98            const struct sockaddr_in6 *sa,
      99            const struct in6_addr *addr, uint32_t scope)
     100  {
     101    if (memcmp (addr, &sa->sin6_addr, sizeof (*addr)) != 0)
     102      {
     103        support_record_failure ();
     104        printf ("error: getaddrinfo %s address mismatch for %s%%%s\n",
     105                what, addr_string, scope_string);
     106      }
     107    if (sa->sin6_scope_id != scope)
     108      {
     109        support_record_failure ();
     110        printf ("error: getaddrinfo %s scope mismatch for %s%%%s\n"
     111                "  expected: %" PRIu32 "\n"
     112                "  actual:   %" PRIu32 "\n",
     113                what, addr_string, scope_string, scope, sa->sin6_scope_id);
     114      }
     115  }
     116  
     117  /* Check a single address were we expected a failure.  */
     118  static void
     119  expect_failure (const char *address, const char *scope)
     120  {
     121    if (test_verbose > 0)
     122      printf ("info: expecting failure for %s%%%s\n", address, scope);
     123    struct in6_addr addr = from_string (address);
     124    uint32_t result = 1234;
     125    if (__inet6_scopeid_pton (&addr, scope, &result) == 0)
     126      {
     127        support_record_failure ();
     128        printf ("error: unexpected success for %s%%%s\n",
     129                address, scope);
     130      }
     131    if (result != 1234)
     132      {
     133        support_record_failure ();
     134        printf ("error: unexpected result update for %s%%%s\n",
     135                address, scope);
     136      }
     137  
     138    struct sockaddr_in6 sa;
     139    if (call_gai (AF_UNSPEC, address, scope, &sa))
     140      {
     141        support_record_failure ();
     142        printf ("error: unexpected getaddrinfo success for %s%%%s (AF_UNSPEC)\n",
     143                address, scope);
     144      }
     145    if (call_gai (AF_INET6, address, scope, &sa))
     146      {
     147        support_record_failure ();
     148        printf ("error: unexpected getaddrinfo success for %s%%%s (AF_INET6)\n",
     149                address, scope);
     150      }
     151  }
     152  
     153  /* Check a single address were we expected a success.  */
     154  static void
     155  expect_success (const char *address, const char *scope, uint32_t expected)
     156  {
     157    if (test_verbose > 0)
     158      printf ("info: expecting success for %s%%%s\n", address, scope);
     159    struct in6_addr addr = from_string (address);
     160    uint32_t actual = expected + 1;
     161    if (__inet6_scopeid_pton (&addr, scope, &actual) != 0)
     162      {
     163        support_record_failure ();
     164        printf ("error: unexpected failure for %s%%%s\n",
     165                address, scope);
     166      }
     167    if (actual != expected)
     168      {
     169        support_record_failure ();
     170        printf ("error: unexpected result for for %s%%%s\n",
     171                address, scope);
     172        printf ("  expected: %" PRIu32 "\n", expected);
     173        printf ("  actual:   %" PRIu32 "\n", actual);
     174      }
     175  
     176    struct sockaddr_in6 sa;
     177    memset (&sa, 0xc0, sizeof (sa));
     178    if (call_gai (AF_UNSPEC, address, scope, &sa))
     179      check_ai ("AF_UNSPEC", address, scope, &sa, &addr, expected);
     180    else
     181      {
     182        support_record_failure ();
     183        printf ("error: unexpected getaddrinfo failure for %s%%%s (AF_UNSPEC)\n",
     184                address, scope);
     185      }
     186    memset (&sa, 0xc0, sizeof (sa));
     187    if (call_gai (AF_INET6, address, scope, &sa))
     188      check_ai ("AF_INET6", address, scope, &sa, &addr, expected);
     189    else
     190      {
     191        support_record_failure ();
     192        printf ("error: unexpected getaddrinfo failure for %s%%%s (AF_INET6)\n",
     193                address, scope);
     194      }
     195  }
     196  
     197  static int
     198  do_test (void)
     199  {
     200    setup_interface ();
     201  
     202    static const char *test_addresses[]
     203      = { "::", "::1", "2001:db8::1", NULL };
     204    for (int i = 0; test_addresses[i] != NULL; ++i)
     205      {
     206        expect_success (test_addresses[i], "0", 0);
     207        expect_success (test_addresses[i], "5555", 5555);
     208  
     209        expect_failure (test_addresses[i], "");
     210        expect_failure (test_addresses[i], "-1");
     211        expect_failure (test_addresses[i], "-99");
     212        expect_failure (test_addresses[i], "037777777777");
     213        expect_failure (test_addresses[i], "0x");
     214        expect_failure (test_addresses[i], "0x1");
     215      }
     216  
     217    if (interface_name != NULL)
     218      {
     219        expect_success ("fe80::1", interface_name, interface_index);
     220        expect_success ("ff02::1", interface_name, interface_index);
     221        expect_success ("ff01::1", interface_name, interface_index);
     222        expect_failure ("::", interface_name);
     223        expect_failure ("::1", interface_name);
     224        expect_failure ("2001:db8::1", interface_name);
     225      }
     226  
     227    return 0;
     228  }
     229  
     230  #include <support/test-driver.c>