]> git.ipfire.org Git - thirdparty/glibc.git/blob - inet/tst-inet6_scopeid_pton.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / inet / tst-inet6_scopeid_pton.c
1 /* Tests for __inet6_scopeid_pton and IPv6 scopes in getaddrinfo.
2 Copyright (C) 2016-2021 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>