]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-radv.c
Merge pull request #20303 from andir/sysconfig-example
[thirdparty/systemd.git] / src / network / networkd-radv.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2017 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/icmp6.h>
7 #include <arpa/inet.h>
8
9 #include "dns-domain.h"
10 #include "networkd-link.h"
11 #include "networkd-manager.h"
12 #include "networkd-network.h"
13 #include "networkd-queue.h"
14 #include "networkd-radv.h"
15 #include "parse-util.h"
16 #include "string-util.h"
17 #include "string-table.h"
18 #include "strv.h"
19
20 Prefix *prefix_free(Prefix *prefix) {
21 if (!prefix)
22 return NULL;
23
24 if (prefix->network) {
25 assert(prefix->section);
26 hashmap_remove(prefix->network->prefixes_by_section, prefix->section);
27 }
28
29 network_config_section_free(prefix->section);
30 sd_radv_prefix_unref(prefix->radv_prefix);
31
32 return mfree(prefix);
33 }
34
35 DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
36
37 static int prefix_new(Prefix **ret) {
38 _cleanup_(prefix_freep) Prefix *prefix = NULL;
39
40 prefix = new0(Prefix, 1);
41 if (!prefix)
42 return -ENOMEM;
43
44 if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
45 return -ENOMEM;
46
47 *ret = TAKE_PTR(prefix);
48
49 return 0;
50 }
51
52 static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
53 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
54 _cleanup_(prefix_freep) Prefix *prefix = NULL;
55 int r;
56
57 assert(network);
58 assert(ret);
59 assert(filename);
60 assert(section_line > 0);
61
62 r = network_config_section_new(filename, section_line, &n);
63 if (r < 0)
64 return r;
65
66 prefix = hashmap_get(network->prefixes_by_section, n);
67 if (prefix) {
68 *ret = TAKE_PTR(prefix);
69 return 0;
70 }
71
72 r = prefix_new(&prefix);
73 if (r < 0)
74 return r;
75
76 prefix->network = network;
77 prefix->section = TAKE_PTR(n);
78
79 r = hashmap_ensure_put(&network->prefixes_by_section, &network_config_hash_ops, prefix->section, prefix);
80 if (r < 0)
81 return r;
82
83 *ret = TAKE_PTR(prefix);
84
85 return 0;
86 }
87
88 RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
89 if (!prefix)
90 return NULL;
91
92 if (prefix->network) {
93 assert(prefix->section);
94 hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section);
95 }
96
97 network_config_section_free(prefix->section);
98 sd_radv_route_prefix_unref(prefix->radv_route_prefix);
99
100 return mfree(prefix);
101 }
102
103 DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
104
105 static int route_prefix_new(RoutePrefix **ret) {
106 _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
107
108 prefix = new0(RoutePrefix, 1);
109 if (!prefix)
110 return -ENOMEM;
111
112 if (sd_radv_route_prefix_new(&prefix->radv_route_prefix) < 0)
113 return -ENOMEM;
114
115 *ret = TAKE_PTR(prefix);
116
117 return 0;
118 }
119
120 static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
121 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
122 _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
123 int r;
124
125 assert(network);
126 assert(ret);
127 assert(filename);
128 assert(section_line > 0);
129
130 r = network_config_section_new(filename, section_line, &n);
131 if (r < 0)
132 return r;
133
134 prefix = hashmap_get(network->route_prefixes_by_section, n);
135 if (prefix) {
136 *ret = TAKE_PTR(prefix);
137 return 0;
138 }
139
140 r = route_prefix_new(&prefix);
141 if (r < 0)
142 return r;
143
144 prefix->network = network;
145 prefix->section = TAKE_PTR(n);
146
147 r = hashmap_ensure_put(&network->route_prefixes_by_section, &network_config_hash_ops, prefix->section, prefix);
148 if (r < 0)
149 return r;
150
151 *ret = TAKE_PTR(prefix);
152
153 return 0;
154 }
155
156 void network_drop_invalid_prefixes(Network *network) {
157 Prefix *prefix;
158
159 assert(network);
160
161 HASHMAP_FOREACH(prefix, network->prefixes_by_section)
162 if (section_is_invalid(prefix->section))
163 prefix_free(prefix);
164 }
165
166 void network_drop_invalid_route_prefixes(Network *network) {
167 RoutePrefix *prefix;
168
169 assert(network);
170
171 HASHMAP_FOREACH(prefix, network->route_prefixes_by_section)
172 if (section_is_invalid(prefix->section))
173 route_prefix_free(prefix);
174 }
175
176 void network_adjust_radv(Network *network) {
177 assert(network);
178
179 /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
180
181 if (network->dhcp6_pd < 0)
182 /* For backward compatibility. */
183 network->dhcp6_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6);
184
185 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
186 if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE)
187 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
188 "Disabling IPv6PrefixDelegation=.", network->filename);
189
190 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
191 }
192
193 if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) {
194 network->n_router_dns = 0;
195 network->router_dns = mfree(network->router_dns);
196 network->router_search_domains = ordered_set_free(network->router_search_domains);
197 }
198
199 if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
200 network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
201 network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
202 }
203 }
204
205 int config_parse_prefix(
206 const char *unit,
207 const char *filename,
208 unsigned line,
209 const char *section,
210 unsigned section_line,
211 const char *lvalue,
212 int ltype,
213 const char *rvalue,
214 void *data,
215 void *userdata) {
216
217 Network *network = userdata;
218 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
219 uint8_t prefixlen = 64;
220 union in_addr_union in6addr;
221 int r;
222
223 assert(filename);
224 assert(section);
225 assert(lvalue);
226 assert(rvalue);
227 assert(data);
228
229 r = prefix_new_static(network, filename, section_line, &p);
230 if (r < 0)
231 return log_oom();
232
233 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
234 if (r < 0) {
235 log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
236 return 0;
237 }
238
239 r = sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen);
240 if (r < 0) {
241 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set radv prefix, ignoring assignment: %s", rvalue);
242 return 0;
243 }
244
245 p = NULL;
246
247 return 0;
248 }
249
250 int config_parse_prefix_flags(
251 const char *unit,
252 const char *filename,
253 unsigned line,
254 const char *section,
255 unsigned section_line,
256 const char *lvalue,
257 int ltype,
258 const char *rvalue,
259 void *data,
260 void *userdata) {
261
262 Network *network = userdata;
263 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
264 int r;
265
266 assert(filename);
267 assert(section);
268 assert(lvalue);
269 assert(rvalue);
270 assert(data);
271
272 r = prefix_new_static(network, filename, section_line, &p);
273 if (r < 0)
274 return log_oom();
275
276 r = parse_boolean(rvalue);
277 if (r < 0) {
278 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
279 return 0;
280 }
281
282 if (streq(lvalue, "OnLink"))
283 r = sd_radv_prefix_set_onlink(p->radv_prefix, r);
284 else if (streq(lvalue, "AddressAutoconfiguration"))
285 r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, r);
286 if (r < 0) {
287 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue);
288 return 0;
289 }
290
291 p = NULL;
292
293 return 0;
294 }
295
296 int config_parse_prefix_lifetime(
297 const char *unit,
298 const char *filename,
299 unsigned line,
300 const char *section,
301 unsigned section_line,
302 const char *lvalue,
303 int ltype,
304 const char *rvalue,
305 void *data,
306 void *userdata) {
307
308 Network *network = userdata;
309 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
310 usec_t usec;
311 int r;
312
313 assert(filename);
314 assert(section);
315 assert(lvalue);
316 assert(rvalue);
317 assert(data);
318
319 r = prefix_new_static(network, filename, section_line, &p);
320 if (r < 0)
321 return log_oom();
322
323 r = parse_sec(rvalue, &usec);
324 if (r < 0) {
325 log_syntax(unit, LOG_WARNING, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
326 return 0;
327 }
328
329 /* a value of 0xffffffff represents infinity */
330 if (streq(lvalue, "PreferredLifetimeSec"))
331 r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
332 DIV_ROUND_UP(usec, USEC_PER_SEC));
333 else if (streq(lvalue, "ValidLifetimeSec"))
334 r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
335 DIV_ROUND_UP(usec, USEC_PER_SEC));
336 if (r < 0) {
337 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue);
338 return 0;
339 }
340
341 p = NULL;
342
343 return 0;
344 }
345
346 int config_parse_prefix_assign(
347 const char *unit,
348 const char *filename,
349 unsigned line,
350 const char *section,
351 unsigned section_line,
352 const char *lvalue,
353 int ltype,
354 const char *rvalue,
355 void *data,
356 void *userdata) {
357
358 Network *network = userdata;
359 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
360 int r;
361
362 assert(filename);
363 assert(section);
364 assert(lvalue);
365 assert(rvalue);
366 assert(data);
367
368 r = prefix_new_static(network, filename, section_line, &p);
369 if (r < 0)
370 return log_oom();
371
372 r = parse_boolean(rvalue);
373 if (r < 0) {
374 log_syntax(unit, LOG_WARNING, filename, line, r,
375 "Failed to parse %s=, ignoring assignment: %s",
376 lvalue, rvalue);
377 return 0;
378 }
379
380 p->assign = r;
381 p = NULL;
382
383 return 0;
384 }
385
386 int config_parse_prefix_metric(
387 const char *unit,
388 const char *filename,
389 unsigned line,
390 const char *section,
391 unsigned section_line,
392 const char *lvalue,
393 int ltype,
394 const char *rvalue,
395 void *data,
396 void *userdata) {
397
398 Network *network = userdata;
399 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
400 int r;
401
402 assert(filename);
403 assert(section);
404 assert(lvalue);
405 assert(rvalue);
406 assert(data);
407
408 r = prefix_new_static(network, filename, section_line, &p);
409 if (r < 0)
410 return log_oom();
411
412 r = safe_atou32(rvalue, &p->route_metric);
413 if (r < 0) {
414 log_syntax(unit, LOG_WARNING, filename, line, r,
415 "Failed to parse %s=, ignoring assignment: %s",
416 lvalue, rvalue);
417 return 0;
418 }
419
420 TAKE_PTR(p);
421
422 return 0;
423 }
424
425 int config_parse_route_prefix(
426 const char *unit,
427 const char *filename,
428 unsigned line,
429 const char *section,
430 unsigned section_line,
431 const char *lvalue,
432 int ltype,
433 const char *rvalue,
434 void *data,
435 void *userdata) {
436
437 Network *network = userdata;
438 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
439 uint8_t prefixlen = 64;
440 union in_addr_union in6addr;
441 int r;
442
443 assert(filename);
444 assert(section);
445 assert(lvalue);
446 assert(rvalue);
447 assert(data);
448
449 r = route_prefix_new_static(network, filename, section_line, &p);
450 if (r < 0)
451 return log_oom();
452
453 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
454 if (r < 0) {
455 log_syntax(unit, LOG_WARNING, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue);
456 return 0;
457 }
458
459 r = sd_radv_prefix_set_route_prefix(p->radv_route_prefix, &in6addr.in6, prefixlen);
460 if (r < 0) {
461 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set route prefix, ignoring assignment: %m");
462 return 0;
463 }
464
465 p = NULL;
466
467 return 0;
468 }
469
470 int config_parse_route_prefix_lifetime(
471 const char *unit,
472 const char *filename,
473 unsigned line,
474 const char *section,
475 unsigned section_line,
476 const char *lvalue,
477 int ltype,
478 const char *rvalue,
479 void *data,
480 void *userdata) {
481
482 Network *network = userdata;
483 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
484 usec_t usec;
485 int r;
486
487 assert(filename);
488 assert(section);
489 assert(lvalue);
490 assert(rvalue);
491 assert(data);
492
493 r = route_prefix_new_static(network, filename, section_line, &p);
494 if (r < 0)
495 return log_oom();
496
497 r = parse_sec(rvalue, &usec);
498 if (r < 0) {
499 log_syntax(unit, LOG_WARNING, filename, line, r,
500 "Route lifetime is invalid, ignoring assignment: %s", rvalue);
501 return 0;
502 }
503
504 /* a value of 0xffffffff represents infinity */
505 r = sd_radv_route_prefix_set_lifetime(p->radv_route_prefix, DIV_ROUND_UP(usec, USEC_PER_SEC));
506 if (r < 0) {
507 log_syntax(unit, LOG_WARNING, filename, line, r,
508 "Failed to set route lifetime, ignoring assignment: %m");
509 return 0;
510 }
511
512 p = NULL;
513
514 return 0;
515 }
516
517 static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
518 _cleanup_free_ struct in6_addr *addresses = NULL;
519 size_t n_addresses = 0;
520
521 assert(network);
522 assert(ret_addresses);
523 assert(ret_size);
524
525 for (size_t i = 0; i < network->n_dns; i++) {
526 union in_addr_union *addr;
527
528 if (network->dns[i]->family != AF_INET6)
529 continue;
530
531 addr = &network->dns[i]->address;
532
533 if (in_addr_is_null(AF_INET6, addr) ||
534 in_addr_is_link_local(AF_INET6, addr) ||
535 in_addr_is_localhost(AF_INET6, addr))
536 continue;
537
538 if (!GREEDY_REALLOC(addresses, n_addresses + 1))
539 return -ENOMEM;
540
541 addresses[n_addresses++] = addr->in6;
542 }
543
544 *ret_addresses = TAKE_PTR(addresses);
545 *ret_size = n_addresses;
546
547 return n_addresses;
548 }
549
550 static int radv_set_dns(Link *link, Link *uplink) {
551 _cleanup_free_ struct in6_addr *dns = NULL;
552 usec_t lifetime_usec;
553 size_t n_dns;
554 int r;
555
556 if (!link->network->router_emit_dns)
557 return 0;
558
559 if (link->network->router_dns) {
560 struct in6_addr *p;
561
562 dns = new(struct in6_addr, link->network->n_router_dns);
563 if (!dns)
564 return -ENOMEM;
565
566 p = dns;
567 for (size_t i = 0; i < link->network->n_router_dns; i++)
568 if (in6_addr_is_null(&link->network->router_dns[i])) {
569 if (in6_addr_is_set(&link->ipv6ll_address))
570 *(p++) = link->ipv6ll_address;
571 } else
572 *(p++) = link->network->router_dns[i];
573
574 n_dns = p - dns;
575 lifetime_usec = link->network->router_dns_lifetime_usec;
576
577 goto set_dns;
578 }
579
580 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
581
582 r = network_get_ipv6_dns(link->network, &dns, &n_dns);
583 if (r > 0)
584 goto set_dns;
585
586 if (uplink) {
587 assert(uplink->network);
588
589 r = network_get_ipv6_dns(uplink->network, &dns, &n_dns);
590 if (r > 0)
591 goto set_dns;
592 }
593
594 return 0;
595
596 set_dns:
597 return sd_radv_set_rdnss(link->radv,
598 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
599 dns, n_dns);
600 }
601
602 static int radv_set_domains(Link *link, Link *uplink) {
603 OrderedSet *search_domains;
604 usec_t lifetime_usec;
605 _cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */
606
607 if (!link->network->router_emit_domains)
608 return 0;
609
610 search_domains = link->network->router_search_domains;
611 lifetime_usec = link->network->router_dns_lifetime_usec;
612
613 if (search_domains)
614 goto set_domains;
615
616 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
617
618 search_domains = link->network->search_domains;
619 if (search_domains)
620 goto set_domains;
621
622 if (uplink) {
623 assert(uplink->network);
624
625 search_domains = uplink->network->search_domains;
626 if (search_domains)
627 goto set_domains;
628 }
629
630 return 0;
631
632 set_domains:
633 s = ordered_set_get_strv(search_domains);
634 if (!s)
635 return log_oom();
636
637 return sd_radv_set_dnssl(link->radv,
638 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
639 s);
640
641 }
642
643 static int radv_find_uplink(Link *link, Link **ret) {
644 assert(link);
645
646 if (link->network->router_uplink_name)
647 return link_get_by_name(link->manager, link->network->router_uplink_name, ret);
648
649 if (link->network->router_uplink_index > 0)
650 return link_get_by_index(link->manager, link->network->router_uplink_index, ret);
651
652 if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) {
653 /* It is not necessary to propagate error in automatic selection. */
654 if (manager_find_uplink(link->manager, AF_INET6, link, ret) < 0)
655 *ret = NULL;
656 return 0;
657 }
658
659 *ret = NULL;
660 return 0;
661 }
662
663 static bool link_radv_enabled(Link *link) {
664 assert(link);
665
666 if (!link_ipv6ll_enabled(link))
667 return false;
668
669 return link->network->router_prefix_delegation;
670 }
671
672 static int radv_configure(Link *link) {
673 uint16_t router_lifetime;
674 Link *uplink = NULL;
675 RoutePrefix *q;
676 Prefix *p;
677 int r;
678
679 assert(link);
680 assert(link->network);
681
682 if (link->radv)
683 return -EBUSY;
684
685 r = sd_radv_new(&link->radv);
686 if (r < 0)
687 return r;
688
689 r = sd_radv_attach_event(link->radv, link->manager->event, 0);
690 if (r < 0)
691 return r;
692
693 r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
694 if (r < 0)
695 return r;
696
697 r = sd_radv_set_ifindex(link->radv, link->ifindex);
698 if (r < 0)
699 return r;
700
701 r = sd_radv_set_managed_information(link->radv, link->network->router_managed);
702 if (r < 0)
703 return r;
704
705 r = sd_radv_set_other_information(link->radv, link->network->router_other_information);
706 if (r < 0)
707 return r;
708
709 /* a value of UINT16_MAX represents infinity, 0x0 means this host is not a router */
710 if (link->network->router_lifetime_usec == USEC_INFINITY)
711 router_lifetime = UINT16_MAX;
712 else if (link->network->router_lifetime_usec > (UINT16_MAX - 1) * USEC_PER_SEC)
713 router_lifetime = UINT16_MAX - 1;
714 else
715 router_lifetime = DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC);
716
717 r = sd_radv_set_router_lifetime(link->radv, router_lifetime);
718 if (r < 0)
719 return r;
720
721 if (router_lifetime > 0) {
722 r = sd_radv_set_preference(link->radv, link->network->router_preference);
723 if (r < 0)
724 return r;
725 }
726
727 HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
728 r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
729 if (r == -EEXIST)
730 continue;
731 if (r == -ENOEXEC) {
732 log_link_warning_errno(link, r, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
733 continue;
734 }
735 if (r < 0)
736 return r;
737 }
738
739 HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) {
740 r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false);
741 if (r == -EEXIST)
742 continue;
743 if (r < 0)
744 return r;
745 }
746
747 (void) radv_find_uplink(link, &uplink);
748
749 r = radv_set_dns(link, uplink);
750 if (r < 0)
751 return log_link_debug_errno(link, r, "Could not set RA DNS: %m");
752
753 r = radv_set_domains(link, uplink);
754 if (r < 0)
755 return log_link_debug_errno(link, r, "Could not set RA Domains: %m");
756
757 return 0;
758 }
759
760 int radv_update_mac(Link *link) {
761 bool restart;
762 int r;
763
764 assert(link);
765
766 if (!link->radv)
767 return 0;
768
769 restart = sd_radv_is_running(link->radv);
770
771 r = sd_radv_stop(link->radv);
772 if (r < 0)
773 return r;
774
775 r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
776 if (r < 0)
777 return r;
778
779 if (restart) {
780 r = sd_radv_start(link->radv);
781 if (r < 0)
782 return r;
783 }
784
785 return 0;
786 }
787
788 static int radv_is_ready_to_configure(Link *link) {
789 bool needs_uplink = false;
790 int r;
791
792 assert(link);
793 assert(link->network);
794
795 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
796 return false;
797
798 if (in6_addr_is_null(&link->ipv6ll_address))
799 return false;
800
801 if (link->network->router_emit_dns && !link->network->router_dns) {
802 _cleanup_free_ struct in6_addr *dns = NULL;
803 size_t n_dns;
804
805 r = network_get_ipv6_dns(link->network, &dns, &n_dns);
806 if (r < 0)
807 return r;
808
809 needs_uplink = r == 0;
810 }
811
812 if (link->network->router_emit_domains &&
813 !link->network->router_search_domains &&
814 !link->network->search_domains)
815 needs_uplink = true;
816
817 if (needs_uplink) {
818 Link *uplink = NULL;
819
820 if (radv_find_uplink(link, &uplink) < 0)
821 return false;
822
823 if (uplink && !uplink->network)
824 return false;
825 }
826
827 return true;
828 }
829
830 int request_process_radv(Request *req) {
831 Link *link;
832 int r;
833
834 assert(req);
835 assert(req->link);
836 assert(req->type == REQUEST_TYPE_RADV);
837
838 link = req->link;
839
840 r = radv_is_ready_to_configure(link);
841 if (r <= 0)
842 return r;
843
844 r = radv_configure(link);
845 if (r < 0)
846 return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Advertisement engine: %m");
847
848 if (link_has_carrier(link)) {
849 r = sd_radv_start(link->radv);
850 if (r < 0)
851 return log_link_warning_errno(link, r, "Failed to start IPv6 Router Advertisement engine: %m");
852 }
853
854 log_link_debug(link, "IPv6 Router Advertisement engine is configured%s.",
855 link_has_carrier(link) ? " and started." : "");
856 return 1;
857 }
858
859 int link_request_radv(Link *link) {
860 int r;
861
862 assert(link);
863
864 if (!link_radv_enabled(link))
865 return 0;
866
867 if (link->radv)
868 return 0;
869
870 r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL);
871 if (r < 0)
872 return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m");
873
874 log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine.");
875 return 0;
876 }
877
878 int radv_add_prefix(
879 Link *link,
880 const struct in6_addr *prefix,
881 uint8_t prefix_len,
882 uint32_t lifetime_preferred,
883 uint32_t lifetime_valid) {
884
885 _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
886 int r;
887
888 assert(link);
889
890 if (!link->radv)
891 return 0;
892
893 r = sd_radv_prefix_new(&p);
894 if (r < 0)
895 return r;
896
897 r = sd_radv_prefix_set_prefix(p, prefix, prefix_len);
898 if (r < 0)
899 return r;
900
901 r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred);
902 if (r < 0)
903 return r;
904
905 r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid);
906 if (r < 0)
907 return r;
908
909 r = sd_radv_add_prefix(link->radv, p, true);
910 if (r < 0 && r != -EEXIST)
911 return r;
912
913 return 0;
914 }
915
916 int config_parse_radv_dns(
917 const char *unit,
918 const char *filename,
919 unsigned line,
920 const char *section,
921 unsigned section_line,
922 const char *lvalue,
923 int ltype,
924 const char *rvalue,
925 void *data,
926 void *userdata) {
927
928 Network *n = data;
929 int r;
930
931 assert(filename);
932 assert(lvalue);
933 assert(rvalue);
934
935 if (isempty(rvalue)) {
936 n->n_router_dns = 0;
937 n->router_dns = mfree(n->router_dns);
938 return 0;
939 }
940
941 for (const char *p = rvalue;;) {
942 _cleanup_free_ char *w = NULL;
943 union in_addr_union a;
944
945 r = extract_first_word(&p, &w, NULL, 0);
946 if (r == -ENOMEM)
947 return log_oom();
948 if (r < 0) {
949 log_syntax(unit, LOG_WARNING, filename, line, r,
950 "Failed to extract word, ignoring: %s", rvalue);
951 return 0;
952 }
953 if (r == 0)
954 return 0;
955
956 if (streq(w, "_link_local"))
957 a = IN_ADDR_NULL;
958 else {
959 r = in_addr_from_string(AF_INET6, w, &a);
960 if (r < 0) {
961 log_syntax(unit, LOG_WARNING, filename, line, r,
962 "Failed to parse DNS server address, ignoring: %s", w);
963 continue;
964 }
965
966 if (in_addr_is_null(AF_INET6, &a)) {
967 log_syntax(unit, LOG_WARNING, filename, line, 0,
968 "DNS server address is null, ignoring: %s", w);
969 continue;
970 }
971 }
972
973 struct in6_addr *m;
974 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
975 if (!m)
976 return log_oom();
977
978 m[n->n_router_dns++] = a.in6;
979 n->router_dns = m;
980 }
981 }
982
983 int config_parse_radv_search_domains(
984 const char *unit,
985 const char *filename,
986 unsigned line,
987 const char *section,
988 unsigned section_line,
989 const char *lvalue,
990 int ltype,
991 const char *rvalue,
992 void *data,
993 void *userdata) {
994
995 Network *n = data;
996 int r;
997
998 assert(filename);
999 assert(lvalue);
1000 assert(rvalue);
1001
1002 if (isempty(rvalue)) {
1003 n->router_search_domains = ordered_set_free(n->router_search_domains);
1004 return 0;
1005 }
1006
1007 for (const char *p = rvalue;;) {
1008 _cleanup_free_ char *w = NULL, *idna = NULL;
1009
1010 r = extract_first_word(&p, &w, NULL, 0);
1011 if (r == -ENOMEM)
1012 return log_oom();
1013 if (r < 0) {
1014 log_syntax(unit, LOG_WARNING, filename, line, r,
1015 "Failed to extract word, ignoring: %s", rvalue);
1016 return 0;
1017 }
1018 if (r == 0)
1019 return 0;
1020
1021 r = dns_name_apply_idna(w, &idna);
1022 if (r < 0) {
1023 log_syntax(unit, LOG_WARNING, filename, line, r,
1024 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
1025 continue;
1026 } else if (r == 0)
1027 /* transfer ownership to simplify subsequent operations */
1028 idna = TAKE_PTR(w);
1029
1030 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops_free);
1031 if (r < 0)
1032 return log_oom();
1033
1034 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1035 if (r < 0)
1036 return log_oom();
1037 }
1038 }
1039
1040 static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
1041 [RADV_PREFIX_DELEGATION_NONE] = "no",
1042 [RADV_PREFIX_DELEGATION_STATIC] = "static",
1043 [RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
1044 [RADV_PREFIX_DELEGATION_BOTH] = "yes",
1045 };
1046
1047 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
1048 radv_prefix_delegation,
1049 RADVPrefixDelegation,
1050 RADV_PREFIX_DELEGATION_BOTH);
1051
1052 int config_parse_router_prefix_delegation(
1053 const char *unit,
1054 const char *filename,
1055 unsigned line,
1056 const char *section,
1057 unsigned section_line,
1058 const char *lvalue,
1059 int ltype,
1060 const char *rvalue,
1061 void *data,
1062 void *userdata) {
1063
1064 RADVPrefixDelegation val, *ra = data;
1065 int r;
1066
1067 assert(filename);
1068 assert(lvalue);
1069 assert(rvalue);
1070 assert(data);
1071
1072 if (streq(lvalue, "IPv6SendRA")) {
1073 r = parse_boolean(rvalue);
1074 if (r < 0) {
1075 log_syntax(unit, LOG_WARNING, filename, line, r,
1076 "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1077 return 0;
1078 }
1079
1080 /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users
1081 * need to explicitly enable DHCPv6PrefixDelegation=. */
1082 *ra = r ? RADV_PREFIX_DELEGATION_STATIC : RADV_PREFIX_DELEGATION_NONE;
1083 return 0;
1084 }
1085
1086 /* For backward compatibility */
1087 val = radv_prefix_delegation_from_string(rvalue);
1088 if (val < 0) {
1089 log_syntax(unit, LOG_WARNING, filename, line, val,
1090 "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1091 return 0;
1092 }
1093
1094 *ra = val;
1095 return 0;
1096 }
1097
1098 int config_parse_router_preference(
1099 const char *unit,
1100 const char *filename,
1101 unsigned line,
1102 const char *section,
1103 unsigned section_line,
1104 const char *lvalue,
1105 int ltype,
1106 const char *rvalue,
1107 void *data,
1108 void *userdata) {
1109
1110 Network *network = userdata;
1111
1112 assert(filename);
1113 assert(section);
1114 assert(lvalue);
1115 assert(rvalue);
1116 assert(data);
1117
1118 if (streq(rvalue, "high"))
1119 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
1120 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
1121 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
1122 else if (streq(rvalue, "low"))
1123 network->router_preference = SD_NDISC_PREFERENCE_LOW;
1124 else
1125 log_syntax(unit, LOG_WARNING, filename, line, 0,
1126 "Invalid router preference, ignoring assignment: %s", rvalue);
1127
1128 return 0;
1129 }