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)
135 int prefix_new_static(Network
*network
, const char *filename
,
136 unsigned section_line
, Prefix
**ret
) {
137 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
138 _cleanup_prefix_free_ Prefix
*prefix
= NULL
;
143 assert(!!filename
== (section_line
> 0));
146 r
= network_config_section_new(filename
, section_line
, &n
);
151 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
161 r
= prefix_new(&prefix
);
169 r
= hashmap_put(network
->prefixes_by_section
, prefix
->section
,
175 prefix
->network
= network
;
176 LIST_APPEND(prefixes
, network
->static_prefixes
, prefix
);
177 network
->n_static_prefixes
++;
185 int config_parse_prefix(const char *unit
,
186 const char *filename
,
189 unsigned section_line
,
196 Network
*network
= userdata
;
197 _cleanup_prefix_free_ 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_ERR
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
218 if (sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
) < 0)
219 return -EADDRNOTAVAIL
;
221 log_syntax(unit
, LOG_INFO
, filename
, line
, r
, "Found prefix %s", rvalue
);
228 int config_parse_prefix_flags(const char *unit
,
229 const char *filename
,
232 unsigned section_line
,
238 Network
*network
= userdata
;
239 _cleanup_prefix_free_ Prefix
*p
= NULL
;
248 r
= prefix_new_static(network
, filename
, section_line
, &p
);
252 r
= parse_boolean(rvalue
);
254 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address flag, ignoring: %s", rvalue
);
260 if (streq(lvalue
, "OnLink"))
261 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, val
);
262 else if (streq(lvalue
, "AddressAutoconfiguration"))
263 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, val
);
272 int config_parse_prefix_lifetime(const char *unit
,
273 const char *filename
,
276 unsigned section_line
,
282 Network
*network
= userdata
;
283 _cleanup_prefix_free_ Prefix
*p
= NULL
;
293 r
= prefix_new_static(network
, filename
, section_line
, &p
);
297 r
= parse_sec(rvalue
, &usec
);
299 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
303 /* a value of 0xffffffff represents infinity */
304 if (streq(lvalue
, "PreferredLifetimeSec"))
305 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
306 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
307 else if (streq(lvalue
, "ValidLifetimeSec"))
308 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
309 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
318 static int radv_get_ip6dns(Network
*network
, struct in6_addr
**dns
,
320 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
321 size_t i
, n_addresses
= 0, n_allocated
= 0;
327 for (i
= 0; i
< network
->n_dns
; i
++) {
328 union in_addr_union
*addr
;
330 if (network
->dns
[i
].family
!= AF_INET6
)
333 addr
= &network
->dns
[i
].address
;
335 if (in_addr_is_null(AF_INET6
, addr
) ||
336 in_addr_is_link_local(AF_INET6
, addr
) ||
337 in_addr_is_localhost(AF_INET6
, addr
))
340 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
343 addresses
[n_addresses
++] = addr
->in6
;
350 *n_dns
= n_addresses
;
356 static int radv_set_dns(Link
*link
, Link
*uplink
) {
357 _cleanup_free_
struct in6_addr
*dns
= NULL
;
359 usec_t lifetime_usec
;
362 if (!link
->network
->router_emit_dns
)
365 if (link
->network
->router_dns
) {
366 dns
= newdup(struct in6_addr
, link
->network
->router_dns
,
367 link
->network
->n_router_dns
);
371 n_dns
= link
->network
->n_router_dns
;
372 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
377 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
379 r
= radv_get_ip6dns(link
->network
, &dns
, &n_dns
);
384 if (uplink
->network
== NULL
) {
385 log_link_debug(uplink
, "Cannot fetch DNS servers as uplink interface is not managed by us");
389 r
= radv_get_ip6dns(uplink
->network
, &dns
, &n_dns
);
397 return sd_radv_set_rdnss(link
->radv
,
398 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
402 static int radv_set_domains(Link
*link
, Link
*uplink
) {
403 char **search_domains
;
404 usec_t lifetime_usec
;
406 if (!link
->network
->router_emit_domains
)
409 search_domains
= link
->network
->router_search_domains
;
410 lifetime_usec
= link
->network
->router_dns_lifetime_usec
;
415 lifetime_usec
= SD_RADV_DEFAULT_DNS_LIFETIME_USEC
;
417 search_domains
= link
->network
->search_domains
;
422 if (uplink
->network
== NULL
) {
423 log_link_debug(uplink
, "Cannot fetch DNS search domains as uplink interface is not managed by us");
427 search_domains
= uplink
->network
->search_domains
;
435 return sd_radv_set_dnssl(link
->radv
,
436 DIV_ROUND_UP(lifetime_usec
, USEC_PER_SEC
),
441 int radv_emit_dns(Link
*link
) {
445 uplink
= manager_find_uplink(link
->manager
, link
);
447 r
= radv_set_dns(link
, uplink
);
449 log_link_warning_errno(link
, r
, "Could not set RA DNS: %m");
451 r
= radv_set_domains(link
, uplink
);
453 log_link_warning_errno(link
, r
, "Could not set RA Domains: %m");
458 int radv_configure(Link
*link
) {
463 assert(link
->network
);
465 r
= sd_radv_new(&link
->radv
);
469 r
= sd_radv_attach_event(link
->radv
, NULL
, 0);
473 r
= sd_radv_set_mac(link
->radv
, &link
->mac
);
477 r
= sd_radv_set_ifindex(link
->radv
, link
->ifindex
);
481 r
= sd_radv_set_managed_information(link
->radv
, link
->network
->router_managed
);
485 r
= sd_radv_set_other_information(link
->radv
, link
->network
->router_other_information
);
489 /* a value of 0xffffffff represents infinity, 0x0 means this host is
491 r
= sd_radv_set_router_lifetime(link
->radv
,
492 DIV_ROUND_UP(link
->network
->router_lifetime_usec
, USEC_PER_SEC
));
496 if (link
->network
->router_lifetime_usec
> 0) {
497 r
= sd_radv_set_preference(link
->radv
,
498 link
->network
->router_preference
);
503 if (IN_SET(link
->network
->router_prefix_delegation
,
504 RADV_PREFIX_DELEGATION_STATIC
,
505 RADV_PREFIX_DELEGATION_BOTH
)) {
506 LIST_FOREACH(prefixes
, p
, link
->network
->static_prefixes
) {
507 r
= sd_radv_add_prefix(link
->radv
, p
->radv_prefix
, false);
508 if (r
!= -EEXIST
&& r
< 0)
513 return radv_emit_dns(link
);