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"
12 #include "parse-util.h"
15 #include "hexdecoct.h"
16 #include "string-util.h"
17 #include "wireguard.h"
18 #include "networkd-link.h"
19 #include "networkd-util.h"
20 #include "networkd-manager.h"
21 #include "wireguard-netlink.h"
23 static void resolve_endpoints(NetDev
*netdev
);
25 static WireguardPeer
*wireguard_peer_new(Wireguard
*w
, unsigned section
) {
30 if (w
->last_peer_section
== section
&& w
->peers
)
33 peer
= new(WireguardPeer
, 1);
37 *peer
= (WireguardPeer
) {
38 .flags
= WGPEER_F_REPLACE_ALLOWEDIPS
,
41 LIST_PREPEND(peers
, w
->peers
, peer
);
42 w
->last_peer_section
= section
;
47 static int set_wireguard_interface(NetDev
*netdev
) {
50 WireguardPeer
*peer
, *peer_start
;
51 WireguardIPmask
*mask
, *mask_start
= NULL
;
52 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
57 w
= WIREGUARD(netdev
);
60 peer_start
= w
->peers
;
63 message
= sd_netlink_message_unref(message
);
65 r
= sd_genl_message_new(netdev
->manager
->genl
, SD_GENL_WIREGUARD
, WG_CMD_SET_DEVICE
, &message
);
67 return log_netdev_error_errno(netdev
, r
, "Failed to allocate generic netlink message: %m");
69 r
= sd_netlink_message_append_string(message
, WGDEVICE_A_IFNAME
, netdev
->ifname
);
71 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard interface name: %m");
73 if (peer_start
== w
->peers
) {
74 r
= sd_netlink_message_append_data(message
, WGDEVICE_A_PRIVATE_KEY
, &w
->private_key
, WG_KEY_LEN
);
76 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard private key: %m");
78 r
= sd_netlink_message_append_u16(message
, WGDEVICE_A_LISTEN_PORT
, w
->port
);
80 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard port: %m");
82 r
= sd_netlink_message_append_u32(message
, WGDEVICE_A_FWMARK
, w
->fwmark
);
84 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard fwmark: %m");
86 r
= sd_netlink_message_append_u32(message
, WGDEVICE_A_FLAGS
, w
->flags
);
88 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard flags: %m");
91 r
= sd_netlink_message_open_container(message
, WGDEVICE_A_PEERS
);
93 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard peer attributes: %m");
97 LIST_FOREACH(peers
, peer
, peer_start
) {
98 r
= sd_netlink_message_open_array(message
, ++i
);
102 r
= sd_netlink_message_append_data(message
, WGPEER_A_PUBLIC_KEY
, &peer
->public_key
, sizeof(peer
->public_key
));
107 r
= sd_netlink_message_append_data(message
, WGPEER_A_PRESHARED_KEY
, &peer
->preshared_key
, WG_KEY_LEN
);
111 r
= sd_netlink_message_append_u32(message
, WGPEER_A_FLAGS
, peer
->flags
);
115 r
= sd_netlink_message_append_u16(message
, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL
, peer
->persistent_keepalive_interval
);
119 if (peer
->endpoint
.sa
.sa_family
== AF_INET
) {
120 r
= sd_netlink_message_append_data(message
, WGPEER_A_ENDPOINT
, &peer
->endpoint
.in
, sizeof(peer
->endpoint
.in
));
123 } else if (peer
->endpoint
.sa
.sa_family
== AF_INET6
) {
124 r
= sd_netlink_message_append_data(message
, WGPEER_A_ENDPOINT
, &peer
->endpoint
.in6
, sizeof(peer
->endpoint
.in6
));
129 mask_start
= peer
->ipmasks
;
132 r
= sd_netlink_message_open_container(message
, WGPEER_A_ALLOWEDIPS
);
138 LIST_FOREACH(ipmasks
, mask
, mask_start
) {
139 r
= sd_netlink_message_open_array(message
, ++j
);
143 r
= sd_netlink_message_append_u16(message
, WGALLOWEDIP_A_FAMILY
, mask
->family
);
147 if (mask
->family
== AF_INET
) {
148 r
= sd_netlink_message_append_in_addr(message
, WGALLOWEDIP_A_IPADDR
, &mask
->ip
.in
);
151 } else if (mask
->family
== AF_INET6
) {
152 r
= sd_netlink_message_append_in6_addr(message
, WGALLOWEDIP_A_IPADDR
, &mask
->ip
.in6
);
157 r
= sd_netlink_message_append_u8(message
, WGALLOWEDIP_A_CIDR_MASK
, mask
->cidr
);
161 r
= sd_netlink_message_close_container(message
);
163 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard allowed ip: %m");
167 r
= sd_netlink_message_cancel_array(message
);
169 return log_netdev_error_errno(netdev
, r
, "Could not cancel wireguard allowed ip message attribute: %m");
171 r
= sd_netlink_message_close_container(message
);
173 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard allowed ip: %m");
175 r
= sd_netlink_message_close_container(message
);
177 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard peer: %m");
181 if (peer_start
&& !mask_start
) {
182 r
= sd_netlink_message_cancel_array(message
);
184 return log_netdev_error_errno(netdev
, r
, "Could not cancel wireguard peers: %m");
187 r
= sd_netlink_message_close_container(message
);
189 return log_netdev_error_errno(netdev
, r
, "Could not close wireguard container: %m");
191 r
= sd_netlink_send(netdev
->manager
->genl
, message
, &serial
);
193 return log_netdev_error_errno(netdev
, r
, "Could not set wireguard device: %m");
195 } while (peer
|| mask_start
);
200 static WireguardEndpoint
* wireguard_endpoint_free(WireguardEndpoint
*e
) {
203 e
->host
= mfree(e
->host
);
204 e
->port
= mfree(e
->port
);
208 static void wireguard_endpoint_destroy_callback(void *userdata
) {
209 WireguardEndpoint
*e
= userdata
;
214 netdev_unref(e
->netdev
);
215 wireguard_endpoint_free(e
);
218 DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint
*, wireguard_endpoint_free
);
220 static int on_resolve_retry(sd_event_source
*s
, usec_t usec
, void *userdata
) {
221 NetDev
*netdev
= userdata
;
225 w
= WIREGUARD(netdev
);
228 if (!netdev
->manager
)
229 /* The netdev is detached. */
232 assert(!w
->unresolved_endpoints
);
233 w
->unresolved_endpoints
= TAKE_PTR(w
->failed_endpoints
);
235 resolve_endpoints(netdev
);
241 * Given the number of retries this function will return will an exponential
242 * increasing time in milliseconds to wait starting at 200ms and capped at 25 seconds.
244 static int exponential_backoff_milliseconds(unsigned n_retries
) {
245 return (2 << MAX(n_retries
, 7U)) * 100 * USEC_PER_MSEC
;
248 static int wireguard_resolve_handler(sd_resolve_query
*q
,
250 const struct addrinfo
*ai
,
252 _cleanup_(netdev_unrefp
) NetDev
*netdev_will_unrefed
= NULL
;
253 NetDev
*netdev
= NULL
;
254 WireguardEndpoint
*e
;
263 w
= WIREGUARD(netdev
);
266 if (!netdev
->manager
)
267 /* The netdev is detached. */
271 log_netdev_error(netdev
, "Failed to resolve host '%s:%s': %s", e
->host
, e
->port
, gai_strerror(ret
));
272 LIST_PREPEND(endpoints
, w
->failed_endpoints
, e
);
273 (void) sd_resolve_query_set_destroy_callback(q
, NULL
); /* Avoid freeing endpoint by destroy callback. */
274 netdev_will_unrefed
= netdev
; /* But netdev needs to be unrefed. */
275 } else if ((ai
->ai_family
== AF_INET
&& ai
->ai_addrlen
== sizeof(struct sockaddr_in
)) ||
276 (ai
->ai_family
== AF_INET6
&& ai
->ai_addrlen
== sizeof(struct sockaddr_in6
)))
277 memcpy(&e
->peer
->endpoint
, ai
->ai_addr
, ai
->ai_addrlen
);
279 log_netdev_error(netdev
, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e
->host
, e
->port
);
281 if (w
->unresolved_endpoints
) {
282 resolve_endpoints(netdev
);
286 set_wireguard_interface(netdev
);
287 if (w
->failed_endpoints
) {
288 _cleanup_(sd_event_source_unrefp
) sd_event_source
*s
= NULL
;
291 r
= sd_event_add_time(netdev
->manager
->event
,
294 now(CLOCK_MONOTONIC
) + exponential_backoff_milliseconds(w
->n_retries
),
299 log_netdev_warning_errno(netdev
, r
, "Could not arm resolve retry handler: %m");
303 r
= sd_event_source_set_destroy_callback(s
, netdev_destroy_callback
);
305 log_netdev_warning_errno(netdev
, r
, "Failed to set destroy callback to event source: %m");
309 (void) sd_event_source_set_floating(s
, true);
316 static void resolve_endpoints(NetDev
*netdev
) {
317 static const struct addrinfo hints
= {
318 .ai_family
= AF_UNSPEC
,
319 .ai_socktype
= SOCK_DGRAM
,
320 .ai_protocol
= IPPROTO_UDP
322 WireguardEndpoint
*endpoint
;
327 w
= WIREGUARD(netdev
);
330 LIST_FOREACH(endpoints
, endpoint
, w
->unresolved_endpoints
) {
331 _cleanup_(sd_resolve_query_unrefp
) sd_resolve_query
*q
= NULL
;
333 r
= sd_resolve_getaddrinfo(netdev
->manager
->resolve
,
338 wireguard_resolve_handler
,
344 log_netdev_error_errno(netdev
, r
, "Failed to create resolver: %m");
348 r
= sd_resolve_query_set_destroy_callback(q
, wireguard_endpoint_destroy_callback
);
350 log_netdev_error_errno(netdev
, r
, "Failed to set destroy callback to resolving query: %m");
354 (void) sd_resolve_query_set_floating(q
, true);
356 /* Avoid freeing netdev. It will be unrefed by the destroy callback. */
359 LIST_REMOVE(endpoints
, w
->unresolved_endpoints
, endpoint
);
363 static int netdev_wireguard_post_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
367 w
= WIREGUARD(netdev
);
370 set_wireguard_interface(netdev
);
371 resolve_endpoints(netdev
);
375 int config_parse_wireguard_listen_port(const char *unit
,
376 const char *filename
,
379 unsigned section_line
,
392 if (!streq(rvalue
, "auto")) {
393 r
= parse_ip_port(rvalue
, &port
);
395 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid port specification, ignoring assignment: %s", rvalue
);
403 static int parse_wireguard_key(const char *unit
,
404 const char *filename
,
407 unsigned section_line
,
413 _cleanup_free_
void *key
= NULL
;
421 r
= unbase64mem(rvalue
, strlen(rvalue
), &key
, &len
);
423 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue
);
426 if (len
!= WG_KEY_LEN
) {
427 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
428 "Wireguard key is too short, ignoring assignment: %s", rvalue
);
432 memcpy(userdata
, key
, WG_KEY_LEN
);
436 int config_parse_wireguard_private_key(const char *unit
,
437 const char *filename
,
440 unsigned section_line
,
454 return parse_wireguard_key(unit
,
467 int config_parse_wireguard_preshared_key(const char *unit
,
468 const char *filename
,
471 unsigned section_line
,
486 peer
= wireguard_peer_new(w
, section_line
);
490 return parse_wireguard_key(unit
,
499 peer
->preshared_key
);
502 int config_parse_wireguard_public_key(const char *unit
,
503 const char *filename
,
506 unsigned section_line
,
521 peer
= wireguard_peer_new(w
, section_line
);
525 return parse_wireguard_key(unit
,
537 int config_parse_wireguard_allowed_ips(const char *unit
,
538 const char *filename
,
541 unsigned section_line
,
547 union in_addr_union addr
;
548 unsigned char prefixlen
;
552 WireguardIPmask
*ipmask
;
559 peer
= wireguard_peer_new(w
, section_line
);
564 _cleanup_free_
char *word
= NULL
;
566 r
= extract_first_word(&rvalue
, &word
, "," WHITESPACE
, 0);
572 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to split allowed ips \"%s\" option: %m", rvalue
);
576 r
= in_addr_prefix_from_string_auto(word
, &family
, &addr
, &prefixlen
);
578 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Network address is invalid, ignoring assignment: %s", word
);
582 ipmask
= new(WireguardIPmask
, 1);
586 *ipmask
= (WireguardIPmask
) {
592 LIST_PREPEND(ipmasks
, peer
->ipmasks
, ipmask
);
598 int config_parse_wireguard_endpoint(const char *unit
,
599 const char *filename
,
602 unsigned section_line
,
611 const char *begin
, *end
= NULL
;
612 _cleanup_free_
char *host
= NULL
, *port
= NULL
;
613 _cleanup_(wireguard_endpoint_freep
) WireguardEndpoint
*endpoint
= NULL
;
622 peer
= wireguard_peer_new(w
, section_line
);
626 if (rvalue
[0] == '[') {
628 end
= strchr(rvalue
, ']');
630 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unable to find matching brace of endpoint, ignoring assignment: %s", rvalue
);
635 if (*end
!= ':' || !*(end
+ 1)) {
636 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unable to find port of endpoint: %s", rvalue
);
642 end
= strrchr(rvalue
, ':');
643 if (!end
|| !*(end
+ 1)) {
644 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unable to find port of endpoint: %s", rvalue
);
651 host
= strndup(begin
, len
);
659 endpoint
= new(WireguardEndpoint
, 1);
663 *endpoint
= (WireguardEndpoint
) {
664 .peer
= TAKE_PTR(peer
),
665 .host
= TAKE_PTR(host
),
666 .port
= TAKE_PTR(port
),
669 LIST_PREPEND(endpoints
, w
->unresolved_endpoints
, TAKE_PTR(endpoint
));
674 int config_parse_wireguard_keepalive(const char *unit
,
675 const char *filename
,
678 unsigned section_line
,
685 uint16_t keepalive
= 0;
696 peer
= wireguard_peer_new(w
, section_line
);
700 if (streq(rvalue
, "off"))
703 r
= safe_atou16(rvalue
, &keepalive
);
705 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue
);
708 peer
->persistent_keepalive_interval
= keepalive
;
712 static void wireguard_init(NetDev
*netdev
) {
717 w
= WIREGUARD(netdev
);
721 w
->flags
= WGDEVICE_F_REPLACE_PEERS
;
724 static void wireguard_done(NetDev
*netdev
) {
727 WireguardIPmask
*mask
;
728 WireguardEndpoint
*e
;
731 w
= WIREGUARD(netdev
);
734 while ((peer
= w
->peers
)) {
735 LIST_REMOVE(peers
, w
->peers
, peer
);
736 while ((mask
= peer
->ipmasks
)) {
737 LIST_REMOVE(ipmasks
, peer
->ipmasks
, mask
);
743 while ((e
= w
->unresolved_endpoints
)) {
744 LIST_REMOVE(endpoints
, w
->unresolved_endpoints
, e
);
745 wireguard_endpoint_free(e
);
748 while ((e
= w
->failed_endpoints
)) {
749 LIST_REMOVE(endpoints
, w
->failed_endpoints
, e
);
750 wireguard_endpoint_free(e
);
754 const NetDevVTable wireguard_vtable
= {
755 .object_size
= sizeof(Wireguard
),
756 .sections
= "Match\0NetDev\0WireGuard\0WireGuardPeer\0",
757 .post_create
= netdev_wireguard_post_create
,
758 .init
= wireguard_init
,
759 .done
= wireguard_done
,
760 .create_type
= NETDEV_CREATE_INDEPENDENT
,