]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ndisc.c
test-network: add test case for ndisc MTU option
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <arpa/inet.h>
7 #include <netinet/icmp6.h>
8 #include <linux/if.h>
9 #include <linux/if_arp.h>
10
11 #include "sd-ndisc.h"
12
13 #include "event-util.h"
14 #include "missing_network.h"
15 #include "networkd-address-generation.h"
16 #include "networkd-address.h"
17 #include "networkd-dhcp6.h"
18 #include "networkd-manager.h"
19 #include "networkd-ndisc.h"
20 #include "networkd-queue.h"
21 #include "networkd-route.h"
22 #include "networkd-state-file.h"
23 #include "networkd-sysctl.h"
24 #include "string-table.h"
25 #include "string-util.h"
26 #include "strv.h"
27 #include "sysctl-util.h"
28
29 #define NDISC_DNSSL_MAX 64U
30 #define NDISC_RDNSS_MAX 64U
31 /* Not defined in the RFC, but let's set an upper limit to make not consume much memory.
32 * This should be safe as typically there should be at most 1 portal per network. */
33 #define NDISC_CAPTIVE_PORTAL_MAX 64U
34 /* Neither defined in the RFC. Just for safety. Otherwise, malformed messages can make clients trigger OOM.
35 * Not sure if the threshold is high enough. Let's adjust later if not. */
36 #define NDISC_PREF64_MAX 64U
37
38 bool link_ndisc_enabled(Link *link) {
39 assert(link);
40
41 if (!socket_ipv6_is_supported())
42 return false;
43
44 if (link->flags & IFF_LOOPBACK)
45 return false;
46
47 if (link->iftype == ARPHRD_CAN)
48 return false;
49
50 if (!link->network)
51 return false;
52
53 if (!link_may_have_ipv6ll(link, /* check_multicast = */ true))
54 return false;
55
56 if (link->network->ndisc >= 0)
57 return link->network->ndisc;
58
59 /* Accept RAs if IPv6 forwarding is disabled, and ignore RAs if IPv6 forwarding is enabled. */
60 int t = link_get_ip_forwarding(link, AF_INET6);
61 if (t >= 0)
62 return !t;
63
64 /* Otherwise, defaults to true. */
65 return true;
66 }
67
68 void network_adjust_ndisc(Network *network) {
69 assert(network);
70
71 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
72 if (network->ndisc > 0)
73 log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link-local addressing is disabled or not supported. "
74 "Disabling IPv6AcceptRA=.", network->filename);
75 network->ndisc = false;
76 }
77
78 /* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
79 * RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
80 if (!set_isempty(network->ndisc_allow_listed_router))
81 network->ndisc_deny_listed_router = set_free_free(network->ndisc_deny_listed_router);
82 if (!set_isempty(network->ndisc_allow_listed_prefix))
83 network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
84 if (!set_isempty(network->ndisc_allow_listed_route_prefix))
85 network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix);
86 }
87
88 static int ndisc_check_ready(Link *link);
89
90 static int ndisc_address_ready_callback(Address *address) {
91 Address *a;
92
93 assert(address);
94 assert(address->link);
95
96 SET_FOREACH(a, address->link->addresses)
97 if (a->source == NETWORK_CONFIG_SOURCE_NDISC)
98 a->callback = NULL;
99
100 return ndisc_check_ready(address->link);
101 }
102
103 static int ndisc_check_ready(Link *link) {
104 bool found = false, ready = false;
105 Address *address;
106
107 assert(link);
108
109 if (link->ndisc_messages > 0) {
110 log_link_debug(link, "%s(): SLAAC addresses and routes are not set.", __func__);
111 return 0;
112 }
113
114 SET_FOREACH(address, link->addresses) {
115 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
116 continue;
117
118 found = true;
119
120 if (address_is_ready(address)) {
121 ready = true;
122 break;
123 }
124 }
125
126 if (found && !ready) {
127 SET_FOREACH(address, link->addresses)
128 if (address->source == NETWORK_CONFIG_SOURCE_NDISC)
129 address->callback = ndisc_address_ready_callback;
130
131 log_link_debug(link, "%s(): no SLAAC address is ready.", __func__);
132 return 0;
133 }
134
135 link->ndisc_configured = true;
136 log_link_debug(link, "SLAAC addresses and routes set.");
137
138 link_check_ready(link);
139 return 0;
140 }
141
142 static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
143 int r;
144
145 assert(link);
146
147 r = route_configure_handler_internal(rtnl, m, link, route, "Could not set NDisc route");
148 if (r <= 0)
149 return r;
150
151 r = ndisc_check_ready(link);
152 if (r < 0)
153 link_enter_failed(link);
154
155 return 1;
156 }
157
158 static void ndisc_set_route_priority(Link *link, Route *route) {
159 assert(link);
160 assert(route);
161
162 if (route->priority_set)
163 return; /* explicitly configured. */
164
165 switch (route->pref) {
166 case SD_NDISC_PREFERENCE_LOW:
167 route->priority = link->network->ndisc_route_metric_low;
168 break;
169 case SD_NDISC_PREFERENCE_MEDIUM:
170 route->priority = link->network->ndisc_route_metric_medium;
171 break;
172 case SD_NDISC_PREFERENCE_HIGH:
173 route->priority = link->network->ndisc_route_metric_high;
174 break;
175 default:
176 assert_not_reached();
177 }
178 }
179
180 static int ndisc_request_route(Route *route, Link *link, sd_ndisc_router *rt) {
181 struct in6_addr router;
182 uint8_t hop_limit = 0;
183 uint32_t mtu = 0;
184 bool is_new;
185 int r;
186
187 assert(route);
188 assert(link);
189 assert(link->manager);
190 assert(link->network);
191 assert(rt);
192
193 r = sd_ndisc_router_get_sender_address(rt, &router);
194 if (r < 0)
195 return r;
196
197 if (link->network->ndisc_use_mtu) {
198 r = sd_ndisc_router_get_mtu(rt, &mtu);
199 if (r < 0 && r != -ENODATA)
200 return log_link_warning_errno(link, r, "Failed to get MTU from RA: %m");
201 }
202
203 if (link->network->ndisc_use_hop_limit) {
204 r = sd_ndisc_router_get_hop_limit(rt, &hop_limit);
205 if (r < 0 && r != -ENODATA)
206 return log_link_warning_errno(link, r, "Failed to get hop limit from RA: %m");
207 }
208
209 route->source = NETWORK_CONFIG_SOURCE_NDISC;
210 route->provider.in6 = router;
211 if (!route->table_set)
212 route->table = link_get_ndisc_route_table(link);
213 if (!route->protocol_set)
214 route->protocol = RTPROT_RA;
215 r = route_metric_set(&route->metric, RTAX_MTU, mtu);
216 if (r < 0)
217 return r;
218 r = route_metric_set(&route->metric, RTAX_HOPLIMIT, hop_limit);
219 if (r < 0)
220 return r;
221 r = route_metric_set(&route->metric, RTAX_QUICKACK, link->network->ndisc_quickack);
222 if (r < 0)
223 return r;
224
225 r = route_adjust_nexthops(route, link);
226 if (r < 0)
227 return r;
228
229 uint8_t pref, pref_original = route->pref;
230 FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) {
231 Route *existing;
232 Request *req;
233
234 /* If the preference is specified by the user config (that is, for semi-static routes),
235 * rather than RA, then only search conflicting routes that have the same preference. */
236 if (route->pref_set && pref != pref_original)
237 continue;
238
239 route->pref = pref;
240 ndisc_set_route_priority(link, route);
241
242 /* Note, here do not call route_remove_and_cancel() with 'route' directly, otherwise
243 * existing route(s) may be removed needlessly. */
244
245 if (route_get(link->manager, route, &existing) >= 0) {
246 /* Found an existing route that may conflict with this route. */
247 if (!route_can_update(existing, route)) {
248 log_link_debug(link, "Found an existing route that conflicts with new route based on a received RA, removing.");
249 r = route_remove_and_cancel(existing, link->manager);
250 if (r < 0)
251 return r;
252 }
253 }
254
255 if (route_get_request(link->manager, route, &req) >= 0) {
256 existing = ASSERT_PTR(req->userdata);
257 if (!route_can_update(existing, route)) {
258 log_link_debug(link, "Found a pending route request that conflicts with new request based on a received RA, cancelling.");
259 r = route_remove_and_cancel(existing, link->manager);
260 if (r < 0)
261 return r;
262 }
263 }
264 }
265
266 /* The preference (and priority) may be changed in the above loop. Restore it. */
267 route->pref = pref_original;
268 ndisc_set_route_priority(link, route);
269
270 is_new = route_get(link->manager, route, NULL) < 0;
271
272 r = link_request_route(link, route, &link->ndisc_messages, ndisc_route_handler);
273 if (r < 0)
274 return r;
275 if (r > 0 && is_new)
276 link->ndisc_configured = false;
277
278 return 0;
279 }
280
281 static int ndisc_remove_route(Route *route, Link *link) {
282 int r;
283
284 assert(route);
285 assert(link);
286 assert(link->manager);
287
288 ndisc_set_route_priority(link, route);
289
290 if (!route->table_set)
291 route->table = link_get_ndisc_route_table(link);
292
293 r = route_adjust_nexthops(route, link);
294 if (r < 0)
295 return r;
296
297 if (route->pref_set) {
298 ndisc_set_route_priority(link, route);
299 return route_remove_and_cancel(route, link->manager);
300 }
301
302 uint8_t pref;
303 FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) {
304 route->pref = pref;
305 ndisc_set_route_priority(link, route);
306 r = route_remove_and_cancel(route, link->manager);
307 if (r < 0)
308 return r;
309 }
310
311 return 0;
312 }
313
314 static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
315 int r;
316
317 assert(link);
318
319 r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address");
320 if (r <= 0)
321 return r;
322
323 r = ndisc_check_ready(link);
324 if (r < 0)
325 link_enter_failed(link);
326
327 return 1;
328 }
329
330 static int ndisc_request_address(Address *address, Link *link, sd_ndisc_router *rt) {
331 struct in6_addr router;
332 bool is_new;
333 int r;
334
335 assert(address);
336 assert(link);
337 assert(rt);
338
339 r = sd_ndisc_router_get_sender_address(rt, &router);
340 if (r < 0)
341 return r;
342
343 address->source = NETWORK_CONFIG_SOURCE_NDISC;
344 address->provider.in6 = router;
345
346 r = free_and_strdup_warn(&address->netlabel, link->network->ndisc_netlabel);
347 if (r < 0)
348 return r;
349
350 Address *existing;
351 if (address_get_harder(link, address, &existing) < 0)
352 is_new = true;
353 else if (address_can_update(existing, address))
354 is_new = false;
355 else if (existing->source == NETWORK_CONFIG_SOURCE_DHCP6) {
356 /* SLAAC address is preferred over DHCPv6 address. */
357 log_link_debug(link, "Conflicting DHCPv6 address %s exists, removing.",
358 IN_ADDR_PREFIX_TO_STRING(existing->family, &existing->in_addr, existing->prefixlen));
359 r = address_remove(existing, link);
360 if (r < 0)
361 return r;
362
363 is_new = true;
364 } else {
365 /* Conflicting static address is configured?? */
366 log_link_debug(link, "Conflicting address %s exists, ignoring request.",
367 IN_ADDR_PREFIX_TO_STRING(existing->family, &existing->in_addr, existing->prefixlen));
368 return 0;
369 }
370
371 r = link_request_address(link, address, &link->ndisc_messages,
372 ndisc_address_handler, NULL);
373 if (r < 0)
374 return r;
375 if (r > 0 && is_new)
376 link->ndisc_configured = false;
377
378 return 0;
379 }
380
381 static int ndisc_redirect_route_new(sd_ndisc_redirect *rd, Route **ret) {
382 _cleanup_(route_unrefp) Route *route = NULL;
383 struct in6_addr gateway, destination;
384 int r;
385
386 assert(rd);
387 assert(ret);
388
389 r = sd_ndisc_redirect_get_target_address(rd, &gateway);
390 if (r < 0)
391 return r;
392
393 r = sd_ndisc_redirect_get_destination_address(rd, &destination);
394 if (r < 0)
395 return r;
396
397 r = route_new(&route);
398 if (r < 0)
399 return r;
400
401 route->family = AF_INET6;
402 if (!in6_addr_equal(&gateway, &destination)) {
403 route->nexthop.gw.in6 = gateway;
404 route->nexthop.family = AF_INET6;
405 }
406 route->dst.in6 = destination;
407 route->dst_prefixlen = 128;
408
409 *ret = TAKE_PTR(route);
410 return 0;
411 }
412
413 static int ndisc_request_redirect_route(Link *link, sd_ndisc_redirect *rd) {
414 struct in6_addr router, sender;
415 int r;
416
417 assert(link);
418 assert(link->ndisc_default_router);
419 assert(rd);
420
421 r = sd_ndisc_router_get_sender_address(link->ndisc_default_router, &router);
422 if (r < 0)
423 return r;
424
425 r = sd_ndisc_redirect_get_sender_address(rd, &sender);
426 if (r < 0)
427 return r;
428
429 if (!in6_addr_equal(&sender, &router))
430 return 0;
431
432 _cleanup_(route_unrefp) Route *route = NULL;
433 r = ndisc_redirect_route_new(rd, &route);
434 if (r < 0)
435 return r;
436
437 route->protocol = RTPROT_REDIRECT;
438 route->protocol_set = true; /* To make ndisc_request_route() not override the protocol. */
439
440 /* Redirect message does not have the lifetime, let's use the lifetime of the default router, and
441 * update the lifetime of the redirect route every time when we receive RA. */
442 return ndisc_request_route(route, link, link->ndisc_default_router);
443 }
444
445 static int ndisc_remove_redirect_route(Link *link, sd_ndisc_redirect *rd) {
446 _cleanup_(route_unrefp) Route *route = NULL;
447 int r;
448
449 assert(link);
450 assert(rd);
451
452 r = ndisc_redirect_route_new(rd, &route);
453 if (r < 0)
454 return r;
455
456 return ndisc_remove_route(route, link);
457 }
458
459 static void ndisc_redirect_hash_func(const sd_ndisc_redirect *x, struct siphash *state) {
460 struct in6_addr dest = {};
461
462 assert(x);
463 assert(state);
464
465 (void) sd_ndisc_redirect_get_destination_address((sd_ndisc_redirect*) x, &dest);
466
467 siphash24_compress_typesafe(dest, state);
468 }
469
470 static int ndisc_redirect_compare_func(const sd_ndisc_redirect *x, const sd_ndisc_redirect *y) {
471 struct in6_addr dest_x = {}, dest_y = {};
472
473 assert(x);
474 assert(y);
475
476 (void) sd_ndisc_redirect_get_destination_address((sd_ndisc_redirect*) x, &dest_x);
477 (void) sd_ndisc_redirect_get_destination_address((sd_ndisc_redirect*) y, &dest_y);
478
479 return memcmp(&dest_x, &dest_y, sizeof(dest_x));
480 }
481
482 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
483 ndisc_redirect_hash_ops,
484 sd_ndisc_redirect,
485 ndisc_redirect_hash_func,
486 ndisc_redirect_compare_func,
487 sd_ndisc_redirect_unref);
488
489 static int ndisc_redirect_equal(sd_ndisc_redirect *x, sd_ndisc_redirect *y) {
490 struct in6_addr a, b;
491 int r;
492
493 assert(x);
494 assert(y);
495
496 r = sd_ndisc_redirect_get_destination_address(x, &a);
497 if (r < 0)
498 return r;
499
500 r = sd_ndisc_redirect_get_destination_address(y, &b);
501 if (r < 0)
502 return r;
503
504 if (!in6_addr_equal(&a, &b))
505 return false;
506
507 r = sd_ndisc_redirect_get_target_address(x, &a);
508 if (r < 0)
509 return r;
510
511 r = sd_ndisc_redirect_get_target_address(y, &b);
512 if (r < 0)
513 return r;
514
515 return in6_addr_equal(&a, &b);
516 }
517
518 static int ndisc_redirect_drop_conflict(Link *link, sd_ndisc_redirect *rd) {
519 _cleanup_(sd_ndisc_redirect_unrefp) sd_ndisc_redirect *existing = NULL;
520 int r;
521
522 assert(link);
523 assert(rd);
524
525 existing = set_remove(link->ndisc_redirects, rd);
526 if (!existing)
527 return 0;
528
529 r = ndisc_redirect_equal(rd, existing);
530 if (r != 0)
531 return r;
532
533 return ndisc_remove_redirect_route(link, existing);
534 }
535
536 static int ndisc_redirect_handler(Link *link, sd_ndisc_redirect *rd) {
537 struct in6_addr router, sender;
538 usec_t lifetime_usec, now_usec;
539 int r;
540
541 assert(link);
542 assert(link->network);
543 assert(rd);
544
545 if (!link->network->ndisc_use_redirect)
546 return 0;
547
548 /* Ignore all Redirect messages from non-default router. */
549
550 if (!link->ndisc_default_router)
551 return 0;
552
553 r = sd_ndisc_router_get_lifetime_timestamp(link->ndisc_default_router, CLOCK_BOOTTIME, &lifetime_usec);
554 if (r < 0)
555 return r;
556
557 r = sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec);
558 if (r < 0)
559 return r;
560
561 if (lifetime_usec <= now_usec)
562 return 0; /* The default router is outdated. Ignore the redirect message. */
563
564 r = sd_ndisc_router_get_sender_address(link->ndisc_default_router, &router);
565 if (r < 0)
566 return r;
567
568 r = sd_ndisc_redirect_get_sender_address(rd, &sender);
569 if (r < 0)
570 return r;
571
572 if (!in6_addr_equal(&sender, &router))
573 return 0; /* The redirect message is sent from a non-default router. */
574
575 /* OK, the Redirect message is sent from the current default router. */
576
577 r = ndisc_redirect_drop_conflict(link, rd);
578 if (r < 0)
579 return r;
580
581 r = set_ensure_put(&link->ndisc_redirects, &ndisc_redirect_hash_ops, rd);
582 if (r < 0)
583 return r;
584
585 sd_ndisc_redirect_ref(rd);
586
587 return ndisc_request_redirect_route(link, rd);
588 }
589
590 static int ndisc_router_update_redirect(Link *link) {
591 int r, ret = 0;
592
593 assert(link);
594
595 /* Reconfigure redirect routes to update their lifetime. */
596
597 sd_ndisc_redirect *rd;
598 SET_FOREACH(rd, link->ndisc_redirects) {
599 r = ndisc_request_redirect_route(link, rd);
600 if (r < 0)
601 RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to update lifetime of the Redirect route: %m"));
602 }
603
604 return ret;
605 }
606
607 static int ndisc_drop_redirect(Link *link, const struct in6_addr *router, bool remove) {
608 int r;
609
610 assert(link);
611
612 /* If the router is purged, then drop the redirect routes configured with the Redirect message sent
613 * by the router. */
614
615 if (!router)
616 return 0;
617
618 sd_ndisc_redirect *rd;
619 SET_FOREACH(rd, link->ndisc_redirects) {
620 struct in6_addr sender;
621
622 r = sd_ndisc_redirect_get_sender_address(rd, &sender);
623 if (r < 0)
624 return r;
625
626 if (!in6_addr_equal(&sender, router))
627 continue;
628
629 if (remove) {
630 r = ndisc_remove_redirect_route(link, rd);
631 if (r < 0)
632 return r;
633 }
634
635 sd_ndisc_redirect_unref(set_remove(link->ndisc_redirects, rd));
636 }
637
638 return 0;
639 }
640
641 static int ndisc_update_redirect_sender(Link *link, const struct in6_addr *original_address, const struct in6_addr *current_address) {
642 int r;
643
644 assert(link);
645 assert(original_address);
646 assert(current_address);
647
648 sd_ndisc_redirect *rd;
649 SET_FOREACH(rd, link->ndisc_redirects) {
650 struct in6_addr sender;
651
652 r = sd_ndisc_redirect_get_sender_address(rd, &sender);
653 if (r < 0)
654 return r;
655
656 if (!in6_addr_equal(&sender, original_address))
657 continue;
658
659 r = sd_ndisc_redirect_set_sender_address(rd, current_address);
660 if (r < 0)
661 return r;
662 }
663
664 return 0;
665 }
666
667 static int ndisc_router_drop_default(Link *link, sd_ndisc_router *rt) {
668 _cleanup_(route_unrefp) Route *route = NULL;
669 struct in6_addr gateway;
670 int r;
671
672 assert(link);
673 assert(link->network);
674 assert(rt);
675
676 r = sd_ndisc_router_get_sender_address(rt, &gateway);
677 if (r < 0)
678 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
679
680 r = route_new(&route);
681 if (r < 0)
682 return log_oom();
683
684 route->family = AF_INET6;
685 route->nexthop.family = AF_INET6;
686 route->nexthop.gw.in6 = gateway;
687
688 r = ndisc_remove_route(route, link);
689 if (r < 0)
690 return log_link_warning_errno(link, r, "Failed to remove the default gateway configured by RA: %m");
691
692 Route *route_gw;
693 HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
694 _cleanup_(route_unrefp) Route *tmp = NULL;
695
696 if (!route_gw->gateway_from_dhcp_or_ra)
697 continue;
698
699 if (route_gw->nexthop.family != AF_INET6)
700 continue;
701
702 r = route_dup(route_gw, NULL, &tmp);
703 if (r < 0)
704 return r;
705
706 tmp->nexthop.gw.in6 = gateway;
707
708 r = ndisc_remove_route(tmp, link);
709 if (r < 0)
710 return log_link_warning_errno(link, r, "Could not remove semi-static gateway: %m");
711 }
712
713 return 0;
714 }
715
716 static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
717 usec_t lifetime_usec;
718 struct in6_addr gateway;
719 uint8_t preference;
720 int r;
721
722 assert(link);
723 assert(link->network);
724 assert(rt);
725
726 /* If the router lifetime is zero, the router should not be used as the default gateway. */
727 r = sd_ndisc_router_get_lifetime(rt, NULL);
728 if (r < 0)
729 return r;
730 if (r == 0)
731 return ndisc_router_drop_default(link, rt);
732
733 if (!link->network->ndisc_use_gateway &&
734 hashmap_isempty(link->network->routes_by_section))
735 return 0;
736
737 r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
738 if (r < 0)
739 return log_link_warning_errno(link, r, "Failed to get gateway lifetime from RA: %m");
740
741 r = sd_ndisc_router_get_sender_address(rt, &gateway);
742 if (r < 0)
743 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
744
745 r = sd_ndisc_router_get_preference(rt, &preference);
746 if (r < 0)
747 return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
748
749 if (link->network->ndisc_use_gateway) {
750 _cleanup_(route_unrefp) Route *route = NULL;
751
752 r = route_new(&route);
753 if (r < 0)
754 return log_oom();
755
756 route->family = AF_INET6;
757 route->pref = preference;
758 route->nexthop.family = AF_INET6;
759 route->nexthop.gw.in6 = gateway;
760 route->lifetime_usec = lifetime_usec;
761
762 r = ndisc_request_route(route, link, rt);
763 if (r < 0)
764 return log_link_warning_errno(link, r, "Could not request default route: %m");
765 }
766
767 Route *route_gw;
768 HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
769 _cleanup_(route_unrefp) Route *route = NULL;
770
771 if (!route_gw->gateway_from_dhcp_or_ra)
772 continue;
773
774 if (route_gw->nexthop.family != AF_INET6)
775 continue;
776
777 r = route_dup(route_gw, NULL, &route);
778 if (r < 0)
779 return r;
780
781 route->nexthop.gw.in6 = gateway;
782 if (!route->pref_set)
783 route->pref = preference;
784 route->lifetime_usec = lifetime_usec;
785
786 r = ndisc_request_route(route, link, rt);
787 if (r < 0)
788 return log_link_warning_errno(link, r, "Could not request gateway: %m");
789 }
790
791 return 0;
792 }
793
794 static int update_default_router_address(Link *link, const struct in6_addr *original_address, const struct in6_addr *current_address) {
795 struct in6_addr a;
796 int r;
797
798 assert(link);
799 assert(original_address);
800 assert(current_address);
801
802 if (!link->ndisc_default_router)
803 return 0;
804
805 r = sd_ndisc_router_get_sender_address(link->ndisc_default_router, &a);
806 if (r < 0)
807 return r;
808
809 if (!in6_addr_equal(&a, original_address))
810 return 0;
811
812 return sd_ndisc_router_set_sender_address(link->ndisc_default_router, current_address);
813 }
814
815 static int drop_default_router(Link *link, const struct in6_addr *router, usec_t timestamp_usec) {
816 usec_t lifetime_usec;
817 int r;
818
819 assert(link);
820
821 if (!link->ndisc_default_router)
822 return 0;
823
824 if (router) {
825 struct in6_addr a;
826
827 r = sd_ndisc_router_get_sender_address(link->ndisc_default_router, &a);
828 if (r < 0)
829 return r;
830
831 if (!in6_addr_equal(&a, router))
832 return 0;
833 }
834
835 r = sd_ndisc_router_get_lifetime_timestamp(link->ndisc_default_router, CLOCK_BOOTTIME, &lifetime_usec);
836 if (r < 0)
837 return r;
838
839 if (lifetime_usec > timestamp_usec)
840 return 0;
841
842 link->ndisc_default_router = sd_ndisc_router_unref(link->ndisc_default_router);
843 return 0;
844 }
845
846 static int accept_default_router(sd_ndisc_router *new_router, sd_ndisc_router *existing_router) {
847 usec_t lifetime_usec;
848 struct in6_addr a, b;
849 uint8_t p, q;
850 int r;
851
852 assert(new_router);
853
854 r = sd_ndisc_router_get_lifetime(new_router, &lifetime_usec);
855 if (r < 0)
856 return r;
857
858 if (lifetime_usec == 0)
859 return false; /* Received a new RA about revoking the router, ignoring. */
860
861 if (!existing_router)
862 return true;
863
864 /* lifetime of the existing router is already checked in ndisc_drop_outdated(). */
865
866 r = sd_ndisc_router_get_sender_address(new_router, &a);
867 if (r < 0)
868 return r;
869
870 r = sd_ndisc_router_get_sender_address(existing_router, &b);
871 if (r < 0)
872 return r;
873
874 if (in6_addr_equal(&a, &b))
875 return true; /* Received a new RA from the remembered router. Replace the remembered RA. */
876
877 r = sd_ndisc_router_get_preference(new_router, &p);
878 if (r < 0)
879 return r;
880
881 r = sd_ndisc_router_get_preference(existing_router, &q);
882 if (r < 0)
883 return r;
884
885 if (p == q)
886 return true;
887
888 if (p == SD_NDISC_PREFERENCE_HIGH)
889 return true;
890
891 if (p == SD_NDISC_PREFERENCE_MEDIUM && q == SD_NDISC_PREFERENCE_LOW)
892 return true;
893
894 return false;
895 }
896
897 static int ndisc_remember_default_router(Link *link, sd_ndisc_router *rt) {
898 int r;
899
900 assert(link);
901 assert(rt);
902
903 r = accept_default_router(rt, link->ndisc_default_router);
904 if (r <= 0)
905 return r;
906
907 sd_ndisc_router_ref(rt);
908 sd_ndisc_router_unref(link->ndisc_default_router);
909 link->ndisc_default_router = rt;
910
911 return 1; /* The received router advertisement is from the default router. */
912 }
913
914 static int ndisc_router_process_reachable_time(Link *link, sd_ndisc_router *rt) {
915 usec_t reachable_time, msec;
916 int r;
917
918 assert(link);
919 assert(link->network);
920 assert(rt);
921
922 if (!link->network->ndisc_use_reachable_time)
923 return 0;
924
925 /* Ignore the reachable time field of the RA header if the lifetime is zero. */
926 r = sd_ndisc_router_get_lifetime(rt, NULL);
927 if (r <= 0)
928 return r;
929
930 r = sd_ndisc_router_get_reachable_time(rt, &reachable_time);
931 if (r < 0)
932 return log_link_warning_errno(link, r, "Failed to get reachable time from RA: %m");
933
934 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
935 if (!timestamp_is_set(reachable_time))
936 return 0;
937
938 msec = DIV_ROUND_UP(reachable_time, USEC_PER_MSEC);
939 if (msec <= 0 || msec > UINT32_MAX) {
940 log_link_debug(link, "Failed to get reachable time from RA - out of range (%"PRIu64"), ignoring", msec);
941 return 0;
942 }
943
944 /* Set the reachable time for Neighbor Solicitations. */
945 r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "base_reachable_time_ms", (uint32_t) msec);
946 if (r < 0)
947 log_link_warning_errno(link, r, "Failed to apply neighbor reachable time (%"PRIu64"), ignoring: %m", msec);
948
949 return 0;
950 }
951
952 static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router *rt) {
953 usec_t retrans_time, msec;
954 int r;
955
956 assert(link);
957 assert(link->network);
958 assert(rt);
959
960 if (!link->network->ndisc_use_retransmission_time)
961 return 0;
962
963 /* Ignore the retransmission time field of the RA header if the lifetime is zero. */
964 r = sd_ndisc_router_get_lifetime(rt, NULL);
965 if (r <= 0)
966 return r;
967
968 r = sd_ndisc_router_get_retransmission_time(rt, &retrans_time);
969 if (r < 0)
970 return log_link_warning_errno(link, r, "Failed to get retransmission time from RA: %m");
971
972 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
973 if (!timestamp_is_set(retrans_time))
974 return 0;
975
976 msec = DIV_ROUND_UP(retrans_time, USEC_PER_MSEC);
977 if (msec <= 0 || msec > UINT32_MAX) {
978 log_link_debug(link, "Failed to get retransmission time from RA - out of range (%"PRIu64"), ignoring", msec);
979 return 0;
980 }
981
982 /* Set the retransmission time for Neighbor Solicitations. */
983 r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", (uint32_t) msec);
984 if (r < 0)
985 log_link_warning_errno(link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec);
986
987 return 0;
988 }
989
990 static int ndisc_router_process_hop_limit(Link *link, sd_ndisc_router *rt) {
991 uint8_t hop_limit;
992 int r;
993
994 assert(link);
995 assert(link->network);
996 assert(rt);
997
998 if (!link->network->ndisc_use_hop_limit)
999 return 0;
1000
1001 /* Ignore the hop limit field of the RA header if the lifetime is zero. */
1002 r = sd_ndisc_router_get_lifetime(rt, NULL);
1003 if (r <= 0)
1004 return r;
1005
1006 r = sd_ndisc_router_get_hop_limit(rt, &hop_limit);
1007 if (r < 0)
1008 return log_link_warning_errno(link, r, "Failed to get hop limit from RA: %m");
1009
1010 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4):
1011 *
1012 * A Router Advertisement field (e.g., Cur Hop Limit, Reachable Time, and Retrans Timer) may contain
1013 * a value denoting that it is unspecified. In such cases, the parameter should be ignored and the
1014 * host should continue using whatever value it is already using. In particular, a host MUST NOT
1015 * interpret the unspecified value as meaning change back to the default value that was in use before
1016 * the first Router Advertisement was received.
1017 *
1018 * If the received Cur Hop Limit value is non-zero, the host SHOULD set
1019 * its CurHopLimit variable to the received value.*/
1020 if (hop_limit <= 0)
1021 return 0;
1022
1023 r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "hop_limit", (uint32_t) hop_limit);
1024 if (r < 0)
1025 log_link_warning_errno(link, r, "Failed to apply hop_limit (%u), ignoring: %m", hop_limit);
1026
1027 return 0;
1028 }
1029
1030 static int ndisc_router_process_mtu(Link *link, sd_ndisc_router *rt) {
1031 uint32_t mtu;
1032 int r;
1033
1034 assert(link);
1035 assert(link->network);
1036 assert(rt);
1037
1038 if (!link->network->ndisc_use_mtu)
1039 return 0;
1040
1041 /* Ignore the MTU option if the lifetime is zero. */
1042 r = sd_ndisc_router_get_lifetime(rt, NULL);
1043 if (r <= 0)
1044 return r;
1045
1046 r = sd_ndisc_router_get_mtu(rt, &mtu);
1047 if (r == -ENODATA)
1048 return 0;
1049 if (r < 0)
1050 return log_link_warning_errno(link, r, "Failed to get MTU from RA: %m");
1051
1052 link->ndisc_mtu = mtu;
1053
1054 r = link_set_ipv6_mtu(link, LOG_DEBUG);
1055 if (r < 0)
1056 log_link_warning_errno(link, r, "Failed to apply IPv6 MTU (%"PRIu32"), ignoring: %m", mtu);
1057
1058 return 0;
1059 }
1060
1061 static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
1062 usec_t lifetime_valid_usec, lifetime_preferred_usec;
1063 _cleanup_set_free_ Set *addresses = NULL;
1064 struct in6_addr prefix, *a;
1065 uint8_t prefixlen;
1066 int r;
1067
1068 assert(link);
1069 assert(link->network);
1070 assert(rt);
1071
1072 if (!link->network->ndisc_use_autonomous_prefix)
1073 return 0;
1074
1075 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
1076 if (r < 0)
1077 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
1078
1079 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
1080 if (r < 0)
1081 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
1082
1083 /* ndisc_generate_addresses() below requires the prefix length <= 64. */
1084 if (prefixlen > 64) {
1085 log_link_debug(link, "Prefix is longer than 64, ignoring autonomous prefix %s.",
1086 IN6_ADDR_PREFIX_TO_STRING(&prefix, prefixlen));
1087 return 0;
1088 }
1089
1090 r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_valid_usec);
1091 if (r < 0)
1092 return log_link_warning_errno(link, r, "Failed to get prefix valid lifetime: %m");
1093
1094 r = sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_preferred_usec);
1095 if (r < 0)
1096 return log_link_warning_errno(link, r, "Failed to get prefix preferred lifetime: %m");
1097
1098 /* The preferred lifetime is never greater than the valid lifetime */
1099 if (lifetime_preferred_usec > lifetime_valid_usec)
1100 return 0;
1101
1102 r = ndisc_generate_addresses(link, &prefix, prefixlen, &addresses);
1103 if (r < 0)
1104 return log_link_warning_errno(link, r, "Failed to generate SLAAC addresses: %m");
1105
1106 SET_FOREACH(a, addresses) {
1107 _cleanup_(address_unrefp) Address *address = NULL;
1108
1109 r = address_new(&address);
1110 if (r < 0)
1111 return log_oom();
1112
1113 address->family = AF_INET6;
1114 address->in_addr.in6 = *a;
1115 address->prefixlen = prefixlen;
1116 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
1117 address->lifetime_valid_usec = lifetime_valid_usec;
1118 address->lifetime_preferred_usec = lifetime_preferred_usec;
1119
1120 /* draft-ietf-6man-slaac-renum-07 section 4.2
1121 * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-07#section-4.2
1122 *
1123 * If the advertised prefix is equal to the prefix of an address configured by stateless
1124 * autoconfiguration in the list, the valid lifetime and the preferred lifetime of the
1125 * address should be updated by processing the Valid Lifetime and the Preferred Lifetime
1126 * (respectively) in the received advertisement. */
1127 if (lifetime_valid_usec == 0) {
1128 r = address_remove_and_cancel(address, link);
1129 if (r < 0)
1130 return log_link_warning_errno(link, r, "Could not remove SLAAC address: %m");
1131 } else {
1132 r = ndisc_request_address(address, link, rt);
1133 if (r < 0)
1134 return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
1135 }
1136 }
1137
1138 return 0;
1139 }
1140
1141 static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
1142 _cleanup_(route_unrefp) Route *route = NULL;
1143 uint8_t prefixlen, preference;
1144 usec_t lifetime_usec;
1145 struct in6_addr prefix;
1146 int r;
1147
1148 assert(link);
1149 assert(link->network);
1150 assert(rt);
1151
1152 if (!link->network->ndisc_use_onlink_prefix)
1153 return 0;
1154
1155 r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1156 if (r < 0)
1157 return log_link_warning_errno(link, r, "Failed to get prefix lifetime: %m");
1158
1159 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
1160 if (r < 0)
1161 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
1162
1163 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
1164 if (r < 0)
1165 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
1166
1167 /* Prefix Information option does not have preference, hence we use the 'main' preference here */
1168 r = sd_ndisc_router_get_preference(rt, &preference);
1169 if (r < 0)
1170 return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
1171
1172 r = route_new(&route);
1173 if (r < 0)
1174 return log_oom();
1175
1176 route->family = AF_INET6;
1177 route->dst.in6 = prefix;
1178 route->dst_prefixlen = prefixlen;
1179 route->pref = preference;
1180 route->lifetime_usec = lifetime_usec;
1181
1182 r = ndisc_request_route(route, link, rt);
1183 if (r < 0)
1184 return log_link_warning_errno(link, r, "Could not request prefix route: %m");
1185
1186 return 0;
1187 }
1188
1189 static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) {
1190 _cleanup_(route_unrefp) Route *route = NULL;
1191 uint8_t prefixlen;
1192 struct in6_addr prefix;
1193 usec_t lifetime_usec;
1194 int r;
1195
1196 assert(link);
1197 assert(link->network);
1198 assert(rt);
1199
1200 /* RFC 4861 section 6.3.4.
1201 * Note, however, that a Prefix Information option with the on-link flag set to zero conveys no
1202 * information concerning on-link determination and MUST NOT be interpreted to mean that addresses
1203 * covered by the prefix are off-link. The only way to cancel a previous on-link indication is to
1204 * advertise that prefix with the L-bit set and the Lifetime set to zero. */
1205
1206 if (!link->network->ndisc_use_onlink_prefix)
1207 return 0;
1208
1209 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_usec);
1210 if (r < 0)
1211 return log_link_warning_errno(link, r, "Failed to get prefix lifetime: %m");
1212
1213 if (lifetime_usec != 0)
1214 return 0;
1215
1216 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
1217 if (r < 0)
1218 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
1219
1220 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
1221 if (r < 0)
1222 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
1223
1224 r = route_new(&route);
1225 if (r < 0)
1226 return log_oom();
1227
1228 route->family = AF_INET6;
1229 route->dst.in6 = prefix;
1230 route->dst_prefixlen = prefixlen;
1231
1232 r = ndisc_remove_route(route, link);
1233 if (r < 0)
1234 return log_link_warning_errno(link, r, "Could not remove prefix route: %m");
1235
1236 return 0;
1237 }
1238
1239 static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt) {
1240 uint8_t flags, prefixlen;
1241 struct in6_addr a;
1242 int r;
1243
1244 assert(link);
1245 assert(link->network);
1246 assert(rt);
1247
1248 r = sd_ndisc_router_prefix_get_address(rt, &a);
1249 if (r < 0)
1250 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
1251
1252 /* RFC 4861 Section 4.6.2:
1253 * A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
1254 * a prefix option. */
1255 if (in6_addr_is_link_local(&a)) {
1256 log_link_debug(link, "Received link-local prefix, ignoring prefix.");
1257 return 0;
1258 }
1259
1260 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
1261 if (r < 0)
1262 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
1263
1264 if (in6_prefix_is_filtered(&a, prefixlen, link->network->ndisc_allow_listed_prefix, link->network->ndisc_deny_listed_prefix)) {
1265 if (DEBUG_LOGGING)
1266 log_link_debug(link, "Prefix '%s' is %s, ignoring",
1267 !set_isempty(link->network->ndisc_allow_listed_prefix) ? "not in allow list"
1268 : "in deny list",
1269 IN6_ADDR_PREFIX_TO_STRING(&a, prefixlen));
1270 return 0;
1271 }
1272
1273 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
1274 if (r < 0)
1275 return log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
1276
1277 if (FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK))
1278 r = ndisc_router_process_onlink_prefix(link, rt);
1279 else
1280 r = ndisc_router_drop_onlink_prefix(link, rt);
1281 if (r < 0)
1282 return r;
1283
1284 if (FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO)) {
1285 r = ndisc_router_process_autonomous_prefix(link, rt);
1286 if (r < 0)
1287 return r;
1288 }
1289
1290 return 0;
1291 }
1292
1293 static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
1294 _cleanup_(route_unrefp) Route *route = NULL;
1295 uint8_t preference, prefixlen;
1296 struct in6_addr gateway, dst;
1297 usec_t lifetime_usec;
1298 int r;
1299
1300 assert(link);
1301
1302 if (!link->network->ndisc_use_route_prefix)
1303 return 0;
1304
1305 r = sd_ndisc_router_route_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1306 if (r < 0)
1307 return log_link_warning_errno(link, r, "Failed to get route lifetime from RA: %m");
1308
1309 r = sd_ndisc_router_route_get_address(rt, &dst);
1310 if (r < 0)
1311 return log_link_warning_errno(link, r, "Failed to get route destination address: %m");
1312
1313 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
1314 if (r < 0)
1315 return log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
1316
1317 if (in6_prefix_is_filtered(&dst, prefixlen,
1318 link->network->ndisc_allow_listed_route_prefix,
1319 link->network->ndisc_deny_listed_route_prefix)) {
1320
1321 if (DEBUG_LOGGING)
1322 log_link_debug(link, "Route prefix %s is %s, ignoring",
1323 !set_isempty(link->network->ndisc_allow_listed_route_prefix) ? "not in allow list"
1324 : "in deny list",
1325 IN6_ADDR_PREFIX_TO_STRING(&dst, prefixlen));
1326 return 0;
1327 }
1328
1329 r = sd_ndisc_router_get_sender_address(rt, &gateway);
1330 if (r < 0)
1331 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
1332
1333 if (link_get_ipv6_address(link, &gateway, 0, NULL) >= 0) {
1334 if (DEBUG_LOGGING)
1335 log_link_debug(link, "Advertised route gateway %s is local to the link, ignoring route",
1336 IN6_ADDR_TO_STRING(&gateway));
1337 return 0;
1338 }
1339
1340 r = sd_ndisc_router_route_get_preference(rt, &preference);
1341 if (r == -EOPNOTSUPP) {
1342 log_link_debug_errno(link, r, "Received route prefix with unsupported preference, ignoring: %m");
1343 return 0;
1344 }
1345 if (r < 0)
1346 return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
1347
1348 r = route_new(&route);
1349 if (r < 0)
1350 return log_oom();
1351
1352 route->family = AF_INET6;
1353 route->pref = preference;
1354 route->nexthop.gw.in6 = gateway;
1355 route->nexthop.family = AF_INET6;
1356 route->dst.in6 = dst;
1357 route->dst_prefixlen = prefixlen;
1358 route->lifetime_usec = lifetime_usec;
1359
1360 if (lifetime_usec != 0) {
1361 r = ndisc_request_route(route, link, rt);
1362 if (r < 0)
1363 return log_link_warning_errno(link, r, "Could not request additional route: %m");
1364 } else {
1365 r = ndisc_remove_route(route, link);
1366 if (r < 0)
1367 return log_link_warning_errno(link, r, "Could not remove additional route with zero lifetime: %m");
1368 }
1369
1370 return 0;
1371 }
1372
1373 static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
1374 siphash24_compress_typesafe(x->address, state);
1375 }
1376
1377 static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
1378 return memcmp(&a->address, &b->address, sizeof(a->address));
1379 }
1380
1381 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1382 ndisc_rdnss_hash_ops,
1383 NDiscRDNSS,
1384 ndisc_rdnss_hash_func,
1385 ndisc_rdnss_compare_func,
1386 free);
1387
1388 static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
1389 usec_t lifetime_usec;
1390 const struct in6_addr *a;
1391 struct in6_addr router;
1392 bool updated = false, logged_about_too_many = false;
1393 int n, r;
1394
1395 assert(link);
1396 assert(link->network);
1397 assert(rt);
1398
1399 if (!link->network->ndisc_use_dns)
1400 return 0;
1401
1402 r = sd_ndisc_router_get_sender_address(rt, &router);
1403 if (r < 0)
1404 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1405
1406 r = sd_ndisc_router_rdnss_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1407 if (r < 0)
1408 return log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
1409
1410 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
1411 if (n < 0)
1412 return log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
1413
1414 for (int j = 0; j < n; j++) {
1415 _cleanup_free_ NDiscRDNSS *x = NULL;
1416 NDiscRDNSS *rdnss, d = {
1417 .address = a[j],
1418 };
1419
1420 if (lifetime_usec == 0) {
1421 /* The entry is outdated. */
1422 free(set_remove(link->ndisc_rdnss, &d));
1423 updated = true;
1424 continue;
1425 }
1426
1427 rdnss = set_get(link->ndisc_rdnss, &d);
1428 if (rdnss) {
1429 rdnss->router = router;
1430 rdnss->lifetime_usec = lifetime_usec;
1431 continue;
1432 }
1433
1434 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
1435 if (!logged_about_too_many)
1436 log_link_warning(link, "Too many RDNSS records per link. Only first %u records will be used.", NDISC_RDNSS_MAX);
1437 logged_about_too_many = true;
1438 continue;
1439 }
1440
1441 x = new(NDiscRDNSS, 1);
1442 if (!x)
1443 return log_oom();
1444
1445 *x = (NDiscRDNSS) {
1446 .address = a[j],
1447 .router = router,
1448 .lifetime_usec = lifetime_usec,
1449 };
1450
1451 r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
1452 if (r < 0)
1453 return log_oom();
1454 assert(r > 0);
1455
1456 updated = true;
1457 }
1458
1459 if (updated)
1460 link_dirty(link);
1461
1462 return 0;
1463 }
1464
1465 static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
1466 siphash24_compress_string(NDISC_DNSSL_DOMAIN(x), state);
1467 }
1468
1469 static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
1470 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
1471 }
1472
1473 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1474 ndisc_dnssl_hash_ops,
1475 NDiscDNSSL,
1476 ndisc_dnssl_hash_func,
1477 ndisc_dnssl_compare_func,
1478 free);
1479
1480 static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
1481 char **l;
1482 usec_t lifetime_usec;
1483 struct in6_addr router;
1484 bool updated = false, logged_about_too_many = false;
1485 int r;
1486
1487 assert(link);
1488 assert(link->network);
1489 assert(rt);
1490
1491 if (link->network->ndisc_use_domains == DHCP_USE_DOMAINS_NO)
1492 return 0;
1493
1494 r = sd_ndisc_router_get_sender_address(rt, &router);
1495 if (r < 0)
1496 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1497
1498 r = sd_ndisc_router_dnssl_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1499 if (r < 0)
1500 return log_link_warning_errno(link, r, "Failed to get DNSSL lifetime: %m");
1501
1502 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
1503 if (r < 0)
1504 return log_link_warning_errno(link, r, "Failed to get DNSSL addresses: %m");
1505
1506 STRV_FOREACH(j, l) {
1507 _cleanup_free_ NDiscDNSSL *s = NULL;
1508 NDiscDNSSL *dnssl;
1509
1510 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
1511 if (!s)
1512 return log_oom();
1513
1514 strcpy(NDISC_DNSSL_DOMAIN(s), *j);
1515
1516 if (lifetime_usec == 0) {
1517 /* The entry is outdated. */
1518 free(set_remove(link->ndisc_dnssl, s));
1519 updated = true;
1520 continue;
1521 }
1522
1523 dnssl = set_get(link->ndisc_dnssl, s);
1524 if (dnssl) {
1525 dnssl->router = router;
1526 dnssl->lifetime_usec = lifetime_usec;
1527 continue;
1528 }
1529
1530 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
1531 if (!logged_about_too_many)
1532 log_link_warning(link, "Too many DNSSL records per link. Only first %u records will be used.", NDISC_DNSSL_MAX);
1533 logged_about_too_many = true;
1534 continue;
1535 }
1536
1537 s->router = router;
1538 s->lifetime_usec = lifetime_usec;
1539
1540 r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
1541 if (r < 0)
1542 return log_oom();
1543 assert(r > 0);
1544
1545 updated = true;
1546 }
1547
1548 if (updated)
1549 link_dirty(link);
1550
1551 return 0;
1552 }
1553
1554 static NDiscCaptivePortal* ndisc_captive_portal_free(NDiscCaptivePortal *x) {
1555 if (!x)
1556 return NULL;
1557
1558 free(x->captive_portal);
1559 return mfree(x);
1560 }
1561
1562 DEFINE_TRIVIAL_CLEANUP_FUNC(NDiscCaptivePortal*, ndisc_captive_portal_free);
1563
1564 static void ndisc_captive_portal_hash_func(const NDiscCaptivePortal *x, struct siphash *state) {
1565 assert(x);
1566 siphash24_compress_string(x->captive_portal, state);
1567 }
1568
1569 static int ndisc_captive_portal_compare_func(const NDiscCaptivePortal *a, const NDiscCaptivePortal *b) {
1570 assert(a);
1571 assert(b);
1572 return strcmp_ptr(a->captive_portal, b->captive_portal);
1573 }
1574
1575 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1576 ndisc_captive_portal_hash_ops,
1577 NDiscCaptivePortal,
1578 ndisc_captive_portal_hash_func,
1579 ndisc_captive_portal_compare_func,
1580 ndisc_captive_portal_free);
1581
1582 static int ndisc_router_process_captive_portal(Link *link, sd_ndisc_router *rt) {
1583 _cleanup_(ndisc_captive_portal_freep) NDiscCaptivePortal *new_entry = NULL;
1584 _cleanup_free_ char *captive_portal = NULL;
1585 const char *uri;
1586 usec_t lifetime_usec;
1587 NDiscCaptivePortal *exist;
1588 struct in6_addr router;
1589 int r;
1590
1591 assert(link);
1592 assert(link->network);
1593 assert(rt);
1594
1595 if (!link->network->ndisc_use_captive_portal)
1596 return 0;
1597
1598 r = sd_ndisc_router_get_sender_address(rt, &router);
1599 if (r < 0)
1600 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1601
1602 /* RFC 4861 section 4.2. states that the lifetime in the message header should be used only for the
1603 * default gateway, but the captive portal option does not have a lifetime field, hence, we use the
1604 * main lifetime for the portal. */
1605 r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1606 if (r < 0)
1607 return log_link_warning_errno(link, r, "Failed to get lifetime of RA message: %m");
1608
1609 r = sd_ndisc_router_get_captive_portal(rt, &uri);
1610 if (r < 0)
1611 return log_link_warning_errno(link, r, "Failed to get captive portal from RA: %m");
1612
1613 captive_portal = strdup(uri);
1614 if (!captive_portal)
1615 return log_oom();
1616
1617 if (lifetime_usec == 0) {
1618 /* Drop the portal with zero lifetime. */
1619 ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals,
1620 &(const NDiscCaptivePortal) {
1621 .captive_portal = captive_portal,
1622 }));
1623 return 0;
1624 }
1625
1626 exist = set_get(link->ndisc_captive_portals,
1627 &(const NDiscCaptivePortal) {
1628 .captive_portal = captive_portal,
1629 });
1630 if (exist) {
1631 /* update existing entry */
1632 exist->router = router;
1633 exist->lifetime_usec = lifetime_usec;
1634 return 1;
1635 }
1636
1637 if (set_size(link->ndisc_captive_portals) >= NDISC_CAPTIVE_PORTAL_MAX) {
1638 NDiscCaptivePortal *c, *target = NULL;
1639
1640 /* Find the portal who has the minimal lifetime and drop it to store new one. */
1641 SET_FOREACH(c, link->ndisc_captive_portals)
1642 if (!target || c->lifetime_usec < target->lifetime_usec)
1643 target = c;
1644
1645 assert(target);
1646 assert(set_remove(link->ndisc_captive_portals, target) == target);
1647 ndisc_captive_portal_free(target);
1648 }
1649
1650 new_entry = new(NDiscCaptivePortal, 1);
1651 if (!new_entry)
1652 return log_oom();
1653
1654 *new_entry = (NDiscCaptivePortal) {
1655 .router = router,
1656 .lifetime_usec = lifetime_usec,
1657 .captive_portal = TAKE_PTR(captive_portal),
1658 };
1659
1660 r = set_ensure_put(&link->ndisc_captive_portals, &ndisc_captive_portal_hash_ops, new_entry);
1661 if (r < 0)
1662 return log_oom();
1663 assert(r > 0);
1664 TAKE_PTR(new_entry);
1665
1666 link_dirty(link);
1667 return 1;
1668 }
1669
1670 static void ndisc_pref64_hash_func(const NDiscPREF64 *x, struct siphash *state) {
1671 assert(x);
1672
1673 siphash24_compress_typesafe(x->prefix_len, state);
1674 siphash24_compress_typesafe(x->prefix, state);
1675 }
1676
1677 static int ndisc_pref64_compare_func(const NDiscPREF64 *a, const NDiscPREF64 *b) {
1678 int r;
1679
1680 assert(a);
1681 assert(b);
1682
1683 r = CMP(a->prefix_len, b->prefix_len);
1684 if (r != 0)
1685 return r;
1686
1687 return memcmp(&a->prefix, &b->prefix, sizeof(a->prefix));
1688 }
1689
1690 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1691 ndisc_pref64_hash_ops,
1692 NDiscPREF64,
1693 ndisc_pref64_hash_func,
1694 ndisc_pref64_compare_func,
1695 mfree);
1696
1697 static int ndisc_router_process_pref64(Link *link, sd_ndisc_router *rt) {
1698 _cleanup_free_ NDiscPREF64 *new_entry = NULL;
1699 usec_t lifetime_usec;
1700 struct in6_addr a, router;
1701 uint8_t prefix_len;
1702 NDiscPREF64 *exist;
1703 int r;
1704
1705 assert(link);
1706 assert(link->network);
1707 assert(rt);
1708
1709 if (!link->network->ndisc_use_pref64)
1710 return 0;
1711
1712 r = sd_ndisc_router_get_sender_address(rt, &router);
1713 if (r < 0)
1714 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1715
1716 r = sd_ndisc_router_prefix64_get_prefix(rt, &a);
1717 if (r < 0)
1718 return log_link_warning_errno(link, r, "Failed to get pref64 prefix: %m");
1719
1720 r = sd_ndisc_router_prefix64_get_prefixlen(rt, &prefix_len);
1721 if (r < 0)
1722 return log_link_warning_errno(link, r, "Failed to get pref64 prefix length: %m");
1723
1724 r = sd_ndisc_router_prefix64_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1725 if (r < 0)
1726 return log_link_warning_errno(link, r, "Failed to get pref64 prefix lifetime: %m");
1727
1728 if (lifetime_usec == 0) {
1729 free(set_remove(link->ndisc_pref64,
1730 &(NDiscPREF64) {
1731 .prefix = a,
1732 .prefix_len = prefix_len
1733 }));
1734 return 0;
1735 }
1736
1737 exist = set_get(link->ndisc_pref64,
1738 &(NDiscPREF64) {
1739 .prefix = a,
1740 .prefix_len = prefix_len
1741 });
1742 if (exist) {
1743 /* update existing entry */
1744 exist->router = router;
1745 exist->lifetime_usec = lifetime_usec;
1746 return 0;
1747 }
1748
1749 if (set_size(link->ndisc_pref64) >= NDISC_PREF64_MAX) {
1750 log_link_debug(link, "Too many PREF64 records received. Only first %u records will be used.", NDISC_PREF64_MAX);
1751 return 0;
1752 }
1753
1754 new_entry = new(NDiscPREF64, 1);
1755 if (!new_entry)
1756 return log_oom();
1757
1758 *new_entry = (NDiscPREF64) {
1759 .router = router,
1760 .lifetime_usec = lifetime_usec,
1761 .prefix = a,
1762 .prefix_len = prefix_len,
1763 };
1764
1765 r = set_ensure_put(&link->ndisc_pref64, &ndisc_pref64_hash_ops, new_entry);
1766 if (r < 0)
1767 return log_oom();
1768
1769 assert(r > 0);
1770 TAKE_PTR(new_entry);
1771
1772 return 0;
1773 }
1774
1775 static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
1776 size_t n_captive_portal = 0;
1777 int r;
1778
1779 assert(link);
1780 assert(link->network);
1781 assert(rt);
1782
1783 for (r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
1784 uint8_t type;
1785
1786 if (r < 0)
1787 return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
1788 if (r == 0) /* EOF */
1789 return 0;
1790
1791 r = sd_ndisc_router_option_get_type(rt, &type);
1792 if (r < 0)
1793 return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
1794
1795 switch (type) {
1796 case SD_NDISC_OPTION_PREFIX_INFORMATION:
1797 r = ndisc_router_process_prefix(link, rt);
1798 break;
1799
1800 case SD_NDISC_OPTION_ROUTE_INFORMATION:
1801 r = ndisc_router_process_route(link, rt);
1802 break;
1803
1804 case SD_NDISC_OPTION_RDNSS:
1805 r = ndisc_router_process_rdnss(link, rt);
1806 break;
1807
1808 case SD_NDISC_OPTION_DNSSL:
1809 r = ndisc_router_process_dnssl(link, rt);
1810 break;
1811 case SD_NDISC_OPTION_CAPTIVE_PORTAL:
1812 if (n_captive_portal > 0) {
1813 if (n_captive_portal == 1)
1814 log_link_notice(link, "Received RA with multiple captive portals, only using the first one.");
1815
1816 n_captive_portal++;
1817 continue;
1818 }
1819 r = ndisc_router_process_captive_portal(link, rt);
1820 if (r > 0)
1821 n_captive_portal++;
1822 break;
1823 case SD_NDISC_OPTION_PREF64:
1824 r = ndisc_router_process_pref64(link, rt);
1825 break;
1826 }
1827 if (r < 0 && r != -EBADMSG)
1828 return r;
1829 }
1830 }
1831
1832 static int ndisc_drop_outdated(Link *link, const struct in6_addr *router, usec_t timestamp_usec) {
1833 bool updated = false;
1834 NDiscDNSSL *dnssl;
1835 NDiscRDNSS *rdnss;
1836 NDiscCaptivePortal *cp;
1837 NDiscPREF64 *p64;
1838 Address *address;
1839 Route *route;
1840 int r, ret = 0;
1841
1842 assert(link);
1843 assert(link->manager);
1844
1845 /* If an address or friends is already assigned, but not valid anymore, then refuse to update it,
1846 * and let's immediately remove it.
1847 * See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by honoring all
1848 * valid lifetimes to improve the reaction of SLAAC to renumbering events.
1849 * See draft-ietf-6man-slaac-renum-02, section 4.2. */
1850
1851 r = drop_default_router(link, router, timestamp_usec);
1852 if (r < 0)
1853 RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to drop outdated default router, ignoring: %m"));
1854
1855 r = ndisc_drop_redirect(link, router, /* remove = */ false);
1856 if (r < 0)
1857 RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to drop outdated Redirect messages, ignoring: %m"));
1858
1859 SET_FOREACH(route, link->manager->routes) {
1860 if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
1861 continue;
1862
1863 if (route->nexthop.ifindex != link->ifindex)
1864 continue;
1865
1866 if (route->lifetime_usec > timestamp_usec)
1867 continue; /* the route is still valid */
1868
1869 if (router && !in6_addr_equal(&route->provider.in6, router))
1870 continue;
1871
1872 r = route_remove_and_cancel(route, link->manager);
1873 if (r < 0)
1874 RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC route, ignoring: %m"));
1875 }
1876
1877 SET_FOREACH(address, link->addresses) {
1878 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
1879 continue;
1880
1881 if (address->lifetime_valid_usec > timestamp_usec)
1882 continue; /* the address is still valid */
1883
1884 if (router && !in6_addr_equal(&address->provider.in6, router))
1885 continue;
1886
1887 r = address_remove_and_cancel(address, link);
1888 if (r < 0)
1889 RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC address, ignoring: %m"));
1890 }
1891
1892 SET_FOREACH(rdnss, link->ndisc_rdnss) {
1893 if (rdnss->lifetime_usec > timestamp_usec)
1894 continue; /* the DNS server is still valid */
1895
1896 if (router && !in6_addr_equal(&rdnss->router, router))
1897 continue;
1898
1899 free(set_remove(link->ndisc_rdnss, rdnss));
1900 updated = true;
1901 }
1902
1903 SET_FOREACH(dnssl, link->ndisc_dnssl) {
1904 if (dnssl->lifetime_usec > timestamp_usec)
1905 continue; /* the DNS domain is still valid */
1906
1907 if (router && !in6_addr_equal(&dnssl->router, router))
1908 continue;
1909
1910 free(set_remove(link->ndisc_dnssl, dnssl));
1911 updated = true;
1912 }
1913
1914 SET_FOREACH(cp, link->ndisc_captive_portals) {
1915 if (cp->lifetime_usec > timestamp_usec)
1916 continue; /* the captive portal is still valid */
1917
1918 if (router && !in6_addr_equal(&cp->router, router))
1919 continue;
1920
1921 ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals, cp));
1922 updated = true;
1923 }
1924
1925 SET_FOREACH(p64, link->ndisc_pref64) {
1926 if (p64->lifetime_usec > timestamp_usec)
1927 continue; /* the pref64 prefix is still valid */
1928
1929 if (router && !in6_addr_equal(&p64->router, router))
1930 continue;
1931
1932 free(set_remove(link->ndisc_pref64, p64));
1933 /* The pref64 prefix is not exported through the state file, hence it is not necessary to set
1934 * the 'updated' flag. */
1935 }
1936
1937 if (updated)
1938 link_dirty(link);
1939
1940 return ret;
1941 }
1942
1943 static int ndisc_setup_expire(Link *link);
1944
1945 static int ndisc_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
1946 Link *link = ASSERT_PTR(userdata);
1947 usec_t now_usec;
1948
1949 assert(link->manager);
1950
1951 assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
1952
1953 (void) ndisc_drop_outdated(link, /* router = */ NULL, now_usec);
1954 (void) ndisc_setup_expire(link);
1955 return 0;
1956 }
1957
1958 static int ndisc_setup_expire(Link *link) {
1959 usec_t lifetime_usec = USEC_INFINITY;
1960 NDiscCaptivePortal *cp;
1961 NDiscDNSSL *dnssl;
1962 NDiscRDNSS *rdnss;
1963 NDiscPREF64 *p64;
1964 Address *address;
1965 Route *route;
1966 int r;
1967
1968 assert(link);
1969 assert(link->manager);
1970
1971 SET_FOREACH(route, link->manager->routes) {
1972 if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
1973 continue;
1974
1975 if (route->nexthop.ifindex != link->ifindex)
1976 continue;
1977
1978 if (!route_exists(route))
1979 continue;
1980
1981 lifetime_usec = MIN(lifetime_usec, route->lifetime_usec);
1982 }
1983
1984 SET_FOREACH(address, link->addresses) {
1985 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
1986 continue;
1987
1988 if (!address_exists(address))
1989 continue;
1990
1991 lifetime_usec = MIN(lifetime_usec, address->lifetime_valid_usec);
1992 }
1993
1994 SET_FOREACH(rdnss, link->ndisc_rdnss)
1995 lifetime_usec = MIN(lifetime_usec, rdnss->lifetime_usec);
1996
1997 SET_FOREACH(dnssl, link->ndisc_dnssl)
1998 lifetime_usec = MIN(lifetime_usec, dnssl->lifetime_usec);
1999
2000 SET_FOREACH(cp, link->ndisc_captive_portals)
2001 lifetime_usec = MIN(lifetime_usec, cp->lifetime_usec);
2002
2003 SET_FOREACH(p64, link->ndisc_pref64)
2004 lifetime_usec = MIN(lifetime_usec, p64->lifetime_usec);
2005
2006 if (lifetime_usec == USEC_INFINITY)
2007 return 0;
2008
2009 r = event_reset_time(link->manager->event, &link->ndisc_expire, CLOCK_BOOTTIME,
2010 lifetime_usec, 0, ndisc_expire_handler, link, 0, "ndisc-expiration", true);
2011 if (r < 0)
2012 return log_link_warning_errno(link, r, "Failed to update expiration timer for ndisc: %m");
2013
2014 return 0;
2015 }
2016
2017 static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
2018 int r;
2019
2020 assert(link);
2021 assert(link->network);
2022
2023 /* Do not start DHCPv6 client if the router lifetime is zero, as the message sent as a signal of
2024 * that the router is e.g. shutting down, revoked, etc,. */
2025 r = sd_ndisc_router_get_lifetime(rt, NULL);
2026 if (r <= 0)
2027 return r;
2028
2029 switch (link->network->ndisc_start_dhcp6_client) {
2030 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO:
2031 return 0;
2032
2033 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES: {
2034 uint64_t flags;
2035
2036 r = sd_ndisc_router_get_flags(rt, &flags);
2037 if (r < 0)
2038 return log_link_warning_errno(link, r, "Failed to get RA flags: %m");
2039
2040 if ((flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) == 0)
2041 return 0;
2042
2043 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags.
2044 * Note, if both "managed" and "other configuration" bits are set, then ignore
2045 * "other configuration" bit. See RFC 4861. */
2046 r = dhcp6_start_on_ra(link, !(flags & ND_RA_FLAG_MANAGED));
2047 break;
2048 }
2049 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS:
2050 /* When IPv6AcceptRA.DHCPv6Client=always, start dhcp6 client in solicit mode
2051 * even if the router flags have neither M nor O flags. */
2052 r = dhcp6_start_on_ra(link, /* information_request = */ false);
2053 break;
2054
2055 default:
2056 assert_not_reached();
2057 }
2058
2059 if (r < 0)
2060 return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
2061
2062 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
2063 return 0;
2064 }
2065
2066 static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
2067 struct in6_addr router;
2068 usec_t timestamp_usec;
2069 bool is_default;
2070 int r;
2071
2072 assert(link);
2073 assert(link->network);
2074 assert(link->manager);
2075 assert(rt);
2076
2077 r = sd_ndisc_router_get_sender_address(rt, &router);
2078 if (r == -ENODATA) {
2079 log_link_debug(link, "Received RA without router address, ignoring.");
2080 return 0;
2081 }
2082 if (r < 0)
2083 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
2084
2085 if (in6_prefix_is_filtered(&router, 128, link->network->ndisc_allow_listed_router, link->network->ndisc_deny_listed_router)) {
2086 if (DEBUG_LOGGING) {
2087 if (!set_isempty(link->network->ndisc_allow_listed_router))
2088 log_link_debug(link, "Router %s is not in allow list, ignoring.", IN6_ADDR_TO_STRING(&router));
2089 else
2090 log_link_debug(link, "Router %s is in deny list, ignoring.", IN6_ADDR_TO_STRING(&router));
2091 }
2092 return 0;
2093 }
2094
2095 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
2096 if (r == -ENODATA) {
2097 log_link_debug(link, "Received RA without timestamp, ignoring.");
2098 return 0;
2099 }
2100 if (r < 0)
2101 return r;
2102
2103 r = ndisc_drop_outdated(link, /* router = */ NULL, timestamp_usec);
2104 if (r < 0)
2105 return r;
2106
2107 r = ndisc_remember_default_router(link, rt);
2108 if (r < 0)
2109 return r;
2110 is_default = r;
2111
2112 r = ndisc_start_dhcp6_client(link, rt);
2113 if (r < 0)
2114 return r;
2115
2116 r = ndisc_router_process_default(link, rt);
2117 if (r < 0)
2118 return r;
2119
2120 r = ndisc_router_process_reachable_time(link, rt);
2121 if (r < 0)
2122 return r;
2123
2124 r = ndisc_router_process_retransmission_time(link, rt);
2125 if (r < 0)
2126 return r;
2127
2128 r = ndisc_router_process_hop_limit(link, rt);
2129 if (r < 0)
2130 return r;
2131
2132 r = ndisc_router_process_mtu(link, rt);
2133 if (r < 0)
2134 return r;
2135
2136 r = ndisc_router_process_options(link, rt);
2137 if (r < 0)
2138 return r;
2139
2140 r = ndisc_setup_expire(link);
2141 if (r < 0)
2142 return r;
2143
2144 if (is_default) {
2145 r = ndisc_router_update_redirect(link);
2146 if (r < 0)
2147 return r;
2148
2149 } else if (sd_ndisc_router_get_lifetime(rt, NULL) <= 0) {
2150 r = ndisc_drop_redirect(link, &router, /* remove = */ true);
2151 if (r < 0)
2152 return r;
2153 }
2154
2155 if (link->ndisc_messages == 0)
2156 link->ndisc_configured = true;
2157 else
2158 log_link_debug(link, "Setting SLAAC addresses and router.");
2159
2160 if (!link->ndisc_configured)
2161 link_set_state(link, LINK_STATE_CONFIGURING);
2162
2163 link_check_ready(link);
2164 return 0;
2165 }
2166
2167 static int ndisc_neighbor_handle_non_router_message(Link *link, sd_ndisc_neighbor *na) {
2168 struct in6_addr address;
2169 int r;
2170
2171 assert(link);
2172 assert(na);
2173
2174 /* Received Neighbor Advertisement message without Router flag. The node might have been a router,
2175 * and now it is not. Let's drop all configurations based on RAs sent from the node. */
2176
2177 r = sd_ndisc_neighbor_get_target_address(na, &address);
2178 if (r == -ENODATA)
2179 return 0;
2180 if (r < 0)
2181 return r;
2182
2183 (void) ndisc_drop_outdated(link, /* router = */ &address, /* timestamp_usec = */ USEC_INFINITY);
2184 return 0;
2185 }
2186
2187 static int ndisc_neighbor_handle_router_message(Link *link, sd_ndisc_neighbor *na) {
2188 struct in6_addr current_address, original_address;
2189 int r;
2190
2191 assert(link);
2192 assert(link->manager);
2193 assert(na);
2194
2195 /* Received Neighbor Advertisement message with Router flag. If the router address is changed, update
2196 * the provider field of configurations. */
2197
2198 r = sd_ndisc_neighbor_get_sender_address(na, &current_address);
2199 if (r == -ENODATA)
2200 return 0;
2201 if (r < 0)
2202 return r;
2203
2204 r = sd_ndisc_neighbor_get_target_address(na, &original_address);
2205 if (r == -ENODATA)
2206 return 0;
2207 if (r < 0)
2208 return r;
2209
2210 if (in6_addr_equal(&current_address, &original_address))
2211 return 0; /* the router address is not changed */
2212
2213 r = update_default_router_address(link, &original_address, &current_address);
2214 if (r < 0)
2215 return r;
2216
2217 r = ndisc_update_redirect_sender(link, &original_address, &current_address);
2218 if (r < 0)
2219 return r;
2220
2221 Route *route;
2222 SET_FOREACH(route, link->manager->routes) {
2223 if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
2224 continue;
2225
2226 if (route->nexthop.ifindex != link->ifindex)
2227 continue;
2228
2229 if (!in6_addr_equal(&route->provider.in6, &original_address))
2230 continue;
2231
2232 route->provider.in6 = current_address;
2233 }
2234
2235 Address *address;
2236 SET_FOREACH(address, link->addresses) {
2237 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
2238 continue;
2239
2240 if (!in6_addr_equal(&address->provider.in6, &original_address))
2241 continue;
2242
2243 address->provider.in6 = current_address;
2244 }
2245
2246 NDiscRDNSS *rdnss;
2247 SET_FOREACH(rdnss, link->ndisc_rdnss) {
2248 if (!in6_addr_equal(&rdnss->router, &original_address))
2249 continue;
2250
2251 rdnss->router = current_address;
2252 }
2253
2254 NDiscDNSSL *dnssl;
2255 SET_FOREACH(dnssl, link->ndisc_dnssl) {
2256 if (!in6_addr_equal(&dnssl->router, &original_address))
2257 continue;
2258
2259 dnssl->router = current_address;
2260 }
2261
2262 NDiscCaptivePortal *cp;
2263 SET_FOREACH(cp, link->ndisc_captive_portals) {
2264 if (!in6_addr_equal(&cp->router, &original_address))
2265 continue;
2266
2267 cp->router = current_address;
2268 }
2269
2270 NDiscPREF64 *p64;
2271 SET_FOREACH(p64, link->ndisc_pref64) {
2272 if (!in6_addr_equal(&p64->router, &original_address))
2273 continue;
2274
2275 p64->router = current_address;
2276 }
2277
2278 return 0;
2279 }
2280
2281 static int ndisc_neighbor_handler(Link *link, sd_ndisc_neighbor *na) {
2282 int r;
2283
2284 assert(link);
2285 assert(na);
2286
2287 r = sd_ndisc_neighbor_is_router(na);
2288 if (r < 0)
2289 return r;
2290 if (r == 0)
2291 r = ndisc_neighbor_handle_non_router_message(link, na);
2292 else
2293 r = ndisc_neighbor_handle_router_message(link, na);
2294 if (r < 0)
2295 return r;
2296
2297 return 0;
2298 }
2299
2300 static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
2301 Link *link = ASSERT_PTR(userdata);
2302 int r;
2303
2304 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
2305 return;
2306
2307 switch (event) {
2308
2309 case SD_NDISC_EVENT_ROUTER:
2310 r = ndisc_router_handler(link, ASSERT_PTR(message));
2311 if (r < 0 && r != -EBADMSG) {
2312 link_enter_failed(link);
2313 return;
2314 }
2315 break;
2316
2317 case SD_NDISC_EVENT_NEIGHBOR:
2318 r = ndisc_neighbor_handler(link, ASSERT_PTR(message));
2319 if (r < 0 && r != -EBADMSG) {
2320 link_enter_failed(link);
2321 return;
2322 }
2323 break;
2324
2325 case SD_NDISC_EVENT_REDIRECT:
2326 r = ndisc_redirect_handler(link, ASSERT_PTR(message));
2327 if (r < 0 && r != -EBADMSG) {
2328 log_link_warning_errno(link, r, "Failed to process Redirect message: %m");
2329 link_enter_failed(link);
2330 return;
2331 }
2332 break;
2333
2334 case SD_NDISC_EVENT_TIMEOUT:
2335 log_link_debug(link, "NDisc handler get timeout event");
2336 if (link->ndisc_messages == 0) {
2337 link->ndisc_configured = true;
2338 link_check_ready(link);
2339 }
2340 break;
2341
2342 default:
2343 log_link_debug(link, "Received unsupported NDisc event, ignoring.");
2344 }
2345 }
2346
2347 static int ndisc_configure(Link *link) {
2348 int r;
2349
2350 assert(link);
2351
2352 if (!link_ndisc_enabled(link))
2353 return 0;
2354
2355 if (link->ndisc)
2356 return -EBUSY; /* Already configured. */
2357
2358 r = sd_ndisc_new(&link->ndisc);
2359 if (r < 0)
2360 return r;
2361
2362 r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
2363 if (r < 0)
2364 return r;
2365
2366 if (link->hw_addr.length == ETH_ALEN) {
2367 r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
2368 if (r < 0)
2369 return r;
2370 }
2371
2372 r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
2373 if (r < 0)
2374 return r;
2375
2376 r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
2377 if (r < 0)
2378 return r;
2379
2380 return 0;
2381 }
2382
2383 int ndisc_start(Link *link) {
2384 int r;
2385
2386 assert(link);
2387
2388 if (!link->ndisc || !link->dhcp6_client)
2389 return 0;
2390
2391 if (!link_has_carrier(link))
2392 return 0;
2393
2394 if (in6_addr_is_null(&link->ipv6ll_address))
2395 return 0;
2396
2397 r = sd_ndisc_set_link_local_address(link->ndisc, &link->ipv6ll_address);
2398 if (r < 0)
2399 return r;
2400
2401 log_link_debug(link, "Discovering IPv6 routers");
2402
2403 r = sd_ndisc_start(link->ndisc);
2404 if (r < 0)
2405 return r;
2406
2407 return 1;
2408 }
2409
2410 static int ndisc_process_request(Request *req, Link *link, void *userdata) {
2411 int r;
2412
2413 assert(link);
2414
2415 if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
2416 return 0;
2417
2418 r = ndisc_configure(link);
2419 if (r < 0)
2420 return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Discovery: %m");
2421
2422 r = ndisc_start(link);
2423 if (r < 0)
2424 return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
2425
2426 log_link_debug(link, "IPv6 Router Discovery is configured%s.",
2427 r > 0 ? " and started" : "");
2428 return 1;
2429 }
2430
2431 int link_request_ndisc(Link *link) {
2432 int r;
2433
2434 assert(link);
2435
2436 if (!link_ndisc_enabled(link))
2437 return 0;
2438
2439 if (link->ndisc)
2440 return 0;
2441
2442 r = link_queue_request(link, REQUEST_TYPE_NDISC, ndisc_process_request, NULL);
2443 if (r < 0)
2444 return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Discovery: %m");
2445
2446 log_link_debug(link, "Requested configuring of the IPv6 Router Discovery.");
2447 return 0;
2448 }
2449
2450 int ndisc_stop(Link *link) {
2451 assert(link);
2452
2453 link->ndisc_expire = sd_event_source_disable_unref(link->ndisc_expire);
2454
2455 return sd_ndisc_stop(link->ndisc);
2456 }
2457
2458
2459 void ndisc_flush(Link *link) {
2460 assert(link);
2461
2462 /* Remove all addresses, routes, RDNSS, DNSSL, and Captive Portal entries, without exception. */
2463 (void) ndisc_drop_outdated(link, /* router = */ NULL, /* timestamp_usec = */ USEC_INFINITY);
2464
2465 link->ndisc_rdnss = set_free(link->ndisc_rdnss);
2466 link->ndisc_dnssl = set_free(link->ndisc_dnssl);
2467 link->ndisc_captive_portals = set_free(link->ndisc_captive_portals);
2468 link->ndisc_pref64 = set_free(link->ndisc_pref64);
2469 link->ndisc_redirects = set_free(link->ndisc_redirects);
2470 link->ndisc_mtu = 0;
2471 }
2472
2473 static const char* const ndisc_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
2474 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
2475 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
2476 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
2477 };
2478
2479 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ndisc_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
2480
2481 DEFINE_CONFIG_PARSE_ENUM(config_parse_ndisc_use_domains, dhcp_use_domains, DHCPUseDomains,
2482 "Failed to parse UseDomains= setting");
2483 DEFINE_CONFIG_PARSE_ENUM(config_parse_ndisc_start_dhcp6_client, ndisc_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
2484 "Failed to parse DHCPv6Client= setting");