2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2017-05-12 15:48:32 +02:00
|
|
|
/***
|
2018-06-12 17:15:23 +02:00
|
|
|
Copyright © 2017 Intel Corporation. All rights reserved.
|
2017-05-12 15:48:32 +02:00
|
|
|
***/
|
|
|
|
|
|
|
|
#include <netinet/icmp6.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2019-06-29 20:57:47 +02:00
|
|
|
#include "dns-domain.h"
|
2020-09-29 23:10:02 +02:00
|
|
|
#include "networkd-link.h"
|
2017-09-29 13:23:38 +02:00
|
|
|
#include "networkd-manager.h"
|
2020-09-29 23:10:02 +02:00
|
|
|
#include "networkd-network.h"
|
2017-05-12 15:48:32 +02:00
|
|
|
#include "networkd-radv.h"
|
2018-01-04 14:11:38 +01:00
|
|
|
#include "parse-util.h"
|
|
|
|
#include "string-util.h"
|
2018-11-01 19:15:25 +01:00
|
|
|
#include "string-table.h"
|
2018-08-22 07:30:49 +02:00
|
|
|
#include "strv.h"
|
2018-01-04 14:11:38 +01:00
|
|
|
|
2020-09-29 22:40:14 +02:00
|
|
|
Prefix *prefix_free(Prefix *prefix) {
|
2018-01-04 14:11:38 +01:00
|
|
|
if (!prefix)
|
2020-09-29 22:40:14 +02:00
|
|
|
return NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
if (prefix->network) {
|
2020-09-29 22:54:19 +02:00
|
|
|
assert(prefix->section);
|
|
|
|
hashmap_remove(prefix->network->prefixes_by_section, prefix->section);
|
2018-01-04 14:11:38 +01:00
|
|
|
}
|
|
|
|
|
2018-11-02 09:14:05 +01:00
|
|
|
network_config_section_free(prefix->section);
|
2019-11-05 02:46:44 +01:00
|
|
|
sd_radv_prefix_unref(prefix->radv_prefix);
|
2018-01-04 14:11:38 +01:00
|
|
|
|
2020-09-29 22:40:14 +02:00
|
|
|
return mfree(prefix);
|
2018-01-04 14:11:38 +01:00
|
|
|
}
|
|
|
|
|
2020-09-29 22:40:14 +02:00
|
|
|
DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
|
|
|
|
|
2019-11-05 14:31:20 +01:00
|
|
|
static int prefix_new(Prefix **ret) {
|
2018-06-07 23:37:30 +02:00
|
|
|
_cleanup_(prefix_freep) Prefix *prefix = NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
prefix = new0(Prefix, 1);
|
|
|
|
if (!prefix)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-03-22 16:53:26 +01:00
|
|
|
*ret = TAKE_PTR(prefix);
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:17:04 +02:00
|
|
|
static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
|
|
|
_cleanup_(prefix_freep) Prefix *prefix = NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
assert(ret);
|
2020-09-29 22:54:19 +02:00
|
|
|
assert(filename);
|
|
|
|
assert(section_line > 0);
|
2018-01-04 14:11:38 +01:00
|
|
|
|
2020-09-29 22:54:19 +02:00
|
|
|
r = network_config_section_new(filename, section_line, &n);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2018-01-04 14:11:38 +01:00
|
|
|
|
2020-09-29 22:54:19 +02:00
|
|
|
prefix = hashmap_get(network->prefixes_by_section, n);
|
|
|
|
if (prefix) {
|
|
|
|
*ret = TAKE_PTR(prefix);
|
|
|
|
return 0;
|
2018-01-04 14:11:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
r = prefix_new(&prefix);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-11-12 06:57:04 +01:00
|
|
|
prefix->network = network;
|
2020-09-29 22:54:19 +02:00
|
|
|
prefix->section = TAKE_PTR(n);
|
2018-01-04 14:11:38 +01:00
|
|
|
|
2020-09-29 22:54:19 +02:00
|
|
|
r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2018-11-12 07:24:11 +01:00
|
|
|
|
2020-09-29 22:54:19 +02:00
|
|
|
r = hashmap_put(network->prefixes_by_section, prefix->section, prefix);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2018-01-04 14:11:38 +01:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(prefix);
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 22:40:14 +02:00
|
|
|
RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
|
2019-09-14 13:14:22 +02:00
|
|
|
if (!prefix)
|
2020-09-29 22:40:14 +02:00
|
|
|
return NULL;
|
2019-09-14 13:14:22 +02:00
|
|
|
|
|
|
|
if (prefix->network) {
|
2020-09-29 22:54:19 +02:00
|
|
|
assert(prefix->section);
|
|
|
|
hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section);
|
2019-09-14 13:14:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
network_config_section_free(prefix->section);
|
2019-11-05 02:46:44 +01:00
|
|
|
sd_radv_route_prefix_unref(prefix->radv_route_prefix);
|
2019-09-14 13:14:22 +02:00
|
|
|
|
2020-09-29 22:40:14 +02:00
|
|
|
return mfree(prefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
|
|
|
|
|
|
|
|
static int route_prefix_new(RoutePrefix **ret) {
|
|
|
|
_cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
|
|
|
|
|
|
|
|
prefix = new0(RoutePrefix, 1);
|
|
|
|
if (!prefix)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (sd_radv_route_prefix_new(&prefix->radv_route_prefix) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*ret = TAKE_PTR(prefix);
|
|
|
|
|
|
|
|
return 0;
|
2019-09-14 13:14:22 +02:00
|
|
|
}
|
|
|
|
|
2020-09-29 23:17:04 +02:00
|
|
|
static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
|
2019-09-14 13:14:22 +02:00
|
|
|
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
2019-11-05 14:31:20 +01:00
|
|
|
_cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
|
2019-09-14 13:14:22 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
assert(ret);
|
2020-09-29 22:54:19 +02:00
|
|
|
assert(filename);
|
|
|
|
assert(section_line > 0);
|
2019-09-14 13:14:22 +02:00
|
|
|
|
2020-09-29 22:54:19 +02:00
|
|
|
r = network_config_section_new(filename, section_line, &n);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2019-09-14 13:14:22 +02:00
|
|
|
|
2020-09-29 22:54:19 +02:00
|
|
|
prefix = hashmap_get(network->route_prefixes_by_section, n);
|
|
|
|
if (prefix) {
|
|
|
|
*ret = TAKE_PTR(prefix);
|
|
|
|
return 0;
|
2019-09-14 13:14:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
r = route_prefix_new(&prefix);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
prefix->network = network;
|
2020-09-29 22:54:19 +02:00
|
|
|
prefix->section = TAKE_PTR(n);
|
2019-09-14 13:14:22 +02:00
|
|
|
|
2020-09-29 22:54:19 +02:00
|
|
|
r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2019-09-14 13:14:22 +02:00
|
|
|
|
2020-09-29 22:54:19 +02:00
|
|
|
r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2019-09-14 13:14:22 +02:00
|
|
|
|
|
|
|
*ret = TAKE_PTR(prefix);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-06 20:21:59 +02:00
|
|
|
void network_drop_invalid_prefixes(Network *network) {
|
2020-09-29 23:01:09 +02:00
|
|
|
Prefix *prefix;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
|
|
|
|
HASHMAP_FOREACH(prefix, network->prefixes_by_section)
|
|
|
|
if (section_is_invalid(prefix->section))
|
|
|
|
prefix_free(prefix);
|
|
|
|
}
|
|
|
|
|
2020-10-06 20:21:59 +02:00
|
|
|
void network_drop_invalid_route_prefixes(Network *network) {
|
2020-09-29 23:01:09 +02:00
|
|
|
RoutePrefix *prefix;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
|
|
|
|
HASHMAP_FOREACH(prefix, network->route_prefixes_by_section)
|
|
|
|
if (section_is_invalid(prefix->section))
|
|
|
|
route_prefix_free(prefix);
|
|
|
|
}
|
|
|
|
|
2020-10-15 09:06:47 +02:00
|
|
|
void network_adjust_radv(Network *network) {
|
|
|
|
assert(network);
|
|
|
|
|
2020-10-16 08:50:44 +02:00
|
|
|
/* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
|
|
|
|
|
|
|
|
if (network->dhcp6_pd < 0)
|
|
|
|
/* For backward compatibility. */
|
|
|
|
network->dhcp6_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6);
|
|
|
|
|
2020-10-15 09:06:47 +02:00
|
|
|
if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
|
|
|
|
if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE)
|
|
|
|
log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
|
|
|
|
"Disabling IPv6PrefixDelegation=.", network->filename);
|
|
|
|
|
|
|
|
network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) {
|
|
|
|
network->n_router_dns = 0;
|
|
|
|
network->router_dns = mfree(network->router_dns);
|
|
|
|
network->router_search_domains = ordered_set_free(network->router_search_domains);
|
2020-10-16 08:48:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
|
2020-10-15 09:06:47 +02:00
|
|
|
network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
|
|
|
|
network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:17:04 +02:00
|
|
|
int config_parse_prefix(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
uint8_t prefixlen = 64;
|
|
|
|
union in_addr_union in6addr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = prefix_new_static(network, filename, section_line, &p);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
|
2018-01-04 14:11:38 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-16 12:12:40 +02:00
|
|
|
r = sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen);
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set radv prefix, ignoring assignment: %s", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:17:04 +02:00
|
|
|
int config_parse_prefix_flags(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
2018-01-04 14:11:38 +01:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
2020-07-16 12:12:40 +02:00
|
|
|
int r;
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = prefix_new_static(network, filename, section_line, &p);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
r = parse_boolean(rvalue);
|
|
|
|
if (r < 0) {
|
2020-07-16 12:12:40 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
|
2018-01-04 14:11:38 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (streq(lvalue, "OnLink"))
|
2020-07-16 12:12:40 +02:00
|
|
|
r = sd_radv_prefix_set_onlink(p->radv_prefix, r);
|
2018-01-04 14:11:38 +01:00
|
|
|
else if (streq(lvalue, "AddressAutoconfiguration"))
|
2020-07-16 12:12:40 +02:00
|
|
|
r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, r);
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:17:04 +02:00
|
|
|
int config_parse_prefix_lifetime(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
2018-01-04 14:11:38 +01:00
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
usec_t usec;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = prefix_new_static(network, filename, section_line, &p);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
r = parse_sec(rvalue, &usec);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
|
2018-01-04 14:11:38 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* a value of 0xffffffff represents infinity */
|
|
|
|
if (streq(lvalue, "PreferredLifetimeSec"))
|
|
|
|
r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
|
|
|
|
DIV_ROUND_UP(usec, USEC_PER_SEC));
|
|
|
|
else if (streq(lvalue, "ValidLifetimeSec"))
|
|
|
|
r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
|
|
|
|
DIV_ROUND_UP(usec, USEC_PER_SEC));
|
2020-07-16 12:12:40 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2017-05-12 15:48:32 +02:00
|
|
|
|
2020-02-27 13:32:43 +01:00
|
|
|
int config_parse_prefix_assign(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
|
|
|
Network *network = userdata;
|
|
|
|
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = prefix_new_static(network, filename, section_line, &p);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2020-02-27 13:32:43 +01:00
|
|
|
|
|
|
|
r = parse_boolean(rvalue);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2020-02-27 13:32:43 +01:00
|
|
|
"Failed to parse %s=, ignoring assignment: %s",
|
|
|
|
lvalue, rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->assign = r;
|
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:17:04 +02:00
|
|
|
int config_parse_route_prefix(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
2019-09-14 13:14:22 +02:00
|
|
|
|
|
|
|
Network *network = userdata;
|
2019-11-05 14:31:20 +01:00
|
|
|
_cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
|
2019-09-14 13:14:22 +02:00
|
|
|
uint8_t prefixlen = 64;
|
|
|
|
union in_addr_union in6addr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = route_prefix_new_static(network, filename, section_line, &p);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2019-09-14 13:14:22 +02:00
|
|
|
|
|
|
|
r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue);
|
2019-09-14 13:14:22 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-16 12:12:40 +02:00
|
|
|
r = sd_radv_prefix_set_route_prefix(p->radv_route_prefix, &in6addr.in6, prefixlen);
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set route prefix, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2019-09-14 13:14:22 +02:00
|
|
|
|
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:17:04 +02:00
|
|
|
int config_parse_route_prefix_lifetime(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
2019-09-14 13:14:22 +02:00
|
|
|
Network *network = userdata;
|
2019-11-05 14:31:20 +01:00
|
|
|
_cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
|
2019-09-14 13:14:22 +02:00
|
|
|
usec_t usec;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = route_prefix_new_static(network, filename, section_line, &p);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2019-09-14 13:14:22 +02:00
|
|
|
|
|
|
|
r = parse_sec(rvalue, &usec);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-11-05 02:42:19 +01:00
|
|
|
"Route lifetime is invalid, ignoring assignment: %s", rvalue);
|
2019-09-14 13:14:22 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* a value of 0xffffffff represents infinity */
|
|
|
|
r = sd_radv_route_prefix_set_lifetime(p->radv_route_prefix, DIV_ROUND_UP(usec, USEC_PER_SEC));
|
2020-07-16 12:12:40 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Failed to set route lifetime, ignoring assignment: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2019-09-14 13:14:22 +02:00
|
|
|
|
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:28:44 +02:00
|
|
|
static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
|
2017-09-29 13:23:38 +02:00
|
|
|
_cleanup_free_ struct in6_addr *addresses = NULL;
|
2020-09-29 23:28:44 +02:00
|
|
|
size_t n_addresses = 0, n_allocated = 0;
|
2017-09-29 13:23:38 +02:00
|
|
|
|
|
|
|
assert(network);
|
2020-09-29 23:28:44 +02:00
|
|
|
assert(ret_addresses);
|
|
|
|
assert(ret_size);
|
2017-09-29 13:23:38 +02:00
|
|
|
|
2020-09-29 23:28:44 +02:00
|
|
|
for (size_t i = 0; i < network->n_dns; i++) {
|
2017-09-29 13:23:38 +02:00
|
|
|
union in_addr_union *addr;
|
|
|
|
|
2020-07-03 09:48:29 +02:00
|
|
|
if (network->dns[i]->family != AF_INET6)
|
2017-09-29 13:23:38 +02:00
|
|
|
continue;
|
|
|
|
|
2020-07-03 09:48:29 +02:00
|
|
|
addr = &network->dns[i]->address;
|
2017-09-29 13:23:38 +02:00
|
|
|
|
|
|
|
if (in_addr_is_null(AF_INET6, addr) ||
|
|
|
|
in_addr_is_link_local(AF_INET6, addr) ||
|
|
|
|
in_addr_is_localhost(AF_INET6, addr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
addresses[n_addresses++] = addr->in6;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:28:44 +02:00
|
|
|
*ret_addresses = TAKE_PTR(addresses);
|
|
|
|
*ret_size = n_addresses;
|
2017-09-29 13:23:38 +02:00
|
|
|
|
|
|
|
return n_addresses;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int radv_set_dns(Link *link, Link *uplink) {
|
|
|
|
_cleanup_free_ struct in6_addr *dns = NULL;
|
|
|
|
usec_t lifetime_usec;
|
2020-01-31 07:52:56 +01:00
|
|
|
size_t n_dns;
|
2017-09-29 13:23:38 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!link->network->router_emit_dns)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->network->router_dns) {
|
2020-01-31 07:52:56 +01:00
|
|
|
struct in6_addr *p;
|
|
|
|
|
|
|
|
dns = new(struct in6_addr, link->network->n_router_dns);
|
2019-04-28 14:28:49 +02:00
|
|
|
if (!dns)
|
2017-09-29 13:23:38 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2020-01-31 07:52:56 +01:00
|
|
|
p = dns;
|
|
|
|
for (size_t i = 0; i < link->network->n_router_dns; i++)
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&link->network->router_dns[i])) {
|
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&link->ipv6ll_address))
|
|
|
|
*(p++) = link->ipv6ll_address;
|
|
|
|
} else
|
|
|
|
*(p++) = link->network->router_dns[i];
|
|
|
|
|
|
|
|
n_dns = p - dns;
|
2017-09-29 13:23:38 +02:00
|
|
|
lifetime_usec = link->network->router_dns_lifetime_usec;
|
|
|
|
|
|
|
|
goto set_dns;
|
|
|
|
}
|
|
|
|
|
|
|
|
lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
|
|
|
|
|
2020-09-29 23:28:44 +02:00
|
|
|
r = network_get_ipv6_dns(link->network, &dns, &n_dns);
|
2017-09-29 13:23:38 +02:00
|
|
|
if (r > 0)
|
|
|
|
goto set_dns;
|
|
|
|
|
|
|
|
if (uplink) {
|
2019-04-28 14:28:49 +02:00
|
|
|
if (!uplink->network) {
|
2017-12-08 13:33:40 +01:00
|
|
|
log_link_debug(uplink, "Cannot fetch DNS servers as uplink interface is not managed by us");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:28:44 +02:00
|
|
|
r = network_get_ipv6_dns(uplink->network, &dns, &n_dns);
|
2017-09-29 13:23:38 +02:00
|
|
|
if (r > 0)
|
|
|
|
goto set_dns;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
set_dns:
|
|
|
|
return sd_radv_set_rdnss(link->radv,
|
|
|
|
DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
|
|
|
|
dns, n_dns);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int radv_set_domains(Link *link, Link *uplink) {
|
2019-02-20 22:50:25 +01:00
|
|
|
OrderedSet *search_domains;
|
2017-09-29 13:23:38 +02:00
|
|
|
usec_t lifetime_usec;
|
2019-02-20 22:50:25 +01:00
|
|
|
_cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */
|
2017-09-29 13:23:38 +02:00
|
|
|
|
|
|
|
if (!link->network->router_emit_domains)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
search_domains = link->network->router_search_domains;
|
|
|
|
lifetime_usec = link->network->router_dns_lifetime_usec;
|
|
|
|
|
|
|
|
if (search_domains)
|
|
|
|
goto set_domains;
|
|
|
|
|
|
|
|
lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
|
|
|
|
|
|
|
|
search_domains = link->network->search_domains;
|
|
|
|
if (search_domains)
|
|
|
|
goto set_domains;
|
|
|
|
|
|
|
|
if (uplink) {
|
2019-04-28 14:28:49 +02:00
|
|
|
if (!uplink->network) {
|
2017-12-08 13:33:40 +01:00
|
|
|
log_link_debug(uplink, "Cannot fetch DNS search domains as uplink interface is not managed by us");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-29 13:23:38 +02:00
|
|
|
search_domains = uplink->network->search_domains;
|
|
|
|
if (search_domains)
|
|
|
|
goto set_domains;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
set_domains:
|
2019-02-20 22:50:25 +01:00
|
|
|
s = ordered_set_get_strv(search_domains);
|
|
|
|
if (!s)
|
|
|
|
return log_oom();
|
|
|
|
|
2017-09-29 13:23:38 +02:00
|
|
|
return sd_radv_set_dnssl(link->radv,
|
|
|
|
DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
|
2019-02-20 22:50:25 +01:00
|
|
|
s);
|
2017-09-29 13:23:38 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int radv_emit_dns(Link *link) {
|
|
|
|
Link *uplink;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
uplink = manager_find_uplink(link->manager, link);
|
|
|
|
|
|
|
|
r = radv_set_dns(link, uplink);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Could not set RA DNS: %m");
|
|
|
|
|
|
|
|
r = radv_set_domains(link, uplink);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Could not set RA Domains: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-02 09:39:45 +02:00
|
|
|
static bool link_radv_enabled(Link *link) {
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (!link_ipv6ll_enabled(link))
|
|
|
|
return false;
|
|
|
|
|
2020-10-16 08:50:44 +02:00
|
|
|
return link->network->router_prefix_delegation;
|
2020-10-02 09:39:45 +02:00
|
|
|
}
|
|
|
|
|
2017-05-12 15:48:32 +02:00
|
|
|
int radv_configure(Link *link) {
|
2020-11-09 08:49:33 +01:00
|
|
|
uint16_t router_lifetime;
|
2020-10-16 08:48:50 +02:00
|
|
|
RoutePrefix *q;
|
|
|
|
Prefix *p;
|
2019-11-05 14:31:20 +01:00
|
|
|
int r;
|
2017-05-12 15:48:32 +02:00
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
|
2020-10-02 09:39:45 +02:00
|
|
|
if (!link_radv_enabled(link))
|
|
|
|
return 0;
|
|
|
|
|
2017-05-12 15:48:32 +02:00
|
|
|
r = sd_radv_new(&link->radv);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-10-04 00:43:41 +02:00
|
|
|
r = sd_radv_attach_event(link->radv, link->manager->event, 0);
|
2017-05-12 15:48:32 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-10-26 18:07:49 +01:00
|
|
|
r = sd_radv_set_mac(link->radv, &link->hw_addr.addr.ether);
|
2017-05-12 15:48:32 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_set_ifindex(link->radv, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_set_managed_information(link->radv, link->network->router_managed);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_set_other_information(link->radv, link->network->router_other_information);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-11-09 08:49:33 +01:00
|
|
|
/* a value of UINT16_MAX represents infinity, 0x0 means this host is not a router */
|
|
|
|
if (link->network->router_lifetime_usec == USEC_INFINITY)
|
|
|
|
router_lifetime = UINT16_MAX;
|
|
|
|
else if (link->network->router_lifetime_usec > (UINT16_MAX - 1) * USEC_PER_SEC)
|
|
|
|
router_lifetime = UINT16_MAX - 1;
|
|
|
|
else
|
|
|
|
router_lifetime = DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC);
|
|
|
|
|
|
|
|
r = sd_radv_set_router_lifetime(link->radv, router_lifetime);
|
2017-05-12 15:48:32 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-11-09 08:49:33 +01:00
|
|
|
if (router_lifetime > 0) {
|
|
|
|
r = sd_radv_set_preference(link->radv, link->network->router_preference);
|
2017-05-12 15:48:32 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-10-16 08:48:50 +02:00
|
|
|
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
|
|
|
|
r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
|
|
|
|
if (r == -EEXIST)
|
|
|
|
continue;
|
|
|
|
if (r == -ENOEXEC) {
|
|
|
|
log_link_warning_errno(link, r, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
|
|
|
|
continue;
|
2018-01-04 14:11:39 +01:00
|
|
|
}
|
2020-10-16 08:48:50 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2019-09-14 13:14:22 +02:00
|
|
|
|
2020-10-16 08:48:50 +02:00
|
|
|
HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) {
|
|
|
|
r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false);
|
|
|
|
if (r == -EEXIST)
|
|
|
|
continue;
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2017-05-12 15:48:32 +02:00
|
|
|
}
|
|
|
|
|
2020-01-31 07:52:56 +01:00
|
|
|
return 0;
|
2017-05-12 15:48:32 +02:00
|
|
|
}
|
2019-06-29 20:57:47 +02:00
|
|
|
|
2020-10-02 13:55:18 +02:00
|
|
|
int radv_update_mac(Link *link) {
|
|
|
|
bool restart;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
|
|
|
|
if (!link->radv)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
restart = sd_radv_is_running(link->radv);
|
|
|
|
|
2020-10-15 00:39:55 +02:00
|
|
|
r = sd_radv_stop(link->radv);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2020-10-02 13:55:18 +02:00
|
|
|
|
2020-10-26 18:07:49 +01:00
|
|
|
r = sd_radv_set_mac(link->radv, &link->hw_addr.addr.ether);
|
2020-10-02 13:55:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
r = sd_radv_start(link->radv);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:17:04 +02:00
|
|
|
int radv_add_prefix(
|
|
|
|
Link *link,
|
|
|
|
const struct in6_addr *prefix,
|
|
|
|
uint8_t prefix_len,
|
|
|
|
uint32_t lifetime_preferred,
|
|
|
|
uint32_t lifetime_valid) {
|
|
|
|
|
2020-07-07 04:19:49 +02:00
|
|
|
_cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
2020-09-11 11:39:16 +02:00
|
|
|
|
|
|
|
if (!link->radv)
|
|
|
|
return 0;
|
2020-07-07 04:19:49 +02:00
|
|
|
|
|
|
|
r = sd_radv_prefix_new(&p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_prefix_set_prefix(p, prefix, prefix_len);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_add_prefix(link->radv, p, true);
|
|
|
|
if (r < 0 && r != -EEXIST)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-29 20:57:47 +02:00
|
|
|
int config_parse_radv_dns(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
|
|
|
Network *n = data;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
|
2020-10-15 08:56:25 +02:00
|
|
|
if (isempty(rvalue)) {
|
|
|
|
n->n_router_dns = 0;
|
|
|
|
n->router_dns = mfree(n->router_dns);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-16 07:48:08 +02:00
|
|
|
for (const char *p = rvalue;;) {
|
2019-06-29 20:57:47 +02:00
|
|
|
_cleanup_free_ char *w = NULL;
|
|
|
|
union in_addr_union a;
|
|
|
|
|
|
|
|
r = extract_first_word(&p, &w, NULL, 0);
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-06-29 20:57:47 +02:00
|
|
|
"Failed to extract word, ignoring: %s", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (r == 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return 0;
|
2019-06-29 20:57:47 +02:00
|
|
|
|
2020-01-31 07:52:56 +01:00
|
|
|
if (streq(w, "_link_local"))
|
|
|
|
a = IN_ADDR_NULL;
|
|
|
|
else {
|
|
|
|
r = in_addr_from_string(AF_INET6, w, &a);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2020-01-31 07:52:56 +01:00
|
|
|
"Failed to parse DNS server address, ignoring: %s", w);
|
|
|
|
continue;
|
|
|
|
}
|
2019-06-29 20:57:47 +02:00
|
|
|
|
2020-01-31 07:52:56 +01:00
|
|
|
if (in_addr_is_null(AF_INET6, &a)) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
2020-01-31 07:52:56 +01:00
|
|
|
"DNS server address is null, ignoring: %s", w);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2019-06-29 20:57:47 +02:00
|
|
|
|
2020-01-31 07:52:56 +01:00
|
|
|
struct in6_addr *m;
|
|
|
|
m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
|
|
|
|
if (!m)
|
|
|
|
return log_oom();
|
2019-06-29 20:57:47 +02:00
|
|
|
|
2020-01-31 07:52:56 +01:00
|
|
|
m[n->n_router_dns++] = a.in6;
|
|
|
|
n->router_dns = m;
|
2019-06-29 20:57:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_radv_search_domains(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
|
|
|
Network *n = data;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
|
2020-10-15 08:56:25 +02:00
|
|
|
if (isempty(rvalue)) {
|
|
|
|
n->router_search_domains = ordered_set_free(n->router_search_domains);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-16 07:48:08 +02:00
|
|
|
for (const char *p = rvalue;;) {
|
2019-06-29 20:57:47 +02:00
|
|
|
_cleanup_free_ char *w = NULL, *idna = NULL;
|
|
|
|
|
|
|
|
r = extract_first_word(&p, &w, NULL, 0);
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-06-29 20:57:47 +02:00
|
|
|
"Failed to extract word, ignoring: %s", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (r == 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return 0;
|
2019-06-29 20:57:47 +02:00
|
|
|
|
|
|
|
r = dns_name_apply_idna(w, &idna);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2019-06-29 20:57:47 +02:00
|
|
|
"Failed to apply IDNA to domain name '%s', ignoring: %m", w);
|
|
|
|
continue;
|
|
|
|
} else if (r == 0)
|
|
|
|
/* transfer ownership to simplify subsequent operations */
|
|
|
|
idna = TAKE_PTR(w);
|
|
|
|
|
2020-10-15 08:49:26 +02:00
|
|
|
r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops_free);
|
2019-06-29 20:57:47 +02:00
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2019-06-29 20:57:47 +02:00
|
|
|
|
|
|
|
r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2019-06-29 20:57:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
|
2020-09-29 23:17:04 +02:00
|
|
|
[RADV_PREFIX_DELEGATION_NONE] = "no",
|
2019-06-29 20:57:47 +02:00
|
|
|
[RADV_PREFIX_DELEGATION_STATIC] = "static",
|
2020-09-29 23:17:04 +02:00
|
|
|
[RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
|
|
|
|
[RADV_PREFIX_DELEGATION_BOTH] = "yes",
|
2019-06-29 20:57:47 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
|
|
|
|
radv_prefix_delegation,
|
|
|
|
RADVPrefixDelegation,
|
|
|
|
RADV_PREFIX_DELEGATION_BOTH);
|
|
|
|
|
2020-10-19 05:08:53 +02:00
|
|
|
int config_parse_router_prefix_delegation(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
|
|
|
RADVPrefixDelegation val, *ra = data;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
if (streq(lvalue, "IPv6SendRA")) {
|
|
|
|
r = parse_boolean(rvalue);
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
|
|
"Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users
|
|
|
|
* need to explicitly enable DHCPv6PrefixDelegation=. */
|
|
|
|
*ra = r ? RADV_PREFIX_DELEGATION_STATIC : RADV_PREFIX_DELEGATION_NONE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For backward compatibility */
|
|
|
|
val = radv_prefix_delegation_from_string(rvalue);
|
|
|
|
if (val < 0) {
|
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
|
|
|
"Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ra = val;
|
|
|
|
return 0;
|
|
|
|
}
|
2020-09-29 23:17:04 +02:00
|
|
|
|
|
|
|
int config_parse_router_preference(
|
|
|
|
const char *unit,
|
|
|
|
const char *filename,
|
|
|
|
unsigned line,
|
|
|
|
const char *section,
|
|
|
|
unsigned section_line,
|
|
|
|
const char *lvalue,
|
|
|
|
int ltype,
|
|
|
|
const char *rvalue,
|
|
|
|
void *data,
|
|
|
|
void *userdata) {
|
|
|
|
|
2019-06-29 20:57:47 +02:00
|
|
|
Network *network = userdata;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
if (streq(rvalue, "high"))
|
|
|
|
network->router_preference = SD_NDISC_PREFERENCE_HIGH;
|
|
|
|
else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
|
|
|
|
network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
|
|
|
|
else if (streq(rvalue, "low"))
|
|
|
|
network->router_preference = SD_NDISC_PREFERENCE_LOW;
|
|
|
|
else
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
|
|
|
"Invalid router preference, ignoring assignment: %s", rvalue);
|
2019-06-29 20:57:47 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|