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