]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
Merge pull request #31044 from keszybz/uhttpd-alloca-print
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/icmp6.h>
7 #include <arpa/inet.h>
8 #include <unistd.h>
9
10 #include "sd-ndisc.h"
11
12 #include "alloc-util.h"
13 #include "fd-util.h"
14 #include "hexdecoct.h"
15 #include "icmp6-util-unix.h"
16 #include "socket-util.h"
17 #include "strv.h"
18 #include "ndisc-internal.h"
19 #include "tests.h"
20
21 static struct ether_addr mac_addr = {
22 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
23 };
24
25 static bool verbose = false;
26 static sd_ndisc *test_timeout_nd;
27
28 static void router_dump(sd_ndisc_router *rt) {
29 struct in6_addr addr;
30 uint8_t hop_limit;
31 usec_t t, lifetime, retrans_time;
32 uint64_t flags;
33 uint32_t mtu;
34 unsigned preference;
35 int r;
36
37 assert_se(rt);
38
39 log_info("--");
40 assert_se(sd_ndisc_router_get_address(rt, &addr) >= 0);
41 log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr));
42
43 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
44 log_info("Timestamp: %s", FORMAT_TIMESTAMP(t));
45
46 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
47 log_info("Monotonic: %" PRIu64, t);
48
49 if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0)
50 log_info("No hop limit set");
51 else
52 log_info("Hop limit: %u", hop_limit);
53
54 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
55 log_info("Flags: <%s|%s>",
56 flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
57 flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
58
59 assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0);
60 log_info("Preference: %s",
61 preference == SD_NDISC_PREFERENCE_LOW ? "low" :
62 preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium");
63
64 assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0);
65 assert_se(sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
66 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
67
68 assert_se(sd_ndisc_router_get_retransmission_time(rt, &retrans_time) >= 0);
69 log_info("Retransmission Time: %s", FORMAT_TIMESPAN(retrans_time, USEC_PER_SEC));
70
71 if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
72 log_info("No MTU set");
73 else
74 log_info("MTU: %" PRIu32, mtu);
75
76 r = sd_ndisc_router_option_rewind(rt);
77 for (;;) {
78 uint8_t type;
79
80 assert_se(r >= 0);
81
82 if (r == 0)
83 break;
84
85 assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
86
87 log_info(">> Option %u", type);
88
89 switch (type) {
90
91 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
92 case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
93 _cleanup_free_ char *c = NULL;
94 const void *p;
95 size_t n;
96
97 assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
98 assert_se(n > 2);
99 assert_se(c = hexmem((uint8_t*) p + 2, n - 2));
100
101 log_info("Address: %s", c);
102 break;
103 }
104
105 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
106 unsigned prefix_len;
107 uint8_t pfl;
108 struct in6_addr a;
109
110 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime) >= 0);
111 assert_se(sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
112 log_info("Valid Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
113
114 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime) >= 0);
115 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
116 log_info("Preferred Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
117
118 assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
119 log_info("Flags: <%s|%s>",
120 pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
121 pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
122
123 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
124 log_info("Prefix Length: %u", prefix_len);
125
126 assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
127 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a));
128
129 break;
130 }
131
132 case SD_NDISC_OPTION_RDNSS: {
133 const struct in6_addr *a;
134 int n, i;
135
136 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
137 assert_se(n > 0);
138
139 for (i = 0; i < n; i++)
140 log_info("DNS: %s", IN6_ADDR_TO_STRING(a + i));
141
142 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime) >= 0);
143 assert_se(sd_ndisc_router_rdnss_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
144 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
145 break;
146 }
147
148 case SD_NDISC_OPTION_DNSSL: {
149 _cleanup_strv_free_ char **l = NULL;
150 int n, i;
151
152 n = sd_ndisc_router_dnssl_get_domains(rt, &l);
153 assert_se(n > 0);
154
155 for (i = 0; i < n; i++)
156 log_info("Domain: %s", l[i]);
157
158 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime) >= 0);
159 assert_se(sd_ndisc_router_dnssl_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
160 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
161 break;
162 }}
163
164 r = sd_ndisc_router_option_next(rt);
165 }
166 }
167
168 static int send_ra(uint8_t flags) {
169 uint8_t advertisement[] = {
170 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
173 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
174 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
177 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
179 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
180 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
181 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
183 };
184
185 advertisement[5] = flags;
186
187 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
188 sizeof(advertisement));
189
190 if (verbose)
191 printf(" sent RA with flag 0x%02x\n", flags);
192
193 return 0;
194 }
195
196 static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
197 sd_event *e = userdata;
198 static unsigned idx = 0;
199 uint64_t flags_array[] = {
200 0,
201 0,
202 0,
203 ND_RA_FLAG_OTHER,
204 ND_RA_FLAG_MANAGED
205 };
206 uint64_t flags;
207
208 assert_se(nd);
209
210 if (event != SD_NDISC_EVENT_ROUTER)
211 return;
212
213 router_dump(rt);
214
215 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
216 assert_se(flags == flags_array[idx]);
217 idx++;
218
219 if (verbose)
220 printf(" got event 0x%02" PRIx64 "\n", flags);
221
222 if (idx < ELEMENTSOF(flags_array)) {
223 send_ra(flags_array[idx]);
224 return;
225 }
226
227 sd_event_exit(e, 0);
228 }
229
230 TEST(rs) {
231 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
232 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
233
234 send_ra_function = send_ra;
235
236 assert_se(sd_event_new(&e) >= 0);
237
238 assert_se(sd_ndisc_new(&nd) >= 0);
239 assert_se(nd);
240
241 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
242
243 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
244 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
245 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
246
247 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
248 30 * USEC_PER_SEC, 0,
249 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
250
251 assert_se(sd_ndisc_stop(nd) >= 0);
252 assert_se(sd_ndisc_start(nd) >= 0);
253 assert_se(sd_ndisc_start(nd) >= 0);
254 assert_se(sd_ndisc_stop(nd) >= 0);
255 test_fd[1] = safe_close(test_fd[1]);
256
257 assert_se(sd_ndisc_start(nd) >= 0);
258
259 assert_se(sd_event_loop(e) >= 0);
260
261 test_fd[1] = safe_close(test_fd[1]);
262 }
263
264 static int test_timeout_value(uint8_t flags) {
265 static int count = 0;
266 static usec_t last = 0;
267 sd_ndisc *nd = test_timeout_nd;
268 usec_t min, max;
269
270 assert_se(nd);
271 assert_se(nd->event);
272
273 if (++count >= 20)
274 sd_event_exit(nd->event, 0);
275
276 if (last == 0) {
277 /* initial RT = IRT + RAND*IRT */
278 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
279 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
280 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
281 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
282 } else {
283 /* next RT = 2*RTprev + RAND*RTprev */
284 min = 2 * last - last / 10;
285 max = 2 * last + last / 10;
286 }
287
288 /* final RT > MRT */
289 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
290 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
291 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
292 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
293 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
294 }
295
296 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
297 count,
298 last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
299 FORMAT_TIMESPAN(min, USEC_PER_MSEC),
300 FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
301 FORMAT_TIMESPAN(max, USEC_PER_MSEC));
302
303 assert_se(min <= nd->retransmit_time);
304 assert_se(max >= nd->retransmit_time);
305
306 last = nd->retransmit_time;
307
308 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
309
310 return 0;
311 }
312
313 TEST(timeout) {
314 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
315 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
316
317 send_ra_function = test_timeout_value;
318
319 assert_se(sd_event_new(&e) >= 0);
320
321 assert_se(sd_ndisc_new(&nd) >= 0);
322 assert_se(nd);
323
324 test_timeout_nd = nd;
325
326 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
327
328 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
329 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
330
331 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
332 30 * USEC_PER_SEC, 0,
333 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
334
335 assert_se(sd_ndisc_start(nd) >= 0);
336
337 assert_se(sd_event_loop(e) >= 0);
338
339 test_fd[1] = safe_close(test_fd[1]);
340 }
341
342 DEFINE_TEST_MAIN(LOG_DEBUG);