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;
62 static int parse_key(const char *str, wg_key key)
67 buf = g_base64_decode(str, &len);
80 static int parse_allowed_ips(const char *allowed_ips, wg_peer *peer)
82 struct wg_allowedip *curaip, *allowedip;
83 char buf[INET6_ADDRSTRLEN];
84 char **tokens, **toks;
89 tokens = g_strsplit(allowed_ips, ", ", -1);
90 for (i = 0; tokens[i]; i++) {
91 toks = g_strsplit(tokens[i], "/", -1);
92 if (g_strv_length(toks) != 2) {
93 DBG("Ignore AllowedIPs value %s", tokens[i]);
98 allowedip = g_malloc0(sizeof(*allowedip));
100 if (inet_pton(AF_INET, toks[0], buf) == 1) {
101 allowedip->family = AF_INET;
102 memcpy(&allowedip->ip4, buf, sizeof(allowedip->ip4));
103 } else if (inet_pton(AF_INET6, toks[0], buf) == 1) {
104 allowedip->family = AF_INET6;
105 memcpy(&allowedip->ip6, buf, sizeof(allowedip->ip6));
107 DBG("Ignore AllowedIPs value %s", tokens[i]);
113 allowedip->cidr = g_ascii_strtoull(toks[1], &send, 10);
116 peer->first_allowedip = allowedip;
118 curaip->next_allowedip = allowedip;
123 peer->last_allowedip = curaip;
129 static int parse_endpoint(const char *host, const char *port, struct sockaddr *addr)
131 struct addrinfo hints;
132 struct addrinfo *result, *rp;
135 memset(&hints, 0, sizeof(struct addrinfo));
136 hints.ai_family = AF_UNSPEC;
137 hints.ai_socktype = SOCK_DGRAM;
139 hints.ai_protocol = 0;
141 if (getaddrinfo(host, port, &hints, &result) < 0) {
142 DBG("Failed to resolve host address");
146 for (rp = result; rp; rp = rp->ai_next) {
147 sk = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
150 if (connect(sk, rp->ai_addr, rp->ai_addrlen) != -1) {
160 freeaddrinfo(result);
164 memcpy(addr, rp->ai_addr, rp->ai_addrlen);
165 freeaddrinfo(result);
170 static int parse_address(const char *address, const char *gateway,
171 struct connman_ipaddress **ipaddress)
173 char buf[INET6_ADDRSTRLEN];
174 unsigned char prefixlen;
179 tokens = g_strsplit(address, "/", -1);
180 if (g_strv_length(tokens) != 2) {
185 prefixlen = g_ascii_strtoull(tokens[1], &end, 10);
187 if (inet_pton(AF_INET, tokens[0], buf) == 1) {
188 netmask = g_strdup_printf("%d.%d.%d.%d",
189 ((0xffffffff << (32 - prefixlen)) >> 24) & 0xff,
190 ((0xffffffff << (32 - prefixlen)) >> 16) & 0xff,
191 ((0xffffffff << (32 - prefixlen)) >> 8) & 0xff,
192 ((0xffffffff << (32 - prefixlen)) >> 0) & 0xff);
194 *ipaddress = connman_ipaddress_alloc(AF_INET);
195 err = connman_ipaddress_set_ipv4(*ipaddress, tokens[0],
198 } else if (inet_pton(AF_INET6, tokens[0], buf) == 1) {
199 *ipaddress = connman_ipaddress_alloc(AF_INET6);
200 err = connman_ipaddress_set_ipv6(*ipaddress, tokens[0],
203 DBG("Invalid Wireguard.Address value");
209 connman_ipaddress_free(*ipaddress);
219 static void ifname_check_cb(int index, void *user_data)
221 struct ifname_data *data = (struct ifname_data *)user_data;
224 ifname = connman_inet_ifname(index);
226 if (!g_strcmp0(ifname, data->ifname))
230 static char *get_ifname(void)
232 struct ifname_data data;
235 for (i = 0; i < 256; i++) {
236 data.ifname = g_strdup_printf("wg%d", i);
238 __vpn_ipconfig_foreach(ifname_check_cb, &data);
249 static bool sockaddr_cmp_addr(struct sockaddr *a, struct sockaddr *b)
251 if (a->sa_family != b->sa_family)
254 if (a->sa_family == AF_INET) {
255 struct sockaddr_in *a4 = (struct sockaddr_in *)a;
256 struct sockaddr_in *b4 = (struct sockaddr_in *)b;
258 return !memcmp(a4, b4, sizeof(struct sockaddr_in));
259 } else if (a->sa_family == AF_INET6) {
260 struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)a;
261 struct sockaddr_in6 *b6 = (struct sockaddr_in6 *)b;
263 return !memcmp(a6->sin6_addr.s6_addr,
264 b6->sin6_addr.s6_addr,
265 sizeof(a6->sin6_addr.s6_addr));
271 static gboolean wg_dns_reresolve_cb(gpointer user_data)
273 struct wireguard_info *info = user_data;
275 struct sockaddr addr;
279 err = parse_endpoint(info->endpoint_fqdn,
284 if (sockaddr_cmp_addr(&addr, &info->peer.endpoint.addr))
287 if (addr.sa_family == AF_INET)
288 memcpy(&info->peer.endpoint.addr, &addr,
289 sizeof(info->peer.endpoint.addr4));
291 memcpy(&info->peer.endpoint.addr, &addr,
292 sizeof(info->peer.endpoint.addr6));
294 DBG("Endpoint address has changed, udpate WireGuard device");
295 err = wg_set_device(&info->device);
297 DBG("Failed to update Endpoint address for WireGuard device %s",
303 static int wg_connect(struct vpn_provider *provider,
304 struct connman_task *task, const char *if_name,
305 vpn_provider_connect_cb_t cb,
306 const char *dbus_sender, void *user_data)
308 struct connman_ipaddress *ipaddress = NULL;
309 struct wireguard_info *info;
310 const char *option, *gateway;
314 info = g_malloc0(sizeof(struct wireguard_info));
315 info->peer.flags = WGPEER_HAS_PUBLIC_KEY | WGPEER_REPLACE_ALLOWEDIPS;
316 info->device.flags = WGDEVICE_HAS_PRIVATE_KEY;
317 info->device.first_peer = &info->peer;
318 info->device.last_peer = &info->peer;
320 vpn_provider_set_plugin_data(provider, info);
322 option = vpn_provider_get_string(provider, "WireGuard.ListenPort");
325 info->device.listen_port = g_ascii_strtoull(option, &end, 10);
326 info->device.flags |= WGDEVICE_HAS_LISTEN_PORT;
329 option = vpn_provider_get_string(provider, "WireGuard.DNS");
331 err = vpn_provider_set_nameservers(provider, option);
336 option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
338 DBG("WireGuard.PrivateKey is missing");
341 err = parse_key(option, info->device.private_key);
345 option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
347 DBG("WireGuard.PublicKey is missing");
350 err = parse_key(option, info->peer.public_key);
354 option = vpn_provider_get_string(provider, "WireGuard.PresharedKey");
356 info->peer.flags |= WGPEER_HAS_PRESHARED_KEY;
357 err = parse_key(option, info->peer.preshared_key);
362 option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
364 DBG("WireGuard.AllowedIPs is missing");
367 err = parse_allowed_ips(option, &info->peer);
371 option = vpn_provider_get_string(provider,
372 "WireGuard.PersistentKeepalive");
375 info->peer.persistent_keepalive_interval =
376 g_ascii_strtoull(option, &end, 10);
377 info->peer.flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
380 option = vpn_provider_get_string(provider, "WireGuard.EndpointPort");
384 gateway = vpn_provider_get_string(provider, "Host");
385 err = parse_endpoint(gateway, option, &info->peer.endpoint.addr);
389 info->endpoint_fqdn = g_strdup(gateway);
390 info->port = g_strdup(option);
392 option = vpn_provider_get_string(provider, "WireGuard.Address");
394 DBG("Missing WireGuard.Address configuration");
397 err = parse_address(option, gateway, &ipaddress);
401 ifname = get_ifname();
403 DBG("Failed to find an usable device name");
407 stpncpy(info->device.name, ifname, sizeof(info->device.name));
410 err = wg_add_device(info->device.name);
412 DBG("Failed to creating WireGuard device %s", info->device.name);
416 err = wg_set_device(&info->device);
418 DBG("Failed to configure WireGuard device %s", info->device.name);
419 wg_del_device(info->device.name);
422 vpn_set_ifname(provider, info->device.name);
424 vpn_provider_set_ipaddress(provider, ipaddress);
428 cb(provider, user_data, err);
430 connman_ipaddress_free(ipaddress);
434 g_timeout_add_seconds(DNS_RERESOLVE_TIMEOUT,
435 wg_dns_reresolve_cb, info);
440 static void wg_disconnect(struct vpn_provider *provider)
442 struct wireguard_info *info;
444 info = vpn_provider_get_plugin_data(provider);
448 if (info->reresolve_id > 0)
449 g_source_remove(info->reresolve_id);
451 vpn_provider_set_plugin_data(provider, NULL);
453 wg_del_device(info->device.name);
455 g_free(info->endpoint_fqdn);
460 static struct vpn_driver vpn_driver = {
461 .flags = VPN_FLAG_NO_TUN | VPN_FLAG_NO_DAEMON,
462 .connect = wg_connect,
463 .disconnect = wg_disconnect,
466 static int wg_init(void)
468 return vpn_register("wireguard", &vpn_driver, NULL);
471 static void wg_exit(void)
473 vpn_unregister("wireguard");
476 CONNMAN_PLUGIN_DEFINE(wireguard, "WireGuard VPN plugin", VERSION,
477 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wg_init, wg_exit)