2 This file is part of systemd.
4 Copyright 2016-2017 Jörg Thalheim <joerg@thalheim.io>
5 Copyright 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <sys/ioctl.h>
24 #include "alloc-util.h"
25 #include "parse-util.h"
28 #include "hexdecoct.h"
29 #include "string-util.h"
30 #include "wireguard.h"
31 #include "networkd-link.h"
32 #include "networkd-util.h"
33 #include "networkd-manager.h"
34 #include "wireguard-netlink.h"
36 static void resolve_endpoints(NetDev
*netdev
);
38 static WireguardPeer
*wireguard_peer_new(Wireguard
*w
, unsigned section
) {
43 if (w
->last_peer_section
== section
&& w
->peers
)
46 peer
= new0(WireguardPeer
, 1);
49 peer
->flags
= WGPEER_F_REPLACE_ALLOWEDIPS
;
51 LIST_PREPEND(peers
, w
->peers
, peer
);
52 w
->last_peer_section
= section
;
57 static int set_wireguard_interface(NetDev
*netdev
) {
60 WireguardPeer
*peer
, *peer_start
;
61 WireguardIPmask
*mask
, *mask_start
= NULL
;
62 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
67 w
= WIREGUARD(netdev
);
70 peer_start
= w
->peers
;
73 message
= sd_netlink_message_unref(message
);
75 r
= sd_genl_message_new(netdev
->manager
->genl
, SD_GENL_WIREGUARD
, WG_CMD_SET_DEVICE
, &message
);
77 return log_netdev_error_errno(netdev
, r
, "Failed to allocate generic netlink message: %m");
79 r
= sd_netlink_message_append_string(message
, WGDEVICE_A_IFNAME
, netdev
->ifname
);
81 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard interface name: %m");
83 if (peer_start
== w
->peers
) {
84 r
= sd_netlink_message_append_data(message
, WGDEVICE_A_PRIVATE_KEY
, &w
->private_key
, WG_KEY_LEN
);
86 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard private key: %m");
88 r
= sd_netlink_message_append_u16(message
, WGDEVICE_A_LISTEN_PORT
, w
->port
);
90 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard port: %m");
92 r
= sd_netlink_message_append_u32(message
, WGDEVICE_A_FWMARK
, w
->fwmark
);
94 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard fwmark: %m");
96 r
= sd_netlink_message_append_u32(message
, WGDEVICE_A_FLAGS
, w
->flags
);
98 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard flags: %m");
101 r
= sd_netlink_message_open_container(message
, WGDEVICE_A_PEERS
);
103 return log_netdev_error_errno(netdev
, r
, "Could not append wireguard peer attributes: %m");
107 LIST_FOREACH(peers
, peer
, peer_start
) {
108 r
= sd_netlink_message_open_array(message
, ++i
);
112 r
= sd_netlink_message_append_data(message
, WGPEER_A_PUBLIC_KEY
, &peer
->public_key
, sizeof(peer
->public_key
));
117 r
= sd_netlink_message_append_data(message
, WGPEER_A_PRESHARED_KEY
, &peer
->preshared_key
, WG_KEY_LEN
);
121 r
= sd_netlink_message_append_u32(message
, WGPEER_A_FLAGS
, peer
->flags
);
125 r
= sd_netlink_message_append_u32(message
, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL
, peer
->persistent_keepalive_interval
);
129 if (peer
->endpoint
.sa
.sa_family
== AF_INET
) {
130 r
= sd_netlink_message_append_data(message
, WGPEER_A_ENDPOINT
, &peer
->endpoint
.in
, sizeof(peer
->endpoint
.in
));
133 } else if (peer
->endpoint
.sa
.sa_family
== AF_INET6
) {
134 r
= sd_netlink_message_append_data(message
, WGPEER_A_ENDPOINT
, &peer
->endpoint
.in6
, sizeof(peer
->endpoint
.in6
));
139 mask_start
= peer
->ipmasks
;
142 r
= sd_netlink_message_open_container(message
, WGPEER_A_ALLOWEDIPS
);
148 LIST_FOREACH(ipmasks
, mask
, mask_start
) {
149 r
= sd_netlink_message_open_array(message
, ++j
);
153 r
= sd_netlink_message_append_u16(message
, WGALLOWEDIP_A_FAMILY
, mask
->family
);
157 if (mask
->family
== AF_INET
) {
158 r
= sd_netlink_message_append_in_addr(message
, WGALLOWEDIP_A_IPADDR
, &mask
->ip
.in
);
161 } else if (mask
->family
== AF_INET6
) {
162 r
= sd_netlink_message_append_in6_addr(message
, WGALLOWEDIP_A_IPADDR
, &mask
->ip
.in6
);
167 r
= sd_netlink_message_append_u8(message
, WGALLOWEDIP_A_CIDR_MASK
, mask
->cidr
);
171 r
= sd_netlink_message_close_container(message
);
173 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard allowed ip: %m");
177 r
= sd_netlink_message_cancel_array(message
);
179 return log_netdev_error_errno(netdev
, r
, "Could not cancel wireguard allowed ip message attribute: %m");
181 r
= sd_netlink_message_close_container(message
);
183 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard allowed ip: %m");
185 r
= sd_netlink_message_close_container(message
);
187 return log_netdev_error_errno(netdev
, r
, "Could not add wireguard peer: %m");
191 if (peer_start
&& !mask_start
) {
192 r
= sd_netlink_message_cancel_array(message
);
194 return log_netdev_error_errno(netdev
, r
, "Could not cancel wireguard peers: %m");
197 r
= sd_netlink_message_close_container(message
);
199 return log_netdev_error_errno(netdev
, r
, "Could not close wireguard container: %m");
201 r
= sd_netlink_send(netdev
->manager
->genl
, message
, &serial
);
203 return log_netdev_error_errno(netdev
, r
, "Could not set wireguard device: %m");
205 } while (peer
|| mask_start
);
210 static WireguardEndpoint
* wireguard_endpoint_free(WireguardEndpoint
*e
) {
213 netdev_unref(e
->netdev
);
214 e
->host
= mfree(e
->host
);
215 e
->port
= mfree(e
->port
);
219 DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint
*, wireguard_endpoint_free
);
221 static int on_resolve_retry(sd_event_source
*s
, usec_t usec
, void *userdata
) {
222 NetDev
*netdev
= userdata
;
226 w
= WIREGUARD(netdev
);
229 w
->resolve_retry_event_source
= sd_event_source_unref(w
->resolve_retry_event_source
);
231 w
->unresolved_endpoints
= TAKE_PTR(w
->failed_endpoints
);
233 resolve_endpoints(netdev
);
239 * Given the number of retries this function will return will an exponential
240 * increasing time in milliseconds to wait starting at 200ms and capped at 25 seconds.
242 static int exponential_backoff_milliseconds(unsigned n_retries
) {
243 return (2 << MAX(n_retries
, 7U)) * 100 * USEC_PER_MSEC
;
246 static int wireguard_resolve_handler(sd_resolve_query
*q
,
248 const struct addrinfo
*ai
,
252 _cleanup_(wireguard_endpoint_freep
) WireguardEndpoint
*e
;
260 w
= WIREGUARD(netdev
);
263 w
->resolve_query
= sd_resolve_query_unref(w
->resolve_query
);
266 log_netdev_error(netdev
, "Failed to resolve host '%s:%s': %s", e
->host
, e
->port
, gai_strerror(ret
));
267 LIST_PREPEND(endpoints
, w
->failed_endpoints
, e
);
269 } else if ((ai
->ai_family
== AF_INET
&& ai
->ai_addrlen
== sizeof(struct sockaddr_in
)) ||
270 (ai
->ai_family
== AF_INET6
&& ai
->ai_addrlen
== sizeof(struct sockaddr_in6
)))
271 memcpy(&e
->peer
->endpoint
, ai
->ai_addr
, ai
->ai_addrlen
);
273 log_netdev_error(netdev
, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e
->host
, e
->port
);
275 if (w
->unresolved_endpoints
) {
276 resolve_endpoints(netdev
);
280 set_wireguard_interface(netdev
);
281 if (w
->failed_endpoints
) {
283 r
= sd_event_add_time(netdev
->manager
->event
,
284 &w
->resolve_retry_event_source
,
286 now(CLOCK_MONOTONIC
) + exponential_backoff_milliseconds(w
->n_retries
),
291 log_netdev_warning_errno(netdev
, r
, "Could not arm resolve retry handler: %m");
297 static void resolve_endpoints(NetDev
*netdev
) {
300 WireguardEndpoint
*endpoint
;
301 static const struct addrinfo hints
= {
302 .ai_family
= AF_UNSPEC
,
303 .ai_socktype
= SOCK_DGRAM
,
304 .ai_protocol
= IPPROTO_UDP
308 w
= WIREGUARD(netdev
);
311 LIST_FOREACH(endpoints
, endpoint
, w
->unresolved_endpoints
) {
312 r
= sd_resolve_getaddrinfo(netdev
->manager
->resolve
,
317 wireguard_resolve_handler
,
323 LIST_REMOVE(endpoints
, w
->unresolved_endpoints
, endpoint
);
326 log_netdev_error_errno(netdev
, r
, "Failed create resolver: %m");
331 static int netdev_wireguard_post_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
335 w
= WIREGUARD(netdev
);
338 set_wireguard_interface(netdev
);
339 resolve_endpoints(netdev
);
343 int config_parse_wireguard_listen_port(const char *unit
,
344 const char *filename
,
347 unsigned section_line
,
360 if (!streq(rvalue
, "auto")) {
361 r
= parse_ip_port(rvalue
, &port
);
363 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid port specification, ignoring assignment: %s", rvalue
);
371 static int parse_wireguard_key(const char *unit
,
372 const char *filename
,
375 unsigned section_line
,
381 _cleanup_free_
void *key
= NULL
;
389 r
= unbase64mem(rvalue
, strlen(rvalue
), &key
, &len
);
391 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue
);
394 if (len
!= WG_KEY_LEN
) {
395 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
396 "Wireguard key is too short, ignoring assignment: %s", rvalue
);
400 memcpy(userdata
, key
, WG_KEY_LEN
);
404 int config_parse_wireguard_private_key(const char *unit
,
405 const char *filename
,
408 unsigned section_line
,
422 return parse_wireguard_key(unit
,
435 int config_parse_wireguard_preshared_key(const char *unit
,
436 const char *filename
,
439 unsigned section_line
,
454 peer
= wireguard_peer_new(w
, section_line
);
458 return parse_wireguard_key(unit
,
467 peer
->preshared_key
);
471 int config_parse_wireguard_public_key(const char *unit
,
472 const char *filename
,
475 unsigned section_line
,
490 peer
= wireguard_peer_new(w
, section_line
);
494 return parse_wireguard_key(unit
,
506 int config_parse_wireguard_allowed_ips(const char *unit
,
507 const char *filename
,
510 unsigned section_line
,
516 union in_addr_union addr
;
517 unsigned char prefixlen
;
521 WireguardIPmask
*ipmask
;
528 peer
= wireguard_peer_new(w
, section_line
);
533 _cleanup_free_
char *word
= NULL
;
535 r
= extract_first_word(&rvalue
, &word
, "," WHITESPACE
, 0);
541 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to split allowed ips \"%s\" option: %m", rvalue
);
545 r
= in_addr_prefix_from_string_auto(word
, &family
, &addr
, &prefixlen
);
547 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Network address is invalid, ignoring assignment: %s", word
);
551 ipmask
= new0(WireguardIPmask
, 1);
554 ipmask
->family
= family
;
555 ipmask
->ip
.in6
= addr
.in6
;
556 ipmask
->cidr
= prefixlen
;
558 LIST_PREPEND(ipmasks
, peer
->ipmasks
, ipmask
);
564 int config_parse_wireguard_endpoint(const char *unit
,
565 const char *filename
,
568 unsigned section_line
,
577 const char *begin
, *end
= NULL
;
578 _cleanup_free_
char *host
= NULL
, *port
= NULL
;
579 _cleanup_(wireguard_endpoint_freep
) WireguardEndpoint
*endpoint
= NULL
;
588 peer
= wireguard_peer_new(w
, section_line
);
592 endpoint
= new0(WireguardEndpoint
, 1);
596 if (rvalue
[0] == '[') {
598 end
= strchr(rvalue
, ']');
600 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unable to find matching brace of endpoint, ignoring assignment: %s", rvalue
);
605 if (*end
!= ':' || !*(end
+ 1)) {
606 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unable to find port of endpoint: %s", rvalue
);
612 end
= strrchr(rvalue
, ':');
613 if (!end
|| !*(end
+ 1)) {
614 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unable to find port of endpoint: %s", rvalue
);
621 host
= strndup(begin
, len
);
629 endpoint
->peer
= peer
;
630 endpoint
->host
= host
;
631 endpoint
->port
= port
;
632 endpoint
->netdev
= netdev_ref(data
);
633 LIST_PREPEND(endpoints
, w
->unresolved_endpoints
, endpoint
);
643 int config_parse_wireguard_keepalive(const char *unit
,
644 const char *filename
,
647 unsigned section_line
,
654 uint16_t keepalive
= 0;
665 peer
= wireguard_peer_new(w
, section_line
);
669 if (streq(rvalue
, "off"))
672 r
= safe_atou16(rvalue
, &keepalive
);
674 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue
);
677 peer
->persistent_keepalive_interval
= keepalive
;
681 static void wireguard_init(NetDev
*netdev
) {
686 w
= WIREGUARD(netdev
);
690 w
->flags
= WGDEVICE_F_REPLACE_PEERS
;
693 static void wireguard_done(NetDev
*netdev
) {
696 WireguardIPmask
*mask
;
699 w
= WIREGUARD(netdev
);
700 assert(!w
->unresolved_endpoints
);
701 w
->resolve_retry_event_source
= sd_event_source_unref(w
->resolve_retry_event_source
);
703 while ((peer
= w
->peers
)) {
704 LIST_REMOVE(peers
, w
->peers
, peer
);
705 while ((mask
= peer
->ipmasks
)) {
706 LIST_REMOVE(ipmasks
, peer
->ipmasks
, mask
);
713 const NetDevVTable wireguard_vtable
= {
714 .object_size
= sizeof(Wireguard
),
715 .sections
= "Match\0NetDev\0WireGuard\0WireGuardPeer\0",
716 .post_create
= netdev_wireguard_post_create
,
717 .init
= wireguard_init
,
718 .done
= wireguard_done
,
719 .create_type
= NETDEV_CREATE_INDEPENDENT
,