1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
9 #include "sd-resolve.h"
11 #include "alloc-util.h"
13 #include "hexdecoct.h"
14 #include "netlink-util.h"
15 #include "networkd-link.h"
16 #include "networkd-manager.h"
17 #include "networkd-util.h"
18 #include "parse-util.h"
19 #include "resolve-private.h"
20 #include "string-util.h"
22 #include "wireguard.h"
23 #include "wireguard-netlink.h"
25 static void resolve_endpoints(NetDev
*netdev
);
27 static WireguardPeer
*wireguard_peer_new(Wireguard
*w
, unsigned section
) {
32 if (w
->last_peer_section
== section
&& w
->peers
)
35 peer
= new(WireguardPeer
, 1);
39 *peer
= (WireguardPeer
) {
40 .flags
= WGPEER_F_REPLACE_ALLOWEDIPS
,
43 LIST_PREPEND(peers
, w
->peers
, peer
);
44 w
->last_peer_section
= section
;
49 static int wireguard_set_ipmask_one(NetDev
*netdev
, sd_netlink_message
*message
, const WireguardIPmask
*mask
, uint16_t index
) {
56 /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */
58 r
= sd_netlink_message_open_array(message
, index
);
62 r
= sd_netlink_message_append_u16(message
, WGALLOWEDIP_A_FAMILY
, mask
->family
);
66 r
= netlink_message_append_in_addr_union(message
, WGALLOWEDIP_A_IPADDR
, mask
->family
, &mask
->ip
);
70 r
= sd_netlink_message_append_u8(message
, WGALLOWEDIP_A_CIDR_MASK
, mask
->cidr
);
74 r
= sd_netlink_message_close_container(message
);
76 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard allowed ip: %m");
81 r
= sd_netlink_message_cancel_array(message
);
83 return log_netdev_error_errno(netdev
, r
, "Could not cancel wireguard allowed ip message attribute: %m");
88 static int wireguard_set_peer_one(NetDev
*netdev
, sd_netlink_message
*message
, const WireguardPeer
*peer
, uint16_t index
, WireguardIPmask
**mask_start
) {
89 WireguardIPmask
*mask
, *start
;
98 /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */
100 start
= *mask_start
?: peer
->ipmasks
;
102 r
= sd_netlink_message_open_array(message
, index
);
106 r
= sd_netlink_message_append_data(message
, WGPEER_A_PUBLIC_KEY
, &peer
->public_key
, sizeof(peer
->public_key
));
111 r
= sd_netlink_message_append_data(message
, WGPEER_A_PRESHARED_KEY
, &peer
->preshared_key
, WG_KEY_LEN
);
115 r
= sd_netlink_message_append_u32(message
, WGPEER_A_FLAGS
, peer
->flags
);
119 r
= sd_netlink_message_append_u16(message
, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL
, peer
->persistent_keepalive_interval
);
123 if (IN_SET(peer
->endpoint
.sa
.sa_family
, AF_INET
, AF_INET6
)) {
124 r
= netlink_message_append_sockaddr_union(message
, WGPEER_A_ENDPOINT
, &peer
->endpoint
);
130 r
= sd_netlink_message_open_container(message
, WGPEER_A_ALLOWEDIPS
);
134 LIST_FOREACH(ipmasks
, mask
, start
) {
135 r
= wireguard_set_ipmask_one(netdev
, message
, mask
, ++j
);
142 r
= sd_netlink_message_close_container(message
);
144 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard allowed ip: %m");
146 r
= sd_netlink_message_close_container(message
);
148 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard peer: %m");
150 *mask_start
= mask
; /* Start next cycle from this mask. */
154 r
= sd_netlink_message_cancel_array(message
);
156 return log_netdev_error_errno(netdev
, r
, "Could not cancel wireguard peers: %m");
161 static int wireguard_set_interface(NetDev
*netdev
) {
162 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
163 WireguardIPmask
*mask_start
= NULL
;
164 WireguardPeer
*peer
, *peer_start
;
170 w
= WIREGUARD(netdev
);
173 for (peer_start
= w
->peers
; peer_start
; ) {
176 message
= sd_netlink_message_unref(message
);
178 r
= sd_genl_message_new(netdev
->manager
->genl
, SD_GENL_WIREGUARD
, WG_CMD_SET_DEVICE
, &message
);
180 return log_netdev_error_errno(netdev
, r
, "Failed to allocate generic netlink message: %m");
182 r
= sd_netlink_message_append_string(message
, WGDEVICE_A_IFNAME
, netdev
->ifname
);
184 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard interface name: %m");
186 if (peer_start
== w
->peers
) {
187 r
= sd_netlink_message_append_data(message
, WGDEVICE_A_PRIVATE_KEY
, &w
->private_key
, WG_KEY_LEN
);
189 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard private key: %m");
191 r
= sd_netlink_message_append_u16(message
, WGDEVICE_A_LISTEN_PORT
, w
->port
);
193 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard port: %m");
195 r
= sd_netlink_message_append_u32(message
, WGDEVICE_A_FWMARK
, w
->fwmark
);
197 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard fwmark: %m");
199 r
= sd_netlink_message_append_u32(message
, WGDEVICE_A_FLAGS
, w
->flags
);
201 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard flags: %m");
204 r
= sd_netlink_message_open_container(message
, WGDEVICE_A_PEERS
);
206 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard peer attributes: %m");
208 LIST_FOREACH(peers
, peer
, peer_start
) {
209 r
= wireguard_set_peer_one(netdev
, message
, peer
, ++i
, &mask_start
);
215 peer_start
= peer
; /* Start next cycle from this peer. */
217 r
= sd_netlink_message_close_container(message
);
219 return log_netdev_error_errno(netdev
, r
, "Could not close wireguard container: %m");
221 r
= sd_netlink_send(netdev
->manager
->genl
, message
, &serial
);
223 return log_netdev_error_errno(netdev
, r
, "Could not set wireguard device: %m");
229 static WireguardEndpoint
* wireguard_endpoint_free(WireguardEndpoint
*e
) {
232 e
->host
= mfree(e
->host
);
233 e
->port
= mfree(e
->port
);
237 static void wireguard_endpoint_destroy_callback(WireguardEndpoint
*e
) {
241 netdev_unref(e
->netdev
);
242 wireguard_endpoint_free(e
);
245 DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint
*, wireguard_endpoint_free
);
247 static int on_resolve_retry(sd_event_source
*s
, usec_t usec
, void *userdata
) {
248 NetDev
*netdev
= userdata
;
252 w
= WIREGUARD(netdev
);
255 if (!netdev_is_managed(netdev
))
258 assert(!w
->unresolved_endpoints
);
259 w
->unresolved_endpoints
= TAKE_PTR(w
->failed_endpoints
);
261 resolve_endpoints(netdev
);
267 * Given the number of retries this function will return will an exponential
268 * increasing time in milliseconds to wait starting at 200ms and capped at 25 seconds.
270 static int exponential_backoff_milliseconds(unsigned n_retries
) {
271 return (2 << MAX(n_retries
, 7U)) * 100 * USEC_PER_MSEC
;
274 static int wireguard_resolve_handler(sd_resolve_query
*q
,
276 const struct addrinfo
*ai
,
277 WireguardEndpoint
*e
) {
278 _cleanup_(netdev_unrefp
) NetDev
*netdev_will_unrefed
= NULL
;
287 w
= WIREGUARD(netdev
);
290 if (!netdev_is_managed(netdev
))
294 log_netdev_error(netdev
, "Failed to resolve host '%s:%s': %s", e
->host
, e
->port
, gai_strerror(ret
));
295 LIST_PREPEND(endpoints
, w
->failed_endpoints
, e
);
296 (void) sd_resolve_query_set_destroy_callback(q
, NULL
); /* Avoid freeing endpoint by destroy callback. */
297 netdev_will_unrefed
= netdev
; /* But netdev needs to be unrefed. */
298 } else if ((ai
->ai_family
== AF_INET
&& ai
->ai_addrlen
== sizeof(struct sockaddr_in
)) ||
299 (ai
->ai_family
== AF_INET6
&& ai
->ai_addrlen
== sizeof(struct sockaddr_in6
)))
300 memcpy(&e
->peer
->endpoint
, ai
->ai_addr
, ai
->ai_addrlen
);
302 log_netdev_error(netdev
, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e
->host
, e
->port
);
304 if (w
->unresolved_endpoints
) {
305 resolve_endpoints(netdev
);
309 (void) wireguard_set_interface(netdev
);
310 if (w
->failed_endpoints
) {
311 _cleanup_(sd_event_source_unrefp
) sd_event_source
*s
= NULL
;
314 r
= sd_event_add_time(netdev
->manager
->event
,
317 now(CLOCK_MONOTONIC
) + exponential_backoff_milliseconds(w
->n_retries
),
322 log_netdev_warning_errno(netdev
, r
, "Could not arm resolve retry handler: %m");
326 r
= sd_event_source_set_destroy_callback(s
, (sd_event_destroy_t
) netdev_destroy_callback
);
328 log_netdev_warning_errno(netdev
, r
, "Failed to set destroy callback to event source: %m");
332 (void) sd_event_source_set_floating(s
, true);
339 static void resolve_endpoints(NetDev
*netdev
) {
340 static const struct addrinfo hints
= {
341 .ai_family
= AF_UNSPEC
,
342 .ai_socktype
= SOCK_DGRAM
,
343 .ai_protocol
= IPPROTO_UDP
345 WireguardEndpoint
*endpoint
;
350 w
= WIREGUARD(netdev
);
353 LIST_FOREACH(endpoints
, endpoint
, w
->unresolved_endpoints
) {
354 r
= resolve_getaddrinfo(netdev
->manager
->resolve
,
359 wireguard_resolve_handler
,
360 wireguard_endpoint_destroy_callback
,
366 log_netdev_error_errno(netdev
, r
, "Failed to create resolver: %m");
370 /* Avoid freeing netdev. It will be unrefed by the destroy callback. */
373 LIST_REMOVE(endpoints
, w
->unresolved_endpoints
, endpoint
);
377 static int netdev_wireguard_post_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
381 w
= WIREGUARD(netdev
);
384 (void) wireguard_set_interface(netdev
);
385 resolve_endpoints(netdev
);
389 int config_parse_wireguard_listen_port(const char *unit
,
390 const char *filename
,
393 unsigned section_line
,
406 if (!streq(rvalue
, "auto")) {
407 r
= parse_ip_port(rvalue
, &port
);
409 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid port specification, ignoring assignment: %s", rvalue
);
417 static int parse_wireguard_key(const char *unit
,
418 const char *filename
,
421 unsigned section_line
,
427 _cleanup_free_
void *key
= NULL
;
435 r
= unbase64mem(rvalue
, strlen(rvalue
), &key
, &len
);
437 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue
);
440 if (len
!= WG_KEY_LEN
) {
441 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
442 "Wireguard key is too short, ignoring assignment: %s", rvalue
);
446 memcpy(userdata
, key
, WG_KEY_LEN
);
450 int config_parse_wireguard_private_key(const char *unit
,
451 const char *filename
,
454 unsigned section_line
,
468 return parse_wireguard_key(unit
,
481 int config_parse_wireguard_preshared_key(const char *unit
,
482 const char *filename
,
485 unsigned section_line
,
500 peer
= wireguard_peer_new(w
, section_line
);
504 return parse_wireguard_key(unit
,
513 peer
->preshared_key
);
516 int config_parse_wireguard_public_key(const char *unit
,
517 const char *filename
,
520 unsigned section_line
,
535 peer
= wireguard_peer_new(w
, section_line
);
539 return parse_wireguard_key(unit
,
551 int config_parse_wireguard_allowed_ips(const char *unit
,
552 const char *filename
,
555 unsigned section_line
,
561 union in_addr_union addr
;
562 unsigned char prefixlen
;
566 WireguardIPmask
*ipmask
;
573 peer
= wireguard_peer_new(w
, section_line
);
578 _cleanup_free_
char *word
= NULL
;
580 r
= extract_first_word(&rvalue
, &word
, "," WHITESPACE
, 0);
586 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to split allowed ips \"%s\" option: %m", rvalue
);
590 r
= in_addr_prefix_from_string_auto(word
, &family
, &addr
, &prefixlen
);
592 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Network address is invalid, ignoring assignment: %s", word
);
596 ipmask
= new(WireguardIPmask
, 1);
600 *ipmask
= (WireguardIPmask
) {
606 LIST_PREPEND(ipmasks
, peer
->ipmasks
, ipmask
);
612 int config_parse_wireguard_endpoint(const char *unit
,
613 const char *filename
,
616 unsigned section_line
,
625 const char *begin
, *end
= NULL
;
626 _cleanup_free_
char *host
= NULL
, *port
= NULL
;
627 _cleanup_(wireguard_endpoint_freep
) WireguardEndpoint
*endpoint
= NULL
;
636 peer
= wireguard_peer_new(w
, section_line
);
640 if (rvalue
[0] == '[') {
642 end
= strchr(rvalue
, ']');
644 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unable to find matching brace of endpoint, ignoring assignment: %s", rvalue
);
649 if (*end
!= ':' || !*(end
+ 1)) {
650 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unable to find port of endpoint: %s", rvalue
);
656 end
= strrchr(rvalue
, ':');
657 if (!end
|| !*(end
+ 1)) {
658 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unable to find port of endpoint: %s", rvalue
);
665 host
= strndup(begin
, len
);
673 endpoint
= new(WireguardEndpoint
, 1);
677 *endpoint
= (WireguardEndpoint
) {
678 .peer
= TAKE_PTR(peer
),
679 .host
= TAKE_PTR(host
),
680 .port
= TAKE_PTR(port
),
683 LIST_PREPEND(endpoints
, w
->unresolved_endpoints
, TAKE_PTR(endpoint
));
688 int config_parse_wireguard_keepalive(const char *unit
,
689 const char *filename
,
692 unsigned section_line
,
699 uint16_t keepalive
= 0;
710 peer
= wireguard_peer_new(w
, section_line
);
714 if (streq(rvalue
, "off"))
717 r
= safe_atou16(rvalue
, &keepalive
);
719 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue
);
722 peer
->persistent_keepalive_interval
= keepalive
;
726 static void wireguard_init(NetDev
*netdev
) {
731 w
= WIREGUARD(netdev
);
735 w
->flags
= WGDEVICE_F_REPLACE_PEERS
;
738 static void wireguard_done(NetDev
*netdev
) {
741 WireguardIPmask
*mask
;
742 WireguardEndpoint
*e
;
745 w
= WIREGUARD(netdev
);
748 while ((peer
= w
->peers
)) {
749 LIST_REMOVE(peers
, w
->peers
, peer
);
750 while ((mask
= peer
->ipmasks
)) {
751 LIST_REMOVE(ipmasks
, peer
->ipmasks
, mask
);
757 while ((e
= w
->unresolved_endpoints
)) {
758 LIST_REMOVE(endpoints
, w
->unresolved_endpoints
, e
);
759 wireguard_endpoint_free(e
);
762 while ((e
= w
->failed_endpoints
)) {
763 LIST_REMOVE(endpoints
, w
->failed_endpoints
, e
);
764 wireguard_endpoint_free(e
);
768 const NetDevVTable wireguard_vtable
= {
769 .object_size
= sizeof(Wireguard
),
770 .sections
= "Match\0NetDev\0WireGuard\0WireGuardPeer\0",
771 .post_create
= netdev_wireguard_post_create
,
772 .init
= wireguard_init
,
773 .done
= wireguard_done
,
774 .create_type
= NETDEV_CREATE_INDEPENDENT
,