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-address.h"
11 #include "networkd-manager.h"
12 #include "networkd-radv.h"
13 #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
,
52 unsigned section_line
, Prefix
**ret
) {
53 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
54 _cleanup_(prefix_freep
) Prefix
*prefix
= NULL
;
60 assert(section_line
> 0);
62 r
= network_config_section_new(filename
, section_line
, &n
);
66 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
68 *ret
= TAKE_PTR(prefix
);
72 r
= prefix_new(&prefix
);
76 prefix
->network
= network
;
77 prefix
->section
= TAKE_PTR(n
);
79 r
= hashmap_ensure_allocated(&network
->prefixes_by_section
, &network_config_hash_ops
);
83 r
= hashmap_put(network
->prefixes_by_section
, prefix
->section
, prefix
);
87 *ret
= TAKE_PTR(prefix
);
92 RoutePrefix
*route_prefix_free(RoutePrefix
*prefix
) {
96 if (prefix
->network
) {
97 assert(prefix
->section
);
98 hashmap_remove(prefix
->network
->route_prefixes_by_section
, prefix
->section
);
101 network_config_section_free(prefix
->section
);
102 sd_radv_route_prefix_unref(prefix
->radv_route_prefix
);
104 return mfree(prefix
);
107 DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix
, route_prefix_free
);
109 static int route_prefix_new(RoutePrefix
**ret
) {
110 _cleanup_(route_prefix_freep
) RoutePrefix
*prefix
= NULL
;
112 prefix
= new0(RoutePrefix
, 1);
116 if (sd_radv_route_prefix_new(&prefix
->radv_route_prefix
) < 0)
119 *ret
= TAKE_PTR(prefix
);
124 static int route_prefix_new_static(Network
*network
, const char *filename
,
125 unsigned section_line
, RoutePrefix
**ret
) {
126 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
127 _cleanup_(route_prefix_freep
) RoutePrefix
*prefix
= NULL
;
133 assert(section_line
> 0);
135 r
= network_config_section_new(filename
, section_line
, &n
);
139 prefix
= hashmap_get(network
->route_prefixes_by_section
, n
);
141 *ret
= TAKE_PTR(prefix
);
145 r
= route_prefix_new(&prefix
);
149 prefix
->network
= network
;
150 prefix
->section
= TAKE_PTR(n
);
152 r
= hashmap_ensure_allocated(&network
->route_prefixes_by_section
, &network_config_hash_ops
);
156 r
= hashmap_put(network
->route_prefixes_by_section
, prefix
->section
, prefix
);
160 *ret
= TAKE_PTR(prefix
);
165 void network_verify_prefixes(Network
*network
) {
170 HASHMAP_FOREACH(prefix
, network
->prefixes_by_section
)
171 if (section_is_invalid(prefix
->section
))
175 void network_verify_route_prefixes(Network
*network
) {
180 HASHMAP_FOREACH(prefix
, network
->route_prefixes_by_section
)
181 if (section_is_invalid(prefix
->section
))
182 route_prefix_free(prefix
);
185 int config_parse_prefix(const char *unit
,
186 const char *filename
,
189 unsigned section_line
,
196 Network
*network
= userdata
;
197 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
198 uint8_t prefixlen
= 64;
199 union in_addr_union in6addr
;
208 r
= prefix_new_static(network
, filename
, section_line
, &p
);
212 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
214 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
218 r
= sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
);
220 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set radv prefix, ignoring assignment: %s", rvalue
);
229 int config_parse_prefix_flags(const char *unit
,
230 const char *filename
,
233 unsigned section_line
,
239 Network
*network
= userdata
;
240 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
249 r
= prefix_new_static(network
, filename
, section_line
, &p
);
253 r
= parse_boolean(rvalue
);
255 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
259 if (streq(lvalue
, "OnLink"))
260 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, r
);
261 else if (streq(lvalue
, "AddressAutoconfiguration"))
262 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, r
);
264 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set %s=, ignoring assignment: %m", lvalue
);
273 int config_parse_prefix_lifetime(const char *unit
,
274 const char *filename
,
277 unsigned section_line
,
283 Network
*network
= userdata
;
284 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
294 r
= prefix_new_static(network
, filename
, section_line
, &p
);
298 r
= parse_sec(rvalue
, &usec
);
300 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
304 /* a value of 0xffffffff represents infinity */
305 if (streq(lvalue
, "PreferredLifetimeSec"))
306 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
307 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
308 else if (streq(lvalue
, "ValidLifetimeSec"))
309 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
310 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
312 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set %s=, ignoring assignment: %m", lvalue
);
321 int config_parse_prefix_assign(
323 const char *filename
,
326 unsigned section_line
,
333 Network
*network
= userdata
;
334 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
343 r
= prefix_new_static(network
, filename
, section_line
, &p
);
347 r
= parse_boolean(rvalue
);
349 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
350 "Failed to parse %s=, ignoring assignment: %s",
361 int config_parse_route_prefix(const char *unit
,
362 const char *filename
,
365 unsigned section_line
,
372 Network
*network
= userdata
;
373 _cleanup_(route_prefix_free_or_set_invalidp
) RoutePrefix
*p
= NULL
;
374 uint8_t prefixlen
= 64;
375 union in_addr_union in6addr
;
384 r
= route_prefix_new_static(network
, filename
, section_line
, &p
);
388 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
390 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Route prefix is invalid, ignoring assignment: %s", rvalue
);
394 r
= sd_radv_prefix_set_route_prefix(p
->radv_route_prefix
, &in6addr
.in6
, prefixlen
);
396 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to set route prefix, ignoring assignment: %m");
405 int config_parse_route_prefix_lifetime(const char *unit
,
406 const char *filename
,
409 unsigned section_line
,
415 Network
*network
= userdata
;
416 _cleanup_(route_prefix_free_or_set_invalidp
) RoutePrefix
*p
= NULL
;
426 r
= route_prefix_new_static(network
, filename
, section_line
, &p
);
430 r
= parse_sec(rvalue
, &usec
);
432 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
433 "Route lifetime is invalid, ignoring assignment: %s", rvalue
);
437 /* a value of 0xffffffff represents infinity */
438 r
= sd_radv_route_prefix_set_lifetime(p
->radv_route_prefix
, DIV_ROUND_UP(usec
, USEC_PER_SEC
));
440 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
441 "Failed to set route lifetime, ignoring assignment: %m");
450 static int radv_get_ip6dns(Network
*network
, struct in6_addr
**dns
,
452 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
453 size_t i
, n_addresses
= 0, n_allocated
= 0;
459 for (i
= 0; i
< network
->n_dns
; i
++) {
460 union in_addr_union
*addr
;
462 if (network
->dns
[i
]->family
!= AF_INET6
)
465 addr
= &network
->dns
[i
]->address
;
467 if (in_addr_is_null(AF_INET6
, addr
) ||
468 in_addr_is_link_local(AF_INET6
, addr
) ||
469 in_addr_is_localhost(AF_INET6
, addr
))
472 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
475 addresses
[n_addresses
++] = addr
->in6
;
479 *dns
= TAKE_PTR(addresses
);
481 *n_dns
= n_addresses
;
487 static int radv_set_dns(Link
*link
, Link
*uplink
) {
488 _cleanup_free_
struct in6_addr
*dns
= NULL
;
489 usec_t lifetime_usec
;
493 if (!link
->network
->router_emit_dns
)
496 if (link
->network
->router_dns
) {
499 dns
= new(struct in6_addr
, link
->network
->n_router_dns
);
504 for (size_t i
= 0; i
< link
->network
->n_router_dns
; i
++)
505 if (IN6_IS_ADDR_UNSPECIFIED(&link
->network
->router_dns
[i
])) {
506 if (!IN6_IS_ADDR_UNSPECIFIED(&link
->ipv6ll_address
))
507 *(p
++) = link
->ipv6ll_address
;
509 *(p
++) = link
->network
->router_dns
[i
];
512 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
517 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
519 r
= radv_get_ip6dns(link
->network
, &dns
, &n_dns
);
524 if (!uplink
->network
) {
525 log_link_debug(uplink
, "Cannot fetch DNS servers as uplink interface is not managed by us");
529 r
= radv_get_ip6dns(uplink
->network
, &dns
, &n_dns
);
537 return sd_radv_set_rdnss(link
->radv
,
538 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
542 static int radv_set_domains(Link
*link
, Link
*uplink
) {
543 OrderedSet
*search_domains
;
544 usec_t lifetime_usec
;
545 _cleanup_free_
char **s
= NULL
; /* just free() because the strings are owned by the set */
547 if (!link
->network
->router_emit_domains
)
550 search_domains
= link
->network
->router_search_domains
;
551 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
556 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
558 search_domains
= link
->network
->search_domains
;
563 if (!uplink
->network
) {
564 log_link_debug(uplink
, "Cannot fetch DNS search domains as uplink interface is not managed by us");
568 search_domains
= uplink
->network
->search_domains
;
576 s
= ordered_set_get_strv(search_domains
);
580 return sd_radv_set_dnssl(link
->radv
,
581 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
586 int radv_emit_dns(Link
*link
) {
590 uplink
= manager_find_uplink(link
->manager
, link
);
592 r
= radv_set_dns(link
, uplink
);
594 log_link_warning_errno(link
, r
, "Could not set RA DNS: %m");
596 r
= radv_set_domains(link
, uplink
);
598 log_link_warning_errno(link
, r
, "Could not set RA Domains: %m");
603 int radv_configure(Link
*link
) {
607 assert(link
->network
);
609 r
= sd_radv_new(&link
->radv
);
613 r
= sd_radv_attach_event(link
->radv
, NULL
, 0);
617 r
= sd_radv_set_mac(link
->radv
, &link
->mac
);
621 r
= sd_radv_set_ifindex(link
->radv
, link
->ifindex
);
625 r
= sd_radv_set_managed_information(link
->radv
, link
->network
->router_managed
);
629 r
= sd_radv_set_other_information(link
->radv
, link
->network
->router_other_information
);
633 /* a value of 0xffffffff represents infinity, 0x0 means this host is
635 r
= sd_radv_set_router_lifetime(link
->radv
,
636 DIV_ROUND_UP(link
->network
->router_lifetime_usec
, USEC_PER_SEC
));
640 if (link
->network
->router_lifetime_usec
> 0) {
641 r
= sd_radv_set_preference(link
->radv
,
642 link
->network
->router_preference
);
647 if (link
->network
->router_prefix_delegation
& RADV_PREFIX_DELEGATION_STATIC
) {
651 HASHMAP_FOREACH(p
, link
->network
->prefixes_by_section
) {
652 r
= sd_radv_add_prefix(link
->radv
, p
->radv_prefix
, false);
656 log_link_warning_errno(link
, r
, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
663 HASHMAP_FOREACH(q
, link
->network
->route_prefixes_by_section
) {
664 r
= sd_radv_add_route_prefix(link
->radv
, q
->radv_route_prefix
, false);
675 int radv_add_prefix(Link
*link
, const struct in6_addr
*prefix
, uint8_t prefix_len
,
676 uint32_t lifetime_preferred
, uint32_t lifetime_valid
) {
677 _cleanup_(sd_radv_prefix_unrefp
) sd_radv_prefix
*p
= NULL
;
685 r
= sd_radv_prefix_new(&p
);
689 r
= sd_radv_prefix_set_prefix(p
, prefix
, prefix_len
);
693 r
= sd_radv_prefix_set_preferred_lifetime(p
, lifetime_preferred
);
697 r
= sd_radv_prefix_set_valid_lifetime(p
, lifetime_valid
);
701 r
= sd_radv_add_prefix(link
->radv
, p
, true);
702 if (r
< 0 && r
!= -EEXIST
)
708 int config_parse_radv_dns(
710 const char *filename
,
713 unsigned section_line
,
727 for (const char *p
= rvalue
;;) {
728 _cleanup_free_
char *w
= NULL
;
729 union in_addr_union a
;
731 r
= extract_first_word(&p
, &w
, NULL
, 0);
735 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
736 "Failed to extract word, ignoring: %s", rvalue
);
742 if (streq(w
, "_link_local"))
745 r
= in_addr_from_string(AF_INET6
, w
, &a
);
747 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
748 "Failed to parse DNS server address, ignoring: %s", w
);
752 if (in_addr_is_null(AF_INET6
, &a
)) {
753 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
754 "DNS server address is null, ignoring: %s", w
);
760 m
= reallocarray(n
->router_dns
, n
->n_router_dns
+ 1, sizeof(struct in6_addr
));
764 m
[n
->n_router_dns
++] = a
.in6
;
769 int config_parse_radv_search_domains(
771 const char *filename
,
774 unsigned section_line
,
788 for (const char *p
= rvalue
;;) {
789 _cleanup_free_
char *w
= NULL
, *idna
= NULL
;
791 r
= extract_first_word(&p
, &w
, NULL
, 0);
795 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
796 "Failed to extract word, ignoring: %s", rvalue
);
802 r
= dns_name_apply_idna(w
, &idna
);
804 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
805 "Failed to apply IDNA to domain name '%s', ignoring: %m", w
);
808 /* transfer ownership to simplify subsequent operations */
811 r
= ordered_set_ensure_allocated(&n
->router_search_domains
, &string_hash_ops
);
815 r
= ordered_set_consume(n
->router_search_domains
, TAKE_PTR(idna
));
821 static const char * const radv_prefix_delegation_table
[_RADV_PREFIX_DELEGATION_MAX
] = {
822 [RADV_PREFIX_DELEGATION_NONE
] = "no",
823 [RADV_PREFIX_DELEGATION_STATIC
] = "static",
824 [RADV_PREFIX_DELEGATION_DHCP6
] = "dhcpv6",
825 [RADV_PREFIX_DELEGATION_BOTH
] = "yes",
828 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
829 radv_prefix_delegation
,
830 RADVPrefixDelegation
,
831 RADV_PREFIX_DELEGATION_BOTH
);
833 DEFINE_CONFIG_PARSE_ENUM(config_parse_router_prefix_delegation
,
834 radv_prefix_delegation
,
835 RADVPrefixDelegation
,
836 "Invalid router prefix delegation");
838 int config_parse_router_preference(const char *unit
,
839 const char *filename
,
842 unsigned section_line
,
848 Network
*network
= userdata
;
856 if (streq(rvalue
, "high"))
857 network
->router_preference
= SD_NDISC_PREFERENCE_HIGH
;
858 else if (STR_IN_SET(rvalue
, "medium", "normal", "default"))
859 network
->router_preference
= SD_NDISC_PREFERENCE_MEDIUM
;
860 else if (streq(rvalue
, "low"))
861 network
->router_preference
= SD_NDISC_PREFERENCE_LOW
;
863 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
864 "Invalid router preference, ignoring assignment: %s", rvalue
);