]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
Merge pull request #29059 from YHNdnzj/catalog-followup
[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 uint64_t t, flags;
32 uint32_t mtu;
33 uint16_t lifetime;
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 log_info("Lifetime: %" PRIu16, lifetime);
66
67 if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
68 log_info("No MTU set");
69 else
70 log_info("MTU: %" PRIu32, mtu);
71
72 r = sd_ndisc_router_option_rewind(rt);
73 for (;;) {
74 uint8_t type;
75
76 assert_se(r >= 0);
77
78 if (r == 0)
79 break;
80
81 assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
82
83 log_info(">> Option %u", type);
84
85 switch (type) {
86
87 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
88 case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
89 _cleanup_free_ char *c = NULL;
90 const void *p;
91 size_t n;
92
93 assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
94 assert_se(n > 2);
95 assert_se(c = hexmem((uint8_t*) p + 2, n - 2));
96
97 log_info("Address: %s", c);
98 break;
99 }
100
101 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
102 uint32_t lifetime_valid, lifetime_preferred;
103 unsigned prefix_len;
104 uint8_t pfl;
105 struct in6_addr a;
106
107 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid) >= 0);
108 log_info("Valid Lifetime: %" PRIu32, lifetime_valid);
109
110 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred) >= 0);
111 log_info("Preferred Lifetime: %" PRIu32, lifetime_preferred);
112
113 assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
114 log_info("Flags: <%s|%s>",
115 pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
116 pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
117
118 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
119 log_info("Prefix Length: %u", prefix_len);
120
121 assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
122 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a));
123
124 break;
125 }
126
127 case SD_NDISC_OPTION_RDNSS: {
128 const struct in6_addr *a;
129 uint32_t lt;
130 int n, i;
131
132 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
133 assert_se(n > 0);
134
135 for (i = 0; i < n; i++)
136 log_info("DNS: %s", IN6_ADDR_TO_STRING(a + i));
137
138 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lt) >= 0);
139 log_info("Lifetime: %" PRIu32, lt);
140 break;
141 }
142
143 case SD_NDISC_OPTION_DNSSL: {
144 _cleanup_strv_free_ char **l = NULL;
145 uint32_t lt;
146 int n, i;
147
148 n = sd_ndisc_router_dnssl_get_domains(rt, &l);
149 assert_se(n > 0);
150
151 for (i = 0; i < n; i++)
152 log_info("Domain: %s", l[i]);
153
154 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lt) >= 0);
155 log_info("Lifetime: %" PRIu32, lt);
156 break;
157 }}
158
159 r = sd_ndisc_router_option_next(rt);
160 }
161 }
162
163 static int send_ra(uint8_t flags) {
164 uint8_t advertisement[] = {
165 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
168 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
169 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
172 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
174 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
175 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
176 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
178 };
179
180 advertisement[5] = flags;
181
182 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
183 sizeof(advertisement));
184
185 if (verbose)
186 printf(" sent RA with flag 0x%02x\n", flags);
187
188 return 0;
189 }
190
191 static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
192 sd_event *e = userdata;
193 static unsigned idx = 0;
194 uint64_t flags_array[] = {
195 0,
196 0,
197 0,
198 ND_RA_FLAG_OTHER,
199 ND_RA_FLAG_MANAGED
200 };
201 uint64_t flags;
202
203 assert_se(nd);
204
205 if (event != SD_NDISC_EVENT_ROUTER)
206 return;
207
208 router_dump(rt);
209
210 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
211 assert_se(flags == flags_array[idx]);
212 idx++;
213
214 if (verbose)
215 printf(" got event 0x%02" PRIx64 "\n", flags);
216
217 if (idx < ELEMENTSOF(flags_array)) {
218 send_ra(flags_array[idx]);
219 return;
220 }
221
222 sd_event_exit(e, 0);
223 }
224
225 TEST(rs) {
226 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
227 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
228
229 send_ra_function = send_ra;
230
231 assert_se(sd_event_new(&e) >= 0);
232
233 assert_se(sd_ndisc_new(&nd) >= 0);
234 assert_se(nd);
235
236 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
237
238 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
239 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
240 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
241
242 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
243 30 * USEC_PER_SEC, 0,
244 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
245
246 assert_se(sd_ndisc_stop(nd) >= 0);
247 assert_se(sd_ndisc_start(nd) >= 0);
248 assert_se(sd_ndisc_start(nd) >= 0);
249 assert_se(sd_ndisc_stop(nd) >= 0);
250 test_fd[1] = safe_close(test_fd[1]);
251
252 assert_se(sd_ndisc_start(nd) >= 0);
253
254 assert_se(sd_event_loop(e) >= 0);
255
256 test_fd[1] = safe_close(test_fd[1]);
257 }
258
259 static int test_timeout_value(uint8_t flags) {
260 static int count = 0;
261 static usec_t last = 0;
262 sd_ndisc *nd = test_timeout_nd;
263 usec_t min, max;
264
265 assert_se(nd);
266 assert_se(nd->event);
267
268 if (++count >= 20)
269 sd_event_exit(nd->event, 0);
270
271 if (last == 0) {
272 /* initial RT = IRT + RAND*IRT */
273 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
274 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
275 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
276 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
277 } else {
278 /* next RT = 2*RTprev + RAND*RTprev */
279 min = 2 * last - last / 10;
280 max = 2 * last + last / 10;
281 }
282
283 /* final RT > MRT */
284 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
285 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
286 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
287 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
288 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
289 }
290
291 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
292 count,
293 last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
294 FORMAT_TIMESPAN(min, USEC_PER_MSEC),
295 FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
296 FORMAT_TIMESPAN(max, USEC_PER_MSEC));
297
298 assert_se(min <= nd->retransmit_time);
299 assert_se(max >= nd->retransmit_time);
300
301 last = nd->retransmit_time;
302
303 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
304
305 return 0;
306 }
307
308 TEST(timeout) {
309 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
310 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
311
312 send_ra_function = test_timeout_value;
313
314 assert_se(sd_event_new(&e) >= 0);
315
316 assert_se(sd_ndisc_new(&nd) >= 0);
317 assert_se(nd);
318
319 test_timeout_nd = nd;
320
321 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
322
323 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
324 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
325
326 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
327 30 * USEC_PER_SEC, 0,
328 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
329
330 assert_se(sd_ndisc_start(nd) >= 0);
331
332 assert_se(sd_event_loop(e) >= 0);
333
334 test_fd[1] = safe_close(test_fd[1]);
335 }
336
337 DEFINE_TEST_MAIN(LOG_DEBUG);