]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ndisc.c
network: directly compare with in_addr element for IPv4 case
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
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>
a13c50e7 9
a13c50e7
TG
10#include "sd-ndisc.h"
11
d909e4af 12#include "missing_network.h"
093e3533 13#include "networkd-address.h"
ca5ad760 14#include "networkd-dhcp6.h"
73854ba1 15#include "networkd-manager.h"
1e7a0e21 16#include "networkd-ndisc.h"
5e0534f1 17#include "networkd-sysctl.h"
ac24e418 18#include "string-table.h"
5f506a55 19#include "string-util.h"
51517f9e 20#include "strv.h"
1e7a0e21
LP
21
22#define NDISC_DNSSL_MAX 64U
23#define NDISC_RDNSS_MAX 64U
6554550f 24#define NDISC_PREFIX_LFT_MIN 7200U
fe307276 25
5f506a55
SS
26#define DAD_CONFLICTS_IDGEN_RETRIES_RFC7217 3
27
28/* https://tools.ietf.org/html/rfc5453 */
29/* https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xml */
30
31#define SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } })
32#define SUBNET_ROUTER_ANYCAST_PREFIXLEN 8
33#define RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x02, 0x00, 0x5E, 0xFF, 0xFE } })
34#define RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN 5
35#define RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291 ((struct in6_addr) { .s6_addr = { 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } })
36#define RESERVED_SUBNET_ANYCAST_PREFIXLEN 7
37
38#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
39
062c020f
YW
40bool link_ipv6_accept_ra_enabled(Link *link) {
41 assert(link);
42
43 if (!socket_ipv6_is_supported())
44 return false;
45
46 if (link->flags & IFF_LOOPBACK)
47 return false;
48
49 if (!link->network)
50 return false;
51
52 if (!link_ipv6ll_enabled(link))
53 return false;
54
55 /* If unset use system default (enabled if local forwarding is disabled.
56 * disabled if local forwarding is enabled).
57 * If set, ignore or enforce RA independent of local forwarding state.
58 */
59 if (link->network->ipv6_accept_ra < 0)
60 /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
5e0534f1 61 return !link_ip_forward_enabled(link, AF_INET6);
062c020f
YW
62 else if (link->network->ipv6_accept_ra > 0)
63 /* accept RA even if ip_forward is enabled */
64 return true;
65 else
66 /* ignore RA */
67 return false;
68}
69
50550722 70static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force);
69203fba
YW
71
72static int ndisc_address_callback(Address *address) {
50550722
YW
73 struct in6_addr router = {};
74 NDiscAddress *n;
69203fba
YW
75
76 assert(address);
77 assert(address->link);
78
90e74a66 79 SET_FOREACH(n, address->link->ndisc_addresses)
50550722
YW
80 if (n->address == address) {
81 router = n->router;
82 break;
83 }
84
85 if (IN6_IS_ADDR_UNSPECIFIED(&router)) {
86 _cleanup_free_ char *buf = NULL;
87
88 (void) in_addr_to_string(address->family, &address->in_addr, &buf);
89 log_link_debug(address->link, "%s is called for %s/%u, but it is already removed, ignoring.",
90 __func__, strna(buf), address->prefixlen);
91 return 0;
92 }
93
69203fba 94 /* Make this called only once */
90e74a66 95 SET_FOREACH(n, address->link->ndisc_addresses)
50550722
YW
96 if (IN6_ARE_ADDR_EQUAL(&n->router, &router))
97 n->address->callback = NULL;
69203fba 98
50550722 99 return ndisc_remove_old_one(address->link, &router, true);
69203fba
YW
100}
101
50550722
YW
102static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force) {
103 NDiscAddress *na;
104 NDiscRoute *nr;
b0b97766
YW
105 NDiscDNSSL *dnssl;
106 NDiscRDNSS *rdnss;
69203fba
YW
107 int k, r = 0;
108
109 assert(link);
50550722 110 assert(router);
69203fba
YW
111
112 if (!force) {
50550722 113 bool set_callback = false;
69203fba
YW
114
115 if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
116 return 0;
117
90e74a66 118 SET_FOREACH(na, link->ndisc_addresses)
50550722
YW
119 if (!na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) {
120 set_callback = true;
69203fba
YW
121 break;
122 }
123
50550722 124 if (set_callback)
90e74a66 125 SET_FOREACH(na, link->ndisc_addresses)
50550722
YW
126 if (!na->marked && address_is_ready(na->address)) {
127 set_callback = false;
128 break;
129 }
130
69203fba 131 if (set_callback) {
90e74a66 132 SET_FOREACH(na, link->ndisc_addresses)
50550722
YW
133 if (!na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router))
134 na->address->callback = ndisc_address_callback;
135
136 if (DEBUG_LOGGING) {
137 _cleanup_free_ char *buf = NULL;
138
139 (void) in_addr_to_string(AF_INET6, (union in_addr_union *) router, &buf);
140 log_link_debug(link, "No SLAAC address obtained from %s is ready. "
141 "The old NDisc information will be removed later.",
142 strna(buf));
143 }
69203fba
YW
144 return 0;
145 }
146 }
147
50550722
YW
148 if (DEBUG_LOGGING) {
149 _cleanup_free_ char *buf = NULL;
150
151 (void) in_addr_to_string(AF_INET6, (union in_addr_union *) router, &buf);
152 log_link_debug(link, "Removing old NDisc information obtained from %s.", strna(buf));
153 }
69203fba
YW
154
155 link_dirty(link);
156
90e74a66 157 SET_FOREACH(na, link->ndisc_addresses)
50550722
YW
158 if (na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) {
159 k = address_remove(na->address, link, NULL);
160 if (k < 0)
161 r = k;
162 }
69203fba 163
90e74a66 164 SET_FOREACH(nr, link->ndisc_routes)
50550722 165 if (nr->marked && IN6_ARE_ADDR_EQUAL(&nr->router, router)) {
ad208fac 166 k = route_remove(nr->route, NULL, link, NULL);
50550722
YW
167 if (k < 0)
168 r = k;
169 }
69203fba 170
90e74a66 171 SET_FOREACH(rdnss, link->ndisc_rdnss)
50550722 172 if (rdnss->marked && IN6_ARE_ADDR_EQUAL(&rdnss->router, router))
b0b97766
YW
173 free(set_remove(link->ndisc_rdnss, rdnss));
174
90e74a66 175 SET_FOREACH(dnssl, link->ndisc_dnssl)
50550722 176 if (dnssl->marked && IN6_ARE_ADDR_EQUAL(&dnssl->router, router))
b0b97766
YW
177 free(set_remove(link->ndisc_dnssl, dnssl));
178
69203fba
YW
179 return r;
180}
181
50550722
YW
182static int ndisc_remove_old(Link *link) {
183 _cleanup_set_free_free_ Set *routers = NULL;
184 _cleanup_free_ struct in6_addr *router = NULL;
185 struct in6_addr *a;
186 NDiscAddress *na;
187 NDiscRoute *nr;
188 NDiscDNSSL *dnssl;
189 NDiscRDNSS *rdnss;
50550722
YW
190 int k, r;
191
192 assert(link);
193
194 routers = set_new(&in6_addr_hash_ops);
195 if (!routers)
196 return -ENOMEM;
197
90e74a66 198 SET_FOREACH(na, link->ndisc_addresses)
50550722
YW
199 if (!set_contains(routers, &na->router)) {
200 router = newdup(struct in6_addr, &na->router, 1);
201 if (!router)
202 return -ENOMEM;
203
204 r = set_put(routers, router);
205 if (r < 0)
206 return r;
207
208 assert(r > 0);
209 TAKE_PTR(router);
210 }
211
90e74a66 212 SET_FOREACH(nr, link->ndisc_routes)
50550722
YW
213 if (!set_contains(routers, &nr->router)) {
214 router = newdup(struct in6_addr, &nr->router, 1);
215 if (!router)
216 return -ENOMEM;
217
218 r = set_put(routers, router);
219 if (r < 0)
220 return r;
221
222 assert(r > 0);
223 TAKE_PTR(router);
224 }
225
90e74a66 226 SET_FOREACH(rdnss, link->ndisc_rdnss)
50550722
YW
227 if (!set_contains(routers, &rdnss->router)) {
228 router = newdup(struct in6_addr, &rdnss->router, 1);
229 if (!router)
230 return -ENOMEM;
231
232 r = set_put(routers, router);
233 if (r < 0)
234 return r;
235
236 assert(r > 0);
237 TAKE_PTR(router);
238 }
239
90e74a66 240 SET_FOREACH(dnssl, link->ndisc_dnssl)
50550722
YW
241 if (!set_contains(routers, &dnssl->router)) {
242 router = newdup(struct in6_addr, &dnssl->router, 1);
243 if (!router)
244 return -ENOMEM;
245
246 r = set_put(routers, router);
247 if (r < 0)
248 return r;
249
250 assert(r > 0);
251 TAKE_PTR(router);
252 }
253
254 r = 0;
90e74a66 255 SET_FOREACH(a, routers) {
50550722
YW
256 k = ndisc_remove_old_one(link, a, false);
257 if (k < 0)
258 r = k;
259 }
260
261 return r;
262}
263
264static void ndisc_route_hash_func(const NDiscRoute *x, struct siphash *state) {
265 route_hash_func(x->route, state);
266}
267
268static int ndisc_route_compare_func(const NDiscRoute *a, const NDiscRoute *b) {
269 return route_compare_func(a->route, b->route);
270}
271
272DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
273 ndisc_route_hash_ops,
274 NDiscRoute,
275 ndisc_route_hash_func,
276 ndisc_route_compare_func,
277 free);
278
d98c546d 279static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
3b015d40
TG
280 int r;
281
282 assert(link);
d98c546d 283 assert(link->ndisc_routes_messages > 0);
3b015d40 284
d98c546d 285 link->ndisc_routes_messages--;
3b015d40 286
4ff296b0
YW
287 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
288 return 1;
289
3b015d40 290 r = sd_netlink_message_get_errno(m);
4ff296b0 291 if (r < 0 && r != -EEXIST) {
d98c546d 292 log_link_message_error_errno(link, m, r, "Could not set NDisc route");
4ff296b0
YW
293 link_enter_failed(link);
294 return 1;
295 }
3b015d40 296
d98c546d
YW
297 if (link->ndisc_routes_messages == 0) {
298 log_link_debug(link, "NDisc routes set.");
299 link->ndisc_routes_configured = true;
69203fba 300
50550722 301 r = ndisc_remove_old(link);
69203fba
YW
302 if (r < 0) {
303 link_enter_failed(link);
304 return 1;
305 }
306
3b015d40
TG
307 link_check_ready(link);
308 }
309
310 return 1;
311}
312
50550722
YW
313static int ndisc_route_configure(Route *route, Link *link, sd_ndisc_router *rt) {
314 _cleanup_free_ NDiscRoute *nr = NULL;
315 NDiscRoute *nr_exist;
316 struct in6_addr router;
317 Route *ret;
318 int r;
319
320 assert(route);
321 assert(link);
322 assert(rt);
323
324 r = route_configure(route, link, ndisc_route_handler, &ret);
325 if (r < 0)
326 return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
327
328 link->ndisc_routes_messages++;
329
330 r = sd_ndisc_router_get_address(rt, &router);
331 if (r < 0)
332 return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
333
334 nr = new(NDiscRoute, 1);
335 if (!nr)
336 return log_oom();
337
338 *nr = (NDiscRoute) {
339 .router = router,
340 .route = ret,
341 };
342
343 nr_exist = set_get(link->ndisc_routes, nr);
344 if (nr_exist) {
345 nr_exist->marked = false;
346 nr_exist->router = router;
347 return 0;
348 }
349
350 r = set_ensure_put(&link->ndisc_routes, &ndisc_route_hash_ops, nr);
351 if (r < 0)
352 return log_link_error_errno(link, r, "Failed to store NDisc SLAAC route: %m");
353 assert(r > 0);
354 TAKE_PTR(nr);
355
356 return 0;
357}
358
359static void ndisc_address_hash_func(const NDiscAddress *x, struct siphash *state) {
360 address_hash_func(x->address, state);
361}
362
363static int ndisc_address_compare_func(const NDiscAddress *a, const NDiscAddress *b) {
364 return address_compare_func(a->address, b->address);
365}
366
367DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
368 ndisc_address_hash_ops,
369 NDiscAddress,
370 ndisc_address_hash_func,
371 ndisc_address_compare_func,
372 free);
373
d98c546d 374static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
73854ba1
YW
375 int r;
376
377 assert(link);
d98c546d 378 assert(link->ndisc_addresses_messages > 0);
73854ba1 379
d98c546d 380 link->ndisc_addresses_messages--;
73854ba1 381
4ff296b0
YW
382 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
383 return 1;
384
73854ba1 385 r = sd_netlink_message_get_errno(m);
4ff296b0 386 if (r < 0 && r != -EEXIST) {
d98c546d 387 log_link_message_error_errno(link, m, r, "Could not set NDisc address");
4ff296b0
YW
388 link_enter_failed(link);
389 return 1;
390 } else if (r >= 0)
391 (void) manager_rtnl_process_address(rtnl, m, link->manager);
73854ba1 392
d98c546d
YW
393 if (link->ndisc_addresses_messages == 0) {
394 log_link_debug(link, "NDisc SLAAC addresses set.");
395 link->ndisc_addresses_configured = true;
69203fba 396
50550722 397 r = ndisc_remove_old(link);
69203fba
YW
398 if (r < 0) {
399 link_enter_failed(link);
400 return 1;
401 }
402
141318f7 403 r = link_set_routes(link);
4ff296b0
YW
404 if (r < 0) {
405 link_enter_failed(link);
406 return 1;
407 }
73854ba1
YW
408 }
409
410 return 1;
411}
412
50550722
YW
413static int ndisc_address_configure(Address *address, Link *link, sd_ndisc_router *rt) {
414 _cleanup_free_ NDiscAddress *na = NULL;
415 NDiscAddress *na_exist;
416 struct in6_addr router;
69203fba
YW
417 Address *ret;
418 int r;
419
420 assert(address);
421 assert(link);
50550722 422 assert(rt);
69203fba
YW
423
424 r = address_configure(address, link, ndisc_address_handler, true, &ret);
425 if (r < 0)
426 return log_link_error_errno(link, r, "Failed to set NDisc SLAAC address: %m");
427
428 link->ndisc_addresses_messages++;
429
50550722 430 r = sd_ndisc_router_get_address(rt, &router);
69203fba 431 if (r < 0)
50550722
YW
432 return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
433
434 na = new(NDiscAddress, 1);
435 if (!na)
436 return log_oom();
69203fba 437
50550722
YW
438 *na = (NDiscAddress) {
439 .router = router,
440 .address = ret,
441 };
442
443 na_exist = set_get(link->ndisc_addresses, na);
444 if (na_exist) {
445 na_exist->marked = false;
446 na_exist->router = router;
447 return 0;
448 }
449
450 r = set_ensure_put(&link->ndisc_addresses, &ndisc_address_hash_ops, na);
451 if (r < 0)
452 return log_link_error_errno(link, r, "Failed to store NDisc SLAAC address: %m");
453 assert(r > 0);
454 TAKE_PTR(na);
69203fba
YW
455
456 return 0;
457}
458
d5017c84 459static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
8e766630 460 _cleanup_(route_freep) Route *route = NULL;
ce2ea782 461 union in_addr_union gateway;
1e7a0e21
LP
462 uint16_t lifetime;
463 unsigned preference;
d6fceaf1 464 uint32_t mtu;
3b015d40 465 usec_t time_now;
13e8a49a 466 int r;
3b015d40 467
3b015d40 468 assert(link);
1e7a0e21 469 assert(rt);
3b015d40 470
1e7a0e21 471 r = sd_ndisc_router_get_lifetime(rt, &lifetime);
d5017c84 472 if (r < 0)
13e8a49a 473 return log_link_error_errno(link, r, "Failed to get gateway lifetime from RA: %m");
d5017c84 474
1e7a0e21 475 if (lifetime == 0) /* not a default router */
d5017c84 476 return 0;
1e7a0e21 477
ce2ea782 478 r = sd_ndisc_router_get_address(rt, &gateway.in6);
d5017c84 479 if (r < 0)
13e8a49a 480 return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
1e7a0e21 481
5eec0a08
YW
482 if (address_exists(link, AF_INET6, &gateway)) {
483 if (DEBUG_LOGGING) {
484 _cleanup_free_ char *buffer = NULL;
6d7c7615 485
5eec0a08
YW
486 (void) in_addr_to_string(AF_INET6, &gateway, &buffer);
487 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
488 strnull(buffer));
6d7c7615 489 }
5eec0a08 490 return 0;
ce2ea782 491 }
6d7c7615 492
1e7a0e21 493 r = sd_ndisc_router_get_preference(rt, &preference);
d5017c84 494 if (r < 0)
13e8a49a 495 return log_link_error_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21
LP
496
497 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 498 if (r < 0)
13e8a49a 499 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21 500
d6fceaf1 501 r = sd_ndisc_router_get_mtu(rt, &mtu);
29b5ad08
JT
502 if (r == -ENODATA)
503 mtu = 0;
d5017c84 504 else if (r < 0)
13e8a49a 505 return log_link_error_errno(link, r, "Failed to get default router MTU from RA: %m");
d6fceaf1 506
1e7a0e21 507 r = route_new(&route);
d5017c84 508 if (r < 0)
13e8a49a 509 return log_oom();
1e7a0e21
LP
510
511 route->family = AF_INET6;
bdb9f580 512 route->table = link_get_ipv6_accept_ra_route_table(link);
1bf1bfd9 513 route->priority = link->network->dhcp6_route_metric;
1e7a0e21
LP
514 route->protocol = RTPROT_RA;
515 route->pref = preference;
6dd53981 516 route->gw_family = AF_INET6;
ce2ea782 517 route->gw = gateway;
1e7a0e21 518 route->lifetime = time_now + lifetime * USEC_PER_SEC;
d6fceaf1 519 route->mtu = mtu;
1e7a0e21 520
50550722 521 r = ndisc_route_configure(route, link, rt);
13e8a49a
YW
522 if (r < 0)
523 return log_link_error_errno(link, r, "Could not set default route: %m");
d5017c84 524
1985c54f 525 Route *route_gw;
2a54a044 526 HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
1985c54f
YW
527 if (!route_gw->gateway_from_dhcp)
528 continue;
529
530 if (route_gw->family != AF_INET6)
531 continue;
532
533 route_gw->gw = gateway;
6dd53981 534 route_gw->gw_family = AF_INET6;
1985c54f 535
50550722 536 r = ndisc_route_configure(route_gw, link, rt);
13e8a49a
YW
537 if (r < 0)
538 return log_link_error_errno(link, r, "Could not set gateway: %m");
1985c54f
YW
539 }
540
d5017c84 541 return 0;
1e7a0e21
LP
542}
543
92ee90af
YW
544static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
545 assert(addr);
546
547 /* According to rfc4291, generated address should not be in the following ranges. */
548
549 if (memcmp(addr, &SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291, SUBNET_ROUTER_ANYCAST_PREFIXLEN) == 0)
550 return false;
551
552 if (memcmp(addr, &RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291, RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN) == 0)
553 return false;
554
555 if (memcmp(addr, &RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291, RESERVED_SUBNET_ANYCAST_PREFIXLEN) == 0)
556 return false;
557
558 return true;
559}
560
561static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) {
562 _cleanup_free_ struct in6_addr *addr = NULL;
563 sd_id128_t secret_key;
564 struct siphash state;
565 uint64_t rid;
566 size_t l;
567 int r;
568
569 /* According to rfc7217 section 5.1
570 * RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) */
571
572 r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key);
573 if (r < 0)
574 return log_error_errno(r, "Failed to generate key: %m");
575
576 siphash24_init(&state, secret_key.bytes);
577
578 l = MAX(DIV_ROUND_UP(prefix_len, 8), 8);
579 siphash24_compress(prefix, l, &state);
580 siphash24_compress_string(link->ifname, &state);
581 siphash24_compress(&link->mac, sizeof(struct ether_addr), &state);
582 siphash24_compress(&dad_counter, sizeof(uint8_t), &state);
583
584 rid = htole64(siphash24_finalize(&state));
585
586 addr = new(struct in6_addr, 1);
587 if (!addr)
588 return log_oom();
589
590 memcpy(addr->s6_addr, prefix->s6_addr, l);
591 memcpy(addr->s6_addr + l, &rid, 16 - l);
592
593 if (!stableprivate_address_is_valid(addr)) {
594 *ret = NULL;
595 return 0;
596 }
597
598 *ret = TAKE_PTR(addr);
599 return 1;
600}
601
602static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address, uint8_t prefixlen, Set **ret) {
c24c83dc 603 _cleanup_set_free_free_ Set *addresses = NULL;
5f506a55 604 IPv6Token *j;
5f506a55
SS
605 int r;
606
5f506a55 607 assert(link);
c24c83dc
KF
608 assert(address);
609 assert(ret);
610
92ee90af 611 addresses = set_new(&in6_addr_hash_ops);
c24c83dc
KF
612 if (!addresses)
613 return log_oom();
5f506a55 614
90e74a66 615 ORDERED_SET_FOREACH(j, link->network->ipv6_tokens) {
92ee90af 616 _cleanup_free_ struct in6_addr *new_address = NULL;
c24c83dc 617
5f506a55 618 if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
b27caa34 619 && (IN6_IS_ADDR_UNSPECIFIED(&j->prefix) || IN6_ARE_ADDR_EQUAL(&j->prefix, address))) {
0ddad04e
KF
620 /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop
621 does not actually attempt Duplicate Address Detection; the counter will be incremented
622 only when the address generation algorithm produces an invalid address, and the loop
623 may exit with an address which ends up being unusable due to duplication on the link.
624 */
5f506a55 625 for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
b27caa34 626 r = make_stableprivate_address(link, address, prefixlen, j->dad_counter, &new_address);
5f506a55 627 if (r < 0)
92ee90af
YW
628 return r;
629 if (r > 0)
c24c83dc 630 break;
5f506a55 631 }
e2c4070e 632 } else if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_STATIC) {
92ee90af
YW
633 new_address = new(struct in6_addr, 1);
634 if (!new_address)
635 return log_oom();
5f506a55 636
92ee90af
YW
637 memcpy(new_address->s6_addr, address->s6_addr, 8);
638 memcpy(new_address->s6_addr + 8, j->prefix.s6_addr + 8, 8);
639 }
c24c83dc 640
92ee90af 641 if (new_address) {
c24c83dc
KF
642 r = set_put(addresses, new_address);
643 if (r < 0)
13e8a49a 644 return log_link_error_errno(link, r, "Failed to store SLAAC address: %m");
92ee90af
YW
645 else if (r == 0)
646 log_link_debug_errno(link, r, "Generated SLAAC address is duplicated, ignoring.");
647 else
648 TAKE_PTR(new_address);
c24c83dc
KF
649 }
650 }
651
652 /* fall back to EUI-64 if no tokens provided addresses */
653 if (set_isempty(addresses)) {
92ee90af 654 _cleanup_free_ struct in6_addr *new_address = NULL;
c24c83dc 655
92ee90af
YW
656 new_address = newdup(struct in6_addr, address, 1);
657 if (!new_address)
c24c83dc
KF
658 return log_oom();
659
92ee90af 660 r = generate_ipv6_eui_64_address(link, new_address);
a781ddef
SS
661 if (r < 0)
662 return log_link_error_errno(link, r, "Failed to generate EUI64 address: %m");
663
c24c83dc
KF
664 r = set_put(addresses, new_address);
665 if (r < 0)
13e8a49a 666 return log_link_error_errno(link, r, "Failed to store SLAAC address: %m");
92ee90af 667
c24c83dc 668 TAKE_PTR(new_address);
5f506a55
SS
669 }
670
c24c83dc 671 *ret = TAKE_PTR(addresses);
5f506a55
SS
672
673 return 0;
674}
c24c83dc 675
d5017c84 676static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
5f506a55 677 uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
c24c83dc 678 _cleanup_set_free_free_ Set *addresses = NULL;
8e766630 679 _cleanup_(address_freep) Address *address = NULL;
92ee90af 680 struct in6_addr addr, *a;
1e7a0e21 681 unsigned prefixlen;
5f506a55 682 usec_t time_now;
1e7a0e21
LP
683 int r;
684
685 assert(link);
686 assert(rt);
687
6554550f 688 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 689 if (r < 0)
13e8a49a 690 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
6554550f 691
1e7a0e21 692 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84
YW
693 if (r < 0)
694 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21
LP
695
696 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
d5017c84
YW
697 if (r < 0)
698 return log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
1e7a0e21
LP
699
700 r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
d5017c84
YW
701 if (r < 0)
702 return log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
3b015d40 703
92bdc3ff
SS
704 /* The preferred lifetime is never greater than the valid lifetime */
705 if (lifetime_preferred > lifetime_valid)
d5017c84 706 return 0;
92bdc3ff 707
92ee90af 708 r = sd_ndisc_router_prefix_get_address(rt, &addr);
d5017c84
YW
709 if (r < 0)
710 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
1e7a0e21 711
92ee90af 712 r = ndisc_router_generate_addresses(link, &addr, prefixlen, &addresses);
5f506a55 713 if (r < 0)
13e8a49a 714 return r;
c24c83dc 715
92ee90af
YW
716 r = address_new(&address);
717 if (r < 0)
718 return log_oom();
719
720 address->family = AF_INET6;
721 address->prefixlen = prefixlen;
722 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
723 address->cinfo.ifa_prefered = lifetime_preferred;
724
90e74a66 725 SET_FOREACH(a, addresses) {
13e8a49a
YW
726 Address *existing_address;
727
c24c83dc 728 /* see RFC4862 section 5.5.3.e */
92ee90af 729 r = address_get(link, AF_INET6, (union in_addr_union *) a, prefixlen, &existing_address);
c24c83dc
KF
730 if (r > 0) {
731 lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
732 if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
92ee90af 733 address->cinfo.ifa_valid = lifetime_valid;
c24c83dc 734 else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN)
92ee90af 735 address->cinfo.ifa_valid = lifetime_remaining;
c24c83dc 736 else
92ee90af 737 address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN;
c24c83dc 738 } else if (lifetime_valid > 0)
92ee90af 739 address->cinfo.ifa_valid = lifetime_valid;
6554550f 740 else
01c344bd 741 continue; /* see RFC4862 section 5.5.3.d */
6554550f 742
92ee90af 743 if (address->cinfo.ifa_valid == 0)
c24c83dc 744 continue;
3b015d40 745
92ee90af
YW
746 address->in_addr.in6 = *a;
747
50550722 748 r = ndisc_address_configure(address, link, rt);
13e8a49a
YW
749 if (r < 0)
750 return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
3b015d40 751 }
d5017c84
YW
752
753 return 0;
3b015d40
TG
754}
755
d5017c84 756static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
8e766630 757 _cleanup_(route_freep) Route *route = NULL;
3b015d40 758 usec_t time_now;
1e7a0e21
LP
759 uint32_t lifetime;
760 unsigned prefixlen;
3b015d40
TG
761 int r;
762
3b015d40 763 assert(link);
1e7a0e21 764 assert(rt);
3b015d40 765
1e7a0e21 766 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 767 if (r < 0)
13e8a49a 768 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21
LP
769
770 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84
YW
771 if (r < 0)
772 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21
LP
773
774 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime);
d5017c84
YW
775 if (r < 0)
776 return log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
3b015d40
TG
777
778 r = route_new(&route);
d5017c84 779 if (r < 0)
13e8a49a 780 return log_oom();
3b015d40 781
3b015d40 782 route->family = AF_INET6;
bdb9f580 783 route->table = link_get_ipv6_accept_ra_route_table(link);
1bf1bfd9 784 route->priority = link->network->dhcp6_route_metric;
3b015d40
TG
785 route->protocol = RTPROT_RA;
786 route->flags = RTM_F_PREFIX;
3b015d40
TG
787 route->dst_prefixlen = prefixlen;
788 route->lifetime = time_now + lifetime * USEC_PER_SEC;
789
1e7a0e21 790 r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
d5017c84
YW
791 if (r < 0)
792 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
1e7a0e21 793
50550722 794 r = ndisc_route_configure(route, link, rt);
13e8a49a
YW
795 if (r < 0)
796 return log_link_error_errno(link, r, "Could not set prefix route: %m");;
d5017c84
YW
797
798 return 0;
3b015d40
TG
799}
800
d5017c84 801static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
8e766630 802 _cleanup_(route_freep) Route *route = NULL;
1e7a0e21
LP
803 struct in6_addr gateway;
804 uint32_t lifetime;
805 unsigned preference, prefixlen;
fe307276 806 usec_t time_now;
7a695d8e 807 int r;
a13c50e7
TG
808
809 assert(link);
a13c50e7 810
1e7a0e21 811 r = sd_ndisc_router_route_get_lifetime(rt, &lifetime);
d5017c84 812 if (r < 0)
13e8a49a 813 return log_link_error_errno(link, r, "Failed to get gateway lifetime from RA: %m");
d5017c84 814
1e7a0e21 815 if (lifetime == 0)
d5017c84 816 return 0;
a13c50e7 817
1e7a0e21 818 r = sd_ndisc_router_get_address(rt, &gateway);
d5017c84 819 if (r < 0)
13e8a49a 820 return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
3b015d40 821
1e7a0e21 822 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
d5017c84 823 if (r < 0)
13e8a49a 824 return log_link_error_errno(link, r, "Failed to get route prefix length: %m");
1e7a0e21
LP
825
826 r = sd_ndisc_router_route_get_preference(rt, &preference);
d5017c84 827 if (r < 0)
13e8a49a 828 return log_link_error_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21
LP
829
830 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 831 if (r < 0)
13e8a49a 832 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
3b015d40
TG
833
834 r = route_new(&route);
d5017c84 835 if (r < 0)
13e8a49a 836 return log_oom();
3b015d40 837
3b015d40 838 route->family = AF_INET6;
bdb9f580 839 route->table = link_get_ipv6_accept_ra_route_table(link);
1bf1bfd9 840 route->priority = link->network->dhcp6_route_metric;
3b015d40 841 route->protocol = RTPROT_RA;
1e7a0e21
LP
842 route->pref = preference;
843 route->gw.in6 = gateway;
6dd53981 844 route->gw_family = AF_INET6;
1e7a0e21 845 route->dst_prefixlen = prefixlen;
3b015d40
TG
846 route->lifetime = time_now + lifetime * USEC_PER_SEC;
847
1e7a0e21 848 r = sd_ndisc_router_route_get_address(rt, &route->dst.in6);
d5017c84
YW
849 if (r < 0)
850 return log_link_error_errno(link, r, "Failed to get route address: %m");
1e7a0e21 851
50550722 852 r = ndisc_route_configure(route, link, rt);
13e8a49a
YW
853 if (r < 0)
854 return log_link_error_errno(link, r, "Could not set additional route: %m");
d5017c84
YW
855
856 return 0;
9d96e6c3 857}
a13c50e7 858
7a08d314 859static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
1e7a0e21
LP
860 siphash24_compress(&x->address, sizeof(x->address), state);
861}
862
7a08d314 863static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
1e7a0e21
LP
864 return memcmp(&a->address, &b->address, sizeof(a->address));
865}
866
b0b97766
YW
867DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
868 ndisc_rdnss_hash_ops,
869 NDiscRDNSS,
870 ndisc_rdnss_hash_func,
871 ndisc_rdnss_compare_func,
872 free);
1e7a0e21 873
d5017c84 874static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
1e7a0e21
LP
875 uint32_t lifetime;
876 const struct in6_addr *a;
50550722 877 struct in6_addr router;
b0b97766 878 NDiscRDNSS *rdnss;
1e7a0e21 879 usec_t time_now;
13e8a49a 880 int n, r;
1e7a0e21
LP
881
882 assert(link);
883 assert(rt);
884
50550722
YW
885 r = sd_ndisc_router_get_address(rt, &router);
886 if (r < 0)
887 return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
888
1e7a0e21 889 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 890 if (r < 0)
13e8a49a 891 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21
LP
892
893 r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime);
d5017c84 894 if (r < 0)
13e8a49a 895 return log_link_error_errno(link, r, "Failed to get RDNSS lifetime: %m");
1e7a0e21
LP
896
897 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
d5017c84 898 if (n < 0)
13e8a49a 899 return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
1e7a0e21 900
90e74a66 901 SET_FOREACH(rdnss, link->ndisc_rdnss)
50550722
YW
902 if (IN6_ARE_ADDR_EQUAL(&rdnss->router, &router))
903 rdnss->marked = true;
1e7a0e21 904
b0b97766
YW
905 if (lifetime == 0)
906 return 0;
1e7a0e21 907
b0b97766
YW
908 if (n >= (int) NDISC_RDNSS_MAX) {
909 log_link_warning(link, "Too many RDNSS records per link. Only first %i records will be used.", NDISC_RDNSS_MAX);
910 n = NDISC_RDNSS_MAX;
911 }
1e7a0e21 912
b0b97766
YW
913 for (int j = 0; j < n; j++) {
914 _cleanup_free_ NDiscRDNSS *x = NULL;
915 NDiscRDNSS d = {
916 .address = a[j],
917 };
1e7a0e21 918
b0b97766
YW
919 rdnss = set_get(link->ndisc_rdnss, &d);
920 if (rdnss) {
921 rdnss->marked = false;
50550722 922 rdnss->router = router;
b0b97766 923 rdnss->valid_until = time_now + lifetime * USEC_PER_SEC;
1e7a0e21
LP
924 continue;
925 }
926
d5017c84
YW
927 x = new(NDiscRDNSS, 1);
928 if (!x)
929 return log_oom();
1e7a0e21 930
d5017c84 931 *x = (NDiscRDNSS) {
b0b97766 932 .address = a[j],
50550722 933 .router = router,
d5017c84
YW
934 .valid_until = time_now + lifetime * USEC_PER_SEC,
935 };
1e7a0e21 936
35e601d4 937 r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
d5017c84
YW
938 if (r < 0)
939 return log_oom();
1e7a0e21 940 assert(r > 0);
1e7a0e21 941 }
d5017c84
YW
942
943 return 0;
1e7a0e21
LP
944}
945
7a08d314 946static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
f281fc1e 947 siphash24_compress_string(NDISC_DNSSL_DOMAIN(x), state);
1e7a0e21
LP
948}
949
7a08d314 950static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
1e7a0e21
LP
951 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
952}
953
b0b97766
YW
954DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
955 ndisc_dnssl_hash_ops,
956 NDiscDNSSL,
957 ndisc_dnssl_hash_func,
958 ndisc_dnssl_compare_func,
959 free);
1e7a0e21 960
13e8a49a 961static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
1e7a0e21 962 _cleanup_strv_free_ char **l = NULL;
50550722 963 struct in6_addr router;
1e7a0e21
LP
964 uint32_t lifetime;
965 usec_t time_now;
b0b97766 966 NDiscDNSSL *dnssl;
b0b97766 967 char **j;
1e7a0e21
LP
968 int r;
969
970 assert(link);
971 assert(rt);
972
50550722
YW
973 r = sd_ndisc_router_get_address(rt, &router);
974 if (r < 0)
975 return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
976
1e7a0e21 977 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
13e8a49a
YW
978 if (r < 0)
979 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21
LP
980
981 r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime);
13e8a49a
YW
982 if (r < 0)
983 return log_link_error_errno(link, r, "Failed to get DNSSL lifetime: %m");
1e7a0e21
LP
984
985 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
13e8a49a
YW
986 if (r < 0)
987 return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
1e7a0e21 988
90e74a66 989 SET_FOREACH(dnssl, link->ndisc_dnssl)
50550722
YW
990 if (IN6_ARE_ADDR_EQUAL(&dnssl->router, &router))
991 dnssl->marked = true;
1e7a0e21 992
b0b97766
YW
993 if (lifetime == 0)
994 return 0;
a34349e7 995
b0b97766
YW
996 if (strv_length(l) >= NDISC_DNSSL_MAX) {
997 log_link_warning(link, "Too many DNSSL records per link. Only first %i records will be used.", NDISC_DNSSL_MAX);
998 STRV_FOREACH(j, l + NDISC_DNSSL_MAX)
999 *j = mfree(*j);
1000 }
1e7a0e21 1001
b0b97766
YW
1002 STRV_FOREACH(j, l) {
1003 _cleanup_free_ NDiscDNSSL *s = NULL;
1e7a0e21 1004
b0b97766
YW
1005 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
1006 if (!s)
1007 return log_oom();
1e7a0e21 1008
b0b97766 1009 strcpy(NDISC_DNSSL_DOMAIN(s), *j);
1e7a0e21 1010
b0b97766
YW
1011 dnssl = set_get(link->ndisc_dnssl, s);
1012 if (dnssl) {
1013 dnssl->marked = false;
50550722 1014 dnssl->router = router;
b0b97766 1015 dnssl->valid_until = time_now + lifetime * USEC_PER_SEC;
1e7a0e21
LP
1016 continue;
1017 }
1018
50550722 1019 s->router = router;
a34349e7 1020 s->valid_until = time_now + lifetime * USEC_PER_SEC;
1e7a0e21 1021
35e601d4 1022 r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
13e8a49a
YW
1023 if (r < 0)
1024 return log_oom();
1e7a0e21 1025 assert(r > 0);
1e7a0e21 1026 }
13e8a49a
YW
1027
1028 return 0;
1e7a0e21
LP
1029}
1030
e8c9b5b0 1031static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
1e7a0e21 1032 assert(link);
55d3fdcf 1033 assert(link->network);
1e7a0e21
LP
1034 assert(rt);
1035
13e8a49a 1036 for (int r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
1e7a0e21
LP
1037 uint8_t type;
1038
e8c9b5b0 1039 if (r < 0)
13e8a49a 1040 return log_link_error_errno(link, r, "Failed to iterate through options: %m");
1e7a0e21 1041 if (r == 0) /* EOF */
13e8a49a 1042 return 0;
1e7a0e21
LP
1043
1044 r = sd_ndisc_router_option_get_type(rt, &type);
e8c9b5b0 1045 if (r < 0)
13e8a49a 1046 return log_link_error_errno(link, r, "Failed to get RA option type: %m");
1e7a0e21
LP
1047
1048 switch (type) {
1049
1050 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
55d3fdcf 1051 union in_addr_union a;
1e7a0e21
LP
1052 uint8_t flags;
1053
55d3fdcf
YW
1054 r = sd_ndisc_router_prefix_get_address(rt, &a.in6);
1055 if (r < 0)
1056 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
1057
6b000af4 1058 if (set_contains(link->network->ndisc_deny_listed_prefix, &a.in6)) {
55d3fdcf
YW
1059 if (DEBUG_LOGGING) {
1060 _cleanup_free_ char *b = NULL;
1061
1062 (void) in_addr_to_string(AF_INET6, &a, &b);
6b000af4 1063 log_link_debug(link, "Prefix '%s' is deny-listed, ignoring", strna(b));
55d3fdcf 1064 }
55d3fdcf
YW
1065 break;
1066 }
1067
1e7a0e21 1068 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
e8c9b5b0 1069 if (r < 0)
13e8a49a 1070 return log_link_error_errno(link, r, "Failed to get RA prefix flags: %m");
1e7a0e21 1071
87d8a4de 1072 if (link->network->ipv6_accept_ra_use_onlink_prefix &&
13e8a49a
YW
1073 FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK)) {
1074 r = ndisc_router_process_onlink_prefix(link, rt);
1075 if (r < 0)
1076 return r;
1077 }
062c2eea 1078
87d8a4de 1079 if (link->network->ipv6_accept_ra_use_autonomous_prefix &&
13e8a49a
YW
1080 FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO)) {
1081 r = ndisc_router_process_autonomous_prefix(link, rt);
1082 if (r < 0)
1083 return r;
1084 }
1e7a0e21
LP
1085 break;
1086 }
1087
1088 case SD_NDISC_OPTION_ROUTE_INFORMATION:
13e8a49a
YW
1089 r = ndisc_router_process_route(link, rt);
1090 if (r < 0)
1091 return r;
1e7a0e21
LP
1092 break;
1093
1094 case SD_NDISC_OPTION_RDNSS:
13e8a49a
YW
1095 if (link->network->ipv6_accept_ra_use_dns) {
1096 r = ndisc_router_process_rdnss(link, rt);
1097 if (r < 0)
1098 return r;
1099 }
1e7a0e21
LP
1100 break;
1101
1102 case SD_NDISC_OPTION_DNSSL:
13e8a49a
YW
1103 if (link->network->ipv6_accept_ra_use_dns) {
1104 r = ndisc_router_process_dnssl(link, rt);
1105 if (r < 0)
1106 return r;
1107 }
1e7a0e21
LP
1108 break;
1109 }
1e7a0e21
LP
1110 }
1111}
1112
d5017c84 1113static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
50550722 1114 struct in6_addr router;
1e7a0e21 1115 uint64_t flags;
50550722
YW
1116 NDiscAddress *na;
1117 NDiscRoute *nr;
86e2be7b 1118 int r;
1e7a0e21
LP
1119
1120 assert(link);
1121 assert(link->network);
1122 assert(link->manager);
1123 assert(rt);
1124
69203fba
YW
1125 link->ndisc_addresses_configured = false;
1126 link->ndisc_routes_configured = false;
1127
1128 link_dirty(link);
1129
50550722
YW
1130 r = sd_ndisc_router_get_address(rt, &router);
1131 if (r < 0)
1132 return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
69203fba 1133
90e74a66 1134 SET_FOREACH(na, link->ndisc_addresses)
50550722
YW
1135 if (IN6_ARE_ADDR_EQUAL(&na->router, &router))
1136 na->marked = true;
1137
90e74a66 1138 SET_FOREACH(nr, link->ndisc_routes)
50550722
YW
1139 if (IN6_ARE_ADDR_EQUAL(&nr->router, &router))
1140 nr->marked = true;
69203fba 1141
1e7a0e21 1142 r = sd_ndisc_router_get_flags(rt, &flags);
d5017c84 1143 if (r < 0)
13e8a49a 1144 return log_link_error_errno(link, r, "Failed to get RA flags: %m");
1e7a0e21 1145
ac24e418
SS
1146 if ((flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER) && link->network->ipv6_accept_ra_start_dhcp6_client)) {
1147
1148 if (link->network->ipv6_accept_ra_start_dhcp6_client == IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS)
1149 r = dhcp6_request_address(link, false);
1150 else
1151 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
1152 r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
1e7a0e21 1153 if (r < 0 && r != -EBUSY)
13e8a49a 1154 return log_link_error_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
69203fba 1155 else
1e7a0e21
LP
1156 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
1157 }
1158
13e8a49a
YW
1159 r = ndisc_router_process_default(link, rt);
1160 if (r < 0)
1161 return r;
1162 r = ndisc_router_process_options(link, rt);
1163 if (r < 0)
1164 return r;
d5017c84 1165
69203fba
YW
1166 if (link->ndisc_addresses_messages == 0)
1167 link->ndisc_addresses_configured = true;
1168 else {
1169 log_link_debug(link, "Setting SLAAC addresses.");
1170
141318f7
YW
1171 /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are
1172 * called, the related flags must be cleared. Otherwise, the link becomes configured
1173 * state before routes are configured. */
69203fba
YW
1174 link->static_routes_configured = false;
1175 link->static_nexthops_configured = false;
1176 }
1177
1178 if (link->ndisc_routes_messages == 0)
1179 link->ndisc_routes_configured = true;
1180 else
1181 log_link_debug(link, "Setting NDisc routes.");
1182
50550722 1183 r = ndisc_remove_old(link);
69203fba
YW
1184 if (r < 0)
1185 return r;
1186
1187 if (link->ndisc_addresses_configured && link->ndisc_routes_configured)
1188 link_check_ready(link);
1189 else
1190 link_set_state(link, LINK_STATE_CONFIGURING);
1191
1192 return 0;
1e7a0e21
LP
1193}
1194
1195static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
9d96e6c3 1196 Link *link = userdata;
13e8a49a 1197 int r;
a13c50e7 1198
9d96e6c3 1199 assert(link);
a13c50e7 1200
9d96e6c3
TG
1201 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1202 return;
a13c50e7 1203
9d96e6c3 1204 switch (event) {
1e7a0e21
LP
1205
1206 case SD_NDISC_EVENT_ROUTER:
13e8a49a
YW
1207 r = ndisc_router_handler(link, rt);
1208 if (r < 0) {
1209 link_enter_failed(link);
1210 return;
1211 }
1e7a0e21
LP
1212 break;
1213
9d96e6c3 1214 case SD_NDISC_EVENT_TIMEOUT:
a8c10331 1215 log_link_debug(link, "NDisc handler get timeout event");
3336e946
YW
1216 if (link->ndisc_addresses_messages == 0 && link->ndisc_routes_messages == 0) {
1217 link->ndisc_addresses_configured = true;
1218 link->ndisc_routes_configured = true;
1219 link_check_ready(link);
1220 }
9d96e6c3
TG
1221 break;
1222 default:
a8c10331 1223 assert_not_reached("Unknown NDisc event");
a13c50e7
TG
1224 }
1225}
1226
1227int ndisc_configure(Link *link) {
1228 int r;
1229
1e7a0e21
LP
1230 assert(link);
1231
2ffd6d73
YW
1232 if (!link_ipv6_accept_ra_enabled(link))
1233 return 0;
a13c50e7 1234
2ffd6d73
YW
1235 if (!link->ndisc) {
1236 r = sd_ndisc_new(&link->ndisc);
1237 if (r < 0)
1238 return r;
1239
4cf85000 1240 r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
2ffd6d73
YW
1241 if (r < 0)
1242 return r;
1243 }
a13c50e7 1244
1e7a0e21 1245 r = sd_ndisc_set_mac(link->ndisc, &link->mac);
a13c50e7
TG
1246 if (r < 0)
1247 return r;
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
1260void ndisc_vacuum(Link *link) {
1261 NDiscRDNSS *r;
1262 NDiscDNSSL *d;
1e7a0e21 1263 usec_t time_now;
b0b97766 1264 bool updated = false;
1e7a0e21
LP
1265
1266 assert(link);
1267
1268 /* Removes all RDNSS and DNSSL entries whose validity time has passed */
1269
1270 time_now = now(clock_boottime_or_monotonic());
1271
90e74a66 1272 SET_FOREACH(r, link->ndisc_rdnss)
1e7a0e21 1273 if (r->valid_until < time_now) {
02affb4e 1274 free(set_remove(link->ndisc_rdnss, r));
b0b97766 1275 updated = true;
1e7a0e21 1276 }
a13c50e7 1277
90e74a66 1278 SET_FOREACH(d, link->ndisc_dnssl)
1e7a0e21 1279 if (d->valid_until < time_now) {
02affb4e 1280 free(set_remove(link->ndisc_dnssl, d));
b0b97766 1281 updated = true;
1e7a0e21 1282 }
b0b97766
YW
1283
1284 if (updated)
1285 link_dirty(link);
a13c50e7 1286}
c69305ff
LP
1287
1288void ndisc_flush(Link *link) {
1289 assert(link);
1290
1291 /* Removes all RDNSS and DNSSL entries, without exception */
1292
b0b97766
YW
1293 link->ndisc_rdnss = set_free(link->ndisc_rdnss);
1294 link->ndisc_dnssl = set_free(link->ndisc_dnssl);
c69305ff 1295}
e520ce64 1296
5f506a55
SS
1297int ipv6token_new(IPv6Token **ret) {
1298 IPv6Token *p;
1299
1300 p = new(IPv6Token, 1);
1301 if (!p)
1302 return -ENOMEM;
1303
1304 *p = (IPv6Token) {
1305 .address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_NONE,
1306 };
1307
1308 *ret = TAKE_PTR(p);
1309
1310 return 0;
1311}
1312
2c621495
YW
1313static void ipv6_token_hash_func(const IPv6Token *p, struct siphash *state) {
1314 siphash24_compress(&p->address_generation_type, sizeof(p->address_generation_type), state);
1315 siphash24_compress(&p->prefix, sizeof(p->prefix), state);
1316}
1317
1318static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) {
1319 int r;
1320
1321 r = CMP(a->address_generation_type, b->address_generation_type);
1322 if (r != 0)
1323 return r;
1324
1325 return memcmp(&a->prefix, &b->prefix, sizeof(struct in6_addr));
1326}
1327
1328DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
5f506a55 1329 ipv6_token_hash_ops,
5f506a55 1330 IPv6Token,
2c621495
YW
1331 ipv6_token_hash_func,
1332 ipv6_token_compare_func,
5f506a55
SS
1333 free);
1334
6b000af4 1335int config_parse_ndisc_deny_listed_prefix(
e520ce64
SS
1336 const char *unit,
1337 const char *filename,
1338 unsigned line,
1339 const char *section,
1340 unsigned section_line,
1341 const char *lvalue,
1342 int ltype,
1343 const char *rvalue,
1344 void *data,
1345 void *userdata) {
1346
1347 Network *network = data;
1348 const char *p;
1349 int r;
1350
1351 assert(filename);
1352 assert(lvalue);
1353 assert(rvalue);
1354 assert(data);
1355
1356 if (isempty(rvalue)) {
6b000af4 1357 network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
e520ce64
SS
1358 return 0;
1359 }
1360
1361 for (p = rvalue;;) {
1362 _cleanup_free_ char *n = NULL;
1363 _cleanup_free_ struct in6_addr *a = NULL;
1364 union in_addr_union ip;
1365
1366 r = extract_first_word(&p, &n, NULL, 0);
d96edb2c
YW
1367 if (r == -ENOMEM)
1368 return log_oom();
e520ce64 1369 if (r < 0) {
d96edb2c 1370 log_syntax(unit, LOG_WARNING, filename, line, r,
a8c10331 1371 "Failed to parse NDisc deny-listed prefix, ignoring assignment: %s",
e520ce64
SS
1372 rvalue);
1373 return 0;
1374 }
1375 if (r == 0)
1376 return 0;
1377
1378 r = in_addr_from_string(AF_INET6, n, &ip);
1379 if (r < 0) {
d96edb2c 1380 log_syntax(unit, LOG_WARNING, filename, line, r,
a8c10331 1381 "NDisc deny-listed prefix is invalid, ignoring assignment: %s", n);
e520ce64
SS
1382 continue;
1383 }
1384
6b000af4 1385 if (set_contains(network->ndisc_deny_listed_prefix, &ip.in6))
e4443f9b
YW
1386 continue;
1387
e520ce64
SS
1388 a = newdup(struct in6_addr, &ip.in6, 1);
1389 if (!a)
1390 return log_oom();
1391
6b000af4 1392 r = set_ensure_consume(&network->ndisc_deny_listed_prefix, &in6_addr_hash_ops, TAKE_PTR(a));
35e601d4
ZJS
1393 if (r < 0)
1394 return log_oom();
e520ce64 1395 }
e520ce64 1396}
5f506a55
SS
1397
1398int config_parse_address_generation_type(
1399 const char *unit,
1400 const char *filename,
1401 unsigned line,
1402 const char *section,
1403 unsigned section_line,
1404 const char *lvalue,
1405 int ltype,
1406 const char *rvalue,
1407 void *data,
1408 void *userdata) {
1409
1410 _cleanup_free_ IPv6Token *token = NULL;
5f506a55
SS
1411 union in_addr_union buffer;
1412 Network *network = data;
1413 const char *p;
1414 int r;
1415
1416 assert(filename);
1417 assert(lvalue);
1418 assert(rvalue);
1419 assert(data);
1420
1421 if (isempty(rvalue)) {
2c621495 1422 network->ipv6_tokens = ordered_set_free(network->ipv6_tokens);
5f506a55
SS
1423 return 0;
1424 }
1425
5f506a55
SS
1426 r = ipv6token_new(&token);
1427 if (r < 0)
1428 return log_oom();
1429
b27caa34 1430 if ((p = startswith(rvalue, "prefixstable"))) {
5f506a55 1431 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE;
b27caa34
YW
1432 if (*p == ':')
1433 p++;
1434 else if (*p == '\0')
1435 p = NULL;
1436 else {
1437 log_syntax(unit, LOG_WARNING, filename, line, 0,
1438 "Invalid IPv6 token mode in %s=, ignoring assignment: %s",
1439 lvalue, rvalue);
1440 return 0;
1441 }
1442 } else {
e2c4070e 1443 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_STATIC;
b27caa34
YW
1444 p = startswith(rvalue, "static:");
1445 if (!p)
1446 p = rvalue;
f0c1ad30
YW
1447 }
1448
b27caa34
YW
1449 if (p) {
1450 r = in_addr_from_string(AF_INET6, p, &buffer);
1451 if (r < 0) {
1452 log_syntax(unit, LOG_WARNING, filename, line, r,
1453 "Failed to parse IP address in %s=, ignoring assignment: %s",
1454 lvalue, rvalue);
1455 return 0;
1456 }
1457 if (token->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_STATIC &&
1458 in_addr_is_null(AF_INET6, &buffer)) {
1459 log_syntax(unit, LOG_WARNING, filename, line, 0,
1460 "IPv6 address in %s= cannot be the ANY address, ignoring assignment: %s",
1461 lvalue, rvalue);
1462 return 0;
1463 }
1464 token->prefix = buffer.in6;
5f506a55
SS
1465 }
1466
2c621495 1467 r = ordered_set_ensure_allocated(&network->ipv6_tokens, &ipv6_token_hash_ops);
5f506a55
SS
1468 if (r < 0)
1469 return log_oom();
1470
2c621495
YW
1471 r = ordered_set_put(network->ipv6_tokens, token);
1472 if (r == -EEXIST)
1473 log_syntax(unit, LOG_DEBUG, filename, line, r,
1474 "IPv6 token '%s' is duplicated, ignoring: %m", rvalue);
1475 else if (r < 0)
d96edb2c 1476 log_syntax(unit, LOG_WARNING, filename, line, r,
2c621495
YW
1477 "Failed to store IPv6 token '%s', ignoring: %m", rvalue);
1478 else
1479 TAKE_PTR(token);
5f506a55
SS
1480
1481 return 0;
1482}
ac24e418
SS
1483
1484DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
1485 "Failed to parse DHCPv6Client= setting")
1486static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
1487 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
1488 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
1489 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
1490};
1491
1492DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);