]>
Commit | Line | Data |
---|---|---|
965d5c39 | 1 | /* Tests for __inet6_scopeid_pton and IPv6 scopes in getaddrinfo. |
bfff8b1b | 2 | Copyright (C) 2016-2017 Free Software Foundation, Inc. |
80d8cb91 FW |
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 | <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #include <arpa/inet.h> | |
20 | #include <inttypes.h> | |
21 | #include <net-internal.h> | |
22 | #include <net/if.h> | |
965d5c39 | 23 | #include <netdb.h> |
80d8cb91 FW |
24 | #include <stdio.h> |
25 | #include <stdlib.h> | |
965d5c39 FW |
26 | #include <string.h> |
27 | #include <support/check.h> | |
28 | #include <support/support.h> | |
29 | #include <support/test-driver.h> | |
80d8cb91 FW |
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) | |
965d5c39 FW |
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 = | |
80d8cb91 | 64 | { |
965d5c39 FW |
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); | |
80d8cb91 | 114 | } |
80d8cb91 FW |
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 | { | |
965d5c39 FW |
121 | if (test_verbose > 0) |
122 | printf ("info: expecting failure for %s%%%s\n", address, scope); | |
80d8cb91 FW |
123 | struct in6_addr addr = from_string (address); |
124 | uint32_t result = 1234; | |
125 | if (__inet6_scopeid_pton (&addr, scope, &result) == 0) | |
126 | { | |
965d5c39 | 127 | support_record_failure (); |
80d8cb91 FW |
128 | printf ("error: unexpected success for %s%%%s\n", |
129 | address, scope); | |
80d8cb91 FW |
130 | } |
131 | if (result != 1234) | |
132 | { | |
965d5c39 | 133 | support_record_failure (); |
80d8cb91 FW |
134 | printf ("error: unexpected result update for %s%%%s\n", |
135 | address, scope); | |
965d5c39 FW |
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); | |
80d8cb91 FW |
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 | { | |
965d5c39 FW |
157 | if (test_verbose > 0) |
158 | printf ("info: expecting success for %s%%%s\n", address, scope); | |
80d8cb91 FW |
159 | struct in6_addr addr = from_string (address); |
160 | uint32_t actual = expected + 1; | |
161 | if (__inet6_scopeid_pton (&addr, scope, &actual) != 0) | |
162 | { | |
965d5c39 | 163 | support_record_failure (); |
80d8cb91 FW |
164 | printf ("error: unexpected failure for %s%%%s\n", |
165 | address, scope); | |
80d8cb91 FW |
166 | } |
167 | if (actual != expected) | |
168 | { | |
965d5c39 | 169 | support_record_failure (); |
80d8cb91 FW |
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); | |
965d5c39 FW |
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); | |
80d8cb91 FW |
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); | |
f768b450 | 221 | expect_success ("ff01::1", interface_name, interface_index); |
80d8cb91 FW |
222 | expect_failure ("::", interface_name); |
223 | expect_failure ("::1", interface_name); | |
80d8cb91 FW |
224 | expect_failure ("2001:db8::1", interface_name); |
225 | } | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
965d5c39 | 230 | #include <support/test-driver.c> |