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 void prefix_free(Prefix
*prefix
) {
23 if (prefix
->network
) {
24 LIST_REMOVE(prefixes
, prefix
->network
->static_prefixes
, prefix
);
25 assert(prefix
->network
->n_static_prefixes
> 0);
26 prefix
->network
->n_static_prefixes
--;
29 hashmap_remove(prefix
->network
->prefixes_by_section
,
33 network_config_section_free(prefix
->section
);
34 sd_radv_prefix_unref(prefix
->radv_prefix
);
39 static int prefix_new(Prefix
**ret
) {
40 _cleanup_(prefix_freep
) Prefix
*prefix
= NULL
;
42 prefix
= new0(Prefix
, 1);
46 if (sd_radv_prefix_new(&prefix
->radv_prefix
) < 0)
49 *ret
= TAKE_PTR(prefix
);
54 static int prefix_new_static(Network
*network
, const char *filename
,
55 unsigned section_line
, Prefix
**ret
) {
56 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
57 _cleanup_(prefix_freep
) Prefix
*prefix
= NULL
;
62 assert(!!filename
== (section_line
> 0));
65 r
= network_config_section_new(filename
, section_line
, &n
);
70 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
72 *ret
= TAKE_PTR(prefix
);
79 r
= prefix_new(&prefix
);
83 prefix
->network
= network
;
84 LIST_APPEND(prefixes
, network
->static_prefixes
, prefix
);
85 network
->n_static_prefixes
++;
88 prefix
->section
= TAKE_PTR(n
);
90 r
= hashmap_ensure_allocated(&network
->prefixes_by_section
, &network_config_hash_ops
);
94 r
= hashmap_put(network
->prefixes_by_section
, prefix
->section
, prefix
);
99 *ret
= TAKE_PTR(prefix
);
104 static int route_prefix_new(RoutePrefix
**ret
) {
105 _cleanup_(route_prefix_freep
) RoutePrefix
*prefix
= NULL
;
107 prefix
= new0(RoutePrefix
, 1);
111 if (sd_radv_route_prefix_new(&prefix
->radv_route_prefix
) < 0)
114 *ret
= TAKE_PTR(prefix
);
119 void route_prefix_free(RoutePrefix
*prefix
) {
123 if (prefix
->network
) {
124 LIST_REMOVE(route_prefixes
, prefix
->network
->static_route_prefixes
, prefix
);
125 assert(prefix
->network
->n_static_route_prefixes
> 0);
126 prefix
->network
->n_static_route_prefixes
--;
129 hashmap_remove(prefix
->network
->route_prefixes_by_section
,
133 network_config_section_free(prefix
->section
);
134 sd_radv_route_prefix_unref(prefix
->radv_route_prefix
);
139 static int route_prefix_new_static(Network
*network
, const char *filename
,
140 unsigned section_line
, RoutePrefix
**ret
) {
141 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
142 _cleanup_(route_prefix_freep
) RoutePrefix
*prefix
= NULL
;
147 assert(!!filename
== (section_line
> 0));
150 r
= network_config_section_new(filename
, section_line
, &n
);
155 prefix
= hashmap_get(network
->route_prefixes_by_section
, n
);
157 *ret
= TAKE_PTR(prefix
);
164 r
= route_prefix_new(&prefix
);
168 prefix
->network
= network
;
169 LIST_APPEND(route_prefixes
, network
->static_route_prefixes
, prefix
);
170 network
->n_static_route_prefixes
++;
173 prefix
->section
= TAKE_PTR(n
);
175 r
= hashmap_ensure_allocated(&network
->route_prefixes_by_section
, &network_config_hash_ops
);
179 r
= hashmap_put(network
->route_prefixes_by_section
, prefix
->section
, prefix
);
184 *ret
= TAKE_PTR(prefix
);
189 int config_parse_prefix(const char *unit
,
190 const char *filename
,
193 unsigned section_line
,
200 Network
*network
= userdata
;
201 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
202 uint8_t prefixlen
= 64;
203 union in_addr_union in6addr
;
212 r
= prefix_new_static(network
, filename
, section_line
, &p
);
216 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
218 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
222 if (sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
) < 0)
223 return -EADDRNOTAVAIL
;
225 log_syntax(unit
, LOG_INFO
, filename
, line
, r
, "Found prefix %s", rvalue
);
232 int config_parse_prefix_flags(const char *unit
,
233 const char *filename
,
236 unsigned section_line
,
242 Network
*network
= userdata
;
243 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
252 r
= prefix_new_static(network
, filename
, section_line
, &p
);
256 r
= parse_boolean(rvalue
);
258 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse address flag, ignoring: %s", rvalue
);
264 if (streq(lvalue
, "OnLink"))
265 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, val
);
266 else if (streq(lvalue
, "AddressAutoconfiguration"))
267 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, val
);
276 int config_parse_prefix_lifetime(const char *unit
,
277 const char *filename
,
280 unsigned section_line
,
286 Network
*network
= userdata
;
287 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
297 r
= prefix_new_static(network
, filename
, section_line
, &p
);
301 r
= parse_sec(rvalue
, &usec
);
303 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
307 /* a value of 0xffffffff represents infinity */
308 if (streq(lvalue
, "PreferredLifetimeSec"))
309 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
310 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
311 else if (streq(lvalue
, "ValidLifetimeSec"))
312 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
313 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
322 int config_parse_prefix_assign(
324 const char *filename
,
327 unsigned section_line
,
334 Network
*network
= userdata
;
335 _cleanup_(prefix_free_or_set_invalidp
) Prefix
*p
= NULL
;
344 r
= prefix_new_static(network
, filename
, section_line
, &p
);
348 r
= parse_boolean(rvalue
);
350 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
351 "Failed to parse %s=, ignoring assignment: %s",
362 int config_parse_route_prefix(const char *unit
,
363 const char *filename
,
366 unsigned section_line
,
373 Network
*network
= userdata
;
374 _cleanup_(route_prefix_free_or_set_invalidp
) RoutePrefix
*p
= NULL
;
375 uint8_t prefixlen
= 64;
376 union in_addr_union in6addr
;
385 r
= route_prefix_new_static(network
, filename
, section_line
, &p
);
389 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
391 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Route prefix is invalid, ignoring assignment: %s", rvalue
);
395 if (sd_radv_prefix_set_route_prefix(p
->radv_route_prefix
, &in6addr
.in6
, prefixlen
) < 0)
396 return -EADDRNOTAVAIL
;
398 log_syntax(unit
, LOG_INFO
, filename
, line
, r
, "Found route prefix %s", rvalue
);
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
));
447 static int radv_get_ip6dns(Network
*network
, struct in6_addr
**dns
,
449 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
450 size_t i
, n_addresses
= 0, n_allocated
= 0;
456 for (i
= 0; i
< network
->n_dns
; i
++) {
457 union in_addr_union
*addr
;
459 if (network
->dns
[i
].family
!= AF_INET6
)
462 addr
= &network
->dns
[i
].address
;
464 if (in_addr_is_null(AF_INET6
, addr
) ||
465 in_addr_is_link_local(AF_INET6
, addr
) ||
466 in_addr_is_localhost(AF_INET6
, addr
))
469 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
472 addresses
[n_addresses
++] = addr
->in6
;
476 *dns
= TAKE_PTR(addresses
);
478 *n_dns
= n_addresses
;
484 static int radv_set_dns(Link
*link
, Link
*uplink
) {
485 _cleanup_free_
struct in6_addr
*dns
= NULL
;
486 usec_t lifetime_usec
;
490 if (!link
->network
->router_emit_dns
)
493 if (link
->network
->router_dns
) {
496 dns
= new(struct in6_addr
, link
->network
->n_router_dns
);
501 for (size_t i
= 0; i
< link
->network
->n_router_dns
; i
++)
502 if (IN6_IS_ADDR_UNSPECIFIED(&link
->network
->router_dns
[i
])) {
503 if (!IN6_IS_ADDR_UNSPECIFIED(&link
->ipv6ll_address
))
504 *(p
++) = link
->ipv6ll_address
;
506 *(p
++) = link
->network
->router_dns
[i
];
509 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
514 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
516 r
= radv_get_ip6dns(link
->network
, &dns
, &n_dns
);
521 if (!uplink
->network
) {
522 log_link_debug(uplink
, "Cannot fetch DNS servers as uplink interface is not managed by us");
526 r
= radv_get_ip6dns(uplink
->network
, &dns
, &n_dns
);
534 return sd_radv_set_rdnss(link
->radv
,
535 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
539 static int radv_set_domains(Link
*link
, Link
*uplink
) {
540 OrderedSet
*search_domains
;
541 usec_t lifetime_usec
;
542 _cleanup_free_
char **s
= NULL
; /* just free() because the strings are owned by the set */
544 if (!link
->network
->router_emit_domains
)
547 search_domains
= link
->network
->router_search_domains
;
548 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
553 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
555 search_domains
= link
->network
->search_domains
;
560 if (!uplink
->network
) {
561 log_link_debug(uplink
, "Cannot fetch DNS search domains as uplink interface is not managed by us");
565 search_domains
= uplink
->network
->search_domains
;
573 s
= ordered_set_get_strv(search_domains
);
577 return sd_radv_set_dnssl(link
->radv
,
578 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
583 int radv_emit_dns(Link
*link
) {
587 uplink
= manager_find_uplink(link
->manager
, link
);
589 r
= radv_set_dns(link
, uplink
);
591 log_link_warning_errno(link
, r
, "Could not set RA DNS: %m");
593 r
= radv_set_domains(link
, uplink
);
595 log_link_warning_errno(link
, r
, "Could not set RA Domains: %m");
600 int radv_configure(Link
*link
) {
606 assert(link
->network
);
608 r
= sd_radv_new(&link
->radv
);
612 r
= sd_radv_attach_event(link
->radv
, NULL
, 0);
616 r
= sd_radv_set_mac(link
->radv
, &link
->mac
);
620 r
= sd_radv_set_ifindex(link
->radv
, link
->ifindex
);
624 r
= sd_radv_set_managed_information(link
->radv
, link
->network
->router_managed
);
628 r
= sd_radv_set_other_information(link
->radv
, link
->network
->router_other_information
);
632 /* a value of 0xffffffff represents infinity, 0x0 means this host is
634 r
= sd_radv_set_router_lifetime(link
->radv
,
635 DIV_ROUND_UP(link
->network
->router_lifetime_usec
, USEC_PER_SEC
));
639 if (link
->network
->router_lifetime_usec
> 0) {
640 r
= sd_radv_set_preference(link
->radv
,
641 link
->network
->router_preference
);
646 if (IN_SET(link
->network
->router_prefix_delegation
,
647 RADV_PREFIX_DELEGATION_STATIC
,
648 RADV_PREFIX_DELEGATION_BOTH
)) {
650 LIST_FOREACH(prefixes
, p
, link
->network
->static_prefixes
) {
651 r
= sd_radv_add_prefix(link
->radv
, p
->radv_prefix
, false);
655 log_link_warning_errno(link
, r
, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
662 LIST_FOREACH(route_prefixes
, q
, link
->network
->static_route_prefixes
) {
663 r
= sd_radv_add_route_prefix(link
->radv
, q
->radv_route_prefix
, false);
675 int radv_add_prefix(Link
*link
, 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
;
683 r
= sd_radv_prefix_new(&p
);
687 r
= sd_radv_prefix_set_prefix(p
, prefix
, prefix_len
);
691 r
= sd_radv_prefix_set_preferred_lifetime(p
, lifetime_preferred
);
695 r
= sd_radv_prefix_set_valid_lifetime(p
, lifetime_valid
);
699 r
= sd_radv_add_prefix(link
->radv
, p
, true);
700 if (r
< 0 && r
!= -EEXIST
)
706 int config_parse_radv_dns(
708 const char *filename
,
711 unsigned section_line
,
725 for (const char *p
= rvalue
;;) {
726 _cleanup_free_
char *w
= NULL
;
727 union in_addr_union a
;
729 r
= extract_first_word(&p
, &w
, NULL
, 0);
733 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
734 "Failed to extract word, ignoring: %s", rvalue
);
740 if (streq(w
, "_link_local"))
743 r
= in_addr_from_string(AF_INET6
, w
, &a
);
745 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
746 "Failed to parse DNS server address, ignoring: %s", w
);
750 if (in_addr_is_null(AF_INET6
, &a
)) {
751 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
752 "DNS server address is null, ignoring: %s", w
);
758 m
= reallocarray(n
->router_dns
, n
->n_router_dns
+ 1, sizeof(struct in6_addr
));
762 m
[n
->n_router_dns
++] = a
.in6
;
767 int config_parse_radv_search_domains(
769 const char *filename
,
772 unsigned section_line
,
786 for (const char *p
= rvalue
;;) {
787 _cleanup_free_
char *w
= NULL
, *idna
= NULL
;
789 r
= extract_first_word(&p
, &w
, NULL
, 0);
793 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
794 "Failed to extract word, ignoring: %s", rvalue
);
800 r
= dns_name_apply_idna(w
, &idna
);
802 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
803 "Failed to apply IDNA to domain name '%s', ignoring: %m", w
);
806 /* transfer ownership to simplify subsequent operations */
809 r
= ordered_set_ensure_allocated(&n
->router_search_domains
, &string_hash_ops
);
813 r
= ordered_set_consume(n
->router_search_domains
, TAKE_PTR(idna
));
819 static const char * const radv_prefix_delegation_table
[_RADV_PREFIX_DELEGATION_MAX
] = {
820 [RADV_PREFIX_DELEGATION_NONE
] = "no",
821 [RADV_PREFIX_DELEGATION_STATIC
] = "static",
822 [RADV_PREFIX_DELEGATION_DHCP6
] = "dhcpv6",
823 [RADV_PREFIX_DELEGATION_BOTH
] = "yes",
826 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
827 radv_prefix_delegation
,
828 RADVPrefixDelegation
,
829 RADV_PREFIX_DELEGATION_BOTH
);
831 int config_parse_router_prefix_delegation(
833 const char *filename
,
836 unsigned section_line
,
843 Network
*network
= userdata
;
844 RADVPrefixDelegation d
;
852 d
= radv_prefix_delegation_from_string(rvalue
);
854 log_syntax(unit
, LOG_WARNING
, filename
, line
, SYNTHETIC_ERRNO(EINVAL
),
855 "Invalid router prefix delegation '%s', ignoring assignment.", rvalue
);
859 network
->router_prefix_delegation
= d
;
864 int config_parse_router_preference(const char *unit
,
865 const char *filename
,
868 unsigned section_line
,
874 Network
*network
= userdata
;
882 if (streq(rvalue
, "high"))
883 network
->router_preference
= SD_NDISC_PREFERENCE_HIGH
;
884 else if (STR_IN_SET(rvalue
, "medium", "normal", "default"))
885 network
->router_preference
= SD_NDISC_PREFERENCE_MEDIUM
;
886 else if (streq(rvalue
, "low"))
887 network
->router_preference
= SD_NDISC_PREFERENCE_LOW
;
889 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
890 "Invalid router preference, ignoring assignment: %s", rvalue
);
895 int config_parse_router_prefix_subnet_id(const char *unit
,
896 const char *filename
,
899 unsigned section_line
,
905 Network
*network
= userdata
;
914 if (isempty(rvalue
) || streq(rvalue
, "auto")) {
915 network
->router_prefix_subnet_id
= -1;
919 r
= safe_atoux64(rvalue
, &t
);
920 if (r
< 0 || t
> INT64_MAX
) {
921 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
922 "Subnet id '%s' is invalid, ignoring assignment.",
927 network
->router_prefix_subnet_id
= (int64_t)t
;