1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
6 #include <linux/if_arp.h>
8 #include <netinet/in.h>
10 #include "sd-netlink.h"
11 #include "sd-resolve.h"
13 #include "alloc-util.h"
14 #include "conf-parser.h"
15 #include "creds-util.h"
16 #include "dns-domain.h"
17 #include "event-util.h"
18 #include "extract-word.h"
21 #include "hexdecoct.h"
22 #include "memory-util.h"
23 #include "netlink-util.h"
24 #include "networkd-manager.h"
25 #include "networkd-route.h"
26 #include "networkd-route-util.h"
27 #include "networkd-util.h"
28 #include "parse-helpers.h"
29 #include "parse-util.h"
30 #include "path-util.h"
31 #include "random-util.h"
33 #include "string-util.h"
34 #include "wireguard.h"
36 static void wireguard_resolve_endpoints(NetDev
*netdev
);
37 static int peer_resolve_endpoint(WireguardPeer
*peer
);
39 static void wireguard_peer_clear_ipmasks(WireguardPeer
*peer
) {
42 LIST_CLEAR(ipmasks
, peer
->ipmasks
, free
);
45 static WireguardPeer
* wireguard_peer_free(WireguardPeer
*peer
) {
49 if (peer
->wireguard
) {
50 LIST_REMOVE(peers
, peer
->wireguard
->peers
, peer
);
53 hashmap_remove(peer
->wireguard
->peers_by_section
, peer
->section
);
56 config_section_free(peer
->section
);
58 wireguard_peer_clear_ipmasks(peer
);
60 free(peer
->endpoint_host
);
61 free(peer
->endpoint_port
);
62 free(peer
->public_key_file
);
63 free(peer
->preshared_key_file
);
64 explicit_bzero_safe(peer
->preshared_key
, WG_KEY_LEN
);
66 sd_event_source_disable_unref(peer
->resolve_retry_event_source
);
67 sd_resolve_query_unref(peer
->resolve_query
);
72 DEFINE_SECTION_CLEANUP_FUNCTIONS(WireguardPeer
, wireguard_peer_free
);
74 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
75 wireguard_peer_hash_ops_by_section
,
76 ConfigSection
, config_section_hash_func
, config_section_compare_func
,
77 WireguardPeer
, wireguard_peer_free
);
79 static int wireguard_peer_new_static(Wireguard
*w
, const char *filename
, unsigned section_line
, WireguardPeer
**ret
) {
80 _cleanup_(config_section_freep
) ConfigSection
*n
= NULL
;
81 _cleanup_(wireguard_peer_freep
) WireguardPeer
*peer
= NULL
;
87 assert(section_line
> 0);
89 r
= config_section_new(filename
, section_line
, &n
);
93 peer
= hashmap_get(w
->peers_by_section
, n
);
95 *ret
= TAKE_PTR(peer
);
99 peer
= new(WireguardPeer
, 1);
103 *peer
= (WireguardPeer
) {
104 .flags
= WGPEER_F_REPLACE_ALLOWEDIPS
,
106 .section
= TAKE_PTR(n
),
109 LIST_PREPEND(peers
, w
->peers
, peer
);
111 r
= hashmap_ensure_put(&w
->peers_by_section
, &wireguard_peer_hash_ops_by_section
, peer
->section
, peer
);
115 *ret
= TAKE_PTR(peer
);
119 static int wireguard_set_ipmask_one(NetDev
*netdev
, sd_netlink_message
*message
, const WireguardIPmask
*mask
, uint16_t index
) {
126 /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */
128 r
= sd_netlink_message_open_array(message
, index
);
132 r
= sd_netlink_message_append_u16(message
, WGALLOWEDIP_A_FAMILY
, mask
->family
);
136 r
= netlink_message_append_in_addr_union(message
, WGALLOWEDIP_A_IPADDR
, mask
->family
, &mask
->ip
);
140 r
= sd_netlink_message_append_u8(message
, WGALLOWEDIP_A_CIDR_MASK
, mask
->cidr
);
144 r
= sd_netlink_message_close_container(message
);
146 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard allowed ip: %m");
151 r
= sd_netlink_message_cancel_array(message
);
153 return log_netdev_error_errno(netdev
, r
, "Could not cancel wireguard allowed ip message attribute: %m");
158 static int wireguard_set_peer_one(NetDev
*netdev
, sd_netlink_message
*message
, const WireguardPeer
*peer
, uint16_t index
, WireguardIPmask
**mask_start
) {
159 WireguardIPmask
*start
, *last
= NULL
;
168 /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */
170 start
= *mask_start
?: peer
->ipmasks
;
172 r
= sd_netlink_message_open_array(message
, index
);
176 r
= sd_netlink_message_append_data(message
, WGPEER_A_PUBLIC_KEY
, &peer
->public_key
, sizeof(peer
->public_key
));
181 r
= sd_netlink_message_append_data(message
, WGPEER_A_PRESHARED_KEY
, &peer
->preshared_key
, WG_KEY_LEN
);
185 r
= sd_netlink_message_append_u32(message
, WGPEER_A_FLAGS
, peer
->flags
);
189 r
= sd_netlink_message_append_u16(message
, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL
, peer
->persistent_keepalive_interval
);
193 if (IN_SET(peer
->endpoint
.sa
.sa_family
, AF_INET
, AF_INET6
)) {
194 r
= netlink_message_append_sockaddr_union(message
, WGPEER_A_ENDPOINT
, &peer
->endpoint
);
200 r
= sd_netlink_message_open_container(message
, WGPEER_A_ALLOWEDIPS
);
204 LIST_FOREACH(ipmasks
, mask
, start
) {
205 r
= wireguard_set_ipmask_one(netdev
, message
, mask
, ++j
);
214 r
= sd_netlink_message_close_container(message
);
216 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard allowed ip: %m");
218 r
= sd_netlink_message_close_container(message
);
220 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard peer: %m");
222 *mask_start
= last
; /* Start next cycle from this mask. */
226 r
= sd_netlink_message_cancel_array(message
);
228 return log_netdev_error_errno(netdev
, r
, "Could not cancel wireguard peers: %m");
233 static int wireguard_set_interface(NetDev
*netdev
) {
234 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
235 WireguardIPmask
*mask_start
= NULL
;
236 bool sent_once
= false;
238 Wireguard
*w
= WIREGUARD(netdev
);
241 if (!netdev_is_managed(netdev
))
242 return 0; /* Already detached, due to e.g. reloading .netdev files. */
244 for (WireguardPeer
*peer_start
= w
->peers
; peer_start
|| !sent_once
; ) {
247 message
= sd_netlink_message_unref(message
);
249 r
= sd_genl_message_new(netdev
->manager
->genl
, WG_GENL_NAME
, WG_CMD_SET_DEVICE
, &message
);
251 return log_netdev_error_errno(netdev
, r
, "Failed to allocate generic netlink message: %m");
253 r
= sd_netlink_message_append_string(message
, WGDEVICE_A_IFNAME
, netdev
->ifname
);
255 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard interface name: %m");
257 if (peer_start
== w
->peers
) {
258 r
= sd_netlink_message_append_data(message
, WGDEVICE_A_PRIVATE_KEY
, &w
->private_key
, WG_KEY_LEN
);
260 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard private key: %m");
262 r
= sd_netlink_message_append_u16(message
, WGDEVICE_A_LISTEN_PORT
, w
->port
);
264 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard port: %m");
266 r
= sd_netlink_message_append_u32(message
, WGDEVICE_A_FWMARK
, w
->fwmark
);
268 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard fwmark: %m");
270 r
= sd_netlink_message_append_u32(message
, WGDEVICE_A_FLAGS
, w
->flags
);
272 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard flags: %m");
275 r
= sd_netlink_message_open_container(message
, WGDEVICE_A_PEERS
);
277 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard peer attributes: %m");
279 WireguardPeer
*peer_last
= NULL
;
280 LIST_FOREACH(peers
, peer
, peer_start
) {
281 r
= wireguard_set_peer_one(netdev
, message
, peer
, ++i
, &mask_start
);
289 peer_start
= peer_last
; /* Start next cycle from this peer. */
291 r
= sd_netlink_message_close_container(message
);
293 return log_netdev_error_errno(netdev
, r
, "Could not close wireguard container: %m");
295 r
= sd_netlink_send(netdev
->manager
->genl
, message
, &serial
);
297 return log_netdev_error_errno(netdev
, r
, "Could not set wireguard device: %m");
305 static int on_resolve_retry(sd_event_source
*s
, usec_t usec
, void *userdata
) {
306 WireguardPeer
*peer
= ASSERT_PTR(userdata
);
309 assert(peer
->wireguard
);
311 netdev
= NETDEV(peer
->wireguard
);
313 if (!netdev_is_managed(netdev
))
316 peer
->resolve_query
= sd_resolve_query_unref(peer
->resolve_query
);
318 (void) peer_resolve_endpoint(peer
);
322 static usec_t
peer_next_resolve_usec(WireguardPeer
*peer
) {
325 /* Given the number of retries this function will return an exponential increasing amount of
326 * milliseconds to wait starting at 200ms and capped at 25 seconds. */
330 usec
= (2 << MIN(peer
->n_retries
, 7U)) * 100 * USEC_PER_MSEC
;
332 return random_u64_range(usec
/ 10) + usec
* 9 / 10;
335 static int wireguard_peer_resolve_handler(
338 const struct addrinfo
*ai
,
341 WireguardPeer
*peer
= ASSERT_PTR(userdata
);
345 assert(peer
->wireguard
);
347 netdev
= NETDEV(peer
->wireguard
);
349 if (!netdev_is_managed(netdev
))
353 log_netdev_warning(netdev
, "Failed to resolve host '%s:%s', ignoring: %s",
354 peer
->endpoint_host
, peer
->endpoint_port
, gai_strerror(ret
));
359 for (; ai
; ai
= ai
->ai_next
) {
360 if (!IN_SET(ai
->ai_family
, AF_INET
, AF_INET6
))
363 if (ai
->ai_addrlen
!= (ai
->ai_family
== AF_INET
? sizeof(struct sockaddr_in
) : sizeof(struct sockaddr_in6
)))
366 memcpy(&peer
->endpoint
, ai
->ai_addr
, ai
->ai_addrlen
);
367 (void) wireguard_set_interface(netdev
);
374 log_netdev_warning(netdev
, "Neither IPv4 nor IPv6 address found for peer endpoint %s:%s, ignoring the endpoint.",
375 peer
->endpoint_host
, peer
->endpoint_port
);
380 if (peer
->n_retries
> 0) {
381 r
= event_reset_time_relative(netdev
->manager
->event
,
382 &peer
->resolve_retry_event_source
,
384 peer_next_resolve_usec(peer
), 0,
385 on_resolve_retry
, peer
, 0, "wireguard-resolve-retry", true);
387 log_netdev_warning_errno(netdev
, r
, "Could not arm resolve retry handler for endpoint %s:%s, ignoring: %m",
388 peer
->endpoint_host
, peer
->endpoint_port
);
391 wireguard_resolve_endpoints(netdev
);
395 static int peer_resolve_endpoint(WireguardPeer
*peer
) {
396 static const struct addrinfo hints
= {
397 .ai_family
= AF_UNSPEC
,
398 .ai_socktype
= SOCK_DGRAM
,
399 .ai_protocol
= IPPROTO_UDP
405 assert(peer
->wireguard
);
407 netdev
= NETDEV(peer
->wireguard
);
409 if (!netdev_is_managed(netdev
))
410 return 0; /* Already detached, due to e.g. reloading .netdev files. */
412 if (!peer
->endpoint_host
|| !peer
->endpoint_port
)
413 /* Not necessary to resolve the endpoint. */
416 if (sd_event_source_get_enabled(peer
->resolve_retry_event_source
, NULL
) > 0)
417 /* Timer event source is enabled. The endpoint will be resolved later. */
420 if (peer
->resolve_query
)
421 /* Being resolved, or already resolved. */
424 r
= sd_resolve_getaddrinfo(netdev
->manager
->resolve
,
425 &peer
->resolve_query
,
429 wireguard_peer_resolve_handler
,
432 return log_netdev_full_errno(netdev
, r
== -ENOBUFS
? LOG_DEBUG
: LOG_WARNING
, r
,
433 "Failed to create endpoint resolver for %s:%s, ignoring: %m",
434 peer
->endpoint_host
, peer
->endpoint_port
);
439 static void wireguard_resolve_endpoints(NetDev
*netdev
) {
440 Wireguard
*w
= WIREGUARD(netdev
);
442 LIST_FOREACH(peers
, peer
, w
->peers
)
443 if (peer_resolve_endpoint(peer
) == -ENOBUFS
)
444 /* Too many requests. Let's resolve remaining endpoints later. */
448 static int netdev_wireguard_post_create(NetDev
*netdev
, Link
*link
) {
449 assert(WIREGUARD(netdev
));
451 (void) wireguard_set_interface(netdev
);
452 wireguard_resolve_endpoints(netdev
);
456 int config_parse_wireguard_listen_port(
458 const char *filename
,
461 unsigned section_line
,
468 uint16_t *s
= ASSERT_PTR(data
);
473 if (isempty(rvalue
) || streq(rvalue
, "auto")) {
478 r
= parse_ip_port(rvalue
, s
);
480 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
481 "Invalid port specification, ignoring assignment: %s", rvalue
);
488 static int wireguard_decode_key_and_warn(
490 uint8_t ret
[static WG_KEY_LEN
],
492 const char *filename
,
494 const char *lvalue
) {
496 _cleanup_(erase_and_freep
) void *key
= NULL
;
497 _cleanup_(erase_and_freep
) char *cred
= NULL
;
498 const char *cred_name
;
507 if (isempty(rvalue
)) {
508 memzero(ret
, WG_KEY_LEN
);
512 cred_name
= startswith(rvalue
, "@");
514 r
= read_credential(cred_name
, (void**) &cred
, /* ret_size = */ NULL
);
518 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
519 "Failed to read credential for wireguard key (%s=), ignoring assignment: %m",
524 } else if (!streq(lvalue
, "PublicKey"))
525 (void) warn_file_is_world_accessible(filename
, NULL
, unit
, line
);
527 r
= unbase64mem_full(cred
?: rvalue
, SIZE_MAX
, /* secure = */ true, &key
, &len
);
531 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
532 "Failed to decode wireguard key provided by %s=, ignoring assignment: %m", lvalue
);
535 if (len
!= WG_KEY_LEN
) {
536 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
537 "Wireguard key provided by %s= has invalid length (%zu bytes), ignoring assignment.",
542 memcpy(ret
, key
, WG_KEY_LEN
);
546 int config_parse_wireguard_private_key(
548 const char *filename
,
551 unsigned section_line
,
558 Wireguard
*w
= WIREGUARD(data
);
560 return wireguard_decode_key_and_warn(rvalue
, w
->private_key
, unit
, filename
, line
, lvalue
);
563 int config_parse_wireguard_private_key_file(
565 const char *filename
,
568 unsigned section_line
,
575 Wireguard
*w
= WIREGUARD(data
);
576 _cleanup_free_
char *path
= NULL
;
578 if (isempty(rvalue
)) {
579 w
->private_key_file
= mfree(w
->private_key_file
);
583 path
= strdup(rvalue
);
587 if (path_simplify_and_warn(path
, PATH_CHECK_ABSOLUTE
|PATH_CHECK_NON_API_VFS
, unit
, filename
, line
, lvalue
) < 0)
590 return free_and_replace(w
->private_key_file
, path
);
593 int config_parse_wireguard_peer_key(
595 const char *filename
,
598 unsigned section_line
,
605 Wireguard
*w
= WIREGUARD(data
);
606 _cleanup_(wireguard_peer_free_or_set_invalidp
) WireguardPeer
*peer
= NULL
;
609 r
= wireguard_peer_new_static(w
, filename
, section_line
, &peer
);
613 r
= wireguard_decode_key_and_warn(rvalue
,
614 streq(lvalue
, "PublicKey") ? peer
->public_key
: peer
->preshared_key
,
615 unit
, filename
, line
, lvalue
);
623 int config_parse_wireguard_peer_key_file(
625 const char *filename
,
628 unsigned section_line
,
635 Wireguard
*w
= WIREGUARD(data
);
636 _cleanup_(wireguard_peer_free_or_set_invalidp
) WireguardPeer
*peer
= NULL
;
637 _cleanup_free_
char *path
= NULL
;
644 r
= wireguard_peer_new_static(w
, filename
, section_line
, &peer
);
648 if (streq(lvalue
, "PublicKeyFile"))
649 key_file
= &peer
->public_key_file
;
650 else if (streq(lvalue
, "PresharedKeyFile"))
651 key_file
= &peer
->preshared_key_file
;
653 assert_not_reached();
655 if (isempty(rvalue
)) {
656 *key_file
= mfree(*key_file
);
661 path
= strdup(rvalue
);
665 if (path_simplify_and_warn(path
, PATH_CHECK_ABSOLUTE
|PATH_CHECK_NON_API_VFS
, unit
, filename
, line
, lvalue
) < 0)
668 free_and_replace(*key_file
, path
);
673 int config_parse_wireguard_allowed_ips(
675 const char *filename
,
678 unsigned section_line
,
687 Wireguard
*w
= WIREGUARD(data
);
688 _cleanup_(wireguard_peer_free_or_set_invalidp
) WireguardPeer
*peer
= NULL
;
689 union in_addr_union addr
;
690 unsigned char prefixlen
;
692 WireguardIPmask
*ipmask
;
694 r
= wireguard_peer_new_static(w
, filename
, section_line
, &peer
);
698 if (isempty(rvalue
)) {
699 wireguard_peer_clear_ipmasks(peer
);
704 for (const char *p
= rvalue
;;) {
705 _cleanup_free_
char *word
= NULL
;
706 union in_addr_union masked
;
708 r
= extract_first_word(&p
, &word
, "," WHITESPACE
, 0);
714 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
715 "Failed to split allowed ips \"%s\" option: %m", rvalue
);
719 r
= in_addr_prefix_from_string_auto(word
, &family
, &addr
, &prefixlen
);
721 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
722 "Network address is invalid, ignoring assignment: %s", word
);
727 assert_se(in_addr_mask(family
, &masked
, prefixlen
) >= 0);
728 if (!in_addr_equal(family
, &masked
, &addr
))
729 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
730 "Specified address '%s' is not properly masked, assuming '%s'.",
732 IN_ADDR_PREFIX_TO_STRING(family
, &masked
, prefixlen
));
734 ipmask
= new(WireguardIPmask
, 1);
738 *ipmask
= (WireguardIPmask
) {
744 LIST_PREPEND(ipmasks
, peer
->ipmasks
, ipmask
);
751 int config_parse_wireguard_endpoint(
753 const char *filename
,
756 unsigned section_line
,
763 Wireguard
*w
= WIREGUARD(userdata
);
764 _cleanup_(wireguard_peer_free_or_set_invalidp
) WireguardPeer
*peer
= NULL
;
765 _cleanup_free_
char *cred
= NULL
;
766 const char *cred_name
, *endpoint
;
773 r
= wireguard_peer_new_static(w
, filename
, section_line
, &peer
);
777 cred_name
= startswith(rvalue
, "@");
779 r
= read_credential(cred_name
, (void**) &cred
, /* ret_size = */ NULL
);
783 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
784 "Failed to read credential for wireguard endpoint, ignoring assignment: %m");
788 endpoint
= strstrip(cred
);
792 union in_addr_union addr
;
795 r
= in_addr_port_ifindex_name_from_string_auto(endpoint
, &family
, &addr
, &port
, NULL
, NULL
);
797 if (family
== AF_INET
)
798 peer
->endpoint
.in
= (struct sockaddr_in
) {
799 .sin_family
= AF_INET
,
801 .sin_port
= htobe16(port
),
803 else if (family
== AF_INET6
)
804 peer
->endpoint
.in6
= (struct sockaddr_in6
) {
805 .sin6_family
= AF_INET6
,
806 .sin6_addr
= addr
.in6
,
807 .sin6_port
= htobe16(port
),
810 assert_not_reached();
812 peer
->endpoint_host
= mfree(peer
->endpoint_host
);
813 peer
->endpoint_port
= mfree(peer
->endpoint_port
);
819 _cleanup_free_
char *host
= NULL
;
822 p
= strrchr(endpoint
, ':');
824 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
825 "Unable to find port of endpoint, ignoring assignment: %s",
826 rvalue
); /* We log the original assignment instead of resolved credential here,
827 as the latter might be previously encrypted and we'd expose them in
828 unprotected logs otherwise. */
832 host
= strndup(endpoint
, p
- endpoint
);
837 if (!dns_name_is_valid(host
)) {
838 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
839 "Invalid domain name of endpoint, ignoring assignment: %s",
844 r
= parse_ip_port(p
, &port
);
846 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
847 "Invalid port of endpoint, ignoring assignment: %s",
852 peer
->endpoint
= (union sockaddr_union
) {};
854 free_and_replace(peer
->endpoint_host
, host
);
856 r
= free_and_strdup(&peer
->endpoint_port
, p
);
860 TAKE_PTR(peer
); /* The peer may already have been in the hash map, that is fine too. */
864 int config_parse_wireguard_keepalive(
866 const char *filename
,
869 unsigned section_line
,
878 Wireguard
*w
= WIREGUARD(data
);
879 _cleanup_(wireguard_peer_free_or_set_invalidp
) WireguardPeer
*peer
= NULL
;
880 uint16_t keepalive
= 0;
883 r
= wireguard_peer_new_static(w
, filename
, section_line
, &peer
);
887 if (streq(rvalue
, "off"))
890 r
= safe_atou16(rvalue
, &keepalive
);
892 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
893 "Failed to parse \"%s\" as keepalive interval (range 0–65535), ignoring assignment: %m",
899 peer
->persistent_keepalive_interval
= keepalive
;
905 int config_parse_wireguard_route_table(
907 const char *filename
,
910 unsigned section_line
,
917 NetDev
*netdev
= ASSERT_PTR(userdata
);
918 uint32_t *table
= ASSERT_PTR(data
);
925 if (isempty(rvalue
) || parse_boolean(rvalue
) == 0) {
926 *table
= 0; /* Disabled. */
930 r
= manager_get_route_table_from_string(netdev
->manager
, rvalue
, table
);
932 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
933 "Failed to parse %s=, ignoring assignment: %s",
941 int config_parse_wireguard_peer_route_table(
943 const char *filename
,
946 unsigned section_line
,
953 Wireguard
*w
= WIREGUARD(userdata
);
954 _cleanup_(wireguard_peer_free_or_set_invalidp
) WireguardPeer
*peer
= NULL
;
960 assert(NETDEV(w
)->manager
);
962 r
= wireguard_peer_new_static(w
, filename
, section_line
, &peer
);
966 if (isempty(rvalue
)) {
967 peer
->route_table_set
= false; /* Use the table specified in [WireGuard] section. */
972 if (parse_boolean(rvalue
) == 0) {
973 peer
->route_table
= 0; /* Disabled. */
974 peer
->route_table_set
= true;
979 r
= manager_get_route_table_from_string(NETDEV(w
)->manager
, rvalue
, &peer
->route_table
);
981 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
982 "Failed to parse %s=, ignoring assignment: %s",
987 peer
->route_table_set
= true;
992 int config_parse_wireguard_route_priority(
994 const char *filename
,
997 unsigned section_line
,
1004 uint32_t *priority
= ASSERT_PTR(data
);
1011 if (isempty(rvalue
)) {
1016 r
= safe_atou32(rvalue
, priority
);
1018 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1019 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue
);
1026 int config_parse_wireguard_peer_route_priority(
1028 const char *filename
,
1030 const char *section
,
1031 unsigned section_line
,
1038 _cleanup_(wireguard_peer_free_or_set_invalidp
) WireguardPeer
*peer
= NULL
;
1047 w
= WIREGUARD(userdata
);
1050 r
= wireguard_peer_new_static(w
, filename
, section_line
, &peer
);
1054 if (isempty(rvalue
)) {
1055 peer
->route_priority_set
= false; /* Use the priority specified in [WireGuard] section. */
1060 r
= safe_atou32(rvalue
, &peer
->route_priority
);
1062 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1063 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue
);
1067 peer
->route_priority_set
= true;
1072 static void wireguard_init(NetDev
*netdev
) {
1073 Wireguard
*w
= WIREGUARD(netdev
);
1075 w
->flags
= WGDEVICE_F_REPLACE_PEERS
;
1078 static void wireguard_done(NetDev
*netdev
) {
1079 Wireguard
*w
= WIREGUARD(netdev
);
1081 explicit_bzero_safe(w
->private_key
, WG_KEY_LEN
);
1082 free(w
->private_key_file
);
1084 hashmap_free(w
->peers_by_section
);
1086 set_free(w
->routes
);
1089 static int wireguard_read_key_file(const char *filename
, uint8_t dest
[static WG_KEY_LEN
]) {
1090 _cleanup_(erase_and_freep
) char *key
= NULL
;
1099 r
= read_full_file_full(
1100 AT_FDCWD
, filename
, UINT64_MAX
, WG_KEY_LEN
,
1101 READ_FULL_FILE_SECURE
|
1102 READ_FULL_FILE_UNBASE64
|
1103 READ_FULL_FILE_WARN_WORLD_READABLE
|
1104 READ_FULL_FILE_CONNECT_SOCKET
|
1105 READ_FULL_FILE_FAIL_WHEN_LARGER
,
1106 NULL
, &key
, &key_len
);
1110 if (key_len
!= WG_KEY_LEN
)
1113 memcpy(dest
, key
, WG_KEY_LEN
);
1117 static int wireguard_peer_verify(WireguardPeer
*peer
) {
1118 NetDev
*netdev
= NETDEV(peer
->wireguard
);
1121 if (section_is_invalid(peer
->section
))
1124 r
= wireguard_read_key_file(peer
->public_key_file
, peer
->public_key
);
1126 return log_netdev_error_errno(netdev
, r
,
1127 "%s: Failed to read public key from '%s'. "
1128 "Ignoring [WireGuardPeer] section from line %u.",
1129 peer
->section
->filename
, peer
->public_key_file
,
1130 peer
->section
->line
);
1132 if (eqzero(peer
->public_key
))
1133 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1134 "%s: WireGuardPeer section without PublicKey= configured. "
1135 "Ignoring [WireGuardPeer] section from line %u.",
1136 peer
->section
->filename
, peer
->section
->line
);
1138 r
= wireguard_read_key_file(peer
->preshared_key_file
, peer
->preshared_key
);
1140 return log_netdev_error_errno(netdev
, r
,
1141 "%s: Failed to read preshared key from '%s'. "
1142 "Ignoring [WireGuardPeer] section from line %u.",
1143 peer
->section
->filename
, peer
->preshared_key_file
,
1144 peer
->section
->line
);
1149 static int wireguard_read_default_key_cred(NetDev
*netdev
, const char *filename
) {
1150 Wireguard
*w
= WIREGUARD(netdev
);
1151 _cleanup_free_
char *config_name
= NULL
;
1156 r
= path_extract_filename(filename
, &config_name
);
1158 return log_netdev_error_errno(netdev
, r
,
1159 "%s: Failed to extract config name, ignoring network device: %m",
1162 char *p
= endswith(config_name
, ".netdev");
1164 /* Fuzzer run? Then we just ignore this device. */
1165 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1166 "%s: Invalid netdev config name, refusing default key lookup.",
1170 _cleanup_(erase_and_freep
) char *cred
= NULL
;
1172 r
= read_credential(strjoina("network.wireguard.private.", config_name
), (void**) &cred
, /* ret_size = */ NULL
);
1174 return log_netdev_error_errno(netdev
, r
,
1175 "%s: No private key specified and default key isn't available, "
1176 "ignoring network device: %m",
1179 _cleanup_(erase_and_freep
) void *key
= NULL
;
1182 r
= unbase64mem_full(cred
, SIZE_MAX
, /* secure = */ true, &key
, &len
);
1184 return log_netdev_error_errno(netdev
, r
,
1185 "%s: No private key specified and default key cannot be parsed, "
1186 "ignoring network device: %m",
1188 if (len
!= WG_KEY_LEN
|| memeqzero(key
, len
))
1189 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1190 "%s: No private key specified and default key is invalid. "
1191 "Ignoring network device.",
1194 memcpy(w
->private_key
, key
, WG_KEY_LEN
);
1198 static int wireguard_verify(NetDev
*netdev
, const char *filename
) {
1199 Wireguard
*w
= WIREGUARD(netdev
);
1202 r
= wireguard_read_key_file(w
->private_key_file
, w
->private_key
);
1204 return log_netdev_error_errno(netdev
, r
,
1205 "Failed to read private key from '%s', ignoring network device: %m",
1206 w
->private_key_file
);
1208 if (eqzero(w
->private_key
)) {
1209 r
= wireguard_read_default_key_cred(netdev
, filename
);
1214 LIST_FOREACH(peers
, peer
, w
->peers
) {
1215 if (wireguard_peer_verify(peer
) < 0) {
1216 wireguard_peer_free(peer
);
1220 if ((peer
->route_table_set
? peer
->route_table
: w
->route_table
) == 0)
1223 LIST_FOREACH(ipmasks
, ipmask
, peer
->ipmasks
) {
1224 _cleanup_(route_unrefp
) Route
*route
= NULL
;
1226 r
= route_new(&route
);
1230 /* For route_section_verify() below. */
1231 r
= config_section_new(peer
->section
->filename
, peer
->section
->line
, &route
->section
);
1235 route
->source
= NETWORK_CONFIG_SOURCE_STATIC
;
1236 route
->family
= ipmask
->family
;
1237 route
->dst
= ipmask
->ip
;
1238 route
->dst_prefixlen
= ipmask
->cidr
;
1239 route
->protocol
= RTPROT_STATIC
;
1240 route
->protocol_set
= true;
1241 route
->table
= peer
->route_table_set
? peer
->route_table
: w
->route_table
;
1242 route
->table_set
= true;
1243 route
->priority
= peer
->route_priority_set
? peer
->route_priority
: w
->route_priority
;
1244 route
->priority_set
= true;
1246 if (route_section_verify(route
) < 0)
1249 r
= set_ensure_put(&w
->routes
, &route_hash_ops
, route
);
1255 route
->wireguard
= w
;
1263 const NetDevVTable wireguard_vtable
= {
1264 .object_size
= sizeof(Wireguard
),
1265 .sections
= NETDEV_COMMON_SECTIONS
"WireGuard\0WireGuardPeer\0",
1266 .post_create
= netdev_wireguard_post_create
,
1267 .init
= wireguard_init
,
1268 .done
= wireguard_done
,
1269 .create_type
= NETDEV_CREATE_INDEPENDENT
,
1270 .config_verify
= wireguard_verify
,
1271 .iftype
= ARPHRD_NONE
,
1272 .keep_existing
= true,