]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ndisc.c
Merge pull request #15036 from yuwata/can-termination-mod
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/icmp6.h>
7 #include <arpa/inet.h>
8
9 #include "sd-ndisc.h"
10
11 #include "missing_network.h"
12 #include "networkd-dhcp6.h"
13 #include "networkd-manager.h"
14 #include "networkd-ndisc.h"
15 #include "networkd-route.h"
16 #include "string-util.h"
17 #include "strv.h"
18
19 #define NDISC_DNSSL_MAX 64U
20 #define NDISC_RDNSS_MAX 64U
21 #define NDISC_PREFIX_LFT_MIN 7200U
22
23 #define DAD_CONFLICTS_IDGEN_RETRIES_RFC7217 3
24
25 /* https://tools.ietf.org/html/rfc5453 */
26 /* https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xml */
27
28 #define SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } })
29 #define SUBNET_ROUTER_ANYCAST_PREFIXLEN 8
30 #define RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x02, 0x00, 0x5E, 0xFF, 0xFE } })
31 #define RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN 5
32 #define RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291 ((struct in6_addr) { .s6_addr = { 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } })
33 #define RESERVED_SUBNET_ANYCAST_PREFIXLEN 7
34
35 #define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
36
37 static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
38 assert(addr);
39
40 /* According to rfc4291, generated address should not be in the following ranges. */
41
42 if (memcmp(addr, &SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291, SUBNET_ROUTER_ANYCAST_PREFIXLEN) == 0)
43 return false;
44
45 if (memcmp(addr, &RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291, RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN) == 0)
46 return false;
47
48 if (memcmp(addr, &RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291, RESERVED_SUBNET_ANYCAST_PREFIXLEN) == 0)
49 return false;
50
51 return true;
52 }
53
54 static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr *addr) {
55 sd_id128_t secret_key;
56 struct siphash state;
57 uint64_t rid;
58 size_t l;
59 int r;
60
61 /* According to rfc7217 section 5.1
62 * RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) */
63
64 r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key);
65 if (r < 0)
66 return log_error_errno(r, "Failed to generate key: %m");
67
68 siphash24_init(&state, secret_key.bytes);
69
70 l = MAX(DIV_ROUND_UP(prefix_len, 8), 8);
71 siphash24_compress(prefix, l, &state);
72 siphash24_compress(link->ifname, strlen(link->ifname), &state);
73 siphash24_compress(&link->mac, sizeof(struct ether_addr), &state);
74 siphash24_compress(&dad_counter, sizeof(uint8_t), &state);
75
76 rid = htole64(siphash24_finalize(&state));
77
78 memcpy(addr->s6_addr, prefix->s6_addr, l);
79 memcpy((uint8_t *) &addr->s6_addr + l, &rid, 16 - l);
80
81 return 0;
82 }
83
84 static int ndisc_netlink_route_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
85 int r;
86
87 assert(link);
88 assert(link->ndisc_messages > 0);
89
90 link->ndisc_messages--;
91
92 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
93 return 1;
94
95 r = sd_netlink_message_get_errno(m);
96 if (r < 0 && r != -EEXIST) {
97 log_link_message_error_errno(link, m, r, "Could not set NDisc route or address");
98 link_enter_failed(link);
99 return 1;
100 }
101
102 if (link->ndisc_messages == 0) {
103 link->ndisc_configured = true;
104 r = link_request_set_routes(link);
105 if (r < 0) {
106 link_enter_failed(link);
107 return 1;
108 }
109 link_check_ready(link);
110 }
111
112 return 1;
113 }
114
115 static int ndisc_netlink_address_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
116 int r;
117
118 assert(link);
119 assert(link->ndisc_messages > 0);
120
121 link->ndisc_messages--;
122
123 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
124 return 1;
125
126 r = sd_netlink_message_get_errno(m);
127 if (r < 0 && r != -EEXIST) {
128 log_link_message_error_errno(link, m, r, "Could not set NDisc route or address");
129 link_enter_failed(link);
130 return 1;
131 } else if (r >= 0)
132 (void) manager_rtnl_process_address(rtnl, m, link->manager);
133
134 if (link->ndisc_messages == 0) {
135 link->ndisc_configured = true;
136 r = link_request_set_routes(link);
137 if (r < 0) {
138 link_enter_failed(link);
139 return 1;
140 }
141 link_check_ready(link);
142 }
143
144 return 1;
145 }
146
147 static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
148 _cleanup_(route_freep) Route *route = NULL;
149 union in_addr_union gateway;
150 uint16_t lifetime;
151 unsigned preference;
152 uint32_t mtu;
153 usec_t time_now;
154 int r;
155 Address *address;
156 Iterator i;
157
158 assert(link);
159 assert(rt);
160
161 r = sd_ndisc_router_get_lifetime(rt, &lifetime);
162 if (r < 0)
163 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
164
165 if (lifetime == 0) /* not a default router */
166 return 0;
167
168 r = sd_ndisc_router_get_address(rt, &gateway.in6);
169 if (r < 0)
170 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
171
172 SET_FOREACH(address, link->addresses, i) {
173 if (address->family != AF_INET6)
174 continue;
175 if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
176 _cleanup_free_ char *buffer = NULL;
177
178 (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
179 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
180 strnull(buffer));
181 return 0;
182 }
183 }
184
185 SET_FOREACH(address, link->addresses_foreign, i) {
186 if (address->family != AF_INET6)
187 continue;
188 if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
189 _cleanup_free_ char *buffer = NULL;
190
191 (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
192 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
193 strnull(buffer));
194 return 0;
195 }
196 }
197
198 r = sd_ndisc_router_get_preference(rt, &preference);
199 if (r < 0)
200 return log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
201
202 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
203 if (r < 0)
204 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
205
206 r = sd_ndisc_router_get_mtu(rt, &mtu);
207 if (r == -ENODATA)
208 mtu = 0;
209 else if (r < 0)
210 return log_link_warning_errno(link, r, "Failed to get default router MTU from RA: %m");
211
212 r = route_new(&route);
213 if (r < 0)
214 return log_link_error_errno(link, r, "Could not allocate route: %m");
215
216 route->family = AF_INET6;
217 route->table = link_get_ipv6_accept_ra_route_table(link);
218 route->priority = link->network->dhcp_route_metric;
219 route->protocol = RTPROT_RA;
220 route->pref = preference;
221 route->gw = gateway;
222 route->lifetime = time_now + lifetime * USEC_PER_SEC;
223 route->mtu = mtu;
224
225 r = route_configure(route, link, ndisc_netlink_route_message_handler);
226 if (r < 0) {
227 log_link_warning_errno(link, r, "Could not set default route: %m");
228 link_enter_failed(link);
229 return r;
230 }
231 if (r > 0)
232 link->ndisc_messages++;
233
234 Route *route_gw;
235 LIST_FOREACH(routes, route_gw, link->network->static_routes) {
236 if (!route_gw->gateway_from_dhcp)
237 continue;
238
239 if (route_gw->family != AF_INET6)
240 continue;
241
242 route_gw->gw = gateway;
243
244 r = route_configure(route_gw, link, ndisc_netlink_route_message_handler);
245 if (r < 0) {
246 log_link_error_errno(link, r, "Could not set gateway: %m");
247 link_enter_failed(link);
248 return r;
249 }
250 if (r > 0)
251 link->ndisc_messages++;
252 }
253
254 return 0;
255 }
256
257 static int ndisc_router_generate_addresses(Link *link, unsigned prefixlen, uint32_t lifetime_preferred, Address *address, Set **ret) {
258 _cleanup_set_free_free_ Set *addresses = NULL;
259 struct in6_addr addr;
260 IPv6Token *j;
261 Iterator i;
262 int r;
263
264 assert(link);
265 assert(address);
266 assert(ret);
267
268 addresses = set_new(&address_hash_ops);
269 if (!addresses)
270 return log_oom();
271
272 addr = address->in_addr.in6;
273 ORDERED_HASHMAP_FOREACH(j, link->network->ipv6_tokens, i) {
274 bool have_address = false;
275 _cleanup_(address_freep) Address *new_address = NULL;
276
277 r = address_new(&new_address);
278 if (r < 0)
279 return log_oom();
280
281 *new_address = *address;
282
283 if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
284 && memcmp(&j->prefix, &addr, FAMILY_ADDRESS_SIZE(address->family)) == 0) {
285 /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop
286 does not actually attempt Duplicate Address Detection; the counter will be incremented
287 only when the address generation algorithm produces an invalid address, and the loop
288 may exit with an address which ends up being unusable due to duplication on the link.
289 */
290 for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
291 r = make_stableprivate_address(link, &j->prefix, prefixlen, j->dad_counter, &new_address->in_addr.in6);
292 if (r < 0)
293 break;
294
295 if (stableprivate_address_is_valid(&new_address->in_addr.in6)) {
296 have_address = true;
297 break;
298 }
299 }
300 } else if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_STATIC) {
301 memcpy(((uint8_t *)&new_address->in_addr.in6) + 8, ((uint8_t *) &j->prefix) + 8, 8);
302 have_address = true;
303 }
304
305 if (have_address) {
306 new_address->prefixlen = prefixlen;
307 new_address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
308 new_address->cinfo.ifa_prefered = lifetime_preferred;
309
310 r = set_put(addresses, new_address);
311 if (r < 0)
312 return log_link_warning_errno(link, r, "Failed to store address: %m");
313 TAKE_PTR(new_address);
314 }
315 }
316
317 /* fall back to EUI-64 if no tokens provided addresses */
318 if (set_isempty(addresses)) {
319 _cleanup_(address_freep) Address *new_address = NULL;
320
321 r = address_new(&new_address);
322 if (r < 0)
323 return log_oom();
324
325 *new_address = *address;
326
327 r = generate_ipv6_eui_64_address(link, &new_address->in_addr.in6);
328 if (r < 0)
329 return log_link_error_errno(link, r, "Failed to generate EUI64 address: %m");
330
331 new_address->prefixlen = prefixlen;
332 new_address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
333 new_address->cinfo.ifa_prefered = lifetime_preferred;
334
335 r = set_put(addresses, new_address);
336 if (r < 0)
337 return log_link_warning_errno(link, r, "Failed to store address: %m");
338 TAKE_PTR(new_address);
339 }
340
341 *ret = TAKE_PTR(addresses);
342
343 return 0;
344 }
345
346 static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
347 uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
348 _cleanup_set_free_free_ Set *addresses = NULL;
349 _cleanup_(address_freep) Address *address = NULL;
350 unsigned prefixlen;
351 usec_t time_now;
352 Address *existing_address, *a;
353 Iterator i;
354 int r;
355
356 assert(link);
357 assert(rt);
358
359 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
360 if (r < 0)
361 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
362
363 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
364 if (r < 0)
365 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
366
367 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
368 if (r < 0)
369 return log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
370
371 r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
372 if (r < 0)
373 return log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
374
375 /* The preferred lifetime is never greater than the valid lifetime */
376 if (lifetime_preferred > lifetime_valid)
377 return 0;
378
379 r = address_new(&address);
380 if (r < 0)
381 return log_link_error_errno(link, r, "Could not allocate address: %m");
382
383 address->family = AF_INET6;
384 r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6);
385 if (r < 0)
386 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
387
388 r = ndisc_router_generate_addresses(link, prefixlen, lifetime_preferred, address, &addresses);
389 if (r < 0)
390 return log_link_error_errno(link, r, "Failed to generate SLAAC addresses: %m");
391
392 SET_FOREACH(a, addresses, i) {
393 /* see RFC4862 section 5.5.3.e */
394 r = address_get(link, a->family, &a->in_addr, a->prefixlen, &existing_address);
395 if (r > 0) {
396 lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
397 if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
398 a->cinfo.ifa_valid = lifetime_valid;
399 else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN)
400 a->cinfo.ifa_valid = lifetime_remaining;
401 else
402 a->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN;
403 } else if (lifetime_valid > 0)
404 a->cinfo.ifa_valid = lifetime_valid;
405 else
406 return 0; /* see RFC4862 section 5.5.3.d */
407
408 if (a->cinfo.ifa_valid == 0)
409 continue;
410
411 r = address_configure(a, link, ndisc_netlink_address_message_handler, true);
412 if (r < 0) {
413 log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
414 link_enter_failed(link);
415 return r;
416 }
417
418 if (r > 0)
419 link->ndisc_messages++;
420 }
421
422 return 0;
423 }
424
425 static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
426 _cleanup_(route_freep) Route *route = NULL;
427 usec_t time_now;
428 uint32_t lifetime;
429 unsigned prefixlen;
430 int r;
431
432 assert(link);
433 assert(rt);
434
435 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
436 if (r < 0)
437 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
438
439 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
440 if (r < 0)
441 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
442
443 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime);
444 if (r < 0)
445 return log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
446
447 r = route_new(&route);
448 if (r < 0)
449 return log_link_error_errno(link, r, "Could not allocate route: %m");
450
451 route->family = AF_INET6;
452 route->table = link_get_ipv6_accept_ra_route_table(link);
453 route->priority = link->network->dhcp_route_metric;
454 route->protocol = RTPROT_RA;
455 route->flags = RTM_F_PREFIX;
456 route->dst_prefixlen = prefixlen;
457 route->lifetime = time_now + lifetime * USEC_PER_SEC;
458
459 r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
460 if (r < 0)
461 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
462
463 r = route_configure(route, link, ndisc_netlink_route_message_handler);
464 if (r < 0) {
465 log_link_warning_errno(link, r, "Could not set prefix route: %m");
466 link_enter_failed(link);
467 return r;
468 }
469 if (r > 0)
470 link->ndisc_messages++;
471
472 return 0;
473 }
474
475 static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
476 _cleanup_(route_freep) Route *route = NULL;
477 struct in6_addr gateway;
478 uint32_t lifetime;
479 unsigned preference, prefixlen;
480 usec_t time_now;
481 int r;
482
483 assert(link);
484
485 r = sd_ndisc_router_route_get_lifetime(rt, &lifetime);
486 if (r < 0)
487 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
488
489 if (lifetime == 0)
490 return 0;
491
492 r = sd_ndisc_router_get_address(rt, &gateway);
493 if (r < 0)
494 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
495
496 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
497 if (r < 0)
498 return log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
499
500 r = sd_ndisc_router_route_get_preference(rt, &preference);
501 if (r < 0)
502 return log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
503
504 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
505 if (r < 0)
506 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
507
508 r = route_new(&route);
509 if (r < 0)
510 return log_link_error_errno(link, r, "Could not allocate route: %m");
511
512 route->family = AF_INET6;
513 route->table = link_get_ipv6_accept_ra_route_table(link);
514 route->protocol = RTPROT_RA;
515 route->pref = preference;
516 route->gw.in6 = gateway;
517 route->dst_prefixlen = prefixlen;
518 route->lifetime = time_now + lifetime * USEC_PER_SEC;
519
520 r = sd_ndisc_router_route_get_address(rt, &route->dst.in6);
521 if (r < 0)
522 return log_link_error_errno(link, r, "Failed to get route address: %m");
523
524 r = route_configure(route, link, ndisc_netlink_route_message_handler);
525 if (r < 0) {
526 log_link_warning_errno(link, r, "Could not set additional route: %m");
527 link_enter_failed(link);
528 return r;
529 }
530 if (r > 0)
531 link->ndisc_messages++;
532
533 return 0;
534 }
535
536 static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
537 siphash24_compress(&x->address, sizeof(x->address), state);
538 }
539
540 static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
541 return memcmp(&a->address, &b->address, sizeof(a->address));
542 }
543
544 DEFINE_PRIVATE_HASH_OPS(ndisc_rdnss_hash_ops, NDiscRDNSS, ndisc_rdnss_hash_func, ndisc_rdnss_compare_func);
545
546 static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
547 uint32_t lifetime;
548 const struct in6_addr *a;
549 usec_t time_now;
550 int i, n, r;
551
552 assert(link);
553 assert(rt);
554
555 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
556 if (r < 0)
557 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
558
559 r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime);
560 if (r < 0)
561 return log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
562
563 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
564 if (n < 0)
565 return log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
566
567 for (i = 0; i < n; i++) {
568 _cleanup_free_ NDiscRDNSS *x = NULL;
569 NDiscRDNSS d = {
570 .address = a[i],
571 }, *y;
572
573 if (lifetime == 0) {
574 (void) set_remove(link->ndisc_rdnss, &d);
575 link_dirty(link);
576 continue;
577 }
578
579 y = set_get(link->ndisc_rdnss, &d);
580 if (y) {
581 y->valid_until = time_now + lifetime * USEC_PER_SEC;
582 continue;
583 }
584
585 ndisc_vacuum(link);
586
587 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
588 log_link_warning(link, "Too many RDNSS records per link, ignoring.");
589 continue;
590 }
591
592 r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops);
593 if (r < 0)
594 return log_oom();
595
596 x = new(NDiscRDNSS, 1);
597 if (!x)
598 return log_oom();
599
600 *x = (NDiscRDNSS) {
601 .address = a[i],
602 .valid_until = time_now + lifetime * USEC_PER_SEC,
603 };
604
605 r = set_put(link->ndisc_rdnss, x);
606 if (r < 0)
607 return log_oom();
608
609 TAKE_PTR(x);
610
611 assert(r > 0);
612 link_dirty(link);
613 }
614
615 return 0;
616 }
617
618 static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
619 siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state);
620 }
621
622 static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
623 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
624 }
625
626 DEFINE_PRIVATE_HASH_OPS(ndisc_dnssl_hash_ops, NDiscDNSSL, ndisc_dnssl_hash_func, ndisc_dnssl_compare_func);
627
628 static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
629 _cleanup_strv_free_ char **l = NULL;
630 uint32_t lifetime;
631 usec_t time_now;
632 char **i;
633 int r;
634
635 assert(link);
636 assert(rt);
637
638 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
639 if (r < 0) {
640 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
641 return;
642 }
643
644 r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime);
645 if (r < 0) {
646 log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
647 return;
648 }
649
650 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
651 if (r < 0) {
652 log_link_warning_errno(link, r, "Failed to get RDNSS addresses: %m");
653 return;
654 }
655
656 STRV_FOREACH(i, l) {
657 _cleanup_free_ NDiscDNSSL *s;
658 NDiscDNSSL *x;
659
660 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1);
661 if (!s) {
662 log_oom();
663 return;
664 }
665
666 strcpy(NDISC_DNSSL_DOMAIN(s), *i);
667
668 if (lifetime == 0) {
669 (void) set_remove(link->ndisc_dnssl, s);
670 link_dirty(link);
671 continue;
672 }
673
674 x = set_get(link->ndisc_dnssl, s);
675 if (x) {
676 x->valid_until = time_now + lifetime * USEC_PER_SEC;
677 continue;
678 }
679
680 ndisc_vacuum(link);
681
682 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
683 log_link_warning(link, "Too many DNSSL records per link, ignoring.");
684 continue;
685 }
686
687 r = set_ensure_allocated(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops);
688 if (r < 0) {
689 log_oom();
690 return;
691 }
692
693 s->valid_until = time_now + lifetime * USEC_PER_SEC;
694
695 r = set_put(link->ndisc_dnssl, s);
696 if (r < 0) {
697 log_oom();
698 return;
699 }
700
701 s = NULL;
702 assert(r > 0);
703 link_dirty(link);
704 }
705 }
706
707 static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
708 int r;
709
710 assert(link);
711 assert(link->network);
712 assert(rt);
713
714 r = sd_ndisc_router_option_rewind(rt);
715 for (;;) {
716 uint8_t type;
717
718 if (r < 0)
719 return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
720 if (r == 0) /* EOF */
721 break;
722
723 r = sd_ndisc_router_option_get_type(rt, &type);
724 if (r < 0)
725 return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
726
727 switch (type) {
728
729 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
730 union in_addr_union a;
731 uint8_t flags;
732
733 r = sd_ndisc_router_prefix_get_address(rt, &a.in6);
734 if (r < 0)
735 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
736
737 if (set_contains(link->network->ndisc_black_listed_prefix, &a.in6)) {
738 if (DEBUG_LOGGING) {
739 _cleanup_free_ char *b = NULL;
740
741 (void) in_addr_to_string(AF_INET6, &a, &b);
742 log_link_debug(link, "Prefix '%s' is black listed, ignoring", strna(b));
743 }
744
745 break;
746 }
747
748 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
749 if (r < 0)
750 return log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
751
752 if (link->network->ipv6_accept_ra_use_onlink_prefix &&
753 FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK))
754 (void) ndisc_router_process_onlink_prefix(link, rt);
755
756 if (link->network->ipv6_accept_ra_use_autonomous_prefix &&
757 FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO))
758 (void) ndisc_router_process_autonomous_prefix(link, rt);
759
760 break;
761 }
762
763 case SD_NDISC_OPTION_ROUTE_INFORMATION:
764 (void) ndisc_router_process_route(link, rt);
765 break;
766
767 case SD_NDISC_OPTION_RDNSS:
768 if (link->network->ipv6_accept_ra_use_dns)
769 (void) ndisc_router_process_rdnss(link, rt);
770 break;
771
772 case SD_NDISC_OPTION_DNSSL:
773 if (link->network->ipv6_accept_ra_use_dns)
774 (void) ndisc_router_process_dnssl(link, rt);
775 break;
776 }
777
778 r = sd_ndisc_router_option_next(rt);
779 }
780
781 return 0;
782 }
783
784 static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
785 uint64_t flags;
786 int r;
787
788 assert(link);
789 assert(link->network);
790 assert(link->manager);
791 assert(rt);
792
793 r = sd_ndisc_router_get_flags(rt, &flags);
794 if (r < 0)
795 return log_link_warning_errno(link, r, "Failed to get RA flags: %m");
796
797 if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER) &&
798 link->network->ipv6_accept_ra_start_dhcp6_client) {
799 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
800 r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
801 if (r < 0 && r != -EBUSY)
802 log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
803 else {
804 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
805 r = 0;
806 }
807 }
808
809 (void) ndisc_router_process_default(link, rt);
810 (void) ndisc_router_process_options(link, rt);
811
812 return r;
813 }
814
815 static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
816 Link *link = userdata;
817
818 assert(link);
819
820 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
821 return;
822
823 switch (event) {
824
825 case SD_NDISC_EVENT_ROUTER:
826 (void) ndisc_router_handler(link, rt);
827 break;
828
829 case SD_NDISC_EVENT_TIMEOUT:
830 link->ndisc_configured = true;
831 link_check_ready(link);
832
833 break;
834 default:
835 log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
836 }
837 }
838
839 int ndisc_configure(Link *link) {
840 int r;
841
842 assert(link);
843
844 r = sd_ndisc_new(&link->ndisc);
845 if (r < 0)
846 return r;
847
848 r = sd_ndisc_attach_event(link->ndisc, NULL, 0);
849 if (r < 0)
850 return r;
851
852 r = sd_ndisc_set_mac(link->ndisc, &link->mac);
853 if (r < 0)
854 return r;
855
856 r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
857 if (r < 0)
858 return r;
859
860 r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
861 if (r < 0)
862 return r;
863
864 return 0;
865 }
866
867 void ndisc_vacuum(Link *link) {
868 NDiscRDNSS *r;
869 NDiscDNSSL *d;
870 Iterator i;
871 usec_t time_now;
872
873 assert(link);
874
875 /* Removes all RDNSS and DNSSL entries whose validity time has passed */
876
877 time_now = now(clock_boottime_or_monotonic());
878
879 SET_FOREACH(r, link->ndisc_rdnss, i)
880 if (r->valid_until < time_now) {
881 free(set_remove(link->ndisc_rdnss, r));
882 link_dirty(link);
883 }
884
885 SET_FOREACH(d, link->ndisc_dnssl, i)
886 if (d->valid_until < time_now) {
887 free(set_remove(link->ndisc_dnssl, d));
888 link_dirty(link);
889 }
890 }
891
892 void ndisc_flush(Link *link) {
893 assert(link);
894
895 /* Removes all RDNSS and DNSSL entries, without exception */
896
897 link->ndisc_rdnss = set_free_free(link->ndisc_rdnss);
898 link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
899 }
900
901 int ipv6token_new(IPv6Token **ret) {
902 IPv6Token *p;
903
904 p = new(IPv6Token, 1);
905 if (!p)
906 return -ENOMEM;
907
908 *p = (IPv6Token) {
909 .address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_NONE,
910 };
911
912 *ret = TAKE_PTR(p);
913
914 return 0;
915 }
916
917 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
918 ipv6_token_hash_ops,
919 void,
920 trivial_hash_func,
921 trivial_compare_func,
922 IPv6Token,
923 free);
924
925 int config_parse_ndisc_black_listed_prefix(
926 const char *unit,
927 const char *filename,
928 unsigned line,
929 const char *section,
930 unsigned section_line,
931 const char *lvalue,
932 int ltype,
933 const char *rvalue,
934 void *data,
935 void *userdata) {
936
937 Network *network = data;
938 const char *p;
939 int r;
940
941 assert(filename);
942 assert(lvalue);
943 assert(rvalue);
944 assert(data);
945
946 if (isempty(rvalue)) {
947 network->ndisc_black_listed_prefix = set_free_free(network->ndisc_black_listed_prefix);
948 return 0;
949 }
950
951 for (p = rvalue;;) {
952 _cleanup_free_ char *n = NULL;
953 _cleanup_free_ struct in6_addr *a = NULL;
954 union in_addr_union ip;
955
956 r = extract_first_word(&p, &n, NULL, 0);
957 if (r < 0) {
958 log_syntax(unit, LOG_ERR, filename, line, r,
959 "Failed to parse NDISC black listed prefix, ignoring assignment: %s",
960 rvalue);
961 return 0;
962 }
963 if (r == 0)
964 return 0;
965
966 r = in_addr_from_string(AF_INET6, n, &ip);
967 if (r < 0) {
968 log_syntax(unit, LOG_ERR, filename, line, r,
969 "NDISC black listed prefix is invalid, ignoring assignment: %s", n);
970 continue;
971 }
972
973 if (set_contains(network->ndisc_black_listed_prefix, &ip.in6))
974 continue;
975
976 r = set_ensure_allocated(&network->ndisc_black_listed_prefix, &in6_addr_hash_ops);
977 if (r < 0)
978 return log_oom();
979
980 a = newdup(struct in6_addr, &ip.in6, 1);
981 if (!a)
982 return log_oom();
983
984 r = set_put(network->ndisc_black_listed_prefix, a);
985 if (r < 0) {
986 log_syntax(unit, LOG_ERR, filename, line, r,
987 "Failed to store NDISC black listed prefix '%s', ignoring assignment: %m", n);
988 continue;
989 }
990
991 TAKE_PTR(a);
992 }
993
994 return 0;
995 }
996
997 int config_parse_address_generation_type(
998 const char *unit,
999 const char *filename,
1000 unsigned line,
1001 const char *section,
1002 unsigned section_line,
1003 const char *lvalue,
1004 int ltype,
1005 const char *rvalue,
1006 void *data,
1007 void *userdata) {
1008
1009 _cleanup_free_ IPv6Token *token = NULL;
1010 union in_addr_union buffer;
1011 Network *network = data;
1012 const char *p;
1013 int r;
1014
1015 assert(filename);
1016 assert(lvalue);
1017 assert(rvalue);
1018 assert(data);
1019
1020 if (isempty(rvalue)) {
1021 network->ipv6_tokens = ordered_hashmap_free(network->ipv6_tokens);
1022 return 0;
1023 }
1024
1025 r = ipv6token_new(&token);
1026 if (r < 0)
1027 return log_oom();
1028
1029 if ((p = startswith(rvalue, "static:")))
1030 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_STATIC;
1031 else if ((p = startswith(rvalue, "prefixstable:")))
1032 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE;
1033 else {
1034 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_STATIC;
1035 p = rvalue;
1036 }
1037
1038 r = in_addr_from_string(AF_INET6, p, &buffer);
1039 if (r < 0) {
1040 log_syntax(unit, LOG_ERR, filename, line, r,
1041 "Failed to parse IPv6 %s, ignoring: %s", lvalue, rvalue);
1042 return 0;
1043 }
1044
1045 if (in_addr_is_null(AF_INET6, &buffer)) {
1046 log_syntax(unit, LOG_ERR, filename, line, 0,
1047 "IPv6 %s cannot be the ANY address, ignoring: %s", lvalue, rvalue);
1048 return 0;
1049 }
1050
1051 token->prefix = buffer.in6;
1052
1053 r = ordered_hashmap_ensure_allocated(&network->ipv6_tokens, &ipv6_token_hash_ops);
1054 if (r < 0)
1055 return log_oom();
1056
1057 r = ordered_hashmap_put(network->ipv6_tokens, &token->prefix, token);
1058 if (r < 0) {
1059 log_syntax(unit, LOG_ERR, filename, line, r,
1060 "Failed to store IPv6 token '%s'", rvalue);
1061 return 0;
1062 }
1063
1064 TAKE_PTR(token);
1065
1066 return 0;
1067 }