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