Merge pull request #11861 from yuwata/network-verify-2
network: config parser updates and wireguard refactoring
This commit is contained in:
commit
96c45cc697
|
@ -1113,12 +1113,24 @@
|
|||
<para>The Base64 encoded private key for the interface. It can be
|
||||
generated using the <command>wg genkey</command> command
|
||||
(see <citerefentry project="wireguard"><refentrytitle>wg</refentrytitle><manvolnum>8</manvolnum></citerefentry>).
|
||||
This option is mandatory to use WireGuard.
|
||||
This option or <varname>PrivateKeyFile=</varname> is mandatory to use WireGuard.
|
||||
Note that because this information is secret, you may want to set
|
||||
the permissions of the .netdev file to be owned by <literal>root:systemd-network</literal>
|
||||
with a <literal>0640</literal> file mode.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>PrivateKeyFile=</varname></term>
|
||||
<listitem>
|
||||
<para>Takes a absolute path to a file which contains the Base64 encoded private key for the interface.
|
||||
If both <varname>PrivateKey=</varname> and <varname>PrivateKeyFile=</varname> are specified, and if
|
||||
the file specified in <varname>PrivateKeyFile=</varname> contains valid wireguard key, then
|
||||
the key provided by <varname>PrivateKey=</varname> is ignored.
|
||||
Note that the file must be readable by the user <literal>systemd-network</literal>, so it
|
||||
should be, e.g., owned by <literal>root:systemd-network</literal> with a
|
||||
<literal>0640</literal> file mode.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>ListenPort=</varname></term>
|
||||
<listitem>
|
||||
|
|
|
@ -167,6 +167,7 @@ VRF.Table, config_parse_uint32, 0,
|
|||
WireGuard.FwMark, config_parse_unsigned, 0, offsetof(Wireguard, fwmark)
|
||||
WireGuard.ListenPort, config_parse_wireguard_listen_port, 0, offsetof(Wireguard, port)
|
||||
WireGuard.PrivateKey, config_parse_wireguard_private_key, 0, 0
|
||||
WireGuard.PrivateKeyFile, config_parse_wireguard_private_key_file, 0, 0
|
||||
WireGuardPeer.AllowedIPs, config_parse_wireguard_allowed_ips, 0, 0
|
||||
WireGuardPeer.Endpoint, config_parse_wireguard_endpoint, 0, 0
|
||||
WireGuardPeer.PublicKey, config_parse_wireguard_public_key, 0, 0
|
||||
|
|
|
@ -9,13 +9,16 @@
|
|||
#include "sd-resolve.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "resolve-private.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
@ -24,26 +27,79 @@
|
|||
|
||||
static void resolve_endpoints(NetDev *netdev);
|
||||
|
||||
static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) {
|
||||
WireguardPeer *peer;
|
||||
static void wireguard_peer_free(WireguardPeer *peer) {
|
||||
WireguardIPmask *mask;
|
||||
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
if (peer->wireguard) {
|
||||
LIST_REMOVE(peers, peer->wireguard->peers, peer);
|
||||
|
||||
set_remove(peer->wireguard->peers_with_unresolved_endpoint, peer);
|
||||
set_remove(peer->wireguard->peers_with_failed_endpoint, peer);
|
||||
|
||||
if (peer->section)
|
||||
hashmap_remove(peer->wireguard->peers_by_section, peer->section);
|
||||
}
|
||||
|
||||
network_config_section_free(peer->section);
|
||||
|
||||
while ((mask = peer->ipmasks)) {
|
||||
LIST_REMOVE(ipmasks, peer->ipmasks, mask);
|
||||
free(mask);
|
||||
}
|
||||
|
||||
free(peer->endpoint_host);
|
||||
free(peer->endpoint_port);
|
||||
|
||||
free(peer);
|
||||
}
|
||||
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(WireguardPeer, wireguard_peer_free);
|
||||
|
||||
static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigned section_line, WireguardPeer **ret) {
|
||||
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
||||
_cleanup_(wireguard_peer_freep) WireguardPeer *peer = NULL;
|
||||
int r;
|
||||
|
||||
assert(w);
|
||||
assert(ret);
|
||||
assert(filename);
|
||||
assert(section_line > 0);
|
||||
|
||||
if (w->last_peer_section == section && w->peers)
|
||||
return w->peers;
|
||||
r = network_config_section_new(filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
peer = hashmap_get(w->peers_by_section, n);
|
||||
if (peer) {
|
||||
*ret = TAKE_PTR(peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
peer = new(WireguardPeer, 1);
|
||||
if (!peer)
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
*peer = (WireguardPeer) {
|
||||
.flags = WGPEER_F_REPLACE_ALLOWEDIPS,
|
||||
.wireguard = w,
|
||||
.section = TAKE_PTR(n),
|
||||
};
|
||||
|
||||
LIST_PREPEND(peers, w->peers, peer);
|
||||
w->last_peer_section = section;
|
||||
|
||||
return peer;
|
||||
r = hashmap_ensure_allocated(&w->peers_by_section, &network_config_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_put(w->peers_by_section, peer->section, peer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wireguard_set_ipmask_one(NetDev *netdev, sd_netlink_message *message, const WireguardIPmask *mask, uint16_t index) {
|
||||
|
@ -226,24 +282,20 @@ static int wireguard_set_interface(NetDev *netdev) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static WireguardEndpoint* wireguard_endpoint_free(WireguardEndpoint *e) {
|
||||
if (!e)
|
||||
return NULL;
|
||||
e->host = mfree(e->host);
|
||||
e->port = mfree(e->port);
|
||||
return mfree(e);
|
||||
static void wireguard_peer_destroy_callback(WireguardPeer *peer) {
|
||||
NetDev *netdev;
|
||||
|
||||
assert(peer);
|
||||
assert(peer->wireguard);
|
||||
|
||||
netdev = NETDEV(peer->wireguard);
|
||||
|
||||
if (section_is_invalid(peer->section))
|
||||
wireguard_peer_free(peer);
|
||||
|
||||
netdev_unref(netdev);
|
||||
}
|
||||
|
||||
static void wireguard_endpoint_destroy_callback(WireguardEndpoint *e) {
|
||||
assert(e);
|
||||
assert(e->netdev);
|
||||
|
||||
netdev_unref(e->netdev);
|
||||
wireguard_endpoint_free(e);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint*, wireguard_endpoint_free);
|
||||
|
||||
static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
|
||||
NetDev *netdev = userdata;
|
||||
Wireguard *w;
|
||||
|
@ -255,8 +307,9 @@ static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
|
|||
if (!netdev_is_managed(netdev))
|
||||
return 0;
|
||||
|
||||
assert(!w->unresolved_endpoints);
|
||||
w->unresolved_endpoints = TAKE_PTR(w->failed_endpoints);
|
||||
assert(set_isempty(w->peers_with_unresolved_endpoint));
|
||||
|
||||
SWAP_TWO(w->peers_with_unresolved_endpoint, w->peers_with_failed_endpoint);
|
||||
|
||||
resolve_endpoints(netdev);
|
||||
|
||||
|
@ -274,63 +327,64 @@ static int exponential_backoff_milliseconds(unsigned n_retries) {
|
|||
static int wireguard_resolve_handler(sd_resolve_query *q,
|
||||
int ret,
|
||||
const struct addrinfo *ai,
|
||||
WireguardEndpoint *e) {
|
||||
_cleanup_(netdev_unrefp) NetDev *netdev_will_unrefed = NULL;
|
||||
WireguardPeer *peer) {
|
||||
NetDev *netdev;
|
||||
Wireguard *w;
|
||||
int r;
|
||||
|
||||
assert(e);
|
||||
assert(e->netdev);
|
||||
assert(peer);
|
||||
assert(peer->wireguard);
|
||||
|
||||
netdev = e->netdev;
|
||||
w = WIREGUARD(netdev);
|
||||
assert(w);
|
||||
w = peer->wireguard;
|
||||
netdev = NETDEV(w);
|
||||
|
||||
if (!netdev_is_managed(netdev))
|
||||
return 0;
|
||||
|
||||
if (ret != 0) {
|
||||
log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", e->host, e->port, gai_strerror(ret));
|
||||
LIST_PREPEND(endpoints, w->failed_endpoints, e);
|
||||
(void) sd_resolve_query_set_destroy_callback(q, NULL); /* Avoid freeing endpoint by destroy callback. */
|
||||
netdev_will_unrefed = netdev; /* But netdev needs to be unrefed. */
|
||||
log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", peer->endpoint_host, peer->endpoint_port, gai_strerror(ret));
|
||||
|
||||
r = set_ensure_allocated(&w->peers_with_failed_endpoint, NULL);
|
||||
if (r < 0) {
|
||||
log_oom();
|
||||
peer->section->invalid = true;
|
||||
goto resolve_next;
|
||||
}
|
||||
|
||||
r = set_put(w->peers_with_failed_endpoint, peer);
|
||||
if (r < 0) {
|
||||
log_netdev_error(netdev, "Failed to save a peer, dropping the peer: %m");
|
||||
peer->section->invalid = true;
|
||||
goto resolve_next;
|
||||
}
|
||||
|
||||
} else if ((ai->ai_family == AF_INET && ai->ai_addrlen == sizeof(struct sockaddr_in)) ||
|
||||
(ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
|
||||
memcpy(&e->peer->endpoint, ai->ai_addr, ai->ai_addrlen);
|
||||
memcpy(&peer->endpoint, ai->ai_addr, ai->ai_addrlen);
|
||||
else
|
||||
log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e->host, e->port);
|
||||
log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint %s:%s, ignoring the address.",
|
||||
peer->endpoint_host, peer->endpoint_port);
|
||||
|
||||
if (w->unresolved_endpoints) {
|
||||
resolve_next:
|
||||
if (!set_isempty(w->peers_with_unresolved_endpoint)) {
|
||||
resolve_endpoints(netdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) wireguard_set_interface(netdev);
|
||||
if (w->failed_endpoints) {
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
|
||||
|
||||
if (!set_isempty(w->peers_with_failed_endpoint)) {
|
||||
usec_t usec;
|
||||
|
||||
w->n_retries++;
|
||||
r = sd_event_add_time(netdev->manager->event,
|
||||
&s,
|
||||
CLOCK_MONOTONIC,
|
||||
now(CLOCK_MONOTONIC) + exponential_backoff_milliseconds(w->n_retries),
|
||||
0,
|
||||
on_resolve_retry,
|
||||
netdev);
|
||||
usec = usec_add(now(CLOCK_MONOTONIC), exponential_backoff_milliseconds(w->n_retries));
|
||||
r = event_reset_time(netdev->manager->event, &w->resolve_retry_event_source,
|
||||
CLOCK_MONOTONIC, usec, 0, on_resolve_retry, netdev,
|
||||
0, "wireguard-resolve-retry", true);
|
||||
if (r < 0) {
|
||||
log_netdev_warning_errno(netdev, r, "Could not arm resolve retry handler: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_event_source_set_destroy_callback(s, (sd_event_destroy_t) netdev_destroy_callback);
|
||||
if (r < 0) {
|
||||
log_netdev_warning_errno(netdev, r, "Failed to set destroy callback to event source: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) sd_event_source_set_floating(s, true);
|
||||
netdev_ref(netdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -342,24 +396,24 @@ static void resolve_endpoints(NetDev *netdev) {
|
|||
.ai_socktype = SOCK_DGRAM,
|
||||
.ai_protocol = IPPROTO_UDP
|
||||
};
|
||||
WireguardEndpoint *endpoint;
|
||||
WireguardPeer *peer;
|
||||
Wireguard *w;
|
||||
Iterator i;
|
||||
int r = 0;
|
||||
|
||||
assert(netdev);
|
||||
w = WIREGUARD(netdev);
|
||||
assert(w);
|
||||
|
||||
LIST_FOREACH(endpoints, endpoint, w->unresolved_endpoints) {
|
||||
SET_FOREACH(peer, w->peers_with_unresolved_endpoint, i) {
|
||||
r = resolve_getaddrinfo(netdev->manager->resolve,
|
||||
NULL,
|
||||
endpoint->host,
|
||||
endpoint->port,
|
||||
peer->endpoint_host,
|
||||
peer->endpoint_port,
|
||||
&hints,
|
||||
wireguard_resolve_handler,
|
||||
wireguard_endpoint_destroy_callback,
|
||||
endpoint);
|
||||
|
||||
wireguard_peer_destroy_callback,
|
||||
peer);
|
||||
if (r == -ENOBUFS)
|
||||
break;
|
||||
if (r < 0) {
|
||||
|
@ -370,7 +424,7 @@ static void resolve_endpoints(NetDev *netdev) {
|
|||
/* Avoid freeing netdev. It will be unrefed by the destroy callback. */
|
||||
netdev_ref(netdev);
|
||||
|
||||
LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
|
||||
(void) set_remove(w->peers_with_unresolved_endpoint, peer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,9 +458,12 @@ int config_parse_wireguard_listen_port(const char *unit,
|
|||
assert(data);
|
||||
|
||||
if (!streq(rvalue, "auto")) {
|
||||
r = parse_ip_port(rvalue, &port);
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid port specification, ignoring assignment: %s", rvalue);
|
||||
r = parse_ip_port(rvalue, s);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Invalid port specification, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
*s = port;
|
||||
|
@ -414,36 +471,41 @@ int config_parse_wireguard_listen_port(const char *unit,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int parse_wireguard_key(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) {
|
||||
static int wireguard_decode_key_and_warn(
|
||||
const char *rvalue,
|
||||
uint8_t *ret,
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *lvalue) {
|
||||
_cleanup_free_ void *key = NULL;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(rvalue);
|
||||
assert(userdata);
|
||||
assert(ret);
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
memzero(ret, WG_KEY_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = unbase64mem(rvalue, strlen(rvalue), &key, &len);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to decode wireguard key provided by %s=, ignoring assignment: %m", lvalue);
|
||||
return 0;
|
||||
}
|
||||
if (len != WG_KEY_LEN) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Wireguard key is too short, ignoring assignment: %s", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Wireguard key provided by %s= has invalid length (%zu bytes), ignoring assignment.",
|
||||
lvalue, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(userdata, key, WG_KEY_LEN);
|
||||
memcpy(ret, key, WG_KEY_LEN);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -465,19 +527,44 @@ int config_parse_wireguard_private_key(const char *unit,
|
|||
|
||||
assert(w);
|
||||
|
||||
return parse_wireguard_key(unit,
|
||||
filename,
|
||||
line,
|
||||
section,
|
||||
section_line,
|
||||
lvalue,
|
||||
ltype,
|
||||
rvalue,
|
||||
data,
|
||||
&w->private_key);
|
||||
return wireguard_decode_key_and_warn(rvalue, w->private_key, unit, filename, line, lvalue);
|
||||
|
||||
}
|
||||
|
||||
int config_parse_wireguard_private_key_file(
|
||||
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) {
|
||||
|
||||
_cleanup_free_ char *path = NULL;
|
||||
Wireguard *w;
|
||||
|
||||
assert(data);
|
||||
w = WIREGUARD(data);
|
||||
assert(w);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
w->private_key_file = mfree(w->private_key_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
path = strdup(rvalue);
|
||||
if (!path)
|
||||
return log_oom();
|
||||
|
||||
if (path_simplify_and_warn(path, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue) < 0)
|
||||
return 0;
|
||||
|
||||
return free_and_replace(w->private_key_file, path);
|
||||
}
|
||||
|
||||
int config_parse_wireguard_preshared_key(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
@ -488,8 +575,10 @@ int config_parse_wireguard_preshared_key(const char *unit,
|
|||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
|
||||
Wireguard *w;
|
||||
WireguardPeer *peer;
|
||||
int r;
|
||||
|
||||
assert(data);
|
||||
|
||||
|
@ -497,20 +586,16 @@ int config_parse_wireguard_preshared_key(const char *unit,
|
|||
|
||||
assert(w);
|
||||
|
||||
peer = wireguard_peer_new(w, section_line);
|
||||
if (!peer)
|
||||
return log_oom();
|
||||
r = wireguard_peer_new_static(w, filename, section_line, &peer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return parse_wireguard_key(unit,
|
||||
filename,
|
||||
line,
|
||||
section,
|
||||
section_line,
|
||||
lvalue,
|
||||
ltype,
|
||||
rvalue,
|
||||
data,
|
||||
peer->preshared_key);
|
||||
r = wireguard_decode_key_and_warn(rvalue, peer->preshared_key, unit, filename, line, lvalue);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_wireguard_public_key(const char *unit,
|
||||
|
@ -523,8 +608,10 @@ int config_parse_wireguard_public_key(const char *unit,
|
|||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
|
||||
Wireguard *w;
|
||||
WireguardPeer *peer;
|
||||
int r;
|
||||
|
||||
assert(data);
|
||||
|
||||
|
@ -532,20 +619,16 @@ int config_parse_wireguard_public_key(const char *unit,
|
|||
|
||||
assert(w);
|
||||
|
||||
peer = wireguard_peer_new(w, section_line);
|
||||
if (!peer)
|
||||
return log_oom();
|
||||
r = wireguard_peer_new_static(w, filename, section_line, &peer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return parse_wireguard_key(unit,
|
||||
filename,
|
||||
line,
|
||||
section,
|
||||
section_line,
|
||||
lvalue,
|
||||
ltype,
|
||||
rvalue,
|
||||
data,
|
||||
peer->public_key);
|
||||
r = wireguard_decode_key_and_warn(rvalue, peer->public_key, unit, filename, line, lvalue);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_wireguard_allowed_ips(const char *unit,
|
||||
|
@ -558,11 +641,12 @@ int config_parse_wireguard_allowed_ips(const char *unit,
|
|||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
|
||||
union in_addr_union addr;
|
||||
unsigned char prefixlen;
|
||||
int r, family;
|
||||
Wireguard *w;
|
||||
WireguardPeer *peer;
|
||||
WireguardIPmask *ipmask;
|
||||
|
||||
assert(rvalue);
|
||||
|
@ -570,9 +654,11 @@ int config_parse_wireguard_allowed_ips(const char *unit,
|
|||
|
||||
w = WIREGUARD(data);
|
||||
|
||||
peer = wireguard_peer_new(w, section_line);
|
||||
if (!peer)
|
||||
return log_oom();
|
||||
assert(w);
|
||||
|
||||
r = wireguard_peer_new_static(w, filename, section_line, &peer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
@ -583,14 +669,16 @@ int config_parse_wireguard_allowed_ips(const char *unit,
|
|||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split allowed ips \"%s\" option: %m", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to split allowed ips \"%s\" option: %m", rvalue);
|
||||
break;
|
||||
}
|
||||
|
||||
r = in_addr_prefix_from_string_auto(word, &family, &addr, &prefixlen);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Network address is invalid, ignoring assignment: %s", word);
|
||||
return 0;
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Network address is invalid, ignoring assignment: %s", word);
|
||||
continue;
|
||||
}
|
||||
|
||||
ipmask = new(WireguardIPmask, 1);
|
||||
|
@ -606,6 +694,7 @@ int config_parse_wireguard_allowed_ips(const char *unit,
|
|||
LIST_PREPEND(ipmasks, peer->ipmasks, ipmask);
|
||||
}
|
||||
|
||||
TAKE_PTR(peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -619,12 +708,12 @@ int config_parse_wireguard_endpoint(const char *unit,
|
|||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
|
||||
const char *begin, *end;
|
||||
Wireguard *w;
|
||||
WireguardPeer *peer;
|
||||
size_t len;
|
||||
const char *begin, *end = NULL;
|
||||
_cleanup_free_ char *host = NULL, *port = NULL;
|
||||
_cleanup_(wireguard_endpoint_freep) WireguardEndpoint *endpoint = NULL;
|
||||
int r;
|
||||
|
||||
assert(data);
|
||||
assert(rvalue);
|
||||
|
@ -633,21 +722,25 @@ int config_parse_wireguard_endpoint(const char *unit,
|
|||
|
||||
assert(w);
|
||||
|
||||
peer = wireguard_peer_new(w, section_line);
|
||||
if (!peer)
|
||||
return log_oom();
|
||||
r = wireguard_peer_new_static(w, filename, section_line, &peer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (rvalue[0] == '[') {
|
||||
begin = &rvalue[1];
|
||||
end = strchr(rvalue, ']');
|
||||
if (!end) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find matching brace of endpoint, ignoring assignment: %s", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Unable to find matching brace of endpoint, ignoring assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
len = end - begin;
|
||||
++end;
|
||||
if (*end != ':' || !*(end + 1)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Unable to find port of endpoint, ignoring assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
++end;
|
||||
|
@ -655,33 +748,32 @@ int config_parse_wireguard_endpoint(const char *unit,
|
|||
begin = rvalue;
|
||||
end = strrchr(rvalue, ':');
|
||||
if (!end || !*(end + 1)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Unable to find port of endpoint, ignoring assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
len = end - begin;
|
||||
++end;
|
||||
}
|
||||
|
||||
host = strndup(begin, len);
|
||||
if (!host)
|
||||
peer->endpoint_host = strndup(begin, len);
|
||||
if (!peer->endpoint_host)
|
||||
return log_oom();
|
||||
|
||||
port = strdup(end);
|
||||
if (!port)
|
||||
peer->endpoint_port = strdup(end);
|
||||
if (!peer->endpoint_port)
|
||||
return log_oom();
|
||||
|
||||
endpoint = new(WireguardEndpoint, 1);
|
||||
if (!endpoint)
|
||||
r = set_ensure_allocated(&w->peers_with_unresolved_endpoint, NULL);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
*endpoint = (WireguardEndpoint) {
|
||||
.peer = TAKE_PTR(peer),
|
||||
.host = TAKE_PTR(host),
|
||||
.port = TAKE_PTR(port),
|
||||
.netdev = data,
|
||||
};
|
||||
LIST_PREPEND(endpoints, w->unresolved_endpoints, TAKE_PTR(endpoint));
|
||||
r = set_put(w->peers_with_unresolved_endpoint, peer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -695,10 +787,11 @@ int config_parse_wireguard_keepalive(const char *unit,
|
|||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
int r;
|
||||
|
||||
_cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
|
||||
uint16_t keepalive = 0;
|
||||
Wireguard *w;
|
||||
WireguardPeer *peer;
|
||||
int r;
|
||||
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
@ -707,19 +800,25 @@ int config_parse_wireguard_keepalive(const char *unit,
|
|||
|
||||
assert(w);
|
||||
|
||||
peer = wireguard_peer_new(w, section_line);
|
||||
if (!peer)
|
||||
return log_oom();
|
||||
r = wireguard_peer_new_static(w, filename, section_line, &peer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (streq(rvalue, "off"))
|
||||
keepalive = 0;
|
||||
else {
|
||||
r = safe_atou16(rvalue, &keepalive);
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"The persistent keepalive interval must be 0-65535. Ignore assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
peer->persistent_keepalive_interval = keepalive;
|
||||
|
||||
TAKE_PTR(peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -737,32 +836,97 @@ static void wireguard_init(NetDev *netdev) {
|
|||
|
||||
static void wireguard_done(NetDev *netdev) {
|
||||
Wireguard *w;
|
||||
WireguardPeer *peer;
|
||||
WireguardIPmask *mask;
|
||||
WireguardEndpoint *e;
|
||||
|
||||
assert(netdev);
|
||||
w = WIREGUARD(netdev);
|
||||
assert(w);
|
||||
|
||||
while ((peer = w->peers)) {
|
||||
LIST_REMOVE(peers, w->peers, peer);
|
||||
while ((mask = peer->ipmasks)) {
|
||||
LIST_REMOVE(ipmasks, peer->ipmasks, mask);
|
||||
free(mask);
|
||||
}
|
||||
free(peer);
|
||||
}
|
||||
sd_event_source_unref(w->resolve_retry_event_source);
|
||||
|
||||
while ((e = w->unresolved_endpoints)) {
|
||||
LIST_REMOVE(endpoints, w->unresolved_endpoints, e);
|
||||
wireguard_endpoint_free(e);
|
||||
}
|
||||
free(w->private_key_file);
|
||||
|
||||
while ((e = w->failed_endpoints)) {
|
||||
LIST_REMOVE(endpoints, w->failed_endpoints, e);
|
||||
wireguard_endpoint_free(e);
|
||||
}
|
||||
hashmap_free_with_destructor(w->peers_by_section, wireguard_peer_free);
|
||||
set_free(w->peers_with_unresolved_endpoint);
|
||||
set_free(w->peers_with_failed_endpoint);
|
||||
}
|
||||
|
||||
static int wireguard_read_private_key_file(Wireguard *w, bool fatal) {
|
||||
_cleanup_free_ char *contents = NULL;
|
||||
_cleanup_free_ void *key = NULL;
|
||||
size_t size, key_len;
|
||||
NetDev *netdev;
|
||||
int level, r;
|
||||
|
||||
assert(w);
|
||||
|
||||
netdev = NETDEV(w);
|
||||
|
||||
if (!w->private_key_file)
|
||||
return 0;
|
||||
|
||||
level = fatal ? LOG_ERR : LOG_INFO;
|
||||
|
||||
r = read_full_file(w->private_key_file, &contents, &size);
|
||||
if (r < 0)
|
||||
return log_netdev_full(netdev, level, r,
|
||||
"Failed to read private key from '%s'%s: %m",
|
||||
w->private_key_file, fatal ? "" : ", ignoring");
|
||||
|
||||
r = unbase64mem(contents, size, &key, &key_len);
|
||||
if (r < 0)
|
||||
return log_netdev_full(netdev, level, r,
|
||||
"Failed to decode private key%s: %m",
|
||||
fatal ? "" : ", ignoring");
|
||||
|
||||
if (key_len != WG_KEY_LEN)
|
||||
return log_netdev_full(netdev, level, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Wireguard private key has invalid length (%zu bytes)%s: %m",
|
||||
key_len, fatal ? "" : ", ignoring");
|
||||
|
||||
memcpy(w->private_key, key, WG_KEY_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wireguard_peer_verify(WireguardPeer *peer) {
|
||||
NetDev *netdev = NETDEV(peer->wireguard);
|
||||
|
||||
if (section_is_invalid(peer->section))
|
||||
return -EINVAL;
|
||||
|
||||
if (eqzero(peer->public_key))
|
||||
return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: WireGuardPeer section without PublicKey= configured. "
|
||||
"Ignoring [WireGuardPeer] section from line %u.",
|
||||
peer->section->filename, peer->section->line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wireguard_verify(NetDev *netdev, const char *filename) {
|
||||
WireguardPeer *peer, *peer_next;
|
||||
Wireguard *w;
|
||||
bool empty;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
w = WIREGUARD(netdev);
|
||||
assert(w);
|
||||
|
||||
empty = eqzero(w->private_key);
|
||||
if (empty && !w->private_key_file)
|
||||
return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: Missing PrivateKey= or PrivateKeyFile=, ignoring.",
|
||||
filename);
|
||||
|
||||
r = wireguard_read_private_key_file(w, empty);
|
||||
if (r < 0 && empty)
|
||||
return r;
|
||||
|
||||
LIST_FOREACH_SAFE(peers, peer, peer_next, w->peers)
|
||||
if (wireguard_peer_verify(peer) < 0)
|
||||
wireguard_peer_free(peer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const NetDevVTable wireguard_vtable = {
|
||||
|
@ -772,4 +936,5 @@ const NetDevVTable wireguard_vtable = {
|
|||
.init = wireguard_init,
|
||||
.done = wireguard_done,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.config_verify = wireguard_verify,
|
||||
};
|
||||
|
|
|
@ -7,10 +7,6 @@ typedef struct Wireguard Wireguard;
|
|||
#include "socket-util.h"
|
||||
#include "wireguard-netlink.h"
|
||||
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ 16
|
||||
#endif
|
||||
|
||||
typedef struct WireguardIPmask {
|
||||
uint16_t family;
|
||||
union in_addr_union ip;
|
||||
|
@ -20,44 +16,40 @@ typedef struct WireguardIPmask {
|
|||
} WireguardIPmask;
|
||||
|
||||
typedef struct WireguardPeer {
|
||||
Wireguard *wireguard;
|
||||
NetworkConfigSection *section;
|
||||
|
||||
uint8_t public_key[WG_KEY_LEN];
|
||||
uint8_t preshared_key[WG_KEY_LEN];
|
||||
uint32_t flags;
|
||||
uint16_t persistent_keepalive_interval;
|
||||
|
||||
union sockaddr_union endpoint;
|
||||
|
||||
uint16_t persistent_keepalive_interval;
|
||||
char *endpoint_host;
|
||||
char *endpoint_port;
|
||||
|
||||
LIST_HEAD(WireguardIPmask, ipmasks);
|
||||
LIST_FIELDS(struct WireguardPeer, peers);
|
||||
} WireguardPeer;
|
||||
|
||||
typedef struct WireguardEndpoint {
|
||||
char *host;
|
||||
char *port;
|
||||
|
||||
NetDev *netdev;
|
||||
WireguardPeer *peer;
|
||||
|
||||
LIST_FIELDS(struct WireguardEndpoint, endpoints);
|
||||
} WireguardEndpoint;
|
||||
|
||||
struct Wireguard {
|
||||
NetDev meta;
|
||||
unsigned last_peer_section;
|
||||
|
||||
uint32_t flags;
|
||||
|
||||
uint8_t private_key[WG_KEY_LEN];
|
||||
char *private_key_file;
|
||||
uint16_t port;
|
||||
uint32_t fwmark;
|
||||
|
||||
uint16_t port;
|
||||
Hashmap *peers_by_section;
|
||||
Set *peers_with_unresolved_endpoint;
|
||||
Set *peers_with_failed_endpoint;
|
||||
|
||||
LIST_HEAD(WireguardPeer, peers);
|
||||
|
||||
LIST_HEAD(WireguardEndpoint, unresolved_endpoints);
|
||||
LIST_HEAD(WireguardEndpoint, failed_endpoints);
|
||||
unsigned n_retries;
|
||||
sd_event_source *resolve_retry_event_source;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(WIREGUARD, Wireguard);
|
||||
|
@ -69,5 +61,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_listen_port);
|
|||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_public_key);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key_file);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_preshared_key);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_keepalive);
|
||||
|
|
|
@ -159,7 +159,7 @@ int config_parse_address_label_prefix(const char *unit,
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(address_label_freep) AddressLabel *n = NULL;
|
||||
_cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
@ -196,7 +196,7 @@ int config_parse_address_label(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(address_label_freep) AddressLabel *n = NULL;
|
||||
_cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
|
||||
Network *network = userdata;
|
||||
uint32_t k;
|
||||
int r;
|
||||
|
|
|
@ -11,6 +11,7 @@ typedef struct AddressLabel AddressLabel;
|
|||
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
|
||||
typedef struct Network Network;
|
||||
typedef struct Link Link;
|
||||
|
@ -30,7 +31,7 @@ struct AddressLabel {
|
|||
|
||||
void address_label_free(AddressLabel *label);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(AddressLabel*, address_label_free);
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(AddressLabel, address_label_free);
|
||||
|
||||
int address_label_configure(AddressLabel *address, Link *link, link_netlink_message_handler_t callback, bool update);
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ int address_new(Address **ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
|
||||
static int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
|
||||
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
int r;
|
||||
|
@ -681,7 +681,7 @@ int config_parse_broadcast(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(address_freep) Address *n = NULL;
|
||||
_cleanup_(address_free_or_set_invalidp) Address *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -725,7 +725,7 @@ int config_parse_address(const char *unit,
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(address_freep) Address *n = NULL;
|
||||
_cleanup_(address_free_or_set_invalidp) Address *n = NULL;
|
||||
union in_addr_union buffer;
|
||||
unsigned char prefixlen;
|
||||
int r, f;
|
||||
|
@ -807,7 +807,7 @@ int config_parse_label(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(address_freep) Address *n = NULL;
|
||||
_cleanup_(address_free_or_set_invalidp) Address *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
@ -846,7 +846,7 @@ int config_parse_lifetime(const char *unit,
|
|||
void *data,
|
||||
void *userdata) {
|
||||
Network *network = userdata;
|
||||
_cleanup_(address_freep) Address *n = NULL;
|
||||
_cleanup_(address_free_or_set_invalidp) Address *n = NULL;
|
||||
unsigned k;
|
||||
int r;
|
||||
|
||||
|
@ -888,7 +888,7 @@ int config_parse_address_flags(const char *unit,
|
|||
void *data,
|
||||
void *userdata) {
|
||||
Network *network = userdata;
|
||||
_cleanup_(address_freep) Address *n = NULL;
|
||||
_cleanup_(address_free_or_set_invalidp) Address *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -936,7 +936,7 @@ int config_parse_address_scope(const char *unit,
|
|||
void *data,
|
||||
void *userdata) {
|
||||
Network *network = userdata;
|
||||
_cleanup_(address_freep) Address *n = NULL;
|
||||
_cleanup_(address_free_or_set_invalidp) Address *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -976,3 +976,19 @@ bool address_is_ready(const Address *a) {
|
|||
else
|
||||
return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
|
||||
}
|
||||
|
||||
int address_section_verify(Address *address) {
|
||||
if (section_is_invalid(address->section))
|
||||
return -EINVAL;
|
||||
|
||||
if (address->family == AF_UNSPEC) {
|
||||
assert(address->section);
|
||||
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: Address section without Address= field configured. "
|
||||
"Ignoring [Address] section from line %u.",
|
||||
address->section->filename, address->section->line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ typedef struct Address Address;
|
|||
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
|
||||
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
|
||||
|
||||
|
@ -46,7 +47,6 @@ struct Address {
|
|||
LIST_FIELDS(Address, addresses);
|
||||
};
|
||||
|
||||
int address_new_static(Network *network, const char *filename, unsigned section, Address **ret);
|
||||
int address_new(Address **ret);
|
||||
void address_free(Address *address);
|
||||
int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
|
||||
|
@ -58,8 +58,9 @@ int address_configure(Address *address, Link *link, link_netlink_message_handler
|
|||
int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback);
|
||||
bool address_equal(Address *a1, Address *a2);
|
||||
bool address_is_ready(const Address *a);
|
||||
int address_section_verify(Address *a);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_address);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_broadcast);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U
|
||||
|
||||
/* create a new FDB entry or get an existing one. */
|
||||
int fdb_entry_new_static(
|
||||
static int fdb_entry_new_static(
|
||||
Network *network,
|
||||
const char *filename,
|
||||
unsigned section_line,
|
||||
|
@ -189,7 +189,7 @@ int config_parse_fdb_hwaddr(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(fdb_entry_freep) FdbEntry *fdb_entry = NULL;
|
||||
_cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -235,7 +235,7 @@ int config_parse_fdb_vlan_id(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(fdb_entry_freep) FdbEntry *fdb_entry = NULL;
|
||||
_cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "conf-parser.h"
|
||||
#include "list.h"
|
||||
#include "macro.h"
|
||||
#include "networkd-util.h"
|
||||
|
||||
typedef struct Network Network;
|
||||
typedef struct FdbEntry FdbEntry;
|
||||
|
@ -24,11 +25,10 @@ struct FdbEntry {
|
|||
LIST_FIELDS(FdbEntry, static_fdb_entries);
|
||||
};
|
||||
|
||||
int fdb_entry_new_static(Network *network, const char *filename, unsigned section_line, FdbEntry **ret);
|
||||
void fdb_entry_free(FdbEntry *fdb_entry);
|
||||
int fdb_entry_configure(Link *link, FdbEntry *fdb_entry);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(FdbEntry*, fdb_entry_free);
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(FdbEntry, fdb_entry_free);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_hwaddr);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vlan_id);
|
||||
|
|
|
@ -50,7 +50,7 @@ static int ipv6_proxy_ndp_set(Link *link) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress **ret) {
|
||||
static int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress **ret) {
|
||||
_cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
|
||||
|
||||
assert(network);
|
||||
|
|
|
@ -10,13 +10,12 @@ typedef struct IPv6ProxyNDPAddress IPv6ProxyNDPAddress;
|
|||
typedef struct Link Link;
|
||||
|
||||
struct IPv6ProxyNDPAddress {
|
||||
Network *network;
|
||||
struct in6_addr in_addr;
|
||||
Network *network;
|
||||
struct in6_addr in_addr;
|
||||
|
||||
LIST_FIELDS(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
|
||||
LIST_FIELDS(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
|
||||
};
|
||||
|
||||
int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress ** ipv6_proxy_ndp_address);
|
||||
void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
|
||||
int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
|
||||
int ipv6_proxy_ndp_addresses_configure(Link *link);
|
||||
|
|
|
@ -164,7 +164,7 @@ int config_parse_neighbor_address(const char *unit,
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(neighbor_freep) Neighbor *n = NULL;
|
||||
_cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -200,7 +200,7 @@ int config_parse_neighbor_hwaddr(const char *unit,
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(neighbor_freep) Neighbor *n = NULL;
|
||||
_cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
|
|
@ -13,6 +13,7 @@ typedef struct Neighbor Neighbor;
|
|||
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
|
||||
struct Neighbor {
|
||||
Network *network;
|
||||
|
@ -29,7 +30,7 @@ struct Neighbor {
|
|||
|
||||
void neighbor_free(Neighbor *neighbor);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Neighbor*, neighbor_free);
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor, neighbor_free);
|
||||
|
||||
int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback);
|
||||
|
||||
|
|
|
@ -40,11 +40,11 @@ Link.RequiredForOnline, config_parse_required_for_online,
|
|||
Network.Description, config_parse_string, 0, offsetof(Network, description)
|
||||
Network.Bridge, config_parse_ifname, 0, offsetof(Network, bridge_name)
|
||||
Network.Bond, config_parse_ifname, 0, offsetof(Network, bond_name)
|
||||
Network.VLAN, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names)
|
||||
Network.MACVLAN, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names)
|
||||
Network.MACVTAP, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names)
|
||||
Network.IPVLAN, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names)
|
||||
Network.VXLAN, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names)
|
||||
Network.VLAN, config_parse_stacked_netdev, NETDEV_KIND_VLAN, offsetof(Network, stacked_netdev_names)
|
||||
Network.MACVLAN, config_parse_stacked_netdev, NETDEV_KIND_MACVLAN, offsetof(Network, stacked_netdev_names)
|
||||
Network.MACVTAP, config_parse_stacked_netdev, NETDEV_KIND_MACVTAP, offsetof(Network, stacked_netdev_names)
|
||||
Network.IPVLAN, config_parse_stacked_netdev, NETDEV_KIND_IPVLAN, offsetof(Network, stacked_netdev_names)
|
||||
Network.VXLAN, config_parse_stacked_netdev, NETDEV_KIND_VXLAN, offsetof(Network, stacked_netdev_names)
|
||||
Network.Tunnel, config_parse_stacked_netdev, _NETDEV_KIND_TUNNEL, offsetof(Network, stacked_netdev_names)
|
||||
Network.VRF, config_parse_ifname, 0, offsetof(Network, vrf_name)
|
||||
Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp)
|
||||
|
|
|
@ -26,42 +26,6 @@
|
|||
/* Let's assume that anything above this number is a user misconfiguration. */
|
||||
#define MAX_NTP_SERVERS 128
|
||||
|
||||
static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) {
|
||||
siphash24_compress(c->filename, strlen(c->filename), state);
|
||||
siphash24_compress(&c->line, sizeof(c->line), state);
|
||||
}
|
||||
|
||||
static int network_config_compare_func(const NetworkConfigSection *x, const NetworkConfigSection *y) {
|
||||
int r;
|
||||
|
||||
r = strcmp(x->filename, y->filename);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return CMP(x->line, y->line);
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(network_config_hash_ops, NetworkConfigSection, network_config_hash_func, network_config_compare_func);
|
||||
|
||||
int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
|
||||
NetworkConfigSection *cs;
|
||||
|
||||
cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
|
||||
if (!cs)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy(cs->filename, filename);
|
||||
cs->line = line;
|
||||
|
||||
*s = TAKE_PTR(cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void network_config_section_free(NetworkConfigSection *cs) {
|
||||
free(cs);
|
||||
}
|
||||
|
||||
/* Set defaults following RFC7844 */
|
||||
void network_apply_anonymize_if_set(Network *network) {
|
||||
if (!network->dhcp_anonymize)
|
||||
|
@ -106,14 +70,15 @@ static int network_resolve_netdev_one(Network *network, const char *name, NetDev
|
|||
NetDev *netdev;
|
||||
int r;
|
||||
|
||||
/* For test-networkd-conf, the check must be earlier than the assertions. */
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
assert(network);
|
||||
assert(network->manager);
|
||||
assert(network->filename);
|
||||
assert(ret_netdev);
|
||||
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
if (kind == _NETDEV_KIND_TUNNEL)
|
||||
kind_string = "tunnel";
|
||||
else {
|
||||
|
@ -195,9 +160,14 @@ static uint32_t network_get_stacked_netdevs_mtu(Network *network) {
|
|||
return mtu;
|
||||
}
|
||||
|
||||
static int network_verify(Network *network) {
|
||||
int network_verify(Network *network) {
|
||||
Address *address, *address_next;
|
||||
Route *route, *route_next;
|
||||
FdbEntry *fdb, *fdb_next;
|
||||
Neighbor *neighbor, *neighbor_next;
|
||||
AddressLabel *label, *label_next;
|
||||
Prefix *prefix, *prefix_next;
|
||||
RoutingPolicyRule *rule, *rule_next;
|
||||
uint32_t mtu;
|
||||
|
||||
assert(network);
|
||||
|
@ -285,34 +255,32 @@ static int network_verify(Network *network) {
|
|||
}
|
||||
|
||||
LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
|
||||
if (address->family == AF_UNSPEC) {
|
||||
log_warning("%s: Address section without Address= field configured. "
|
||||
"Ignoring [Address] section from line %u.",
|
||||
network->filename, address->section->line);
|
||||
|
||||
if (address_section_verify(address) < 0)
|
||||
address_free(address);
|
||||
}
|
||||
|
||||
LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes) {
|
||||
if (route->family == AF_UNSPEC) {
|
||||
log_warning("%s: Route section without Gateway=, Destination=, Source=, "
|
||||
"or PreferredSource= field configured. "
|
||||
"Ignoring [Route] section from line %u.",
|
||||
network->filename, route->section->line);
|
||||
|
||||
LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
|
||||
if (route_section_verify(route, network) < 0)
|
||||
route_free(route);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (network->n_static_addresses == 0 &&
|
||||
in_addr_is_null(route->family, &route->gw) == 0 &&
|
||||
route->gateway_onlink < 0) {
|
||||
log_warning("%s: Gateway= without static address configured. "
|
||||
"Enabling GatewayOnLink= option.",
|
||||
network->filename);
|
||||
route->gateway_onlink = true;
|
||||
}
|
||||
}
|
||||
LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
|
||||
if (section_is_invalid(fdb->section))
|
||||
fdb_entry_free(fdb);
|
||||
|
||||
LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
|
||||
if (section_is_invalid(neighbor->section))
|
||||
neighbor_free(neighbor);
|
||||
|
||||
LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
|
||||
if (section_is_invalid(label->section))
|
||||
address_label_free(label);
|
||||
|
||||
LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
|
||||
if (section_is_invalid(prefix->section))
|
||||
prefix_free(prefix);
|
||||
|
||||
LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
|
||||
if (section_is_invalid(rule->section))
|
||||
routing_policy_rule_free(rule);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -460,6 +428,10 @@ int network_load_one(Manager *manager, const char *filename) {
|
|||
|
||||
network_apply_anonymize_if_set(network);
|
||||
|
||||
r = network_add_ipv4ll_route(network);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
|
||||
|
||||
LIST_PREPEND(networks, manager->networks, network);
|
||||
network->manager = manager;
|
||||
|
||||
|
@ -674,33 +646,11 @@ int network_get(Manager *manager, sd_device *device,
|
|||
}
|
||||
|
||||
int network_apply(Network *network, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
assert(link);
|
||||
|
||||
link->network = network;
|
||||
|
||||
if (network->ipv4ll_route) {
|
||||
Route *route;
|
||||
|
||||
r = route_new_static(network, NULL, 0, &route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
|
||||
if (r == 0)
|
||||
return -EINVAL;
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
route->family = AF_INET;
|
||||
route->dst_prefixlen = 16;
|
||||
route->scope = RT_SCOPE_LINK;
|
||||
route->priority = IPV4LL_ROUTE_METRIC;
|
||||
route->protocol = RTPROT_STATIC;
|
||||
}
|
||||
|
||||
if (network->n_dns > 0 ||
|
||||
!strv_isempty(network->ntp) ||
|
||||
!ordered_set_isempty(network->search_domains) ||
|
||||
|
@ -733,35 +683,18 @@ int config_parse_stacked_netdev(const char *unit,
|
|||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
_cleanup_free_ char *kind_string = NULL, *name = NULL;
|
||||
_cleanup_free_ char *name = NULL;
|
||||
NetDevKind kind = ltype;
|
||||
Hashmap **h = data;
|
||||
NetDevKind kind;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (ltype == _NETDEV_KIND_TUNNEL)
|
||||
kind = _NETDEV_KIND_TUNNEL;
|
||||
else {
|
||||
kind_string = strdup(lvalue);
|
||||
if (!kind_string)
|
||||
return log_oom();
|
||||
|
||||
/* the keys are CamelCase versions of the kind */
|
||||
for (p = kind_string; *p; p++)
|
||||
*p = tolower(*p);
|
||||
|
||||
kind = netdev_kind_from_string(kind_string);
|
||||
if (kind < 0 || IN_SET(kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Invalid NetDev kind: %s", lvalue);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
assert(IN_SET(kind,
|
||||
NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
|
||||
NETDEV_KIND_IPVLAN, NETDEV_KIND_VXLAN, _NETDEV_KIND_TUNNEL));
|
||||
|
||||
if (!ifname_valid(rvalue)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
|
|
|
@ -84,16 +84,6 @@ typedef enum RADVPrefixDelegation {
|
|||
_RADV_PREFIX_DELEGATION_INVALID = -1,
|
||||
} RADVPrefixDelegation;
|
||||
|
||||
typedef struct NetworkConfigSection {
|
||||
unsigned line;
|
||||
char filename[];
|
||||
} NetworkConfigSection;
|
||||
|
||||
int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s);
|
||||
void network_config_section_free(NetworkConfigSection *network);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free);
|
||||
extern const struct hash_ops network_config_hash_ops;
|
||||
|
||||
typedef struct Manager Manager;
|
||||
|
||||
struct Network {
|
||||
|
@ -296,6 +286,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free);
|
|||
|
||||
int network_load(Manager *manager);
|
||||
int network_load_one(Manager *manager, const char *filename);
|
||||
int network_verify(Network *network);
|
||||
|
||||
int network_get_by_name(Manager *manager, const char *name, Network **ret);
|
||||
int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *mac, Network **ret);
|
||||
|
|
|
@ -124,8 +124,8 @@ int prefix_new(Prefix **ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int prefix_new_static(Network *network, const char *filename,
|
||||
unsigned section_line, Prefix **ret) {
|
||||
static int prefix_new_static(Network *network, const char *filename,
|
||||
unsigned section_line, Prefix **ret) {
|
||||
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
||||
_cleanup_(prefix_freep) Prefix *prefix = NULL;
|
||||
int r;
|
||||
|
@ -186,7 +186,7 @@ int config_parse_prefix(const char *unit,
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(prefix_freep) Prefix *p = NULL;
|
||||
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
||||
uint8_t prefixlen = 64;
|
||||
union in_addr_union in6addr;
|
||||
int r;
|
||||
|
@ -228,7 +228,7 @@ int config_parse_prefix_flags(const char *unit,
|
|||
void *data,
|
||||
void *userdata) {
|
||||
Network *network = userdata;
|
||||
_cleanup_(prefix_freep) Prefix *p = NULL;
|
||||
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
||||
int r, val;
|
||||
|
||||
assert(filename);
|
||||
|
@ -272,7 +272,7 @@ int config_parse_prefix_lifetime(const char *unit,
|
|||
void *data,
|
||||
void *userdata) {
|
||||
Network *network = userdata;
|
||||
_cleanup_(prefix_freep) Prefix *p = NULL;
|
||||
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
||||
usec_t usec;
|
||||
int r;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "conf-parser.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-util.h"
|
||||
|
||||
typedef struct Prefix Prefix;
|
||||
|
||||
|
@ -22,9 +23,8 @@ struct Prefix {
|
|||
|
||||
int prefix_new(Prefix **ret);
|
||||
void prefix_free(Prefix *prefix);
|
||||
int prefix_new_static(Network *network, const char *filename, unsigned section, Prefix **ret);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Prefix*, prefix_free);
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_router_prefix_delegation);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_router_preference);
|
||||
|
|
|
@ -67,7 +67,7 @@ int route_new(Route **ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
|
||||
static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
|
||||
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
||||
_cleanup_(route_freep) Route *route = NULL;
|
||||
int r;
|
||||
|
@ -677,6 +677,34 @@ int route_configure(
|
|||
return 0;
|
||||
}
|
||||
|
||||
int network_add_ipv4ll_route(Network *network) {
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
|
||||
if (!network->ipv4ll_route)
|
||||
return 0;
|
||||
|
||||
/* IPv4LLRoute= is in [Network] section. */
|
||||
r = route_new_static(network, NULL, 0, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n->family = AF_INET;
|
||||
n->dst_prefixlen = 16;
|
||||
n->scope = RT_SCOPE_LINK;
|
||||
n->priority = IPV4LL_ROUTE_METRIC;
|
||||
n->protocol = RTPROT_STATIC;
|
||||
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_gateway(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
|
@ -690,7 +718,7 @@ int config_parse_gateway(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -735,7 +763,7 @@ int config_parse_preferred_src(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -775,7 +803,7 @@ int config_parse_destination(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
union in_addr_union *buffer;
|
||||
unsigned char *prefixlen;
|
||||
int r;
|
||||
|
@ -826,7 +854,7 @@ int config_parse_route_priority(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -863,7 +891,7 @@ int config_parse_route_scope(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -903,7 +931,7 @@ int config_parse_route_table(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
@ -941,7 +969,7 @@ int config_parse_gateway_onlink(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -980,7 +1008,7 @@ int config_parse_ipv6_route_preference(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
r = route_new_static(network, filename, section_line, &n);
|
||||
|
@ -1015,7 +1043,7 @@ int config_parse_route_protocol(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
r = route_new_static(network, filename, section_line, &n);
|
||||
|
@ -1054,7 +1082,7 @@ int config_parse_route_type(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
r = route_new_static(network, filename, section_line, &n);
|
||||
|
@ -1093,7 +1121,7 @@ int config_parse_tcp_window(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
Network *network = userdata;
|
||||
uint64_t k;
|
||||
int r;
|
||||
|
@ -1143,7 +1171,7 @@ int config_parse_quickack(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
Network *network = userdata;
|
||||
int k, r;
|
||||
|
||||
|
@ -1182,7 +1210,7 @@ int config_parse_route_mtu(
|
|||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(route_freep) Route *n = NULL;
|
||||
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -1202,3 +1230,29 @@ int config_parse_route_mtu(
|
|||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_section_verify(Route *route, Network *network) {
|
||||
if (section_is_invalid(route->section))
|
||||
return -EINVAL;
|
||||
|
||||
if (route->family == AF_UNSPEC) {
|
||||
assert(route->section);
|
||||
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: Route section without Gateway=, Destination=, Source=, "
|
||||
"or PreferredSource= field configured. "
|
||||
"Ignoring [Route] section from line %u.",
|
||||
route->section->filename, route->section->line);
|
||||
}
|
||||
|
||||
if (network->n_static_addresses == 0 &&
|
||||
in_addr_is_null(route->family, &route->gw) == 0 &&
|
||||
route->gateway_onlink < 0) {
|
||||
log_warning("%s: Gateway= without static address configured. "
|
||||
"Enabling GatewayOnLink= option.",
|
||||
network->filename);
|
||||
route->gateway_onlink = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ typedef struct Route Route;
|
|||
typedef struct NetworkConfigSection NetworkConfigSection;
|
||||
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
|
||||
struct Route {
|
||||
Network *network;
|
||||
|
@ -43,7 +44,6 @@ struct Route {
|
|||
LIST_FIELDS(Route, routes);
|
||||
};
|
||||
|
||||
int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret);
|
||||
int route_new(Route **ret);
|
||||
void route_free(Route *route);
|
||||
int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback);
|
||||
|
@ -56,8 +56,11 @@ void route_update(Route *route, const union in_addr_union *src, unsigned char sr
|
|||
bool route_equal(Route *r1, Route *r2);
|
||||
|
||||
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
|
||||
int route_section_verify(Route *route, Network *network);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
|
||||
|
||||
int network_add_ipv4ll_route(Network *network);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);
|
||||
|
|
|
@ -636,7 +636,7 @@ int config_parse_routing_policy_rule_tos(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
|
||||
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
@ -673,7 +673,7 @@ int config_parse_routing_policy_rule_priority(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
|
||||
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
@ -710,7 +710,7 @@ int config_parse_routing_policy_rule_table(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
|
||||
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
@ -747,7 +747,7 @@ int config_parse_routing_policy_rule_fwmark_mask(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
|
||||
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
@ -784,7 +784,7 @@ int config_parse_routing_policy_rule_prefix(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
|
||||
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
union in_addr_union *buffer;
|
||||
uint8_t *prefixlen;
|
||||
|
@ -831,7 +831,7 @@ int config_parse_routing_policy_rule_device(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
|
||||
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
@ -876,7 +876,7 @@ int config_parse_routing_policy_rule_port_range(
|
|||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
|
||||
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
uint16_t low, high;
|
||||
int r;
|
||||
|
@ -922,7 +922,7 @@ int config_parse_routing_policy_rule_ip_protocol(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
|
||||
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
@ -961,7 +961,7 @@ int config_parse_routing_policy_rule_invert(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
|
||||
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ typedef struct RoutingPolicyRule RoutingPolicyRule;
|
|||
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
|
||||
typedef struct Network Network;
|
||||
typedef struct Link Link;
|
||||
|
@ -54,7 +55,7 @@ struct RoutingPolicyRule {
|
|||
int routing_policy_rule_new(RoutingPolicyRule **ret);
|
||||
void routing_policy_rule_free(RoutingPolicyRule *rule);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(RoutingPolicyRule*, routing_policy_rule_free);
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
|
||||
|
||||
int routing_policy_rule_configure(RoutingPolicyRule *address, Link *link, link_netlink_message_handler_t callback, bool update);
|
||||
int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback);
|
||||
|
|
|
@ -102,3 +102,39 @@ int kernel_route_expiration_supported(void) {
|
|||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) {
|
||||
siphash24_compress(c->filename, strlen(c->filename), state);
|
||||
siphash24_compress(&c->line, sizeof(c->line), state);
|
||||
}
|
||||
|
||||
static int network_config_compare_func(const NetworkConfigSection *x, const NetworkConfigSection *y) {
|
||||
int r;
|
||||
|
||||
r = strcmp(x->filename, y->filename);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return CMP(x->line, y->line);
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(network_config_hash_ops, NetworkConfigSection, network_config_hash_func, network_config_compare_func);
|
||||
|
||||
int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
|
||||
NetworkConfigSection *cs;
|
||||
|
||||
cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
|
||||
if (!cs)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy(cs->filename, filename);
|
||||
cs->line = line;
|
||||
|
||||
*s = TAKE_PTR(cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void network_config_section_free(NetworkConfigSection *cs) {
|
||||
free(cs);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "hash-funcs.h"
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum AddressFamilyBoolean {
|
||||
|
@ -14,6 +15,12 @@ typedef enum AddressFamilyBoolean {
|
|||
_ADDRESS_FAMILY_BOOLEAN_INVALID = -1,
|
||||
} AddressFamilyBoolean;
|
||||
|
||||
typedef struct NetworkConfigSection {
|
||||
unsigned line;
|
||||
bool invalid;
|
||||
char filename[];
|
||||
} NetworkConfigSection;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_address_family_boolean);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_address_family_boolean_with_kernel);
|
||||
|
||||
|
@ -21,3 +28,29 @@ const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_;
|
|||
AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_;
|
||||
|
||||
int kernel_route_expiration_supported(void);
|
||||
|
||||
int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s);
|
||||
void network_config_section_free(NetworkConfigSection *network);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free);
|
||||
extern const struct hash_ops network_config_hash_ops;
|
||||
|
||||
static inline bool section_is_invalid(NetworkConfigSection *section) {
|
||||
/* If this retuns false, then it does _not_ mean the section is valid. */
|
||||
|
||||
if (!section)
|
||||
return false;
|
||||
|
||||
return section->invalid;
|
||||
}
|
||||
|
||||
#define DEFINE_NETWORK_SECTION_FUNCTIONS(type, free_func) \
|
||||
static inline void free_func##_or_set_invalid(type *p) { \
|
||||
assert(p); \
|
||||
\
|
||||
if (p->section) \
|
||||
p->section->invalid = true; \
|
||||
else \
|
||||
free_func(p); \
|
||||
} \
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid);
|
||||
|
|
|
@ -172,7 +172,10 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign
|
|||
_cleanup_(network_freep) Network *network = NULL;
|
||||
|
||||
assert_se(network = new0(Network, 1));
|
||||
assert_se(network->filename = strdup("hogehoge.network"));
|
||||
assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0);
|
||||
assert_se(network->n_static_addresses == 1);
|
||||
assert_se(network_verify(network) >= 0);
|
||||
assert_se(network->n_static_addresses == n_addresses);
|
||||
if (n_addresses > 0) {
|
||||
assert_se(network->static_addresses);
|
||||
|
|
|
@ -9,6 +9,7 @@ Mode=
|
|||
[WireGuard]
|
||||
ListenPort=
|
||||
PrivateKey=
|
||||
PrivateKeyFile=
|
||||
FwMark=
|
||||
[MACVTAP]
|
||||
Mode=
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
[Match]
|
||||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
# these lines are ignored
|
||||
Address=hogehoge
|
||||
Address=foofoo
|
||||
|
||||
[Address]
|
||||
Address=10.2.3.4/16
|
||||
PreferredLifetime=0
|
||||
|
@ -8,3 +13,15 @@ Scope=link
|
|||
|
||||
[Address]
|
||||
Address=2001:0db8:0:f101::1/64
|
||||
|
||||
[Address]
|
||||
# this section must be ignored
|
||||
Peer=hoge
|
||||
Address=10.10.0.1/16
|
||||
Label=30
|
||||
|
||||
[Address]
|
||||
# this section must be ignored
|
||||
Label=30
|
||||
Peer=hoge
|
||||
Address=10.10.0.2/16
|
||||
|
|
|
@ -7,7 +7,9 @@ Description=For issue #11404
|
|||
[WireGuard]
|
||||
# 51820 is common port for Wireguard, 4500 is IPSec/UDP
|
||||
ListenPort=4500
|
||||
PrivateKey=CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=
|
||||
# The key below should be overridden by PrivateKeyFile=
|
||||
PrivateKey=EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=
|
||||
PrivateKeyFile=/run/systemd/network/25-wireguard-private-key.txt
|
||||
|
||||
# peer 1
|
||||
[WireGuardPeer]
|
||||
|
|
6
test/test-network/conf/25-wireguard-private-key.txt
Normal file
6
test/test-network/conf/25-wireguard-private-key.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
CJQUtcS9emY2fLY
|
||||
qDlpSZiE/QJyHkP
|
||||
Wr+WHtZ
|
||||
|
||||
|
||||
LZ90FU=
|
|
@ -4,6 +4,7 @@ Kind=wireguard
|
|||
|
||||
[WireGuard]
|
||||
PrivateKey=EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=
|
||||
PrivateKeyFile=/run/systemd/network/not-exist
|
||||
ListenPort=51820
|
||||
FwMark=1234
|
||||
|
||||
|
|
|
@ -242,6 +242,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
|
|||
'25-vxlan.netdev',
|
||||
'25-wireguard-23-peers.netdev',
|
||||
'25-wireguard-23-peers.network',
|
||||
'25-wireguard-private-key.txt',
|
||||
'25-wireguard.netdev',
|
||||
'6rd.network',
|
||||
'gre.network',
|
||||
|
@ -454,16 +455,21 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
|
|||
self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20')
|
||||
output = subprocess.check_output(['wg', 'show', 'wg99', 'endpoints']).rstrip().decode('utf-8')
|
||||
self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820')
|
||||
output = subprocess.check_output(['wg', 'show', 'wg99', 'private-key']).rstrip().decode('utf-8')
|
||||
self.assertTrue(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=')
|
||||
|
||||
self.assertTrue(self.link_exits('wg99'))
|
||||
|
||||
@expectedFailureIfModuleIsNotAvailable('wireguard')
|
||||
def test_wireguard_23_peers(self):
|
||||
self.copy_unit_to_networkd_unit_path('25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network')
|
||||
self.copy_unit_to_networkd_unit_path('25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
|
||||
'25-wireguard-private-key.txt')
|
||||
self.start_networkd()
|
||||
|
||||
if shutil.which('wg'):
|
||||
subprocess.call('wg')
|
||||
output = subprocess.check_output(['wg', 'show', 'wg98', 'private-key']).rstrip().decode('utf-8')
|
||||
self.assertTrue(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=')
|
||||
|
||||
self.assertTrue(self.link_exits('wg98'))
|
||||
|
||||
|
@ -813,6 +819,9 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
|
|||
print(output)
|
||||
self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
|
||||
self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
|
||||
# also tests invalid [Address] section
|
||||
self.assertNotRegex(output, '10.10.0.1/16')
|
||||
self.assertNotRegex(output, '10.10.0.2/16')
|
||||
|
||||
def test_ip_route(self):
|
||||
self.copy_unit_to_networkd_unit_path('25-route-section.network', '12-dummy.netdev')
|
||||
|
|
Loading…
Reference in a new issue