1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include <netinet/icmp6.h>
12 #include "alloc-util.h"
14 #include "hexdecoct.h"
15 #include "icmp6-util-unix.h"
16 #include "socket-util.h"
18 #include "ndisc-internal.h"
21 static struct ether_addr mac_addr
= {
22 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
25 static bool verbose
= false;
26 static sd_ndisc
*test_timeout_nd
;
28 static void router_dump(sd_ndisc_router
*rt
) {
31 usec_t t
, lifetime
, retrans_time
;
40 assert_se(sd_ndisc_router_get_address(rt
, &addr
) >= 0);
41 log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr
));
43 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
44 log_info("Timestamp: %s", FORMAT_TIMESTAMP(t
));
46 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_MONOTONIC
, &t
) >= 0);
47 log_info("Monotonic: %" PRIu64
, t
);
49 if (sd_ndisc_router_get_hop_limit(rt
, &hop_limit
) < 0)
50 log_info("No hop limit set");
52 log_info("Hop limit: %u", hop_limit
);
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" : "");
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");
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
));
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
));
71 if (sd_ndisc_router_get_mtu(rt
, &mtu
) < 0)
72 log_info("No MTU set");
74 log_info("MTU: %" PRIu32
, mtu
);
76 r
= sd_ndisc_router_option_rewind(rt
);
85 assert_se(sd_ndisc_router_option_get_type(rt
, &type
) >= 0);
87 log_info(">> Option %u", type
);
91 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS
:
92 case SD_NDISC_OPTION_TARGET_LL_ADDRESS
: {
93 _cleanup_free_
char *c
= NULL
;
97 assert_se(sd_ndisc_router_option_get_raw(rt
, &p
, &n
) >= 0);
99 assert_se(c
= hexmem((uint8_t*) p
+ 2, n
- 2));
101 log_info("Address: %s", c
);
105 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
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
));
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
));
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" : "");
123 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
124 log_info("Prefix Length: %u", prefix_len
);
126 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
127 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a
));
132 case SD_NDISC_OPTION_RDNSS
: {
133 const struct in6_addr
*a
;
136 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
139 for (i
= 0; i
< n
; i
++)
140 log_info("DNS: %s", IN6_ADDR_TO_STRING(a
+ i
));
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
));
148 case SD_NDISC_OPTION_DNSSL
: {
149 _cleanup_strv_free_
char **l
= NULL
;
152 n
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
154 log_info("Invalid domain(s).");
159 for (i
= 0; i
< n
; i
++)
160 log_info("Domain: %s", l
[i
]);
162 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, &lifetime
) >= 0);
163 assert_se(sd_ndisc_router_dnssl_get_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
164 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
168 r
= sd_ndisc_router_option_next(rt
);
172 static int send_ra(uint8_t flags
) {
173 uint8_t advertisement
[] = {
174 /* struct nd_router_advert */
175 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
178 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
179 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
180 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
183 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
184 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
186 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 24 */
187 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
188 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
189 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
191 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
194 advertisement
[5] = flags
;
196 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
197 sizeof(advertisement
));
200 printf(" sent RA with flag 0x%02x\n", flags
);
205 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event_t event
, sd_ndisc_router
*rt
, void *userdata
) {
206 sd_event
*e
= userdata
;
207 static unsigned idx
= 0;
208 uint64_t flags_array
[] = {
219 if (event
!= SD_NDISC_EVENT_ROUTER
)
224 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
225 assert_se(flags
== flags_array
[idx
]);
229 printf(" got event 0x%02" PRIx64
"\n", flags
);
231 if (idx
< ELEMENTSOF(flags_array
)) {
232 send_ra(flags_array
[idx
]);
241 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
242 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
244 send_ra_function
= send_ra
;
246 assert_se(sd_event_new(&e
) >= 0);
248 assert_se(sd_ndisc_new(&nd
) >= 0);
251 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
253 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
254 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
255 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
257 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
258 30 * USEC_PER_SEC
, 0,
259 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
261 assert_se(sd_ndisc_stop(nd
) >= 0);
262 assert_se(sd_ndisc_start(nd
) >= 0);
263 assert_se(sd_ndisc_start(nd
) >= 0);
264 assert_se(sd_ndisc_stop(nd
) >= 0);
265 test_fd
[1] = safe_close(test_fd
[1]);
267 assert_se(sd_ndisc_start(nd
) >= 0);
269 assert_se(sd_event_loop(e
) >= 0);
271 test_fd
[1] = safe_close(test_fd
[1]);
274 static int send_ra_invalid_domain(uint8_t flags
) {
275 uint8_t advertisement
[] = {
276 /* struct nd_router_advert */
277 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
280 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
281 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
282 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
285 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
286 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
288 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 112 */
289 0x1f, 0x0e, 0xee, 0x68, 0xb0, 0xf4, 0x36, 0x39,
290 0x2c, 0xbc, 0x0b, 0xbc, 0xa9, 0x97, 0x71, 0x37,
291 0xad, 0x86, 0x80, 0x14, 0x2e, 0x58, 0xaa, 0x8a,
292 0xb7, 0xa1, 0xbe, 0x91, 0x59, 0x00, 0xc4, 0xe8,
293 0xdd, 0xd8, 0x6d, 0xe5, 0x4a, 0x7a, 0x71, 0x42,
294 0x74, 0x45, 0x9e, 0x2e, 0xfd, 0x9d, 0x71, 0x1d,
295 0xd0, 0xc0, 0x54, 0x0c, 0x4d, 0x1f, 0xbf, 0x90,
296 0xd9, 0x79, 0x58, 0xc0, 0x1d, 0xa3, 0x39, 0xcf,
297 0xb8, 0xec, 0xd2, 0xe4, 0xcd, 0xb6, 0x13, 0x2f,
298 0xc0, 0x46, 0xe8, 0x07, 0x3f, 0xaa, 0x28, 0xa5,
299 0x23, 0xf1, 0xf0, 0xca, 0xd3, 0x19, 0x3f, 0xfa,
300 0x6c, 0x7c, 0xec, 0x1b, 0xcf, 0x71, 0xeb, 0xba,
301 0x68, 0x1b, 0x8e, 0x7d, 0x93, 0x7e, 0x0b, 0x9f,
302 0xdb, 0x12, 0x9c, 0x75, 0x22, 0x5f, 0x12, 0x00,
303 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
304 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
307 advertisement
[5] = flags
;
309 printf("sizeof(nd_router_advert)=%zu\n", sizeof(struct nd_router_advert
));
311 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
312 sizeof(advertisement
));
315 printf(" sent RA with flag 0x%02x\n", flags
);
320 TEST(invalid_domain
) {
321 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
322 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
324 send_ra_function
= send_ra_invalid_domain
;
326 assert_se(sd_event_new(&e
) >= 0);
328 assert_se(sd_ndisc_new(&nd
) >= 0);
331 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
333 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
334 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
335 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
337 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
338 30 * USEC_PER_SEC
, 0,
339 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
341 assert_se(sd_ndisc_start(nd
) >= 0);
343 assert_se(sd_event_loop(e
) >= 0);
345 test_fd
[1] = safe_close(test_fd
[1]);
348 static int test_timeout_value(uint8_t flags
) {
349 static int count
= 0;
350 static usec_t last
= 0;
351 sd_ndisc
*nd
= test_timeout_nd
;
355 assert_se(nd
->event
);
358 sd_event_exit(nd
->event
, 0);
361 /* initial RT = IRT + RAND*IRT */
362 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
363 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
364 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
365 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
367 /* next RT = 2*RTprev + RAND*RTprev */
368 min
= 2 * last
- last
/ 10;
369 max
= 2 * last
+ last
/ 10;
373 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
374 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
375 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
376 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
377 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
380 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
382 last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
? "(max) ": "",
383 FORMAT_TIMESPAN(min
, USEC_PER_MSEC
),
384 FORMAT_TIMESPAN(nd
->retransmit_time
, USEC_PER_MSEC
),
385 FORMAT_TIMESPAN(max
, USEC_PER_MSEC
));
387 assert_se(min
<= nd
->retransmit_time
);
388 assert_se(max
>= nd
->retransmit_time
);
390 last
= nd
->retransmit_time
;
392 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
398 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
399 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
401 send_ra_function
= test_timeout_value
;
403 assert_se(sd_event_new(&e
) >= 0);
405 assert_se(sd_ndisc_new(&nd
) >= 0);
408 test_timeout_nd
= nd
;
410 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
412 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
413 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
415 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
416 30 * USEC_PER_SEC
, 0,
417 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
419 assert_se(sd_ndisc_start(nd
) >= 0);
421 assert_se(sd_event_loop(e
) >= 0);
423 test_fd
[1] = safe_close(test_fd
[1]);
426 DEFINE_TEST_MAIN(LOG_DEBUG
);