#include "sd-resolve.h"
#include "alloc-util.h"
+#include "creds-util.h"
#include "dns-domain.h"
#include "event-util.h"
#include "fd-util.h"
#include "networkd-util.h"
#include "parse-helpers.h"
#include "parse-util.h"
+#include "path-util.h"
#include "random-util.h"
#include "resolve-private.h"
#include "string-util.h"
const char *lvalue) {
_cleanup_(erase_and_freep) void *key = NULL;
+ _cleanup_(erase_and_freep) char *cred = NULL;
+ const char *cred_name;
size_t len;
int r;
return 0;
}
- if (!streq(lvalue, "PublicKey"))
+ cred_name = startswith(rvalue, "@");
+ if (cred_name) {
+ r = read_credential(cred_name, (void**) &cred, /* ret_size = */ NULL);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to read credential for wireguard key (%s=), ignoring assignment: %m",
+ lvalue);
+ return 0;
+ }
+
+ } else if (!streq(lvalue, "PublicKey"))
(void) warn_file_is_world_accessible(filename, NULL, unit, line);
- r = unbase64mem_full(rvalue, strlen(rvalue), true, &key, &len);
+ r = unbase64mem_full(cred ?: rvalue, SIZE_MAX, /* secure = */ true, &key, &len);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
void *data,
void *userdata) {
- assert(filename);
- assert(rvalue);
- assert(userdata);
-
Wireguard *w = WIREGUARD(userdata);
_cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
- _cleanup_free_ char *host = NULL;
- union in_addr_union addr;
- const char *p;
+ _cleanup_free_ char *cred = NULL;
+ const char *cred_name, *endpoint;
uint16_t port;
- int family, r;
+ int r;
+
+ assert(filename);
+ assert(rvalue);
r = wireguard_peer_new_static(w, filename, section_line, &peer);
if (r < 0)
return log_oom();
- r = in_addr_port_ifindex_name_from_string_auto(rvalue, &family, &addr, &port, NULL, NULL);
+ cred_name = startswith(rvalue, "@");
+ if (cred_name) {
+ r = read_credential(cred_name, (void**) &cred, /* ret_size = */ NULL);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to read credential for wireguard endpoint, ignoring assignment: %m");
+ return 0;
+ }
+
+ endpoint = strstrip(cred);
+ } else
+ endpoint = rvalue;
+
+ union in_addr_union addr;
+ int family;
+
+ r = in_addr_port_ifindex_name_from_string_auto(endpoint, &family, &addr, &port, NULL, NULL);
if (r >= 0) {
if (family == AF_INET)
peer->endpoint.in = (struct sockaddr_in) {
return 0;
}
- p = strrchr(rvalue, ':');
+ _cleanup_free_ char *host = NULL;
+ const char *p;
+
+ p = strrchr(endpoint, ':');
if (!p) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Unable to find port of endpoint, ignoring assignment: %s",
- rvalue);
+ rvalue); /* We log the original assignment instead of resolved credential here,
+ as the latter might be previously encrypted and we'd expose them in
+ unprotected logs otherwise. */
return 0;
}
- host = strndup(rvalue, p - rvalue);
+ host = strndup(endpoint, p - endpoint);
if (!host)
return log_oom();
+ p++;
if (!dns_name_is_valid(host)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
return 0;
}
- p++;
r = parse_ip_port(p, &port);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
assert(dest);
r = read_full_file_full(
- AT_FDCWD, filename, UINT64_MAX, SIZE_MAX,
- READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
+ AT_FDCWD, filename, UINT64_MAX, WG_KEY_LEN,
+ READ_FULL_FILE_SECURE |
+ READ_FULL_FILE_UNBASE64 |
+ READ_FULL_FILE_WARN_WORLD_READABLE |
+ READ_FULL_FILE_CONNECT_SOCKET |
+ READ_FULL_FILE_FAIL_WHEN_LARGER,
NULL, &key, &key_len);
if (r < 0)
return r;
return 0;
}
+static int wireguard_read_default_key_cred(NetDev *netdev, const char *filename) {
+ Wireguard *w = WIREGUARD(netdev);
+ _cleanup_free_ char *config_name = NULL;
+ int r;
+
+ assert(filename);
+
+ r = path_extract_filename(filename, &config_name);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r,
+ "%s: Failed to extract config name, ignoring network device: %m",
+ filename);
+
+ char *p = endswith(config_name, ".netdev");
+ if (!p)
+ /* Fuzzer run? Then we just ignore this device. */
+ return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+ "%s: Invalid netdev config name, refusing default key lookup.",
+ filename);
+ *p = '\0';
+
+ _cleanup_(erase_and_freep) char *cred = NULL;
+
+ r = read_credential(strjoina("network.wireguard.private.", config_name), (void**) &cred, /* ret_size = */ NULL);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r,
+ "%s: No private key specified and default key isn't available, "
+ "ignoring network device: %m",
+ filename);
+
+ _cleanup_(erase_and_freep) void *key = NULL;
+ size_t len;
+
+ r = unbase64mem_full(cred, SIZE_MAX, /* secure = */ true, &key, &len);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r,
+ "%s: No private key specified and default key cannot be parsed, "
+ "ignoring network device: %m",
+ filename);
+ if (len != WG_KEY_LEN)
+ return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+ "%s: No private key specified and default key is invalid. "
+ "Ignoring network device.",
+ filename);
+
+ memcpy(w->private_key, key, WG_KEY_LEN);
+ return 0;
+}
+
static int wireguard_verify(NetDev *netdev, const char *filename) {
Wireguard *w = WIREGUARD(netdev);
int r;
"Failed to read private key from %s. Ignoring network device.",
w->private_key_file);
- if (eqzero(w->private_key))
- return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
- "%s: Missing PrivateKey= or PrivateKeyFile=, "
- "Ignoring network device.", filename);
+ if (eqzero(w->private_key)) {
+ r = wireguard_read_default_key_cred(netdev, filename);
+ if (r < 0)
+ return r;
+ }
LIST_FOREACH(peers, peer, w->peers) {
if (wireguard_peer_verify(peer) < 0) {
continue;
LIST_FOREACH(ipmasks, ipmask, peer->ipmasks) {
- _cleanup_(route_freep) Route *route = NULL;
+ _cleanup_(route_unrefp) Route *route = NULL;
r = route_new(&route);
if (r < 0)
return log_oom();
+ /* For route_section_verify() below. */
+ r = config_section_new(peer->section->filename, peer->section->line, &route->section);
+ if (r < 0)
+ return log_oom();
+
+ route->source = NETWORK_CONFIG_SOURCE_STATIC;
route->family = ipmask->family;
route->dst = ipmask->ip;
route->dst_prefixlen = ipmask->cidr;
- route->scope = RT_SCOPE_UNIVERSE;
route->protocol = RTPROT_STATIC;
+ route->protocol_set = true;
route->table = peer->route_table_set ? peer->route_table : w->route_table;
+ route->table_set = true;
route->priority = peer->route_priority_set ? peer->route_priority : w->route_priority;
- if (route->priority == 0 && route->family == AF_INET6)
- route->priority = IP6_RT_PRIO_USER;
- route->source = NETWORK_CONFIG_SOURCE_STATIC;
+ route->priority_set = true;
- r = set_ensure_consume(&w->routes, &route_hash_ops, TAKE_PTR(route));
+ if (route_section_verify(route) < 0)
+ continue;
+
+ r = set_ensure_put(&w->routes, &route_hash_ops, route);
if (r < 0)
return log_oom();
+ if (r == 0)
+ continue;
+
+ route->wireguard = w;
+ TAKE_PTR(route);
}
}