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