1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright (C) 2017 Intel Corporation. All rights reserved.
8 #include <netinet/icmp6.h>
11 #include "networkd-address.h"
12 #include "networkd-manager.h"
13 #include "networkd-radv.h"
14 #include "parse-util.h"
16 #include "string-util.h"
18 int config_parse_router_prefix_delegation(
23 unsigned section_line
,
30 Network
*network
= userdata
;
39 if (streq(rvalue
, "static"))
40 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_STATIC
;
41 else if (streq(rvalue
, "dhcpv6"))
42 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_DHCP6
;
44 d
= parse_boolean(rvalue
);
46 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_BOTH
;
48 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_NONE
;
51 log_syntax(unit
, LOG_ERR
, filename
, line
, -EINVAL
, "Router prefix delegation '%s' is invalid, ignoring assignment: %m", rvalue
);
57 int config_parse_router_preference(const char *unit
,
61 unsigned section_line
,
67 Network
*network
= userdata
;
75 if (streq(rvalue
, "high"))
76 network
->router_preference
= SD_NDISC_PREFERENCE_HIGH
;
77 else if (STR_IN_SET(rvalue
, "medium", "normal", "default"))
78 network
->router_preference
= SD_NDISC_PREFERENCE_MEDIUM
;
79 else if (streq(rvalue
, "low"))
80 network
->router_preference
= SD_NDISC_PREFERENCE_LOW
;
82 log_syntax(unit
, LOG_ERR
, filename
, line
, -EINVAL
, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue
);
87 void prefix_free(Prefix
*prefix
) {
91 if (prefix
->network
) {
92 LIST_REMOVE(prefixes
, prefix
->network
->static_prefixes
, prefix
);
93 assert(prefix
->network
->n_static_prefixes
> 0);
94 prefix
->network
->n_static_prefixes
--;
97 hashmap_remove(prefix
->network
->prefixes_by_section
,
101 prefix
->radv_prefix
= sd_radv_prefix_unref(prefix
->radv_prefix
);
106 int prefix_new(Prefix
**ret
) {
107 Prefix
*prefix
= NULL
;
109 prefix
= new0(Prefix
, 1);
113 if (sd_radv_prefix_new(&prefix
->radv_prefix
) < 0)
116 *ret
= TAKE_PTR(prefix
);
121 int prefix_new_static(Network
*network
, const char *filename
,
122 unsigned section_line
, Prefix
**ret
) {
123 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
124 _cleanup_(prefix_freep
) Prefix
*prefix
= NULL
;
129 assert(!!filename
== (section_line
> 0));
132 r
= network_config_section_new(filename
, section_line
, &n
);
137 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
139 *ret
= TAKE_PTR(prefix
);
146 r
= prefix_new(&prefix
);
151 prefix
->section
= TAKE_PTR(n
);
153 r
= hashmap_put(network
->prefixes_by_section
, prefix
->section
,
159 prefix
->network
= network
;
160 LIST_APPEND(prefixes
, network
->static_prefixes
, prefix
);
161 network
->n_static_prefixes
++;
163 *ret
= TAKE_PTR(prefix
);
168 int config_parse_prefix(const char *unit
,
169 const char *filename
,
172 unsigned section_line
,
179 Network
*network
= userdata
;
180 _cleanup_(prefix_freep
) Prefix
*p
= NULL
;
181 uint8_t prefixlen
= 64;
182 union in_addr_union in6addr
;
191 r
= prefix_new_static(network
, filename
, section_line
, &p
);
195 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
197 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
201 if (sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
) < 0)
202 return -EADDRNOTAVAIL
;
204 log_syntax(unit
, LOG_INFO
, filename
, line
, r
, "Found prefix %s", rvalue
);
211 int config_parse_prefix_flags(const char *unit
,
212 const char *filename
,
215 unsigned section_line
,
221 Network
*network
= userdata
;
222 _cleanup_(prefix_freep
) Prefix
*p
= NULL
;
231 r
= prefix_new_static(network
, filename
, section_line
, &p
);
235 r
= parse_boolean(rvalue
);
237 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address flag, ignoring: %s", rvalue
);
243 if (streq(lvalue
, "OnLink"))
244 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, val
);
245 else if (streq(lvalue
, "AddressAutoconfiguration"))
246 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, val
);
255 int config_parse_prefix_lifetime(const char *unit
,
256 const char *filename
,
259 unsigned section_line
,
265 Network
*network
= userdata
;
266 _cleanup_(prefix_freep
) Prefix
*p
= NULL
;
276 r
= prefix_new_static(network
, filename
, section_line
, &p
);
280 r
= parse_sec(rvalue
, &usec
);
282 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
286 /* a value of 0xffffffff represents infinity */
287 if (streq(lvalue
, "PreferredLifetimeSec"))
288 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
289 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
290 else if (streq(lvalue
, "ValidLifetimeSec"))
291 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
292 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
301 static int radv_get_ip6dns(Network
*network
, struct in6_addr
**dns
,
303 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
304 size_t i
, n_addresses
= 0, n_allocated
= 0;
310 for (i
= 0; i
< network
->n_dns
; i
++) {
311 union in_addr_union
*addr
;
313 if (network
->dns
[i
].family
!= AF_INET6
)
316 addr
= &network
->dns
[i
].address
;
318 if (in_addr_is_null(AF_INET6
, addr
) ||
319 in_addr_is_link_local(AF_INET6
, addr
) ||
320 in_addr_is_localhost(AF_INET6
, addr
))
323 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
326 addresses
[n_addresses
++] = addr
->in6
;
330 *dns
= TAKE_PTR(addresses
);
332 *n_dns
= n_addresses
;
338 static int radv_set_dns(Link
*link
, Link
*uplink
) {
339 _cleanup_free_
struct in6_addr
*dns
= NULL
;
341 usec_t lifetime_usec
;
344 if (!link
->network
->router_emit_dns
)
347 if (link
->network
->router_dns
) {
348 dns
= newdup(struct in6_addr
, link
->network
->router_dns
,
349 link
->network
->n_router_dns
);
353 n_dns
= link
->network
->n_router_dns
;
354 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
359 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
361 r
= radv_get_ip6dns(link
->network
, &dns
, &n_dns
);
366 if (uplink
->network
== NULL
) {
367 log_link_debug(uplink
, "Cannot fetch DNS servers as uplink interface is not managed by us");
371 r
= radv_get_ip6dns(uplink
->network
, &dns
, &n_dns
);
379 return sd_radv_set_rdnss(link
->radv
,
380 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
384 static int radv_set_domains(Link
*link
, Link
*uplink
) {
385 char **search_domains
;
386 usec_t lifetime_usec
;
388 if (!link
->network
->router_emit_domains
)
391 search_domains
= link
->network
->router_search_domains
;
392 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
397 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
399 search_domains
= link
->network
->search_domains
;
404 if (uplink
->network
== NULL
) {
405 log_link_debug(uplink
, "Cannot fetch DNS search domains as uplink interface is not managed by us");
409 search_domains
= uplink
->network
->search_domains
;
417 return sd_radv_set_dnssl(link
->radv
,
418 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
423 int radv_emit_dns(Link
*link
) {
427 uplink
= manager_find_uplink(link
->manager
, link
);
429 r
= radv_set_dns(link
, uplink
);
431 log_link_warning_errno(link
, r
, "Could not set RA DNS: %m");
433 r
= radv_set_domains(link
, uplink
);
435 log_link_warning_errno(link
, r
, "Could not set RA Domains: %m");
440 int radv_configure(Link
*link
) {
445 assert(link
->network
);
447 r
= sd_radv_new(&link
->radv
);
451 r
= sd_radv_attach_event(link
->radv
, NULL
, 0);
455 r
= sd_radv_set_mac(link
->radv
, &link
->mac
);
459 r
= sd_radv_set_ifindex(link
->radv
, link
->ifindex
);
463 r
= sd_radv_set_managed_information(link
->radv
, link
->network
->router_managed
);
467 r
= sd_radv_set_other_information(link
->radv
, link
->network
->router_other_information
);
471 /* a value of 0xffffffff represents infinity, 0x0 means this host is
473 r
= sd_radv_set_router_lifetime(link
->radv
,
474 DIV_ROUND_UP(link
->network
->router_lifetime_usec
, USEC_PER_SEC
));
478 if (link
->network
->router_lifetime_usec
> 0) {
479 r
= sd_radv_set_preference(link
->radv
,
480 link
->network
->router_preference
);
485 if (IN_SET(link
->network
->router_prefix_delegation
,
486 RADV_PREFIX_DELEGATION_STATIC
,
487 RADV_PREFIX_DELEGATION_BOTH
)) {
488 LIST_FOREACH(prefixes
, p
, link
->network
->static_prefixes
) {
489 r
= sd_radv_add_prefix(link
->radv
, p
->radv_prefix
, false);
490 if (r
!= -EEXIST
&& r
< 0)
495 return radv_emit_dns(link
);