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");
217 connman_ipaddress_free(*ipaddress);
227 static void ifname_check_cb(int index, void *user_data)
229 struct ifname_data *data = (struct ifname_data *)user_data;
232 ifname = connman_inet_ifname(index);
234 if (!g_strcmp0(ifname, data->ifname))
238 static char *get_ifname(void)
240 struct ifname_data data;
243 for (i = 0; i < 256; i++) {
244 data.ifname = g_strdup_printf("wg%d", i);
246 vpn_ipconfig_foreach(ifname_check_cb, &data);
257 static bool sockaddr_cmp_addr(struct sockaddr_u *a, struct sockaddr_u *b)
259 if (a->sa.sa_family != b->sa.sa_family)
262 if (a->sa.sa_family == AF_INET)
263 return !memcmp(&a->sin, &b->sin, sizeof(struct sockaddr_in));
264 else if (a->sa.sa_family == AF_INET6)
265 return !memcmp(a->sin6.sin6_addr.s6_addr,
266 b->sin6.sin6_addr.s6_addr,
267 sizeof(a->sin6.sin6_addr.s6_addr));
272 static gboolean wg_dns_reresolve_cb(gpointer user_data)
274 struct wireguard_info *info = user_data;
275 struct sockaddr_u addr;
280 err = parse_endpoint(info->endpoint_fqdn,
285 if (sockaddr_cmp_addr(&addr,
286 (struct sockaddr_u *)&info->peer.endpoint.addr))
289 if (addr.sa.sa_family == AF_INET)
290 memcpy(&info->peer.endpoint.addr, &addr.sin,
291 sizeof(info->peer.endpoint.addr4));
293 memcpy(&info->peer.endpoint.addr, &addr.sin6,
294 sizeof(info->peer.endpoint.addr6));
296 DBG("Endpoint address has changed, udpate WireGuard device");
297 err = wg_set_device(&info->device);
299 DBG("Failed to update Endpoint address for WireGuard device %s",
305 static int wg_connect(struct vpn_provider *provider,
306 struct connman_task *task, const char *if_name,
307 vpn_provider_connect_cb_t cb,
308 const char *dbus_sender, void *user_data)
310 struct connman_ipaddress *ipaddress = NULL;
311 struct wireguard_info *info;
312 const char *option, *gateway;
316 info = g_malloc0(sizeof(struct wireguard_info));
317 info->peer.flags = WGPEER_HAS_PUBLIC_KEY | WGPEER_REPLACE_ALLOWEDIPS;
318 info->device.flags = WGDEVICE_HAS_PRIVATE_KEY;
319 info->device.first_peer = &info->peer;
320 info->device.last_peer = &info->peer;
322 vpn_provider_set_plugin_data(provider, info);
324 option = vpn_provider_get_string(provider, "WireGuard.ListenPort");
327 info->device.listen_port = g_ascii_strtoull(option, &end, 10);
328 info->device.flags |= WGDEVICE_HAS_LISTEN_PORT;
331 option = vpn_provider_get_string(provider, "WireGuard.DNS");
333 err = vpn_provider_set_nameservers(provider, option);
338 option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
340 DBG("WireGuard.PrivateKey is missing");
343 err = parse_key(option, info->device.private_key);
347 option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
349 DBG("WireGuard.PublicKey is missing");
352 err = parse_key(option, info->peer.public_key);
356 option = vpn_provider_get_string(provider, "WireGuard.PresharedKey");
358 info->peer.flags |= WGPEER_HAS_PRESHARED_KEY;
359 err = parse_key(option, info->peer.preshared_key);
364 option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
366 DBG("WireGuard.AllowedIPs is missing");
369 err = parse_allowed_ips(option, &info->peer);
373 option = vpn_provider_get_string(provider,
374 "WireGuard.PersistentKeepalive");
377 info->peer.persistent_keepalive_interval =
378 g_ascii_strtoull(option, &end, 10);
379 info->peer.flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
382 option = vpn_provider_get_string(provider, "WireGuard.EndpointPort");
386 gateway = vpn_provider_get_string(provider, "Host");
387 err = parse_endpoint(gateway, option,
388 (struct sockaddr_u *)&info->peer.endpoint.addr);
392 info->endpoint_fqdn = g_strdup(gateway);
393 info->port = g_strdup(option);
395 option = vpn_provider_get_string(provider, "WireGuard.Address");
397 DBG("Missing WireGuard.Address configuration");
400 err = parse_address(option, gateway, &ipaddress);
404 ifname = get_ifname();
406 DBG("Failed to find an usable device name");
410 stpncpy(info->device.name, ifname, sizeof(info->device.name) - 1);
413 err = wg_add_device(info->device.name);
415 DBG("Failed to creating WireGuard device %s", info->device.name);
419 err = wg_set_device(&info->device);
421 DBG("Failed to configure WireGuard device %s", info->device.name);
422 wg_del_device(info->device.name);
425 vpn_set_ifname(provider, info->device.name);
427 vpn_provider_set_ipaddress(provider, ipaddress);
431 cb(provider, user_data, err);
433 connman_ipaddress_free(ipaddress);
437 g_timeout_add_seconds(DNS_RERESOLVE_TIMEOUT,
438 wg_dns_reresolve_cb, info);
443 static void wg_disconnect(struct vpn_provider *provider)
445 struct wireguard_info *info;
447 info = vpn_provider_get_plugin_data(provider);
451 if (info->reresolve_id > 0)
452 g_source_remove(info->reresolve_id);
454 vpn_provider_set_plugin_data(provider, NULL);
456 wg_del_device(info->device.name);
458 g_free(info->endpoint_fqdn);
463 #if defined TIZEN_EXT
464 static int wg_save(struct vpn_provider *provider, GKeyFile *keyfile)
471 * The client/own device listen port.
473 option = vpn_provider_get_string(provider, "WireGuard.ListenPort");
475 g_key_file_set_string(keyfile,
476 vpn_provider_get_save_group(provider),
477 "WireGuard.ListenPort",
481 * comma separated DNS.
483 option = vpn_provider_get_string(provider, "WireGuard.DNS");
485 g_key_file_set_string(keyfile,
486 vpn_provider_get_save_group(provider),
491 * The client private key.
493 option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
495 g_key_file_set_string(keyfile,
496 vpn_provider_get_save_group(provider),
497 "WireGuard.PrivateKey",
501 * The server public key.
503 option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
505 g_key_file_set_string(keyfile,
506 vpn_provider_get_save_group(provider),
507 "WireGuard.PublicKey",
513 option = vpn_provider_get_string(provider, "WireGuard.PresharedKey");
515 g_key_file_set_string(keyfile,
516 vpn_provider_get_save_group(provider),
517 "WireGuard.PresharedKey",
521 * Subnets accessed via VPN tunnel, 0.0.0.0/0 routes all traffic.
523 option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
525 g_key_file_set_string(keyfile,
526 vpn_provider_get_save_group(provider),
527 "WireGuard.AllowedIPs",
531 * The time in seconds to emit periodic keep alive message.
533 option = vpn_provider_get_string(provider, "WireGuard.PersistentKeepalive");
535 g_key_file_set_string(keyfile,
536 vpn_provider_get_save_group(provider),
537 "WireGuard.PersistentKeepalive",
541 * The server listen port, default: 51820
543 option = vpn_provider_get_string(provider, "WireGuard.EndpointPort");
545 g_key_file_set_string(keyfile,
546 vpn_provider_get_save_group(provider),
547 "WireGuard.EndpointPort",
551 * Save Address: The internal IP of the client node
553 option = vpn_provider_get_string(provider, "WireGuard.Address");
555 g_key_file_set_string(keyfile,
556 vpn_provider_get_save_group(provider),
564 static struct vpn_driver vpn_driver = {
565 .flags = VPN_FLAG_NO_TUN | VPN_FLAG_NO_DAEMON,
566 .connect = wg_connect,
567 .disconnect = wg_disconnect,
568 #if defined TIZEN_EXT
573 static int wg_init(void)
575 return vpn_register("wireguard", &vpn_driver, NULL);
578 static void wg_exit(void)
580 vpn_unregister("wireguard");
583 CONNMAN_PLUGIN_DEFINE(wireguard, "WireGuard VPN plugin", VERSION,
584 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wg_init, wg_exit)