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