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