1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright (C) 2017 Intel Corporation. All rights reserved.
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/icmp6.h>
22 #include <arpa/inet.h>
24 #include "networkd-address.h"
25 #include "networkd-manager.h"
26 #include "networkd-radv.h"
27 #include "parse-util.h"
29 #include "string-util.h"
31 int config_parse_router_prefix_delegation(
36 unsigned section_line
,
43 Network
*network
= userdata
;
52 if (streq(rvalue
, "static"))
53 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_STATIC
;
54 else if (streq(rvalue
, "dhcpv6"))
55 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_DHCP6
;
57 d
= parse_boolean(rvalue
);
59 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_BOTH
;
61 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_NONE
;
64 log_syntax(unit
, LOG_ERR
, filename
, line
, -EINVAL
, "Router prefix delegation '%s' is invalid, ignoring assignment: %m", rvalue
);
70 int config_parse_router_preference(const char *unit
,
74 unsigned section_line
,
80 Network
*network
= userdata
;
88 if (streq(rvalue
, "high"))
89 network
->router_preference
= SD_NDISC_PREFERENCE_HIGH
;
90 else if (STR_IN_SET(rvalue
, "medium", "normal", "default"))
91 network
->router_preference
= SD_NDISC_PREFERENCE_MEDIUM
;
92 else if (streq(rvalue
, "low"))
93 network
->router_preference
= SD_NDISC_PREFERENCE_LOW
;
95 log_syntax(unit
, LOG_ERR
, filename
, line
, -EINVAL
, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue
);
100 void prefix_free(Prefix
*prefix
) {
104 if (prefix
->network
) {
105 LIST_REMOVE(prefixes
, prefix
->network
->static_prefixes
, prefix
);
106 assert(prefix
->network
->n_static_prefixes
> 0);
107 prefix
->network
->n_static_prefixes
--;
110 hashmap_remove(prefix
->network
->prefixes_by_section
,
114 prefix
->radv_prefix
= sd_radv_prefix_unref(prefix
->radv_prefix
);
119 int prefix_new(Prefix
**ret
) {
120 Prefix
*prefix
= NULL
;
122 prefix
= new0(Prefix
, 1);
126 if (sd_radv_prefix_new(&prefix
->radv_prefix
) < 0)
129 *ret
= TAKE_PTR(prefix
);
134 int prefix_new_static(Network
*network
, const char *filename
,
135 unsigned section_line
, Prefix
**ret
) {
136 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
137 _cleanup_prefix_free_ Prefix
*prefix
= NULL
;
142 assert(!!filename
== (section_line
> 0));
145 r
= network_config_section_new(filename
, section_line
, &n
);
150 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
152 *ret
= TAKE_PTR(prefix
);
159 r
= prefix_new(&prefix
);
164 prefix
->section
= TAKE_PTR(n
);
166 r
= hashmap_put(network
->prefixes_by_section
, prefix
->section
,
172 prefix
->network
= network
;
173 LIST_APPEND(prefixes
, network
->static_prefixes
, prefix
);
174 network
->n_static_prefixes
++;
176 *ret
= TAKE_PTR(prefix
);
181 int config_parse_prefix(const char *unit
,
182 const char *filename
,
185 unsigned section_line
,
192 Network
*network
= userdata
;
193 _cleanup_prefix_free_ Prefix
*p
= NULL
;
194 uint8_t prefixlen
= 64;
195 union in_addr_union in6addr
;
204 r
= prefix_new_static(network
, filename
, section_line
, &p
);
208 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
210 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
214 if (sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
) < 0)
215 return -EADDRNOTAVAIL
;
217 log_syntax(unit
, LOG_INFO
, filename
, line
, r
, "Found prefix %s", rvalue
);
224 int config_parse_prefix_flags(const char *unit
,
225 const char *filename
,
228 unsigned section_line
,
234 Network
*network
= userdata
;
235 _cleanup_prefix_free_ Prefix
*p
= NULL
;
244 r
= prefix_new_static(network
, filename
, section_line
, &p
);
248 r
= parse_boolean(rvalue
);
250 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address flag, ignoring: %s", rvalue
);
256 if (streq(lvalue
, "OnLink"))
257 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, val
);
258 else if (streq(lvalue
, "AddressAutoconfiguration"))
259 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, val
);
268 int config_parse_prefix_lifetime(const char *unit
,
269 const char *filename
,
272 unsigned section_line
,
278 Network
*network
= userdata
;
279 _cleanup_prefix_free_ Prefix
*p
= NULL
;
289 r
= prefix_new_static(network
, filename
, section_line
, &p
);
293 r
= parse_sec(rvalue
, &usec
);
295 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
299 /* a value of 0xffffffff represents infinity */
300 if (streq(lvalue
, "PreferredLifetimeSec"))
301 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
302 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
303 else if (streq(lvalue
, "ValidLifetimeSec"))
304 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
305 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
314 static int radv_get_ip6dns(Network
*network
, struct in6_addr
**dns
,
316 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
317 size_t i
, n_addresses
= 0, n_allocated
= 0;
323 for (i
= 0; i
< network
->n_dns
; i
++) {
324 union in_addr_union
*addr
;
326 if (network
->dns
[i
].family
!= AF_INET6
)
329 addr
= &network
->dns
[i
].address
;
331 if (in_addr_is_null(AF_INET6
, addr
) ||
332 in_addr_is_link_local(AF_INET6
, addr
) ||
333 in_addr_is_localhost(AF_INET6
, addr
))
336 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
339 addresses
[n_addresses
++] = addr
->in6
;
343 *dns
= TAKE_PTR(addresses
);
345 *n_dns
= n_addresses
;
351 static int radv_set_dns(Link
*link
, Link
*uplink
) {
352 _cleanup_free_
struct in6_addr
*dns
= NULL
;
354 usec_t lifetime_usec
;
357 if (!link
->network
->router_emit_dns
)
360 if (link
->network
->router_dns
) {
361 dns
= newdup(struct in6_addr
, link
->network
->router_dns
,
362 link
->network
->n_router_dns
);
366 n_dns
= link
->network
->n_router_dns
;
367 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
372 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
374 r
= radv_get_ip6dns(link
->network
, &dns
, &n_dns
);
379 if (uplink
->network
== NULL
) {
380 log_link_debug(uplink
, "Cannot fetch DNS servers as uplink interface is not managed by us");
384 r
= radv_get_ip6dns(uplink
->network
, &dns
, &n_dns
);
392 return sd_radv_set_rdnss(link
->radv
,
393 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
397 static int radv_set_domains(Link
*link
, Link
*uplink
) {
398 char **search_domains
;
399 usec_t lifetime_usec
;
401 if (!link
->network
->router_emit_domains
)
404 search_domains
= link
->network
->router_search_domains
;
405 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
410 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
412 search_domains
= link
->network
->search_domains
;
417 if (uplink
->network
== NULL
) {
418 log_link_debug(uplink
, "Cannot fetch DNS search domains as uplink interface is not managed by us");
422 search_domains
= uplink
->network
->search_domains
;
430 return sd_radv_set_dnssl(link
->radv
,
431 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
436 int radv_emit_dns(Link
*link
) {
440 uplink
= manager_find_uplink(link
->manager
, link
);
442 r
= radv_set_dns(link
, uplink
);
444 log_link_warning_errno(link
, r
, "Could not set RA DNS: %m");
446 r
= radv_set_domains(link
, uplink
);
448 log_link_warning_errno(link
, r
, "Could not set RA Domains: %m");
453 int radv_configure(Link
*link
) {
458 assert(link
->network
);
460 r
= sd_radv_new(&link
->radv
);
464 r
= sd_radv_attach_event(link
->radv
, NULL
, 0);
468 r
= sd_radv_set_mac(link
->radv
, &link
->mac
);
472 r
= sd_radv_set_ifindex(link
->radv
, link
->ifindex
);
476 r
= sd_radv_set_managed_information(link
->radv
, link
->network
->router_managed
);
480 r
= sd_radv_set_other_information(link
->radv
, link
->network
->router_other_information
);
484 /* a value of 0xffffffff represents infinity, 0x0 means this host is
486 r
= sd_radv_set_router_lifetime(link
->radv
,
487 DIV_ROUND_UP(link
->network
->router_lifetime_usec
, USEC_PER_SEC
));
491 if (link
->network
->router_lifetime_usec
> 0) {
492 r
= sd_radv_set_preference(link
->radv
,
493 link
->network
->router_preference
);
498 if (IN_SET(link
->network
->router_prefix_delegation
,
499 RADV_PREFIX_DELEGATION_STATIC
,
500 RADV_PREFIX_DELEGATION_BOTH
)) {
501 LIST_FOREACH(prefixes
, p
, link
->network
->static_prefixes
) {
502 r
= sd_radv_add_prefix(link
->radv
, p
->radv_prefix
, false);
503 if (r
!= -EEXIST
&& r
< 0)
508 return radv_emit_dns(link
);