1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2017 Intel Corporation. All rights reserved.
6 #include <netinet/icmp6.h>
9 #include "dns-domain.h"
10 #include "networkd-link.h"
11 #include "networkd-manager.h"
12 #include "networkd-network.h"
13 #include "networkd-radv.h"
14 #include "parse-util.h"
15 #include "string-util.h"
16 #include "string-table.h"
19 Prefix
*prefix_free(Prefix
*prefix
) {
23 if (prefix
->network
) {
24 assert(prefix
->section
);
25 hashmap_remove(prefix
->network
->prefixes_by_section
, prefix
->section
);
28 network_config_section_free(prefix
->section
);
29 sd_radv_prefix_unref(prefix
->radv_prefix
);
34 DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix
, prefix_free
);
36 static int prefix_new(Prefix
**ret
) {
37 _cleanup_(prefix_freep
) Prefix
*prefix
= NULL
;
39 prefix
= new0(Prefix
, 1);
43 if (sd_radv_prefix_new(&prefix
->radv_prefix
) < 0)
46 *ret
= TAKE_PTR(prefix
);
51 static int prefix_new_static(Network
*network
, const char *filename
, unsigned section_line
, Prefix
**ret
) {
52 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
53 _cleanup_(prefix_freep
) Prefix
*prefix
= NULL
;
59 assert(section_line
> 0);
61 r
= network_config_section_new(filename
, section_line
, &n
);
65 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
67 *ret
= TAKE_PTR(prefix
);
71 r
= prefix_new(&prefix
);
75 prefix
->network
= network
;
76 prefix
->section
= TAKE_PTR(n
);
78 r
= hashmap_ensure_allocated(&network
->prefixes_by_section
, &network_config_hash_ops
);
82 r
= hashmap_put(network
->prefixes_by_section
, prefix
->section
, prefix
);
86 *ret
= TAKE_PTR(prefix
);
91 RoutePrefix
*route_prefix_free(RoutePrefix
*prefix
) {
95 if (prefix
->network
) {
96 assert(prefix
->section
);
97 hashmap_remove(prefix
->network
->route_prefixes_by_section
, prefix
->section
);
100 network_config_section_free(prefix
->section
);
101 sd_radv_route_prefix_unref(prefix
->radv_route_prefix
);
103 return mfree(prefix
);
106 DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix
, route_prefix_free
);
108 static int route_prefix_new(RoutePrefix
**ret
) {
109 _cleanup_(route_prefix_freep
) RoutePrefix
*prefix
= NULL
;
111 prefix
= new0(RoutePrefix
, 1);
115 if (sd_radv_route_prefix_new(&prefix
->radv_route_prefix
) < 0)
118 *ret
= TAKE_PTR(prefix
);
123 static int route_prefix_new_static(Network
*network
, const char *filename
, unsigned section_line
, RoutePrefix
**ret
) {
124 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
125 _cleanup_(route_prefix_freep
) RoutePrefix
*prefix
= NULL
;
131 assert(section_line
> 0);
133 r
= network_config_section_new(filename
, section_line
, &n
);
137 prefix
= hashmap_get(network
->route_prefixes_by_section
, n
);
139 *ret
= TAKE_PTR(prefix
);
143 r
= route_prefix_new(&prefix
);
147 prefix
->network
= network
;
148 prefix
->section
= TAKE_PTR(n
);
150 r
= hashmap_ensure_allocated(&network
->route_prefixes_by_section
, &network_config_hash_ops
);
154 r
= hashmap_put(network
->route_prefixes_by_section
, prefix
->section
, prefix
);
158 *ret
= TAKE_PTR(prefix
);
163 void network_drop_invalid_prefixes(Network
*network
) {
168 HASHMAP_FOREACH(prefix
, network
->prefixes_by_section
)
169 if (section_is_invalid(prefix
->section
))
173 void network_drop_invalid_route_prefixes(Network
*network
) {
178 HASHMAP_FOREACH(prefix
, network
->route_prefixes_by_section
)
179 if (section_is_invalid(prefix
->section
))
180 route_prefix_free(prefix
);
183 void network_adjust_radv(Network
*network
) {
186 /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
188 if (network
->dhcp6_pd
< 0)
189 /* For backward compatibility. */
190 network
->dhcp6_pd
= FLAGS_SET(network
->router_prefix_delegation
, RADV_PREFIX_DELEGATION_DHCP6
);
192 if (!FLAGS_SET(network
->link_local
, ADDRESS_FAMILY_IPV6
)) {
193 if (network
->router_prefix_delegation
!= RADV_PREFIX_DELEGATION_NONE
)
194 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
195 "Disabling IPv6PrefixDelegation=.", network
->filename
);
197 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_NONE
;
200 if (network
->router_prefix_delegation
== RADV_PREFIX_DELEGATION_NONE
) {
201 network
->n_router_dns
= 0;
202 network
->router_dns
= mfree(network
->router_dns
);
203 network
->router_search_domains
= ordered_set_free(network
->router_search_domains
);
206 if (!FLAGS_SET(network
->router_prefix_delegation
, RADV_PREFIX_DELEGATION_STATIC
)) {
207 network
->prefixes_by_section
= hashmap_free_with_destructor(network
->prefixes_by_section
, prefix_free
);
208 network
->route_prefixes_by_section
= hashmap_free_with_destructor(network
->route_prefixes_by_section
, route_prefix_free
);
212 int config_parse_prefix(
214 const char *filename
,
217 unsigned section_line
,
224 Network
*network
= userdata
;
225 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
226 uint8_t prefixlen
= 64;
227 union in_addr_union in6addr
;
236 r
= prefix_new_static(network
, filename
, section_line
, &p
);
240 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
242 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
246 r
= sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
);
248 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set radv prefix, ignoring assignment: %s", rvalue
);
257 int config_parse_prefix_flags(
259 const char *filename
,
262 unsigned section_line
,
269 Network
*network
= userdata
;
270 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
279 r
= prefix_new_static(network
, filename
, section_line
, &p
);
283 r
= parse_boolean(rvalue
);
285 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
289 if (streq(lvalue
, "OnLink"))
290 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, r
);
291 else if (streq(lvalue
, "AddressAutoconfiguration"))
292 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, r
);
294 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set %s=, ignoring assignment: %m", lvalue
);
303 int config_parse_prefix_lifetime(
305 const char *filename
,
308 unsigned section_line
,
315 Network
*network
= userdata
;
316 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
326 r
= prefix_new_static(network
, filename
, section_line
, &p
);
330 r
= parse_sec(rvalue
, &usec
);
332 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
336 /* a value of 0xffffffff represents infinity */
337 if (streq(lvalue
, "PreferredLifetimeSec"))
338 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
339 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
340 else if (streq(lvalue
, "ValidLifetimeSec"))
341 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
342 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
344 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set %s=, ignoring assignment: %m", lvalue
);
353 int config_parse_prefix_assign(
355 const char *filename
,
358 unsigned section_line
,
365 Network
*network
= userdata
;
366 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
375 r
= prefix_new_static(network
, filename
, section_line
, &p
);
379 r
= parse_boolean(rvalue
);
381 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
382 "Failed to parse %s=, ignoring assignment: %s",
393 int config_parse_route_prefix(
395 const char *filename
,
398 unsigned section_line
,
405 Network
*network
= userdata
;
406 _cleanup_(route_prefix_free_or_set_invalidp
) RoutePrefix
*p
= NULL
;
407 uint8_t prefixlen
= 64;
408 union in_addr_union in6addr
;
417 r
= route_prefix_new_static(network
, filename
, section_line
, &p
);
421 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
423 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Route prefix is invalid, ignoring assignment: %s", rvalue
);
427 r
= sd_radv_prefix_set_route_prefix(p
->radv_route_prefix
, &in6addr
.in6
, prefixlen
);
429 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set route prefix, ignoring assignment: %m");
438 int config_parse_route_prefix_lifetime(
440 const char *filename
,
443 unsigned section_line
,
450 Network
*network
= userdata
;
451 _cleanup_(route_prefix_free_or_set_invalidp
) RoutePrefix
*p
= NULL
;
461 r
= route_prefix_new_static(network
, filename
, section_line
, &p
);
465 r
= parse_sec(rvalue
, &usec
);
467 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
468 "Route lifetime is invalid, ignoring assignment: %s", rvalue
);
472 /* a value of 0xffffffff represents infinity */
473 r
= sd_radv_route_prefix_set_lifetime(p
->radv_route_prefix
, DIV_ROUND_UP(usec
, USEC_PER_SEC
));
475 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
476 "Failed to set route lifetime, ignoring assignment: %m");
485 static int network_get_ipv6_dns(Network
*network
, struct in6_addr
**ret_addresses
, size_t *ret_size
) {
486 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
487 size_t n_addresses
= 0, n_allocated
= 0;
490 assert(ret_addresses
);
493 for (size_t i
= 0; i
< network
->n_dns
; i
++) {
494 union in_addr_union
*addr
;
496 if (network
->dns
[i
]->family
!= AF_INET6
)
499 addr
= &network
->dns
[i
]->address
;
501 if (in_addr_is_null(AF_INET6
, addr
) ||
502 in_addr_is_link_local(AF_INET6
, addr
) ||
503 in_addr_is_localhost(AF_INET6
, addr
))
506 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
509 addresses
[n_addresses
++] = addr
->in6
;
512 *ret_addresses
= TAKE_PTR(addresses
);
513 *ret_size
= n_addresses
;
518 static int radv_set_dns(Link
*link
, Link
*uplink
) {
519 _cleanup_free_
struct in6_addr
*dns
= NULL
;
520 usec_t lifetime_usec
;
524 if (!link
->network
->router_emit_dns
)
527 if (link
->network
->router_dns
) {
530 dns
= new(struct in6_addr
, link
->network
->n_router_dns
);
535 for (size_t i
= 0; i
< link
->network
->n_router_dns
; i
++)
536 if (IN6_IS_ADDR_UNSPECIFIED(&link
->network
->router_dns
[i
])) {
537 if (!IN6_IS_ADDR_UNSPECIFIED(&link
->ipv6ll_address
))
538 *(p
++) = link
->ipv6ll_address
;
540 *(p
++) = link
->network
->router_dns
[i
];
543 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
548 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
550 r
= network_get_ipv6_dns(link
->network
, &dns
, &n_dns
);
555 if (!uplink
->network
) {
556 log_link_debug(uplink
, "Cannot fetch DNS servers as uplink interface is not managed by us");
560 r
= network_get_ipv6_dns(uplink
->network
, &dns
, &n_dns
);
568 return sd_radv_set_rdnss(link
->radv
,
569 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
573 static int radv_set_domains(Link
*link
, Link
*uplink
) {
574 OrderedSet
*search_domains
;
575 usec_t lifetime_usec
;
576 _cleanup_free_
char **s
= NULL
; /* just free() because the strings are owned by the set */
578 if (!link
->network
->router_emit_domains
)
581 search_domains
= link
->network
->router_search_domains
;
582 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
587 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
589 search_domains
= link
->network
->search_domains
;
594 if (!uplink
->network
) {
595 log_link_debug(uplink
, "Cannot fetch DNS search domains as uplink interface is not managed by us");
599 search_domains
= uplink
->network
->search_domains
;
607 s
= ordered_set_get_strv(search_domains
);
611 return sd_radv_set_dnssl(link
->radv
,
612 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
617 int radv_emit_dns(Link
*link
) {
621 uplink
= manager_find_uplink(link
->manager
, link
);
623 r
= radv_set_dns(link
, uplink
);
625 log_link_warning_errno(link
, r
, "Could not set RA DNS: %m");
627 r
= radv_set_domains(link
, uplink
);
629 log_link_warning_errno(link
, r
, "Could not set RA Domains: %m");
634 static bool link_radv_enabled(Link
*link
) {
637 if (!link_ipv6ll_enabled(link
))
640 return link
->network
->router_prefix_delegation
;
643 int radv_configure(Link
*link
) {
649 assert(link
->network
);
651 if (!link_radv_enabled(link
))
654 r
= sd_radv_new(&link
->radv
);
658 r
= sd_radv_attach_event(link
->radv
, link
->manager
->event
, 0);
662 r
= sd_radv_set_mac(link
->radv
, &link
->mac
);
666 r
= sd_radv_set_ifindex(link
->radv
, link
->ifindex
);
670 r
= sd_radv_set_managed_information(link
->radv
, link
->network
->router_managed
);
674 r
= sd_radv_set_other_information(link
->radv
, link
->network
->router_other_information
);
678 /* a value of 0xffffffff represents infinity, 0x0 means this host is
680 r
= sd_radv_set_router_lifetime(link
->radv
,
681 DIV_ROUND_UP(link
->network
->router_lifetime_usec
, USEC_PER_SEC
));
685 if (link
->network
->router_lifetime_usec
> 0) {
686 r
= sd_radv_set_preference(link
->radv
,
687 link
->network
->router_preference
);
692 HASHMAP_FOREACH(p
, link
->network
->prefixes_by_section
) {
693 r
= sd_radv_add_prefix(link
->radv
, p
->radv_prefix
, false);
697 log_link_warning_errno(link
, r
, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
704 HASHMAP_FOREACH(q
, link
->network
->route_prefixes_by_section
) {
705 r
= sd_radv_add_route_prefix(link
->radv
, q
->radv_route_prefix
, false);
715 int radv_update_mac(Link
*link
) {
724 restart
= sd_radv_is_running(link
->radv
);
726 r
= sd_radv_stop(link
->radv
);
730 r
= sd_radv_set_mac(link
->radv
, &link
->mac
);
735 r
= sd_radv_start(link
->radv
);
745 const struct in6_addr
*prefix
,
747 uint32_t lifetime_preferred
,
748 uint32_t lifetime_valid
) {
750 _cleanup_(sd_radv_prefix_unrefp
) sd_radv_prefix
*p
= NULL
;
758 r
= sd_radv_prefix_new(&p
);
762 r
= sd_radv_prefix_set_prefix(p
, prefix
, prefix_len
);
766 r
= sd_radv_prefix_set_preferred_lifetime(p
, lifetime_preferred
);
770 r
= sd_radv_prefix_set_valid_lifetime(p
, lifetime_valid
);
774 r
= sd_radv_add_prefix(link
->radv
, p
, true);
775 if (r
< 0 && r
!= -EEXIST
)
781 int config_parse_radv_dns(
783 const char *filename
,
786 unsigned section_line
,
800 if (isempty(rvalue
)) {
802 n
->router_dns
= mfree(n
->router_dns
);
806 for (const char *p
= rvalue
;;) {
807 _cleanup_free_
char *w
= NULL
;
808 union in_addr_union a
;
810 r
= extract_first_word(&p
, &w
, NULL
, 0);
814 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
815 "Failed to extract word, ignoring: %s", rvalue
);
821 if (streq(w
, "_link_local"))
824 r
= in_addr_from_string(AF_INET6
, w
, &a
);
826 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
827 "Failed to parse DNS server address, ignoring: %s", w
);
831 if (in_addr_is_null(AF_INET6
, &a
)) {
832 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
833 "DNS server address is null, ignoring: %s", w
);
839 m
= reallocarray(n
->router_dns
, n
->n_router_dns
+ 1, sizeof(struct in6_addr
));
843 m
[n
->n_router_dns
++] = a
.in6
;
848 int config_parse_radv_search_domains(
850 const char *filename
,
853 unsigned section_line
,
867 if (isempty(rvalue
)) {
868 n
->router_search_domains
= ordered_set_free(n
->router_search_domains
);
872 for (const char *p
= rvalue
;;) {
873 _cleanup_free_
char *w
= NULL
, *idna
= NULL
;
875 r
= extract_first_word(&p
, &w
, NULL
, 0);
879 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
880 "Failed to extract word, ignoring: %s", rvalue
);
886 r
= dns_name_apply_idna(w
, &idna
);
888 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
889 "Failed to apply IDNA to domain name '%s', ignoring: %m", w
);
892 /* transfer ownership to simplify subsequent operations */
895 r
= ordered_set_ensure_allocated(&n
->router_search_domains
, &string_hash_ops_free
);
899 r
= ordered_set_consume(n
->router_search_domains
, TAKE_PTR(idna
));
905 static const char * const radv_prefix_delegation_table
[_RADV_PREFIX_DELEGATION_MAX
] = {
906 [RADV_PREFIX_DELEGATION_NONE
] = "no",
907 [RADV_PREFIX_DELEGATION_STATIC
] = "static",
908 [RADV_PREFIX_DELEGATION_DHCP6
] = "dhcpv6",
909 [RADV_PREFIX_DELEGATION_BOTH
] = "yes",
912 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
913 radv_prefix_delegation
,
914 RADVPrefixDelegation
,
915 RADV_PREFIX_DELEGATION_BOTH
);
917 int config_parse_router_prefix_delegation(
919 const char *filename
,
922 unsigned section_line
,
929 RADVPrefixDelegation val
, *ra
= data
;
937 if (streq(lvalue
, "IPv6SendRA")) {
938 r
= parse_boolean(rvalue
);
940 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
941 "Invalid %s= setting, ignoring assignment: %s", lvalue
, rvalue
);
945 /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users
946 * need to explicitly enable DHCPv6PrefixDelegation=. */
947 *ra
= r
? RADV_PREFIX_DELEGATION_STATIC
: RADV_PREFIX_DELEGATION_NONE
;
951 /* For backward compatibility */
952 val
= radv_prefix_delegation_from_string(rvalue
);
954 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
955 "Invalid %s= setting, ignoring assignment: %s", lvalue
, rvalue
);
963 int config_parse_router_preference(
965 const char *filename
,
968 unsigned section_line
,
975 Network
*network
= userdata
;
983 if (streq(rvalue
, "high"))
984 network
->router_preference
= SD_NDISC_PREFERENCE_HIGH
;
985 else if (STR_IN_SET(rvalue
, "medium", "normal", "default"))
986 network
->router_preference
= SD_NDISC_PREFERENCE_MEDIUM
;
987 else if (streq(rvalue
, "low"))
988 network
->router_preference
= SD_NDISC_PREFERENCE_LOW
;
990 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
991 "Invalid router preference, ignoring assignment: %s", rvalue
);