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-packet.h"
16 #include "icmp6-util-unix.h"
17 #include "socket-util.h"
19 #include "ndisc-internal.h"
22 static struct ether_addr mac_addr
= {
23 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
26 static bool verbose
= false;
28 static void router_dump(sd_ndisc_router
*rt
) {
31 usec_t t
, lifetime
, retrans_time
;
40 assert_se(sd_ndisc_router_get_sender_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(p
+ 2, n
- 2));
101 log_info("Address: %s", c
);
105 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
106 uint8_t prefix_len
, pfl
;
109 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime
) >= 0);
110 assert_se(sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
111 log_info("Valid Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
113 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime
) >= 0);
114 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
115 log_info("Preferred Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
117 assert_se(sd_ndisc_router_prefix_get_flags(rt
, &pfl
) >= 0);
118 log_info("Flags: <%s|%s>",
119 pfl
& ND_OPT_PI_FLAG_ONLINK
? "ONLINK" : "",
120 pfl
& ND_OPT_PI_FLAG_AUTO
? "AUTO" : "");
122 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
123 log_info("Prefix Length: %u", prefix_len
);
125 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
126 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a
));
131 case SD_NDISC_OPTION_RDNSS
: {
132 const struct in6_addr
*a
;
135 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
138 for (i
= 0; i
< n
; i
++)
139 log_info("DNS: %s", IN6_ADDR_TO_STRING(a
+ i
));
141 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt
, &lifetime
) >= 0);
142 assert_se(sd_ndisc_router_rdnss_get_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
143 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
147 case SD_NDISC_OPTION_DNSSL
: {
150 assert_se(sd_ndisc_router_dnssl_get_domains(rt
, &l
) >= 0);
153 log_info("Domain: %s", *s
);
155 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, &lifetime
) >= 0);
156 assert_se(sd_ndisc_router_dnssl_get_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
157 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
161 r
= sd_ndisc_router_option_next(rt
);
165 static int send_ra(uint8_t flags
) {
166 uint8_t advertisement
[] = {
167 /* struct nd_router_advert */
168 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
171 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
172 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
173 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
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 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 24 */
180 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
181 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
182 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
184 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
187 advertisement
[5] = flags
;
189 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
190 sizeof(advertisement
));
193 printf(" sent RA with flag 0x%02x\n", flags
);
198 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event_t event
, void *message
, void *userdata
) {
199 sd_event
*e
= userdata
;
200 static unsigned idx
= 0;
201 uint64_t flags_array
[] = {
212 if (event
!= SD_NDISC_EVENT_ROUTER
)
215 sd_ndisc_router
*rt
= ASSERT_PTR(message
);
219 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
220 assert_se(flags
== flags_array
[idx
]);
224 printf(" got event 0x%02" PRIx64
"\n", flags
);
226 if (idx
< ELEMENTSOF(flags_array
)) {
227 send_ra(flags_array
[idx
]);
235 static int on_recv_rs(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
236 _cleanup_(icmp6_packet_unrefp
) ICMP6Packet
*packet
= NULL
;
237 assert_se(icmp6_packet_receive(fd
, &packet
) >= 0);
243 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
244 _cleanup_(sd_event_source_unrefp
) sd_event_source
*s
= NULL
;
245 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
247 assert_se(sd_event_new(&e
) >= 0);
249 assert_se(sd_ndisc_new(&nd
) >= 0);
252 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
254 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
255 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
256 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
258 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
259 30 * USEC_PER_SEC
, 0,
260 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
262 assert_se(sd_ndisc_stop(nd
) >= 0);
263 assert_se(sd_ndisc_start(nd
) >= 0);
264 assert_se(sd_ndisc_start(nd
) >= 0);
265 assert_se(sd_ndisc_stop(nd
) >= 0);
266 test_fd
[1] = safe_close(test_fd
[1]);
268 assert_se(sd_ndisc_start(nd
) >= 0);
270 assert_se(sd_event_add_io(e
, &s
, test_fd
[1], EPOLLIN
, on_recv_rs
, nd
) >= 0);
271 assert_se(sd_event_source_set_io_fd_own(s
, true) >= 0);
273 assert_se(sd_event_loop(e
) >= 0);
278 static int send_ra_invalid_domain(uint8_t flags
) {
279 uint8_t advertisement
[] = {
280 /* struct nd_router_advert */
281 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
284 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
285 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
286 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
289 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
290 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
292 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 112 */
293 0x1f, 0x0e, 0xee, 0x68, 0xb0, 0xf4, 0x36, 0x39,
294 0x2c, 0xbc, 0x0b, 0xbc, 0xa9, 0x97, 0x71, 0x37,
295 0xad, 0x86, 0x80, 0x14, 0x2e, 0x58, 0xaa, 0x8a,
296 0xb7, 0xa1, 0xbe, 0x91, 0x59, 0x00, 0xc4, 0xe8,
297 0xdd, 0xd8, 0x6d, 0xe5, 0x4a, 0x7a, 0x71, 0x42,
298 0x74, 0x45, 0x9e, 0x2e, 0xfd, 0x9d, 0x71, 0x1d,
299 0xd0, 0xc0, 0x54, 0x0c, 0x4d, 0x1f, 0xbf, 0x90,
300 0xd9, 0x79, 0x58, 0xc0, 0x1d, 0xa3, 0x39, 0xcf,
301 0xb8, 0xec, 0xd2, 0xe4, 0xcd, 0xb6, 0x13, 0x2f,
302 0xc0, 0x46, 0xe8, 0x07, 0x3f, 0xaa, 0x28, 0xa5,
303 0x23, 0xf1, 0xf0, 0xca, 0xd3, 0x19, 0x3f, 0xfa,
304 0x6c, 0x7c, 0xec, 0x1b, 0xcf, 0x71, 0xeb, 0xba,
305 0x68, 0x1b, 0x8e, 0x7d, 0x93, 0x7e, 0x0b, 0x9f,
306 0xdb, 0x12, 0x9c, 0x75, 0x22, 0x5f, 0x12, 0x00,
307 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
308 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
311 advertisement
[5] = flags
;
313 printf("sizeof(nd_router_advert)=%zu\n", sizeof(struct nd_router_advert
));
315 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
316 sizeof(advertisement
));
319 printf(" sent RA with flag 0x%02x\n", flags
);
324 static int on_recv_rs_invalid_domain(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
325 _cleanup_(icmp6_packet_unrefp
) ICMP6Packet
*packet
= NULL
;
326 assert_se(icmp6_packet_receive(fd
, &packet
) >= 0);
328 return send_ra_invalid_domain(0);
331 TEST(invalid_domain
) {
332 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
333 _cleanup_(sd_event_source_unrefp
) sd_event_source
*s
= NULL
;
334 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
336 assert_se(sd_event_new(&e
) >= 0);
338 assert_se(sd_ndisc_new(&nd
) >= 0);
341 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
343 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
344 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
345 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
347 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
348 30 * USEC_PER_SEC
, 0,
349 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
351 assert_se(sd_ndisc_start(nd
) >= 0);
353 assert_se(sd_event_add_io(e
, &s
, test_fd
[1], EPOLLIN
, on_recv_rs_invalid_domain
, nd
) >= 0);
354 assert_se(sd_event_source_set_io_fd_own(s
, true) >= 0);
356 assert_se(sd_event_loop(e
) >= 0);
361 static int on_recv_rs_timeout(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
362 _cleanup_(icmp6_packet_unrefp
) ICMP6Packet
*packet
= NULL
;
363 sd_ndisc
*nd
= ASSERT_PTR(userdata
);
364 static int count
= 0;
365 static usec_t last
= 0;
368 assert_se(icmp6_packet_receive(fd
, &packet
) >= 0);
371 sd_event_exit(nd
->event
, 0);
374 /* initial RT = IRT + RAND*IRT */
375 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
376 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
377 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
378 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
380 /* next RT = 2*RTprev + RAND*RTprev */
381 min
= 2 * last
- last
/ 10;
382 max
= 2 * last
+ last
/ 10;
386 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
387 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
388 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
389 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
390 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
393 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
395 last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
? "(max) ": "",
396 FORMAT_TIMESPAN(min
, USEC_PER_MSEC
),
397 FORMAT_TIMESPAN(nd
->retransmit_time
, USEC_PER_MSEC
),
398 FORMAT_TIMESPAN(max
, USEC_PER_MSEC
));
400 assert_se(min
<= nd
->retransmit_time
);
401 assert_se(max
>= nd
->retransmit_time
);
403 last
= nd
->retransmit_time
;
405 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
411 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
412 _cleanup_(sd_event_source_unrefp
) sd_event_source
*s
= NULL
;
413 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
415 assert_se(sd_event_new(&e
) >= 0);
417 assert_se(sd_ndisc_new(&nd
) >= 0);
420 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
422 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
423 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
425 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
426 30 * USEC_PER_SEC
, 0,
427 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
429 assert_se(sd_ndisc_start(nd
) >= 0);
431 assert_se(sd_event_add_io(e
, &s
, test_fd
[1], EPOLLIN
, on_recv_rs_timeout
, nd
) >= 0);
432 assert_se(sd_event_source_set_io_fd_own(s
, true) >= 0);
434 assert_se(sd_event_loop(e
) >= 0);
439 DEFINE_TEST_MAIN(LOG_DEBUG
);