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