]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ndisc.c
network/route-nexthop: use RTA_MULTIPATH when weight is not zero
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
a13c50e7 2/***
810adae9 3 Copyright © 2014 Intel Corporation. All rights reserved.
a13c50e7
TG
4***/
5
23f53b99 6#include <arpa/inet.h>
062c020f
YW
7#include <netinet/icmp6.h>
8#include <linux/if.h>
f4ef1c19 9#include <linux/if_arp.h>
a13c50e7 10
a13c50e7
TG
11#include "sd-ndisc.h"
12
77302468 13#include "event-util.h"
d909e4af 14#include "missing_network.h"
f09a4747 15#include "networkd-address-generation.h"
093e3533 16#include "networkd-address.h"
ca5ad760 17#include "networkd-dhcp6.h"
73854ba1 18#include "networkd-manager.h"
1e7a0e21 19#include "networkd-ndisc.h"
76c5a0f2 20#include "networkd-queue.h"
3b6a3bde 21#include "networkd-route.h"
3b5a4fc6 22#include "networkd-state-file.h"
ac24e418 23#include "string-table.h"
5f506a55 24#include "string-util.h"
51517f9e 25#include "strv.h"
91750028 26#include "sysctl-util.h"
1e7a0e21
LP
27
28#define NDISC_DNSSL_MAX 64U
29#define NDISC_RDNSS_MAX 64U
4df16cd0 30/* Not defined in the RFC, but let's set an upper limit to make not consume much memory.
bf943a9d
YW
31 * This should be safe as typically there should be at most 1 portal per network. */
32#define NDISC_CAPTIVE_PORTAL_MAX 64U
4df16cd0
YW
33/* Neither defined in the RFC. Just for safety. Otherwise, malformed messages can make clients trigger OOM.
34 * Not sure if the threshold is high enough. Let's adjust later if not. */
35#define NDISC_PREF64_MAX 64U
fe307276 36
062c020f
YW
37bool link_ipv6_accept_ra_enabled(Link *link) {
38 assert(link);
39
40 if (!socket_ipv6_is_supported())
41 return false;
42
43 if (link->flags & IFF_LOOPBACK)
44 return false;
45
f4ef1c19
YW
46 if (link->iftype == ARPHRD_CAN)
47 return false;
48
062c020f
YW
49 if (!link->network)
50 return false;
51
bd7e0a3f 52 if (!link_may_have_ipv6ll(link, /* check_multicast = */ true))
062c020f
YW
53 return false;
54
3773eb54
YW
55 assert(link->network->ipv6_accept_ra >= 0);
56 return link->network->ipv6_accept_ra;
57}
58
59void network_adjust_ipv6_accept_ra(Network *network) {
60 assert(network);
61
62 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
63 if (network->ipv6_accept_ra > 0)
f81ac115 64 log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link-local addressing is disabled or not supported. "
3773eb54
YW
65 "Disabling IPv6AcceptRA=.", network->filename);
66 network->ipv6_accept_ra = false;
67 }
68
69 if (network->ipv6_accept_ra < 0)
062c020f 70 /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
3773eb54 71 network->ipv6_accept_ra = !FLAGS_SET(network->ip_forward, ADDRESS_FAMILY_IPV6);
de6b6ff8 72
75d26411
YW
73 /* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
74 * RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
75 if (!set_isempty(network->ndisc_allow_listed_router))
76 network->ndisc_deny_listed_router = set_free_free(network->ndisc_deny_listed_router);
de6b6ff8
SS
77 if (!set_isempty(network->ndisc_allow_listed_prefix))
78 network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
79 if (!set_isempty(network->ndisc_allow_listed_route_prefix))
80 network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix);
062c020f
YW
81}
82
3b6a3bde 83static int ndisc_check_ready(Link *link);
50550722 84
3b6a3bde
YW
85static int ndisc_address_ready_callback(Address *address) {
86 Address *a;
50550722 87
3b6a3bde
YW
88 assert(address);
89 assert(address->link);
50550722 90
3b6a3bde
YW
91 SET_FOREACH(a, address->link->addresses)
92 if (a->source == NETWORK_CONFIG_SOURCE_NDISC)
93 a->callback = NULL;
50550722 94
3b6a3bde
YW
95 return ndisc_check_ready(address->link);
96}
50550722 97
3b6a3bde
YW
98static int ndisc_check_ready(Link *link) {
99 bool found = false, ready = false;
100 Address *address;
50550722 101
3b6a3bde 102 assert(link);
50550722 103
3b6a3bde
YW
104 if (link->ndisc_messages > 0) {
105 log_link_debug(link, "%s(): SLAAC addresses and routes are not set.", __func__);
106 return 0;
107 }
50550722 108
3b6a3bde
YW
109 SET_FOREACH(address, link->addresses) {
110 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
111 continue;
50550722 112
3b6a3bde 113 found = true;
50550722 114
3b6a3bde
YW
115 if (address_is_ready(address)) {
116 ready = true;
117 break;
50550722 118 }
3b6a3bde 119 }
50550722 120
3b6a3bde
YW
121 if (found && !ready) {
122 SET_FOREACH(address, link->addresses)
123 if (address->source == NETWORK_CONFIG_SOURCE_NDISC)
124 address->callback = ndisc_address_ready_callback;
50550722 125
3b6a3bde
YW
126 log_link_debug(link, "%s(): no SLAAC address is ready.", __func__);
127 return 0;
50550722
YW
128 }
129
3b6a3bde
YW
130 link->ndisc_configured = true;
131 log_link_debug(link, "SLAAC addresses and routes set.");
50550722 132
3b6a3bde
YW
133 link_check_ready(link);
134 return 0;
50550722
YW
135}
136
80d62d4f 137static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
3b015d40
TG
138 int r;
139
140 assert(link);
3b015d40 141
2c0b49ba 142 r = route_configure_handler_internal(rtnl, m, link, route, "Could not set NDisc route");
5a07fa9d
YW
143 if (r <= 0)
144 return r;
3b015d40 145
3b6a3bde 146 r = ndisc_check_ready(link);
50550722 147 if (r < 0)
3b6a3bde 148 link_enter_failed(link);
76c5a0f2 149
3b6a3bde 150 return 1;
76c5a0f2
YW
151}
152
6f812d28
YW
153static void ndisc_set_route_priority(Link *link, Route *route) {
154 assert(link);
155 assert(route);
156
157 if (route->priority_set)
158 return; /* explicitly configured. */
159
160 switch (route->pref) {
161 case SD_NDISC_PREFERENCE_LOW:
162 route->priority = link->network->ipv6_accept_ra_route_metric_low;
163 break;
164 case SD_NDISC_PREFERENCE_MEDIUM:
165 route->priority = link->network->ipv6_accept_ra_route_metric_medium;
166 break;
167 case SD_NDISC_PREFERENCE_HIGH:
168 route->priority = link->network->ipv6_accept_ra_route_metric_high;
169 break;
170 default:
171 assert_not_reached();
172 }
173}
174
76c5a0f2
YW
175static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
176 _cleanup_(route_freep) Route *route = in;
3b6a3bde 177 struct in6_addr router;
f141b2c0 178 uint8_t hop_limit = 0;
fc4a7f13 179 uint32_t mtu = 0;
d9a95033 180 bool is_new;
76c5a0f2
YW
181 int r;
182
183 assert(route);
184 assert(link);
f95fb199 185 assert(link->network);
76c5a0f2
YW
186 assert(rt);
187
3b6a3bde
YW
188 r = sd_ndisc_router_get_address(rt, &router);
189 if (r < 0)
190 return r;
191
fc4a7f13
SS
192 if (link->network->ipv6_accept_ra_use_mtu) {
193 r = sd_ndisc_router_get_mtu(rt, &mtu);
194 if (r < 0 && r != -ENODATA)
195 return log_link_warning_errno(link, r, "Failed to get default router MTU from RA: %m");
196 }
197
39713b07 198 if (link->network->ipv6_accept_ra_use_hop_limit) {
f141b2c0
SS
199 r = sd_ndisc_router_get_hop_limit(rt, &hop_limit);
200 if (r < 0 && r != -ENODATA)
201 return log_link_warning_errno(link, r, "Failed to get default router hop limit from RA: %m");
93e583aa 202 }
f141b2c0 203
3b6a3bde
YW
204 route->source = NETWORK_CONFIG_SOURCE_NDISC;
205 route->provider.in6 = router;
429dc05a
YW
206 if (!route->table_set)
207 route->table = link_get_ipv6_accept_ra_route_table(link);
6f812d28 208 ndisc_set_route_priority(link, route);
429dc05a
YW
209 if (!route->protocol_set)
210 route->protocol = RTPROT_RA;
ebf4fa1e
YW
211 r = route_metric_set(&route->metric, RTAX_MTU, mtu);
212 if (r < 0)
213 return r;
214 r = route_metric_set(&route->metric, RTAX_HOPLIMIT, hop_limit);
215 if (r < 0)
216 return r;
217 r = route_metric_set(&route->metric, RTAX_QUICKACK, link->network->ipv6_accept_ra_quickack);
218 if (r < 0)
219 return r;
f141b2c0 220
d9a95033
YW
221 is_new = route_get(NULL, link, route, NULL) < 0;
222
223 r = link_request_route(link, TAKE_PTR(route), true, &link->ndisc_messages,
224 ndisc_route_handler, NULL);
225 if (r < 0)
226 return r;
227 if (r > 0 && is_new)
3b6a3bde 228 link->ndisc_configured = false;
50550722 229
d9a95033 230 return 0;
50550722
YW
231}
232
80d62d4f 233static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
73854ba1
YW
234 int r;
235
236 assert(link);
73854ba1 237
5a07fa9d
YW
238 r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address");
239 if (r <= 0)
240 return r;
73854ba1 241
3b6a3bde 242 r = ndisc_check_ready(link);
50550722 243 if (r < 0)
3b6a3bde 244 link_enter_failed(link);
69203fba 245
3b6a3bde 246 return 1;
69203fba
YW
247}
248
76c5a0f2 249static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
ebd96906 250 _cleanup_(address_unrefp) Address *address = in;
3b6a3bde 251 struct in6_addr router;
d9a95033 252 bool is_new;
76c5a0f2
YW
253 int r;
254
255 assert(address);
256 assert(link);
257 assert(rt);
258
3b6a3bde
YW
259 r = sd_ndisc_router_get_address(rt, &router);
260 if (r < 0)
76c5a0f2
YW
261 return r;
262
3b6a3bde
YW
263 address->source = NETWORK_CONFIG_SOURCE_NDISC;
264 address->provider.in6 = router;
76c5a0f2 265
4b3590c3
TM
266 r = free_and_strdup_warn(&address->netlabel, link->network->ndisc_netlabel);
267 if (r < 0)
268 return r;
269
d9a95033
YW
270 is_new = address_get(link, address, NULL) < 0;
271
f60e6558 272 r = link_request_address(link, address, &link->ndisc_messages,
d9a95033
YW
273 ndisc_address_handler, NULL);
274 if (r < 0)
275 return r;
276 if (r > 0 && is_new)
3b6a3bde 277 link->ndisc_configured = false;
3b6a3bde 278
d9a95033 279 return 0;
76c5a0f2
YW
280}
281
d5017c84 282static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
6197db53 283 usec_t lifetime_usec;
b8ce3b44 284 struct in6_addr gateway;
1e7a0e21 285 unsigned preference;
13e8a49a 286 int r;
3b015d40 287
3b015d40 288 assert(link);
610c0db1 289 assert(link->network);
1e7a0e21 290 assert(rt);
3b015d40 291
610c0db1
YW
292 if (!link->network->ipv6_accept_ra_use_gateway &&
293 hashmap_isempty(link->network->routes_by_section))
294 return 0;
295
6197db53 296 r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
d5017c84 297 if (r < 0)
2c5bca17 298 return log_link_warning_errno(link, r, "Failed to get gateway lifetime from RA: %m");
d5017c84 299
b8ce3b44 300 r = sd_ndisc_router_get_address(rt, &gateway);
d5017c84 301 if (r < 0)
2c5bca17 302 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
1e7a0e21 303
5d003031 304 if (link_get_ipv6_address(link, &gateway, 0, NULL) >= 0) {
84dbb3fd 305 if (DEBUG_LOGGING)
5eec0a08 306 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
84dbb3fd 307 IN6_ADDR_TO_STRING(&gateway));
5eec0a08 308 return 0;
ce2ea782 309 }
6d7c7615 310
1e7a0e21 311 r = sd_ndisc_router_get_preference(rt, &preference);
d5017c84 312 if (r < 0)
2c5bca17 313 return log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21 314
610c0db1
YW
315 if (link->network->ipv6_accept_ra_use_gateway) {
316 _cleanup_(route_freep) Route *route = NULL;
1e7a0e21 317
610c0db1
YW
318 r = route_new(&route);
319 if (r < 0)
320 return log_oom();
1e7a0e21 321
610c0db1
YW
322 route->family = AF_INET6;
323 route->pref = preference;
054b8c28
YW
324 route->nexthop.family = AF_INET6;
325 route->nexthop.gw.in6 = gateway;
610c0db1 326 route->lifetime_usec = lifetime_usec;
610c0db1
YW
327
328 r = ndisc_request_route(TAKE_PTR(route), link, rt);
329 if (r < 0)
2c5bca17 330 return log_link_warning_errno(link, r, "Could not request default route: %m");
610c0db1 331 }
d5017c84 332
1985c54f 333 Route *route_gw;
2a54a044 334 HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
610c0db1
YW
335 _cleanup_(route_freep) Route *route = NULL;
336
1a3a6309 337 if (!route_gw->gateway_from_dhcp_or_ra)
1985c54f
YW
338 continue;
339
054b8c28 340 if (route_gw->nexthop.family != AF_INET6)
1985c54f
YW
341 continue;
342
76c5a0f2
YW
343 r = route_dup(route_gw, &route);
344 if (r < 0)
345 return r;
346
054b8c28 347 route->nexthop.gw.in6 = gateway;
76c5a0f2
YW
348 if (!route->pref_set)
349 route->pref = preference;
91fc5135 350 route->lifetime_usec = lifetime_usec;
76c5a0f2
YW
351
352 r = ndisc_request_route(TAKE_PTR(route), link, rt);
13e8a49a 353 if (r < 0)
2c5bca17 354 return log_link_warning_errno(link, r, "Could not request gateway: %m");
1985c54f
YW
355 }
356
0f9a2b80
YW
357 return 0;
358}
91750028 359
0f9a2b80 360static int ndisc_router_process_icmp6_ratelimit(Link *link, sd_ndisc_router *rt) {
be89a76a 361 usec_t icmp6_ratelimit, msec;
0f9a2b80 362 int r;
91750028 363
0f9a2b80
YW
364 assert(link);
365 assert(link->network);
366 assert(rt);
91750028 367
0f9a2b80
YW
368 if (!link->network->ipv6_accept_ra_use_icmp6_ratelimit)
369 return 0;
370
371 r = sd_ndisc_router_get_icmp6_ratelimit(rt, &icmp6_ratelimit);
372 if (r < 0) {
373 log_link_debug(link, "Failed to get ICMP6 ratelimit from RA, ignoring: %m");
374 return 0;
91750028
SS
375 }
376
be89a76a 377 /* We do not allow 0 here. */
6197db53 378 if (!timestamp_is_set(icmp6_ratelimit))
0f9a2b80
YW
379 return 0;
380
be89a76a
YW
381 msec = DIV_ROUND_UP(icmp6_ratelimit, USEC_PER_MSEC);
382 if (msec <= 0 || msec > INT_MAX)
383 return 0;
384
6197db53
YW
385 /* Limit the maximal rates for sending ICMPv6 packets. 0 to disable any limiting, otherwise the
386 * minimal space between responses in milliseconds. Default: 1000. */
be89a76a 387 r = sysctl_write_ip_property_int(AF_INET6, NULL, "icmp/ratelimit", (int) msec);
0f9a2b80
YW
388 if (r < 0)
389 log_link_warning_errno(link, r, "Failed to apply ICMP6 ratelimit, ignoring: %m");
390
d5017c84 391 return 0;
1e7a0e21
LP
392}
393
d5017c84 394static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
6197db53 395 usec_t lifetime_valid_usec, lifetime_preferred_usec;
d207581f 396 _cleanup_set_free_ Set *addresses = NULL;
151b8ea3 397 struct in6_addr prefix, *a;
1e7a0e21
LP
398 unsigned prefixlen;
399 int r;
400
401 assert(link);
fbdda4bb 402 assert(link->network);
1e7a0e21
LP
403 assert(rt);
404
fbdda4bb
YW
405 if (!link->network->ipv6_accept_ra_use_autonomous_prefix)
406 return 0;
407
151b8ea3
YW
408 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
409 if (r < 0)
2c5bca17 410 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
151b8ea3 411
1e7a0e21 412 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84 413 if (r < 0)
2c5bca17 414 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21 415
868bd1aa 416 /* ndisc_generate_addresses() below requires the prefix length <= 64. */
151b8ea3 417 if (prefixlen > 64) {
c71384a9
ZJS
418 log_link_debug(link, "Prefix is longer than 64, ignoring autonomous prefix %s.",
419 IN6_ADDR_PREFIX_TO_STRING(&prefix, prefixlen));
151b8ea3
YW
420 return 0;
421 }
422
6197db53 423 r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_valid_usec);
d5017c84 424 if (r < 0)
2c5bca17 425 return log_link_warning_errno(link, r, "Failed to get prefix valid lifetime: %m");
1e7a0e21 426
6197db53 427 r = sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_preferred_usec);
d5017c84 428 if (r < 0)
2c5bca17 429 return log_link_warning_errno(link, r, "Failed to get prefix preferred lifetime: %m");
3b015d40 430
92bdc3ff 431 /* The preferred lifetime is never greater than the valid lifetime */
6197db53 432 if (lifetime_preferred_usec > lifetime_valid_usec)
d5017c84 433 return 0;
92bdc3ff 434
868bd1aa 435 r = ndisc_generate_addresses(link, &prefix, prefixlen, &addresses);
5f506a55 436 if (r < 0)
2c5bca17 437 return log_link_warning_errno(link, r, "Failed to generate SLAAC addresses: %m");
c24c83dc 438
90e74a66 439 SET_FOREACH(a, addresses) {
ebd96906 440 _cleanup_(address_unrefp) Address *address = NULL;
13e8a49a 441
76c5a0f2
YW
442 r = address_new(&address);
443 if (r < 0)
444 return log_oom();
445
446 address->family = AF_INET6;
25db3aea 447 address->in_addr.in6 = *a;
76c5a0f2
YW
448 address->prefixlen = prefixlen;
449 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
16bc8635
YW
450 address->lifetime_valid_usec = lifetime_valid_usec;
451 address->lifetime_preferred_usec = lifetime_preferred_usec;
fe841414 452
76c5a0f2 453 r = ndisc_request_address(TAKE_PTR(address), link, rt);
13e8a49a 454 if (r < 0)
2c5bca17 455 return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
3b015d40 456 }
d5017c84
YW
457
458 return 0;
3b015d40
TG
459}
460
d5017c84 461static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
8e766630 462 _cleanup_(route_freep) Route *route = NULL;
f44eebd1 463 unsigned prefixlen, preference;
6197db53 464 usec_t lifetime_usec;
167c7ae5 465 struct in6_addr prefix;
3b015d40
TG
466 int r;
467
3b015d40 468 assert(link);
fbdda4bb 469 assert(link->network);
1e7a0e21 470 assert(rt);
3b015d40 471
fbdda4bb
YW
472 if (!link->network->ipv6_accept_ra_use_onlink_prefix)
473 return 0;
474
6197db53 475 r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
09845af5 476 if (r < 0)
2c5bca17 477 return log_link_warning_errno(link, r, "Failed to get prefix lifetime: %m");
09845af5 478
167c7ae5
YW
479 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
480 if (r < 0)
2c5bca17 481 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
167c7ae5 482
1e7a0e21 483 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84 484 if (r < 0)
2c5bca17 485 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21 486
f44eebd1
SS
487 /* Prefix Information option does not have preference, hence we use the 'main' preference here */
488 r = sd_ndisc_router_get_preference(rt, &preference);
489 if (r < 0)
490 log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
491
3b015d40 492 r = route_new(&route);
d5017c84 493 if (r < 0)
13e8a49a 494 return log_oom();
3b015d40 495
3b015d40 496 route->family = AF_INET6;
167c7ae5 497 route->dst.in6 = prefix;
3b015d40 498 route->dst_prefixlen = prefixlen;
f44eebd1 499 route->pref = preference;
6197db53 500 route->lifetime_usec = lifetime_usec;
3b015d40 501
76c5a0f2 502 r = ndisc_request_route(TAKE_PTR(route), link, rt);
13e8a49a 503 if (r < 0)
2c5bca17 504 return log_link_warning_errno(link, r, "Could not request prefix route: %m");
d5017c84
YW
505
506 return 0;
3b015d40
TG
507}
508
fbdda4bb
YW
509static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt) {
510 unsigned prefixlen;
511 struct in6_addr a;
512 uint8_t flags;
513 int r;
514
515 assert(link);
516 assert(link->network);
517 assert(rt);
518
519 r = sd_ndisc_router_prefix_get_address(rt, &a);
520 if (r < 0)
2c5bca17 521 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
fbdda4bb 522
a115c60e
YW
523 /* RFC 4861 Section 4.6.2:
524 * A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
525 * a prefix option. */
526 if (in6_addr_is_link_local(&a)) {
527 log_link_debug(link, "Received link-local prefix, ignoring autonomous prefix.");
528 return 0;
529 }
530
fbdda4bb
YW
531 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
532 if (r < 0)
2c5bca17 533 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
fbdda4bb
YW
534
535 if (in6_prefix_is_filtered(&a, prefixlen, link->network->ndisc_allow_listed_prefix, link->network->ndisc_deny_listed_prefix)) {
c71384a9
ZJS
536 if (DEBUG_LOGGING)
537 log_link_debug(link, "Prefix '%s' is %s, ignoring",
538 !set_isempty(link->network->ndisc_allow_listed_prefix) ? "not in allow list"
539 : "in deny list",
540 IN6_ADDR_PREFIX_TO_STRING(&a, prefixlen));
fbdda4bb
YW
541 return 0;
542 }
543
544 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
545 if (r < 0)
2c5bca17 546 return log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
fbdda4bb
YW
547
548 if (FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK)) {
549 r = ndisc_router_process_onlink_prefix(link, rt);
550 if (r < 0)
551 return r;
552 }
553
554 if (FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO)) {
555 r = ndisc_router_process_autonomous_prefix(link, rt);
556 if (r < 0)
557 return r;
558 }
559
560 return 0;
561}
562
d5017c84 563static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
8e766630 564 _cleanup_(route_freep) Route *route = NULL;
1e7a0e21 565 unsigned preference, prefixlen;
91fc5135 566 struct in6_addr gateway, dst;
6197db53 567 usec_t lifetime_usec;
7a695d8e 568 int r;
a13c50e7
TG
569
570 assert(link);
a13c50e7 571
610c0db1
YW
572 if (!link->network->ipv6_accept_ra_use_route_prefix)
573 return 0;
574
6197db53 575 r = sd_ndisc_router_route_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
d5017c84 576 if (r < 0)
2c5bca17 577 return log_link_warning_errno(link, r, "Failed to get route lifetime from RA: %m");
d5017c84 578
b8ce3b44 579 r = sd_ndisc_router_route_get_address(rt, &dst);
d5017c84 580 if (r < 0)
2c5bca17 581 return log_link_warning_errno(link, r, "Failed to get route destination address: %m");
3b015d40 582
c995fa02
YW
583 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
584 if (r < 0)
2c5bca17 585 return log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
c995fa02 586
80bfc3b9
YW
587 if (in6_addr_is_null(&dst) && prefixlen == 0) {
588 log_link_debug(link, "Route prefix is ::/0, ignoring");
589 return 0;
590 }
591
c71384a9
ZJS
592 if (in6_prefix_is_filtered(&dst, prefixlen,
593 link->network->ndisc_allow_listed_route_prefix,
594 link->network->ndisc_deny_listed_route_prefix)) {
16c89e64 595
c71384a9
ZJS
596 if (DEBUG_LOGGING)
597 log_link_debug(link, "Route prefix %s is %s, ignoring",
598 !set_isempty(link->network->ndisc_allow_listed_route_prefix) ? "not in allow list"
599 : "in deny list",
600 IN6_ADDR_PREFIX_TO_STRING(&dst, prefixlen));
16c89e64
DP
601 return 0;
602 }
603
b8ce3b44 604 r = sd_ndisc_router_get_address(rt, &gateway);
19e334bd 605 if (r < 0)
2c5bca17 606 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
19e334bd 607
5d003031 608 if (link_get_ipv6_address(link, &gateway, 0, NULL) >= 0) {
84dbb3fd
ZJS
609 if (DEBUG_LOGGING)
610 log_link_debug(link, "Advertised route gateway %s is local to the link, ignoring route",
611 IN6_ADDR_TO_STRING(&gateway));
22101916
DP
612 return 0;
613 }
614
1e7a0e21 615 r = sd_ndisc_router_route_get_preference(rt, &preference);
4b68f708 616 if (r == -EOPNOTSUPP) {
3912d49d
SS
617 log_link_debug_errno(link, r, "Received route prefix with unsupported preference, ignoring: %m");
618 return 0;
619 }
d5017c84 620 if (r < 0)
2c5bca17 621 return log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21 622
3b015d40 623 r = route_new(&route);
d5017c84 624 if (r < 0)
13e8a49a 625 return log_oom();
3b015d40 626
3b015d40 627 route->family = AF_INET6;
1e7a0e21 628 route->pref = preference;
054b8c28
YW
629 route->nexthop.gw.in6 = gateway;
630 route->nexthop.family = AF_INET6;
b8ce3b44 631 route->dst.in6 = dst;
1e7a0e21 632 route->dst_prefixlen = prefixlen;
6197db53 633 route->lifetime_usec = lifetime_usec;
3b015d40 634
76c5a0f2 635 r = ndisc_request_route(TAKE_PTR(route), link, rt);
13e8a49a 636 if (r < 0)
2c5bca17 637 return log_link_warning_errno(link, r, "Could not request additional route: %m");
d5017c84
YW
638
639 return 0;
9d96e6c3 640}
a13c50e7 641
7a08d314 642static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
c01a5c05 643 siphash24_compress_typesafe(x->address, state);
1e7a0e21
LP
644}
645
7a08d314 646static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
1e7a0e21
LP
647 return memcmp(&a->address, &b->address, sizeof(a->address));
648}
649
b0b97766
YW
650DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
651 ndisc_rdnss_hash_ops,
652 NDiscRDNSS,
653 ndisc_rdnss_hash_func,
654 ndisc_rdnss_compare_func,
655 free);
1e7a0e21 656
d5017c84 657static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
6197db53 658 usec_t lifetime_usec;
1e7a0e21 659 const struct in6_addr *a;
50550722 660 struct in6_addr router;
8aba7b83 661 bool updated = false, logged_about_too_many = false;
13e8a49a 662 int n, r;
1e7a0e21
LP
663
664 assert(link);
ad0b2df6 665 assert(link->network);
1e7a0e21
LP
666 assert(rt);
667
ad0b2df6
YW
668 if (!link->network->ipv6_accept_ra_use_dns)
669 return 0;
670
50550722
YW
671 r = sd_ndisc_router_get_address(rt, &router);
672 if (r < 0)
2c5bca17 673 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
50550722 674
6197db53 675 r = sd_ndisc_router_rdnss_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
d5017c84 676 if (r < 0)
2c5bca17 677 return log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
1e7a0e21
LP
678
679 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
d5017c84 680 if (n < 0)
2c5bca17 681 return log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
1e7a0e21 682
b0b97766
YW
683 for (int j = 0; j < n; j++) {
684 _cleanup_free_ NDiscRDNSS *x = NULL;
3b6a3bde 685 NDiscRDNSS *rdnss, d = {
b0b97766
YW
686 .address = a[j],
687 };
1e7a0e21 688
af2aea8b
YW
689 if (lifetime_usec == 0) {
690 /* The entry is outdated. */
691 free(set_remove(link->ndisc_rdnss, &d));
692 updated = true;
693 continue;
694 }
695
b0b97766
YW
696 rdnss = set_get(link->ndisc_rdnss, &d);
697 if (rdnss) {
50550722 698 rdnss->router = router;
03ccc4b4 699 rdnss->lifetime_usec = lifetime_usec;
1e7a0e21
LP
700 continue;
701 }
702
8aba7b83
YW
703 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
704 if (!logged_about_too_many)
705 log_link_warning(link, "Too many RDNSS records per link. Only first %u records will be used.", NDISC_RDNSS_MAX);
706 logged_about_too_many = true;
707 continue;
708 }
709
d5017c84
YW
710 x = new(NDiscRDNSS, 1);
711 if (!x)
712 return log_oom();
1e7a0e21 713
d5017c84 714 *x = (NDiscRDNSS) {
b0b97766 715 .address = a[j],
50550722 716 .router = router,
03ccc4b4 717 .lifetime_usec = lifetime_usec,
d5017c84 718 };
1e7a0e21 719
35e601d4 720 r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
d5017c84
YW
721 if (r < 0)
722 return log_oom();
1e7a0e21 723 assert(r > 0);
9092113d
YW
724
725 updated = true;
1e7a0e21 726 }
d5017c84 727
9092113d
YW
728 if (updated)
729 link_dirty(link);
730
d5017c84 731 return 0;
1e7a0e21
LP
732}
733
7a08d314 734static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
f281fc1e 735 siphash24_compress_string(NDISC_DNSSL_DOMAIN(x), state);
1e7a0e21
LP
736}
737
7a08d314 738static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
1e7a0e21
LP
739 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
740}
741
b0b97766
YW
742DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
743 ndisc_dnssl_hash_ops,
744 NDiscDNSSL,
745 ndisc_dnssl_hash_func,
746 ndisc_dnssl_compare_func,
747 free);
1e7a0e21 748
13e8a49a 749static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
1e7a0e21 750 _cleanup_strv_free_ char **l = NULL;
6197db53 751 usec_t lifetime_usec;
50550722 752 struct in6_addr router;
8aba7b83 753 bool updated = false, logged_about_too_many = false;
1e7a0e21
LP
754 int r;
755
756 assert(link);
ad0b2df6 757 assert(link->network);
1e7a0e21
LP
758 assert(rt);
759
ad0b2df6
YW
760 if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_NO)
761 return 0;
762
50550722
YW
763 r = sd_ndisc_router_get_address(rt, &router);
764 if (r < 0)
2c5bca17 765 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
50550722 766
6197db53 767 r = sd_ndisc_router_dnssl_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
13e8a49a 768 if (r < 0)
2c5bca17 769 return log_link_warning_errno(link, r, "Failed to get DNSSL lifetime: %m");
1e7a0e21
LP
770
771 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
13e8a49a 772 if (r < 0)
2c5bca17 773 return log_link_warning_errno(link, r, "Failed to get DNSSL addresses: %m");
1e7a0e21 774
b0b97766
YW
775 STRV_FOREACH(j, l) {
776 _cleanup_free_ NDiscDNSSL *s = NULL;
3b6a3bde 777 NDiscDNSSL *dnssl;
1e7a0e21 778
b0b97766
YW
779 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
780 if (!s)
781 return log_oom();
1e7a0e21 782
b0b97766 783 strcpy(NDISC_DNSSL_DOMAIN(s), *j);
1e7a0e21 784
af2aea8b
YW
785 if (lifetime_usec == 0) {
786 /* The entry is outdated. */
787 free(set_remove(link->ndisc_dnssl, s));
788 updated = true;
789 continue;
790 }
791
b0b97766
YW
792 dnssl = set_get(link->ndisc_dnssl, s);
793 if (dnssl) {
50550722 794 dnssl->router = router;
03ccc4b4 795 dnssl->lifetime_usec = lifetime_usec;
1e7a0e21
LP
796 continue;
797 }
798
8aba7b83
YW
799 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
800 if (!logged_about_too_many)
801 log_link_warning(link, "Too many DNSSL records per link. Only first %u records will be used.", NDISC_DNSSL_MAX);
802 logged_about_too_many = true;
803 continue;
804 }
805
50550722 806 s->router = router;
03ccc4b4 807 s->lifetime_usec = lifetime_usec;
1e7a0e21 808
35e601d4 809 r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
13e8a49a
YW
810 if (r < 0)
811 return log_oom();
1e7a0e21 812 assert(r > 0);
9092113d
YW
813
814 updated = true;
1e7a0e21 815 }
13e8a49a 816
9092113d
YW
817 if (updated)
818 link_dirty(link);
819
13e8a49a 820 return 0;
1e7a0e21
LP
821}
822
64de00c4
YW
823static NDiscCaptivePortal* ndisc_captive_portal_free(NDiscCaptivePortal *x) {
824 if (!x)
825 return NULL;
826
827 free(x->captive_portal);
828 return mfree(x);
829}
830
831DEFINE_TRIVIAL_CLEANUP_FUNC(NDiscCaptivePortal*, ndisc_captive_portal_free);
832
833static void ndisc_captive_portal_hash_func(const NDiscCaptivePortal *x, struct siphash *state) {
834 assert(x);
835 siphash24_compress_string(x->captive_portal, state);
836}
837
838static int ndisc_captive_portal_compare_func(const NDiscCaptivePortal *a, const NDiscCaptivePortal *b) {
839 assert(a);
840 assert(b);
841 return strcmp_ptr(a->captive_portal, b->captive_portal);
842}
843
844DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
845 ndisc_captive_portal_hash_ops,
846 NDiscCaptivePortal,
847 ndisc_captive_portal_hash_func,
848 ndisc_captive_portal_compare_func,
535134bc 849 ndisc_captive_portal_free);
64de00c4
YW
850
851static int ndisc_router_process_captive_portal(Link *link, sd_ndisc_router *rt) {
852 _cleanup_(ndisc_captive_portal_freep) NDiscCaptivePortal *new_entry = NULL;
853 _cleanup_free_ char *captive_portal = NULL;
6197db53 854 usec_t lifetime_usec;
64de00c4
YW
855 NDiscCaptivePortal *exist;
856 struct in6_addr router;
64de00c4
YW
857 const char *uri;
858 size_t len;
859 int r;
860
861 assert(link);
862 assert(link->network);
863 assert(rt);
864
865 if (!link->network->ipv6_accept_ra_use_captive_portal)
866 return 0;
867
868 r = sd_ndisc_router_get_address(rt, &router);
869 if (r < 0)
870 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
871
218f3738
YW
872 /* RFC 4861 section 4.2. states that the lifetime in the message header should be used only for the
873 * default gateway, but the captive portal option does not have a lifetime field, hence, we use the
874 * main lifetime for the portal. */
6197db53 875 r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
64de00c4
YW
876 if (r < 0)
877 return log_link_warning_errno(link, r, "Failed to get lifetime of RA message: %m");
878
64de00c4
YW
879 r = sd_ndisc_router_captive_portal_get_uri(rt, &uri, &len);
880 if (r < 0)
881 return log_link_warning_errno(link, r, "Failed to get captive portal from RA: %m");
882
883 if (len == 0)
6df82d12 884 return log_link_warning_errno(link, SYNTHETIC_ERRNO(EBADMSG), "Received empty captive portal, ignoring.");
64de00c4
YW
885
886 r = make_cstring(uri, len, MAKE_CSTRING_REFUSE_TRAILING_NUL, &captive_portal);
887 if (r < 0)
888 return log_link_warning_errno(link, r, "Failed to convert captive portal URI: %m");
889
890 if (!in_charset(captive_portal, URI_VALID))
6df82d12 891 return log_link_warning_errno(link, SYNTHETIC_ERRNO(EBADMSG), "Received invalid captive portal, ignoring.");
64de00c4 892
218f3738
YW
893 if (lifetime_usec == 0) {
894 /* Drop the portal with zero lifetime. */
895 ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals,
896 &(NDiscCaptivePortal) {
897 .captive_portal = captive_portal,
898 }));
899 return 0;
900 }
901
902 exist = set_get(link->ndisc_captive_portals,
903 &(NDiscCaptivePortal) {
904 .captive_portal = captive_portal,
905 });
64de00c4
YW
906 if (exist) {
907 /* update existing entry */
908 exist->router = router;
909 exist->lifetime_usec = lifetime_usec;
6df82d12 910 return 1;
64de00c4
YW
911 }
912
bf943a9d
YW
913 if (set_size(link->ndisc_captive_portals) >= NDISC_CAPTIVE_PORTAL_MAX) {
914 NDiscCaptivePortal *c, *target = NULL;
915
916 /* Find the portal who has the minimal lifetime and drop it to store new one. */
917 SET_FOREACH(c, link->ndisc_captive_portals)
918 if (!target || c->lifetime_usec < target->lifetime_usec)
919 target = c;
920
921 assert(target);
922 assert(set_remove(link->ndisc_captive_portals, target) == target);
923 ndisc_captive_portal_free(target);
924 }
925
64de00c4
YW
926 new_entry = new(NDiscCaptivePortal, 1);
927 if (!new_entry)
928 return log_oom();
929
930 *new_entry = (NDiscCaptivePortal) {
931 .router = router,
932 .lifetime_usec = lifetime_usec,
933 .captive_portal = TAKE_PTR(captive_portal),
934 };
935
936 r = set_ensure_put(&link->ndisc_captive_portals, &ndisc_captive_portal_hash_ops, new_entry);
937 if (r < 0)
938 return log_oom();
939 assert(r > 0);
940 TAKE_PTR(new_entry);
941
942 link_dirty(link);
6df82d12 943 return 1;
64de00c4
YW
944}
945
6e8f5e4c
SS
946static void ndisc_pref64_hash_func(const NDiscPREF64 *x, struct siphash *state) {
947 assert(x);
948
c01a5c05
YW
949 siphash24_compress_typesafe(x->prefix_len, state);
950 siphash24_compress_typesafe(x->prefix, state);
6e8f5e4c
SS
951}
952
953static int ndisc_pref64_compare_func(const NDiscPREF64 *a, const NDiscPREF64 *b) {
954 int r;
955
956 assert(a);
957 assert(b);
958
959 r = CMP(a->prefix_len, b->prefix_len);
960 if (r != 0)
961 return r;
962
963 return memcmp(&a->prefix, &b->prefix, sizeof(a->prefix));
964}
965
966DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
967 ndisc_pref64_hash_ops,
968 NDiscPREF64,
969 ndisc_pref64_hash_func,
970 ndisc_pref64_compare_func,
971 mfree);
972
973static int ndisc_router_process_pref64(Link *link, sd_ndisc_router *rt) {
974 _cleanup_free_ NDiscPREF64 *new_entry = NULL;
6197db53 975 usec_t lifetime_usec;
6e8f5e4c 976 struct in6_addr a, router;
6e8f5e4c
SS
977 unsigned prefix_len;
978 NDiscPREF64 *exist;
979 int r;
980
981 assert(link);
982 assert(link->network);
983 assert(rt);
984
985 if (!link->network->ipv6_accept_ra_use_pref64)
986 return 0;
987
988 r = sd_ndisc_router_get_address(rt, &router);
989 if (r < 0)
990 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
991
992 r = sd_ndisc_router_prefix64_get_prefix(rt, &a);
993 if (r < 0)
994 return log_link_warning_errno(link, r, "Failed to get pref64 prefix: %m");
995
996 r = sd_ndisc_router_prefix64_get_prefixlen(rt, &prefix_len);
997 if (r < 0)
998 return log_link_warning_errno(link, r, "Failed to get pref64 prefix length: %m");
999
6197db53 1000 r = sd_ndisc_router_prefix64_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
6e8f5e4c
SS
1001 if (r < 0)
1002 return log_link_warning_errno(link, r, "Failed to get pref64 prefix lifetime: %m");
1003
6e8f5e4c
SS
1004 if (lifetime_usec == 0) {
1005 free(set_remove(link->ndisc_pref64,
1006 &(NDiscPREF64) {
1007 .prefix = a,
1008 .prefix_len = prefix_len
1009 }));
1010 return 0;
1011 }
1012
1013 exist = set_get(link->ndisc_pref64,
1014 &(NDiscPREF64) {
1015 .prefix = a,
1016 .prefix_len = prefix_len
1017 });
1018 if (exist) {
1019 /* update existing entry */
1020 exist->router = router;
1021 exist->lifetime_usec = lifetime_usec;
1022 return 0;
1023 }
1024
4df16cd0
YW
1025 if (set_size(link->ndisc_pref64) >= NDISC_PREF64_MAX) {
1026 log_link_debug(link, "Too many PREF64 records received. Only first %u records will be used.", NDISC_PREF64_MAX);
1027 return 0;
1028 }
1029
6e8f5e4c
SS
1030 new_entry = new(NDiscPREF64, 1);
1031 if (!new_entry)
1032 return log_oom();
1033
1034 *new_entry = (NDiscPREF64) {
1035 .router = router,
1036 .lifetime_usec = lifetime_usec,
1037 .prefix = a,
1038 .prefix_len = prefix_len,
1039 };
1040
1041 r = set_ensure_put(&link->ndisc_pref64, &ndisc_pref64_hash_ops, new_entry);
1042 if (r < 0)
1043 return log_oom();
1044
1045 assert(r > 0);
1046 TAKE_PTR(new_entry);
1047
1048 return 0;
1049}
1050
e8c9b5b0 1051static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
6df82d12 1052 size_t n_captive_portal = 0;
fbdda4bb
YW
1053 int r;
1054
1e7a0e21 1055 assert(link);
55d3fdcf 1056 assert(link->network);
1e7a0e21
LP
1057 assert(rt);
1058
fbdda4bb 1059 for (r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
1e7a0e21
LP
1060 uint8_t type;
1061
e8c9b5b0 1062 if (r < 0)
2c5bca17 1063 return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
1e7a0e21 1064 if (r == 0) /* EOF */
13e8a49a 1065 return 0;
1e7a0e21
LP
1066
1067 r = sd_ndisc_router_option_get_type(rt, &type);
e8c9b5b0 1068 if (r < 0)
2c5bca17 1069 return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
1e7a0e21
LP
1070
1071 switch (type) {
fbdda4bb
YW
1072 case SD_NDISC_OPTION_PREFIX_INFORMATION:
1073 r = ndisc_router_process_prefix(link, rt);
1e7a0e21 1074 break;
1e7a0e21
LP
1075
1076 case SD_NDISC_OPTION_ROUTE_INFORMATION:
13e8a49a 1077 r = ndisc_router_process_route(link, rt);
1e7a0e21
LP
1078 break;
1079
1080 case SD_NDISC_OPTION_RDNSS:
ad0b2df6 1081 r = ndisc_router_process_rdnss(link, rt);
1e7a0e21
LP
1082 break;
1083
1084 case SD_NDISC_OPTION_DNSSL:
ad0b2df6 1085 r = ndisc_router_process_dnssl(link, rt);
1e7a0e21 1086 break;
9747955d 1087 case SD_NDISC_OPTION_CAPTIVE_PORTAL:
6df82d12
YW
1088 if (n_captive_portal > 0) {
1089 if (n_captive_portal == 1)
1090 log_link_notice(link, "Received RA with multiple captive portals, only using the first one.");
1091
1092 n_captive_portal++;
1093 continue;
1094 }
9747955d 1095 r = ndisc_router_process_captive_portal(link, rt);
6df82d12
YW
1096 if (r > 0)
1097 n_captive_portal++;
9747955d 1098 break;
6e8f5e4c
SS
1099 case SD_NDISC_OPTION_PREF64:
1100 r = ndisc_router_process_pref64(link, rt);
1101 break;
1e7a0e21 1102 }
5908d864
YW
1103 if (r < 0 && r != -EBADMSG)
1104 return r;
1e7a0e21
LP
1105 }
1106}
1107
2b4fca55 1108static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
94e6d37c
YW
1109 bool updated = false;
1110 NDiscDNSSL *dnssl;
1111 NDiscRDNSS *rdnss;
64de00c4 1112 NDiscCaptivePortal *cp;
fabea9c0 1113 NDiscPREF64 *p64;
94e6d37c
YW
1114 Address *address;
1115 Route *route;
372acaad 1116 int r, ret = 0;
94e6d37c
YW
1117
1118 assert(link);
1119
1120 /* If an address or friends is already assigned, but not valid anymore, then refuse to update it,
1121 * and let's immediately remove it.
1122 * See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by honoring all
1123 * valid lifetimes to improve the reaction of SLAAC to renumbering events.
1124 * See draft-ietf-6man-slaac-renum-02, section 4.2. */
1125
1126 SET_FOREACH(route, link->routes) {
1127 if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
1128 continue;
1129
1130 if (route->lifetime_usec >= timestamp_usec)
1131 continue; /* the route is still valid */
1132
372acaad
YW
1133 r = route_remove_and_drop(route);
1134 if (r < 0)
1135 RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC route, ignoring: %m"));
94e6d37c
YW
1136 }
1137
1138 SET_FOREACH(address, link->addresses) {
1139 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
1140 continue;
1141
1142 if (address->lifetime_valid_usec >= timestamp_usec)
1143 continue; /* the address is still valid */
1144
f22b586a 1145 r = address_remove_and_cancel(address, link);
372acaad
YW
1146 if (r < 0)
1147 RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC address, ignoring: %m"));
94e6d37c
YW
1148 }
1149
1150 SET_FOREACH(rdnss, link->ndisc_rdnss) {
1151 if (rdnss->lifetime_usec >= timestamp_usec)
1152 continue; /* the DNS server is still valid */
1153
1154 free(set_remove(link->ndisc_rdnss, rdnss));
1155 updated = true;
1156 }
1157
1158 SET_FOREACH(dnssl, link->ndisc_dnssl) {
1159 if (dnssl->lifetime_usec >= timestamp_usec)
1160 continue; /* the DNS domain is still valid */
1161
1162 free(set_remove(link->ndisc_dnssl, dnssl));
1163 updated = true;
1164 }
1165
64de00c4
YW
1166 SET_FOREACH(cp, link->ndisc_captive_portals) {
1167 if (cp->lifetime_usec >= timestamp_usec)
1168 continue; /* the captive portal is still valid */
1169
75a91226 1170 ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals, cp));
64de00c4
YW
1171 updated = true;
1172 }
1173
fabea9c0
YW
1174 SET_FOREACH(p64, link->ndisc_pref64) {
1175 if (p64->lifetime_usec >= timestamp_usec)
1176 continue; /* the pref64 prefix is still valid */
1177
1178 free(set_remove(link->ndisc_pref64, p64));
1179 /* The pref64 prefix is not exported through the state file, hence it is not necessary to set
1180 * the 'updated' flag. */
1181 }
1182
94e6d37c
YW
1183 if (updated)
1184 link_dirty(link);
1185
372acaad 1186 return ret;
94e6d37c
YW
1187}
1188
77302468
YW
1189static int ndisc_setup_expire(Link *link);
1190
1191static int ndisc_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
1192 Link *link = ASSERT_PTR(userdata);
1193 usec_t now_usec;
1194
1195 assert(link->manager);
1196
1197 assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
1198
2b4fca55 1199 (void) ndisc_drop_outdated(link, now_usec);
77302468
YW
1200 (void) ndisc_setup_expire(link);
1201 return 0;
1202}
1203
1204static int ndisc_setup_expire(Link *link) {
1205 usec_t lifetime_usec = USEC_INFINITY;
64de00c4 1206 NDiscCaptivePortal *cp;
77302468
YW
1207 NDiscDNSSL *dnssl;
1208 NDiscRDNSS *rdnss;
fabea9c0 1209 NDiscPREF64 *p64;
77302468
YW
1210 Address *address;
1211 Route *route;
1212 int r;
1213
1214 assert(link);
1215 assert(link->manager);
1216
1217 SET_FOREACH(route, link->routes) {
1218 if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
1219 continue;
1220
1221 if (!route_exists(route))
1222 continue;
1223
1224 lifetime_usec = MIN(lifetime_usec, route->lifetime_usec);
1225 }
1226
1227 SET_FOREACH(address, link->addresses) {
1228 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
1229 continue;
1230
1231 if (!address_exists(address))
1232 continue;
1233
1234 lifetime_usec = MIN(lifetime_usec, address->lifetime_valid_usec);
1235 }
1236
1237 SET_FOREACH(rdnss, link->ndisc_rdnss)
1238 lifetime_usec = MIN(lifetime_usec, rdnss->lifetime_usec);
1239
1240 SET_FOREACH(dnssl, link->ndisc_dnssl)
1241 lifetime_usec = MIN(lifetime_usec, dnssl->lifetime_usec);
1242
64de00c4
YW
1243 SET_FOREACH(cp, link->ndisc_captive_portals)
1244 lifetime_usec = MIN(lifetime_usec, cp->lifetime_usec);
1245
fabea9c0
YW
1246 SET_FOREACH(p64, link->ndisc_pref64)
1247 lifetime_usec = MIN(lifetime_usec, p64->lifetime_usec);
1248
77302468
YW
1249 if (lifetime_usec == USEC_INFINITY)
1250 return 0;
1251
1252 r = event_reset_time(link->manager->event, &link->ndisc_expire, CLOCK_BOOTTIME,
1253 lifetime_usec, 0, ndisc_expire_handler, link, 0, "ndisc-expiration", true);
1254 if (r < 0)
1255 return log_link_warning_errno(link, r, "Failed to update expiration timer for ndisc: %m");
1256
1257 return 0;
1258}
1259
928112a4
YW
1260static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
1261 int r;
1262
1263 assert(link);
1264 assert(link->network);
1265
1266 switch (link->network->ipv6_accept_ra_start_dhcp6_client) {
1267 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO:
1268 return 0;
1269
1270 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES: {
1271 uint64_t flags;
1272
1273 r = sd_ndisc_router_get_flags(rt, &flags);
1274 if (r < 0)
1275 return log_link_warning_errno(link, r, "Failed to get RA flags: %m");
1276
1277 if ((flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) == 0)
1278 return 0;
1279
1280 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags.
0bcc6557
AH
1281 * Note, if both "managed" and "other configuration" bits are set, then ignore
1282 * "other configuration" bit. See RFC 4861. */
fac19a21 1283 r = dhcp6_start_on_ra(link, !(flags & ND_RA_FLAG_MANAGED));
928112a4
YW
1284 break;
1285 }
1286 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS:
0bcc6557 1287 /* When IPv6AcceptRA.DHCPv6Client=always, start dhcp6 client in solicit mode
928112a4 1288 * even if the router flags have neither M nor O flags. */
fac19a21 1289 r = dhcp6_start_on_ra(link, /* information_request = */ false);
928112a4
YW
1290 break;
1291
1292 default:
1293 assert_not_reached();
1294 }
1295
1296 if (r < 0)
2c5bca17 1297 return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
928112a4
YW
1298
1299 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
1300 return 0;
1301}
1302
d5017c84 1303static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
b8ce3b44 1304 struct in6_addr router;
94e6d37c 1305 usec_t timestamp_usec;
86e2be7b 1306 int r;
1e7a0e21
LP
1307
1308 assert(link);
1309 assert(link->network);
1310 assert(link->manager);
1311 assert(rt);
1312
b8ce3b44 1313 r = sd_ndisc_router_get_address(rt, &router);
5908d864
YW
1314 if (r == -ENODATA) {
1315 log_link_debug(link, "Received RA without router address, ignoring.");
1316 return 0;
1317 }
75d26411 1318 if (r < 0)
2c5bca17 1319 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
75d26411 1320
c995fa02 1321 if (in6_prefix_is_filtered(&router, 128, link->network->ndisc_allow_listed_router, link->network->ndisc_deny_listed_router)) {
75d26411 1322 if (DEBUG_LOGGING) {
75d26411 1323 if (!set_isempty(link->network->ndisc_allow_listed_router))
84dbb3fd 1324 log_link_debug(link, "Router %s is not in allow list, ignoring.", IN6_ADDR_TO_STRING(&router));
75d26411 1325 else
84dbb3fd 1326 log_link_debug(link, "Router %s is in deny list, ignoring.", IN6_ADDR_TO_STRING(&router));
75d26411
YW
1327 }
1328 return 0;
1329 }
1330
94e6d37c 1331 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
5908d864
YW
1332 if (r == -ENODATA) {
1333 log_link_debug(link, "Received RA without timestamp, ignoring.");
1334 return 0;
1335 }
94e6d37c
YW
1336 if (r < 0)
1337 return r;
1338
2b4fca55 1339 r = ndisc_drop_outdated(link, timestamp_usec);
94e6d37c 1340 if (r < 0)
2b4fca55 1341 return r;
94e6d37c 1342
928112a4
YW
1343 r = ndisc_start_dhcp6_client(link, rt);
1344 if (r < 0)
1345 return r;
1e7a0e21 1346
13e8a49a
YW
1347 r = ndisc_router_process_default(link, rt);
1348 if (r < 0)
1349 return r;
fbdda4bb 1350
0f9a2b80
YW
1351 r = ndisc_router_process_icmp6_ratelimit(link, rt);
1352 if (r < 0)
1353 return r;
1354
13e8a49a
YW
1355 r = ndisc_router_process_options(link, rt);
1356 if (r < 0)
1357 return r;
d5017c84 1358
77302468
YW
1359 r = ndisc_setup_expire(link);
1360 if (r < 0)
1361 return r;
1362
2ccada8d 1363 if (link->ndisc_messages == 0)
3b6a3bde 1364 link->ndisc_configured = true;
2ccada8d 1365 else
3b6a3bde 1366 log_link_debug(link, "Setting SLAAC addresses and router.");
69203fba 1367
3b6a3bde 1368 if (!link->ndisc_configured)
69203fba
YW
1369 link_set_state(link, LINK_STATE_CONFIGURING);
1370
76c5a0f2 1371 link_check_ready(link);
69203fba 1372 return 0;
1e7a0e21
LP
1373}
1374
2324fd3a 1375static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
99534007 1376 Link *link = ASSERT_PTR(userdata);
13e8a49a 1377 int r;
a13c50e7 1378
9d96e6c3
TG
1379 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1380 return;
a13c50e7 1381
9d96e6c3 1382 switch (event) {
1e7a0e21
LP
1383
1384 case SD_NDISC_EVENT_ROUTER:
13e8a49a 1385 r = ndisc_router_handler(link, rt);
5908d864 1386 if (r < 0 && r != -EBADMSG) {
13e8a49a
YW
1387 link_enter_failed(link);
1388 return;
1389 }
1e7a0e21
LP
1390 break;
1391
9d96e6c3 1392 case SD_NDISC_EVENT_TIMEOUT:
a8c10331 1393 log_link_debug(link, "NDisc handler get timeout event");
3b6a3bde
YW
1394 if (link->ndisc_messages == 0) {
1395 link->ndisc_configured = true;
3336e946
YW
1396 link_check_ready(link);
1397 }
9d96e6c3
TG
1398 break;
1399 default:
04499a70 1400 assert_not_reached();
a13c50e7
TG
1401 }
1402}
1403
ba4c7184 1404static int ndisc_configure(Link *link) {
a13c50e7
TG
1405 int r;
1406
1e7a0e21
LP
1407 assert(link);
1408
2ffd6d73
YW
1409 if (!link_ipv6_accept_ra_enabled(link))
1410 return 0;
a13c50e7 1411
5c078687 1412 if (link->ndisc)
bc9e40c9 1413 return -EBUSY; /* Already configured. */
2ffd6d73 1414
5c078687
YW
1415 r = sd_ndisc_new(&link->ndisc);
1416 if (r < 0)
1417 return r;
1418
1419 r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
1420 if (r < 0)
1421 return r;
a13c50e7 1422
3be64aa4
YW
1423 if (link->hw_addr.length == ETH_ALEN) {
1424 r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
1425 if (r < 0)
1426 return r;
1427 }
a13c50e7 1428
1e7a0e21 1429 r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
a13c50e7
TG
1430 if (r < 0)
1431 return r;
1432
1e7a0e21 1433 r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
a13c50e7
TG
1434 if (r < 0)
1435 return r;
1436
1e7a0e21
LP
1437 return 0;
1438}
1439
294f129b 1440int ndisc_start(Link *link) {
ba4c7184
YW
1441 int r;
1442
294f129b
YW
1443 assert(link);
1444
1445 if (!link->ndisc || !link->dhcp6_client)
1446 return 0;
1447
ccffa166
YW
1448 if (!link_has_carrier(link))
1449 return 0;
1450
3b6a3bde
YW
1451 if (in6_addr_is_null(&link->ipv6ll_address))
1452 return 0;
1453
294f129b
YW
1454 log_link_debug(link, "Discovering IPv6 routers");
1455
ba4c7184
YW
1456 r = sd_ndisc_start(link->ndisc);
1457 if (r < 0)
1458 return r;
1459
1460 return 1;
1461}
1462
09d09207 1463static int ndisc_process_request(Request *req, Link *link, void *userdata) {
ba4c7184
YW
1464 int r;
1465
ff51134c 1466 assert(link);
ba4c7184 1467
4b482e8b 1468 if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
ba4c7184
YW
1469 return 0;
1470
ba4c7184
YW
1471 r = ndisc_configure(link);
1472 if (r < 0)
1473 return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Discovery: %m");
1474
1475 r = ndisc_start(link);
1476 if (r < 0)
1477 return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
1478
1479 log_link_debug(link, "IPv6 Router Discovery is configured%s.",
1480 r > 0 ? " and started" : "");
ba4c7184
YW
1481 return 1;
1482}
1483
1484int link_request_ndisc(Link *link) {
1485 int r;
1486
1487 assert(link);
1488
1489 if (!link_ipv6_accept_ra_enabled(link))
1490 return 0;
1491
1492 if (link->ndisc)
1493 return 0;
1494
09d09207 1495 r = link_queue_request(link, REQUEST_TYPE_NDISC, ndisc_process_request, NULL);
ba4c7184
YW
1496 if (r < 0)
1497 return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Discovery: %m");
1498
1499 log_link_debug(link, "Requested configuring of the IPv6 Router Discovery.");
1500 return 0;
294f129b
YW
1501}
1502
77302468
YW
1503int ndisc_stop(Link *link) {
1504 assert(link);
1505
1506 link->ndisc_expire = sd_event_source_disable_unref(link->ndisc_expire);
1507
1508 return sd_ndisc_stop(link->ndisc);
1509}
1510
1511
c69305ff
LP
1512void ndisc_flush(Link *link) {
1513 assert(link);
1514
64de00c4 1515 /* Remove all RDNSS, DNSSL, and Captive Portal entries, without exception. */
c69305ff 1516
b0b97766
YW
1517 link->ndisc_rdnss = set_free(link->ndisc_rdnss);
1518 link->ndisc_dnssl = set_free(link->ndisc_dnssl);
64de00c4 1519 link->ndisc_captive_portals = set_free(link->ndisc_captive_portals);
6e8f5e4c 1520 link->ndisc_pref64 = set_free(link->ndisc_pref64);
c69305ff 1521}
e520ce64 1522
ac24e418
SS
1523static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
1524 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
1525 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
1526 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
1527};
1528
3b6a3bde
YW
1529DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
1530
1531DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains, dhcp_use_domains, DHCPUseDomains,
1532 "Failed to parse UseDomains= setting");
1533DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
1534 "Failed to parse DHCPv6Client= setting");