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(const char *unit
,
35 unsigned section_line
,
41 Network
*network
= userdata
;
50 if (streq(rvalue
, "static"))
51 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_STATIC
;
52 else if (streq(rvalue
, "dhcpv6"))
53 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_DHCP6
;
55 d
= parse_boolean(rvalue
);
57 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_BOTH
;
59 network
->router_prefix_delegation
= RADV_PREFIX_DELEGATION_NONE
;
62 log_syntax(unit
, LOG_ERR
, filename
, line
, -EINVAL
, "Router prefix delegation '%s' is invalid, ignoring assignment: %m", rvalue
);
68 int config_parse_router_preference(const char *unit
,
72 unsigned section_line
,
78 Network
*network
= userdata
;
86 if (streq(rvalue
, "high"))
87 network
->router_preference
= SD_NDISC_PREFERENCE_HIGH
;
88 else if (STR_IN_SET(rvalue
, "medium", "normal", "default"))
89 network
->router_preference
= SD_NDISC_PREFERENCE_MEDIUM
;
90 else if (streq(rvalue
, "low"))
91 network
->router_preference
= SD_NDISC_PREFERENCE_LOW
;
93 log_syntax(unit
, LOG_ERR
, filename
, line
, -EINVAL
, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue
);
98 void prefix_free(Prefix
*prefix
) {
102 if (prefix
->network
) {
103 LIST_REMOVE(prefixes
, prefix
->network
->static_prefixes
, prefix
);
104 assert(prefix
->network
->n_static_prefixes
> 0);
105 prefix
->network
->n_static_prefixes
--;
108 hashmap_remove(prefix
->network
->prefixes_by_section
,
112 prefix
->radv_prefix
= sd_radv_prefix_unref(prefix
->radv_prefix
);
117 int prefix_new(Prefix
**ret
) {
118 Prefix
*prefix
= NULL
;
120 prefix
= new0(Prefix
, 1);
124 if (sd_radv_prefix_new(&prefix
->radv_prefix
) < 0)
133 int prefix_new_static(Network
*network
, const char *filename
,
134 unsigned section_line
, Prefix
**ret
) {
135 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
136 _cleanup_prefix_free_ Prefix
*prefix
= NULL
;
141 assert(!!filename
== (section_line
> 0));
144 r
= network_config_section_new(filename
, section_line
, &n
);
149 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
159 r
= prefix_new(&prefix
);
167 r
= hashmap_put(network
->prefixes_by_section
, prefix
->section
,
173 prefix
->network
= network
;
174 LIST_APPEND(prefixes
, network
->static_prefixes
, prefix
);
175 network
->n_static_prefixes
++;
183 int config_parse_prefix(const char *unit
,
184 const char *filename
,
187 unsigned section_line
,
194 Network
*network
= userdata
;
195 _cleanup_prefix_free_ Prefix
*p
= NULL
;
196 uint8_t prefixlen
= 64;
197 union in_addr_union in6addr
;
206 r
= prefix_new_static(network
, filename
, section_line
, &p
);
210 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
212 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
216 if (sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
) < 0)
217 return -EADDRNOTAVAIL
;
219 log_syntax(unit
, LOG_INFO
, filename
, line
, r
, "Found prefix %s", rvalue
);
226 int config_parse_prefix_flags(const char *unit
,
227 const char *filename
,
230 unsigned section_line
,
236 Network
*network
= userdata
;
237 _cleanup_prefix_free_ Prefix
*p
= NULL
;
246 r
= prefix_new_static(network
, filename
, section_line
, &p
);
250 r
= parse_boolean(rvalue
);
252 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address flag, ignoring: %s", rvalue
);
258 if (streq(lvalue
, "OnLink"))
259 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, val
);
260 else if (streq(lvalue
, "AddressAutoconfiguration"))
261 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, val
);
270 int config_parse_prefix_lifetime(const char *unit
,
271 const char *filename
,
274 unsigned section_line
,
280 Network
*network
= userdata
;
281 _cleanup_prefix_free_ Prefix
*p
= NULL
;
291 r
= prefix_new_static(network
, filename
, section_line
, &p
);
295 r
= parse_sec(rvalue
, &usec
);
297 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
301 /* a value of 0xffffffff represents infinity */
302 if (streq(lvalue
, "PreferredLifetimeSec"))
303 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
304 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
305 else if (streq(lvalue
, "ValidLifetimeSec"))
306 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
307 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
316 static int radv_get_ip6dns(Network
*network
, struct in6_addr
**dns
,
318 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
319 size_t i
, n_addresses
= 0, n_allocated
= 0;
325 for (i
= 0; i
< network
->n_dns
; i
++) {
326 union in_addr_union
*addr
;
328 if (network
->dns
[i
].family
!= AF_INET6
)
331 addr
= &network
->dns
[i
].address
;
333 if (in_addr_is_null(AF_INET6
, addr
) ||
334 in_addr_is_link_local(AF_INET6
, addr
) ||
335 in_addr_is_localhost(AF_INET6
, addr
))
338 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
341 addresses
[n_addresses
++] = addr
->in6
;
348 *n_dns
= n_addresses
;
354 static int radv_set_dns(Link
*link
, Link
*uplink
) {
355 _cleanup_free_
struct in6_addr
*dns
= NULL
;
357 usec_t lifetime_usec
;
360 if (!link
->network
->router_emit_dns
)
363 if (link
->network
->router_dns
) {
364 dns
= newdup(struct in6_addr
, link
->network
->router_dns
,
365 link
->network
->n_router_dns
);
369 n_dns
= link
->network
->n_router_dns
;
370 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
375 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
377 r
= radv_get_ip6dns(link
->network
, &dns
, &n_dns
);
382 if (uplink
->network
== NULL
) {
383 log_link_debug(uplink
, "Cannot fetch DNS servers as uplink interface is not managed by us");
387 r
= radv_get_ip6dns(uplink
->network
, &dns
, &n_dns
);
395 return sd_radv_set_rdnss(link
->radv
,
396 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
400 static int radv_set_domains(Link
*link
, Link
*uplink
) {
401 char **search_domains
;
402 usec_t lifetime_usec
;
404 if (!link
->network
->router_emit_domains
)
407 search_domains
= link
->network
->router_search_domains
;
408 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
413 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
415 search_domains
= link
->network
->search_domains
;
420 if (uplink
->network
== NULL
) {
421 log_link_debug(uplink
, "Cannot fetch DNS search domains as uplink interface is not managed by us");
425 search_domains
= uplink
->network
->search_domains
;
433 return sd_radv_set_dnssl(link
->radv
,
434 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
439 int radv_emit_dns(Link
*link
) {
443 uplink
= manager_find_uplink(link
->manager
, link
);
445 r
= radv_set_dns(link
, uplink
);
447 log_link_warning_errno(link
, r
, "Could not set RA DNS: %m");
449 r
= radv_set_domains(link
, uplink
);
451 log_link_warning_errno(link
, r
, "Could not set RA Domains: %m");
456 int radv_configure(Link
*link
) {
461 assert(link
->network
);
463 r
= sd_radv_new(&link
->radv
);
467 r
= sd_radv_attach_event(link
->radv
, NULL
, 0);
471 r
= sd_radv_set_mac(link
->radv
, &link
->mac
);
475 r
= sd_radv_set_ifindex(link
->radv
, link
->ifindex
);
479 r
= sd_radv_set_managed_information(link
->radv
, link
->network
->router_managed
);
483 r
= sd_radv_set_other_information(link
->radv
, link
->network
->router_other_information
);
487 /* a value of 0xffffffff represents infinity, 0x0 means this host is
489 r
= sd_radv_set_router_lifetime(link
->radv
,
490 DIV_ROUND_UP(link
->network
->router_lifetime_usec
, USEC_PER_SEC
));
494 if (link
->network
->router_lifetime_usec
> 0) {
495 r
= sd_radv_set_preference(link
->radv
,
496 link
->network
->router_preference
);
501 if (IN_SET(link
->network
->router_prefix_delegation
,
502 RADV_PREFIX_DELEGATION_STATIC
,
503 RADV_PREFIX_DELEGATION_BOTH
)) {
504 LIST_FOREACH(prefixes
, p
, link
->network
->static_prefixes
) {
505 r
= sd_radv_add_prefix(link
->radv
, p
->radv_prefix
, false);
506 if (r
!= -EEXIST
&& r
< 0)
511 return radv_emit_dns(link
);