Imported Upstream version 1.38
[platform/upstream/connman.git] / vpn / plugins / wireguard.c
1 /*
2  *  ConnMan VPN daemon
3  *
4  *  Copyright (C) 2019  Daniel Wagner. All rights reserved.
5  *
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.
9  *
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.
14  *
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
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <net/if.h>
29 #include <arpa/inet.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netdb.h>
33
34 #include <glib.h>
35
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>
45
46 #include "../vpn-provider.h"
47 #include "../vpn.h"
48
49 #include "vpn.h"
50 #include "wireguard.h"
51
52 static int parse_key(const char *str, wg_key key)
53 {
54         unsigned char *buf;
55         size_t len;
56
57         buf = g_base64_decode(str, &len);
58
59         if (len != 32) {
60                 g_free(buf);
61                 return -EINVAL;
62         }
63
64         memcpy(key, buf, 32);
65
66         g_free(buf);
67         return 0;
68 }
69
70 static int parse_allowed_ips(const char *allowed_ips, wg_peer *peer)
71 {
72         struct wg_allowedip *curaip, *allowedip;
73         char buf[INET6_ADDRSTRLEN];
74         char **tokens, **toks;
75         char *send;
76         int i;
77
78         curaip = NULL;
79         tokens = g_strsplit(allowed_ips, ", ", -1);
80         for (i = 0; tokens[i]; i++) {
81                 toks = g_strsplit(tokens[i], "/", -1);
82                 if (g_strv_length(toks) != 2) {
83                         DBG("Ignore AllowedIPs value %s", tokens[i]);
84                         g_strfreev(toks);
85                         continue;
86                 }
87
88                 allowedip = g_malloc0(sizeof(*allowedip));
89
90                 if (inet_pton(AF_INET, toks[0], buf) == 1) {
91                         allowedip->family = AF_INET;
92                         memcpy(&allowedip->ip4, buf, sizeof(allowedip->ip4));
93                 } else if (inet_pton(AF_INET6, toks[0], buf) == 1) {
94                         allowedip->family = AF_INET6;
95                         memcpy(&allowedip->ip6, buf, sizeof(allowedip->ip6));
96                 } else {
97                         DBG("Ignore AllowedIPs value %s", tokens[i]);
98                         g_free(allowedip);
99                         g_strfreev(toks);
100                         continue;
101                 }
102
103                 allowedip->cidr = g_ascii_strtoull(toks[1], &send, 10);
104
105                 if (!curaip)
106                         peer->first_allowedip = allowedip;
107                 else
108                         curaip->next_allowedip = allowedip;
109
110                 curaip = allowedip;
111         }
112
113         peer->last_allowedip = curaip;
114         g_strfreev(tokens);
115
116         return 0;
117 }
118
119 static int parse_endpoint(const char *host, const char *port, wg_peer *peer)
120 {
121         struct addrinfo hints;
122         struct addrinfo *result, *rp;
123         int sk;
124
125         memset(&hints, 0, sizeof(struct addrinfo));
126         hints.ai_family = AF_UNSPEC;
127         hints.ai_socktype = SOCK_DGRAM;
128         hints.ai_flags = 0;
129         hints.ai_protocol = 0;
130
131         if (getaddrinfo(host, port, &hints, &result) < 0) {
132                 DBG("Failed to resolve host address");
133                 return -EINVAL;
134         }
135
136         for (rp = result; rp; rp = rp->ai_next) {
137                 sk = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
138                 if (sk < 0)
139                         continue;
140                 if (connect(sk, rp->ai_addr, rp->ai_addrlen) != -1) {
141                         /* success */
142                         close(sk);
143                         break;
144                 }
145
146                 close(sk);
147         }
148
149         if (!rp) {
150                 freeaddrinfo(result);
151                 return -EINVAL;
152         }
153
154         memcpy(&peer->endpoint.addr, rp->ai_addr, rp->ai_addrlen);
155         freeaddrinfo(result);
156
157         return 0;
158 }
159
160 static int parse_address(const char *address, const char *gateway,
161                 struct connman_ipaddress **ipaddress)
162 {
163         char buf[INET6_ADDRSTRLEN];
164         unsigned char prefixlen;
165         char **tokens;
166         char *end, *netmask;
167         int err;
168
169         tokens = g_strsplit(address, "/", -1);
170         if (g_strv_length(tokens) != 2) {
171                 g_strfreev(tokens);
172                 return -EINVAL;
173         }
174
175         prefixlen = g_ascii_strtoull(tokens[1], &end, 10);
176
177         if (inet_pton(AF_INET, tokens[0], buf) == 1) {
178                 netmask = g_strdup_printf("%d.%d.%d.%d",
179                                 ((0xffffffff << (32 - prefixlen)) >> 24) & 0xff,
180                                 ((0xffffffff << (32 - prefixlen)) >> 16) & 0xff,
181                                 ((0xffffffff << (32 - prefixlen)) >> 8) & 0xff,
182                                 ((0xffffffff << (32 - prefixlen)) >> 0) & 0xff);
183
184                 *ipaddress = connman_ipaddress_alloc(AF_INET);
185                 err = connman_ipaddress_set_ipv4(*ipaddress, tokens[0],
186                                                 netmask, gateway);
187                 g_free(netmask);
188         } else if (inet_pton(AF_INET6, tokens[0], buf) == 1) {
189                 *ipaddress = connman_ipaddress_alloc(AF_INET6);
190                 err = connman_ipaddress_set_ipv6(*ipaddress, tokens[0],
191                                                 prefixlen, gateway);
192         } else {
193                 DBG("Invalid Wireguard.Address value");
194                 err = -EINVAL;
195         }
196
197         g_strfreev(tokens);
198         if (err)
199                 connman_ipaddress_free(*ipaddress);
200
201         return err;
202 }
203
204 struct ifname_data {
205         char *ifname;
206         bool found;
207 };
208
209 static void ifname_check_cb(int index, void *user_data)
210 {
211         struct ifname_data *data = (struct ifname_data *)user_data;
212         char *ifname;
213
214         ifname = connman_inet_ifname(index);
215
216         if (!g_strcmp0(ifname, data->ifname))
217                 data->found = true;
218 }
219
220 static char *get_ifname(void)
221 {
222         struct ifname_data data;
223         int i;
224
225         for (i = 0; i < 256; i++) {
226                 data.ifname = g_strdup_printf("wg%d", i);
227                 data.found = false;
228                 __vpn_ipconfig_foreach(ifname_check_cb, &data);
229
230                 if (!data.found)
231                         return data.ifname;
232
233                 g_free(data.ifname);
234         }
235
236         return NULL;
237 }
238
239 struct wireguard_info {
240         struct wg_device device;
241         struct wg_peer peer;
242 };
243
244 static int wg_connect(struct vpn_provider *provider,
245                         struct connman_task *task, const char *if_name,
246                         vpn_provider_connect_cb_t cb,
247                         const char *dbus_sender, void *user_data)
248 {
249         struct connman_ipaddress *ipaddress = NULL;
250         struct wireguard_info *info;
251         const char *option, *gateway;
252         char *ifname;
253         int err = -EINVAL;
254
255         info = g_malloc0(sizeof(struct wireguard_info));
256         info->peer.flags = WGPEER_HAS_PUBLIC_KEY | WGPEER_REPLACE_ALLOWEDIPS;
257         info->device.flags = WGDEVICE_HAS_PRIVATE_KEY;
258         info->device.first_peer = &info->peer;
259         info->device.last_peer = &info->peer;
260
261         vpn_provider_set_plugin_data(provider, info);
262
263         option = vpn_provider_get_string(provider, "WireGuard.ListenPort");
264         if (option) {
265                 char *end;
266                 info->device.listen_port = g_ascii_strtoull(option, &end, 10);
267                 info->device.flags |= WGDEVICE_HAS_LISTEN_PORT;
268         }
269
270         option = vpn_provider_get_string(provider, "WireGuard.DNS");
271         if (option) {
272                 err = vpn_provider_set_nameservers(provider, option);
273                 if (err)
274                         goto done;
275         }
276
277         option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
278         if (!option) {
279                 DBG("WireGuard.PrivateKey is missing");
280                 goto done;
281         }
282         err = parse_key(option, info->device.private_key);
283         if (err)
284                 goto done;
285
286         option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
287         if (!option) {
288                 DBG("WireGuard.PublicKey is missing");
289                 goto done;
290         }
291         err = parse_key(option, info->peer.public_key);
292         if (err)
293                 goto done;
294
295         option = vpn_provider_get_string(provider, "WireGuard.PresharedKey");
296         if (option) {
297                 info->peer.flags |= WGPEER_HAS_PRESHARED_KEY;
298                 err = parse_key(option, info->peer.preshared_key);
299                 if (err)
300                         goto done;
301         }
302
303         option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
304         if (!option) {
305                 DBG("WireGuard.AllowedIPs is missing");
306                 goto done;
307         }
308         err = parse_allowed_ips(option, &info->peer);
309         if (err)
310                 goto done;
311
312         option = vpn_provider_get_string(provider,
313                                         "WireGuard.PersistentKeepalive");
314         if (option) {
315                 char *end;
316                 info->peer.persistent_keepalive_interval =
317                         g_ascii_strtoull(option, &end, 10);
318                 info->peer.flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
319         }
320
321         option = vpn_provider_get_string(provider, "WireGuard.EndpointPort");
322         if (!option)
323                 option = "51820";
324
325         gateway = vpn_provider_get_string(provider, "Host");
326         err = parse_endpoint(gateway, option, &info->peer);
327         if (err)
328                 goto done;
329
330         option = vpn_provider_get_string(provider, "WireGuard.Address");
331         if (!option) {
332                 DBG("Missing WireGuard.Address configuration");
333                 goto done;
334         }
335         err = parse_address(option, gateway, &ipaddress);
336         if (err)
337                 goto done;
338
339         ifname = get_ifname();
340         if (!ifname) {
341                 DBG("Failed to find an usable device name");
342                 err = -ENOENT;
343                 goto done;
344         }
345         stpncpy(info->device.name, ifname, sizeof(info->device.name));
346         g_free(ifname);
347
348         err = wg_add_device(info->device.name);
349         if (err) {
350                 DBG("Failed to creating WireGuard device %s", info->device.name);
351                 goto done;
352         }
353
354         err = wg_set_device(&info->device);
355         if (err) {
356                 DBG("Failed to configure WireGuard device %s", info->device.name);
357                 wg_del_device(info->device.name);
358         }
359
360         vpn_set_ifname(provider, info->device.name);
361         if (ipaddress)
362                 vpn_provider_set_ipaddress(provider, ipaddress);
363
364 done:
365         if (cb)
366                 cb(provider, user_data, err);
367
368         connman_ipaddress_free(ipaddress);
369
370         return err;
371 }
372
373 static void wg_disconnect(struct vpn_provider *provider)
374 {
375         struct wireguard_info *info;
376
377         info = vpn_provider_get_plugin_data(provider);
378         if (!info)
379                 return;
380         vpn_provider_set_plugin_data(provider, NULL);
381
382         wg_del_device(info->device.name);
383
384         g_free(info);
385 }
386
387 static struct vpn_driver vpn_driver = {
388         .flags          = VPN_FLAG_NO_TUN | VPN_FLAG_NO_DAEMON,
389         .connect        = wg_connect,
390         .disconnect     = wg_disconnect,
391 };
392
393 static int wg_init(void)
394 {
395         return vpn_register("wireguard", &vpn_driver, NULL);
396 }
397
398 static void wg_exit(void)
399 {
400         vpn_unregister("wireguard");
401 }
402
403 CONNMAN_PLUGIN_DEFINE(wireguard, "WireGuard VPN plugin", VERSION,
404         CONNMAN_PLUGIN_PRIORITY_DEFAULT, wg_init, wg_exit)