4 * Copyright (C) 2019 Daniel Wagner. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <arpa/inet.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
36 #define CONNMAN_API_SUBJECT_TO_CHANGE
37 #include <connman/plugin.h>
38 #include <connman/log.h>
39 #include <connman/task.h>
40 #include <connman/ipconfig.h>
41 #include <connman/inet.h>
42 #include <connman/dbus.h>
43 #include <connman/setting.h>
44 #include <connman/vpn-dbus.h>
46 #include "../vpn-provider.h"
50 #include "wireguard.h"
52 #define DNS_RERESOLVE_TIMEOUT 20
54 struct wireguard_info {
55 struct wg_device device;
65 struct sockaddr_in sin;
66 struct sockaddr_in6 sin6;
70 static int parse_key(const char *str, wg_key key)
75 buf = g_base64_decode(str, &len);
88 static int parse_allowed_ips(const char *allowed_ips, wg_peer *peer)
90 struct wg_allowedip *curaip, *allowedip;
91 char buf[INET6_ADDRSTRLEN];
92 char **tokens, **toks;
97 tokens = g_strsplit(allowed_ips, ", ", -1);
98 for (i = 0; tokens[i]; i++) {
99 toks = g_strsplit(tokens[i], "/", -1);
100 if (g_strv_length(toks) != 2) {
101 DBG("Ignore AllowedIPs value %s", tokens[i]);
106 allowedip = g_malloc0(sizeof(*allowedip));
108 if (inet_pton(AF_INET, toks[0], buf) == 1) {
109 allowedip->family = AF_INET;
110 memcpy(&allowedip->ip4, buf, sizeof(allowedip->ip4));
111 } else if (inet_pton(AF_INET6, toks[0], buf) == 1) {
112 allowedip->family = AF_INET6;
113 memcpy(&allowedip->ip6, buf, sizeof(allowedip->ip6));
115 DBG("Ignore AllowedIPs value %s", tokens[i]);
121 allowedip->cidr = g_ascii_strtoull(toks[1], &send, 10);
124 peer->first_allowedip = allowedip;
126 curaip->next_allowedip = allowedip;
131 peer->last_allowedip = curaip;
137 static int parse_endpoint(const char *host, const char *port, struct sockaddr_u *addr)
139 struct addrinfo hints;
140 struct addrinfo *result, *rp;
143 memset(&hints, 0, sizeof(struct addrinfo));
144 hints.ai_family = AF_UNSPEC;
145 hints.ai_socktype = SOCK_DGRAM;
147 hints.ai_protocol = 0;
149 if (getaddrinfo(host, port, &hints, &result) < 0) {
150 DBG("Failed to resolve host address");
154 for (rp = result; rp; rp = rp->ai_next) {
155 sk = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
158 if (connect(sk, rp->ai_addr, rp->ai_addrlen) != -1) {
168 freeaddrinfo(result);
172 memcpy(addr, rp->ai_addr, rp->ai_addrlen);
173 freeaddrinfo(result);
178 static int parse_address(const char *address, const char *gateway,
179 struct connman_ipaddress **ipaddress)
181 char buf[INET6_ADDRSTRLEN];
182 unsigned char prefixlen;
187 tokens = g_strsplit(address, "/", -1);
188 if (g_strv_length(tokens) != 2) {
193 prefixlen = g_ascii_strtoull(tokens[1], &end, 10);
195 if (inet_pton(AF_INET, tokens[0], buf) == 1) {
196 netmask = g_strdup_printf("%d.%d.%d.%d",
197 ((0xffffffff << (32 - prefixlen)) >> 24) & 0xff,
198 ((0xffffffff << (32 - prefixlen)) >> 16) & 0xff,
199 ((0xffffffff << (32 - prefixlen)) >> 8) & 0xff,
200 ((0xffffffff << (32 - prefixlen)) >> 0) & 0xff);
202 *ipaddress = connman_ipaddress_alloc(AF_INET);
203 err = connman_ipaddress_set_ipv4(*ipaddress, tokens[0],
206 } else if (inet_pton(AF_INET6, tokens[0], buf) == 1) {
207 *ipaddress = connman_ipaddress_alloc(AF_INET6);
208 err = connman_ipaddress_set_ipv6(*ipaddress, tokens[0],
211 DBG("Invalid Wireguard.Address value");
215 connman_ipaddress_set_p2p(*ipaddress, true);
219 connman_ipaddress_free(*ipaddress);
229 static void ifname_check_cb(int index, void *user_data)
231 struct ifname_data *data = (struct ifname_data *)user_data;
234 ifname = connman_inet_ifname(index);
236 if (!g_strcmp0(ifname, data->ifname))
240 static char *get_ifname(void)
242 struct ifname_data data;
245 for (i = 0; i < 256; i++) {
246 data.ifname = g_strdup_printf("wg%d", i);
248 vpn_ipconfig_foreach(ifname_check_cb, &data);
259 static bool sockaddr_cmp_addr(struct sockaddr_u *a, struct sockaddr_u *b)
261 if (a->sa.sa_family != b->sa.sa_family)
264 if (a->sa.sa_family == AF_INET)
265 return !memcmp(&a->sin, &b->sin, sizeof(struct sockaddr_in));
266 else if (a->sa.sa_family == AF_INET6)
267 return !memcmp(a->sin6.sin6_addr.s6_addr,
268 b->sin6.sin6_addr.s6_addr,
269 sizeof(a->sin6.sin6_addr.s6_addr));
274 static gboolean wg_dns_reresolve_cb(gpointer user_data)
276 struct wireguard_info *info = user_data;
277 struct sockaddr_u addr;
282 err = parse_endpoint(info->endpoint_fqdn,
287 if (sockaddr_cmp_addr(&addr,
288 (struct sockaddr_u *)&info->peer.endpoint.addr))
291 if (addr.sa.sa_family == AF_INET)
292 memcpy(&info->peer.endpoint.addr, &addr.sin,
293 sizeof(info->peer.endpoint.addr4));
295 memcpy(&info->peer.endpoint.addr, &addr.sin6,
296 sizeof(info->peer.endpoint.addr6));
298 DBG("Endpoint address has changed, udpate WireGuard device");
299 err = wg_set_device(&info->device);
301 DBG("Failed to update Endpoint address for WireGuard device %s",
307 static int wg_connect(struct vpn_provider *provider,
308 struct connman_task *task, const char *if_name,
309 vpn_provider_connect_cb_t cb,
310 const char *dbus_sender, void *user_data)
312 struct connman_ipaddress *ipaddress = NULL;
313 struct wireguard_info *info;
314 const char *option, *gateway;
318 info = g_malloc0(sizeof(struct wireguard_info));
319 info->peer.flags = WGPEER_HAS_PUBLIC_KEY | WGPEER_REPLACE_ALLOWEDIPS;
320 info->device.flags = WGDEVICE_HAS_PRIVATE_KEY;
321 info->device.first_peer = &info->peer;
322 info->device.last_peer = &info->peer;
324 vpn_provider_set_plugin_data(provider, info);
326 option = vpn_provider_get_string(provider, "WireGuard.ListenPort");
329 info->device.listen_port = g_ascii_strtoull(option, &end, 10);
330 info->device.flags |= WGDEVICE_HAS_LISTEN_PORT;
333 option = vpn_provider_get_string(provider, "WireGuard.DNS");
335 err = vpn_provider_set_nameservers(provider, option);
340 option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
342 DBG("WireGuard.PrivateKey is missing");
345 err = parse_key(option, info->device.private_key);
349 option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
351 DBG("WireGuard.PublicKey is missing");
354 err = parse_key(option, info->peer.public_key);
358 option = vpn_provider_get_string(provider, "WireGuard.PresharedKey");
360 info->peer.flags |= WGPEER_HAS_PRESHARED_KEY;
361 err = parse_key(option, info->peer.preshared_key);
366 option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
368 DBG("WireGuard.AllowedIPs is missing");
371 err = parse_allowed_ips(option, &info->peer);
375 option = vpn_provider_get_string(provider,
376 "WireGuard.PersistentKeepalive");
379 info->peer.persistent_keepalive_interval =
380 g_ascii_strtoull(option, &end, 10);
381 info->peer.flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
384 option = vpn_provider_get_string(provider, "WireGuard.EndpointPort");
388 gateway = vpn_provider_get_string(provider, "Host");
389 err = parse_endpoint(gateway, option,
390 (struct sockaddr_u *)&info->peer.endpoint.addr);
394 info->endpoint_fqdn = g_strdup(gateway);
395 info->port = g_strdup(option);
397 option = vpn_provider_get_string(provider, "WireGuard.Address");
399 DBG("Missing WireGuard.Address configuration");
402 err = parse_address(option, gateway, &ipaddress);
406 ifname = get_ifname();
408 DBG("Failed to find an usable device name");
412 stpncpy(info->device.name, ifname, sizeof(info->device.name) - 1);
415 err = wg_add_device(info->device.name);
417 DBG("Failed to creating WireGuard device %s", info->device.name);
421 err = wg_set_device(&info->device);
423 DBG("Failed to configure WireGuard device %s", info->device.name);
424 wg_del_device(info->device.name);
427 vpn_set_ifname(provider, info->device.name);
429 vpn_provider_set_ipaddress(provider, ipaddress);
433 cb(provider, user_data, err);
435 connman_ipaddress_free(ipaddress);
439 g_timeout_add_seconds(DNS_RERESOLVE_TIMEOUT,
440 wg_dns_reresolve_cb, info);
445 static void wg_disconnect(struct vpn_provider *provider)
447 struct wireguard_info *info;
449 info = vpn_provider_get_plugin_data(provider);
453 if (info->reresolve_id > 0)
454 g_source_remove(info->reresolve_id);
456 vpn_provider_set_plugin_data(provider, NULL);
458 wg_del_device(info->device.name);
460 g_free(info->endpoint_fqdn);
465 static struct vpn_driver vpn_driver = {
466 .flags = VPN_FLAG_NO_TUN | VPN_FLAG_NO_DAEMON,
467 .connect = wg_connect,
468 .disconnect = wg_disconnect,
471 static int wg_init(void)
473 return vpn_register("wireguard", &vpn_driver, NULL);
476 static void wg_exit(void)
478 vpn_unregister("wireguard");
481 CONNMAN_PLUGIN_DEFINE(wireguard, "WireGuard VPN plugin", VERSION,
482 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wg_init, wg_exit)