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
= TAKE_PTR(peer
);
630 endpoint
->host
= TAKE_PTR(host
);
631 endpoint
->port
= TAKE_PTR(port
);
632 endpoint
->netdev
= netdev_ref(data
);
633 LIST_PREPEND(endpoints
, w
->unresolved_endpoints
, endpoint
);
639 int config_parse_wireguard_keepalive(const char *unit
,
640 const char *filename
,
643 unsigned section_line
,
650 uint16_t keepalive
= 0;
661 peer
= wireguard_peer_new(w
, section_line
);
665 if (streq(rvalue
, "off"))
668 r
= safe_atou16(rvalue
, &keepalive
);
670 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue
);
673 peer
->persistent_keepalive_interval
= keepalive
;
677 static void wireguard_init(NetDev
*netdev
) {
682 w
= WIREGUARD(netdev
);
686 w
->flags
= WGDEVICE_F_REPLACE_PEERS
;
689 static void wireguard_done(NetDev
*netdev
) {
692 WireguardIPmask
*mask
;
695 w
= WIREGUARD(netdev
);
696 assert(!w
->unresolved_endpoints
);
697 w
->resolve_retry_event_source
= sd_event_source_unref(w
->resolve_retry_event_source
);
699 while ((peer
= w
->peers
)) {
700 LIST_REMOVE(peers
, w
->peers
, peer
);
701 while ((mask
= peer
->ipmasks
)) {
702 LIST_REMOVE(ipmasks
, peer
->ipmasks
, mask
);
709 const NetDevVTable wireguard_vtable
= {
710 .object_size
= sizeof(Wireguard
),
711 .sections
= "Match\0NetDev\0WireGuard\0WireGuardPeer\0",
712 .post_create
= netdev_wireguard_post_create
,
713 .init
= wireguard_init
,
714 .done
= wireguard_done
,
715 .create_type
= NETDEV_CREATE_INDEPENDENT
,