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