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