wireguard: Regular reresolve endpoint address
[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 #define DNS_RERESOLVE_TIMEOUT 20
53
54 struct wireguard_info {
55         struct wg_device device;
56         struct wg_peer peer;
57         char *endpoint_fqdn;
58         char *port;
59         int reresolve_id;
60 };
61
62 static int parse_key(const char *str, wg_key key)
63 {
64         unsigned char *buf;
65         size_t len;
66
67         buf = g_base64_decode(str, &len);
68
69         if (len != 32) {
70                 g_free(buf);
71                 return -EINVAL;
72         }
73
74         memcpy(key, buf, 32);
75
76         g_free(buf);
77         return 0;
78 }
79
80 static int parse_allowed_ips(const char *allowed_ips, wg_peer *peer)
81 {
82         struct wg_allowedip *curaip, *allowedip;
83         char buf[INET6_ADDRSTRLEN];
84         char **tokens, **toks;
85         char *send;
86         int i;
87
88         curaip = NULL;
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]);
94                         g_strfreev(toks);
95                         continue;
96                 }
97
98                 allowedip = g_malloc0(sizeof(*allowedip));
99
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));
106                 } else {
107                         DBG("Ignore AllowedIPs value %s", tokens[i]);
108                         g_free(allowedip);
109                         g_strfreev(toks);
110                         continue;
111                 }
112
113                 allowedip->cidr = g_ascii_strtoull(toks[1], &send, 10);
114
115                 if (!curaip)
116                         peer->first_allowedip = allowedip;
117                 else
118                         curaip->next_allowedip = allowedip;
119
120                 curaip = allowedip;
121         }
122
123         peer->last_allowedip = curaip;
124         g_strfreev(tokens);
125
126         return 0;
127 }
128
129 static int parse_endpoint(const char *host, const char *port, struct sockaddr *addr)
130 {
131         struct addrinfo hints;
132         struct addrinfo *result, *rp;
133         int sk;
134
135         memset(&hints, 0, sizeof(struct addrinfo));
136         hints.ai_family = AF_UNSPEC;
137         hints.ai_socktype = SOCK_DGRAM;
138         hints.ai_flags = 0;
139         hints.ai_protocol = 0;
140
141         if (getaddrinfo(host, port, &hints, &result) < 0) {
142                 DBG("Failed to resolve host address");
143                 return -EINVAL;
144         }
145
146         for (rp = result; rp; rp = rp->ai_next) {
147                 sk = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
148                 if (sk < 0)
149                         continue;
150                 if (connect(sk, rp->ai_addr, rp->ai_addrlen) != -1) {
151                         /* success */
152                         close(sk);
153                         break;
154                 }
155
156                 close(sk);
157         }
158
159         if (!rp) {
160                 freeaddrinfo(result);
161                 return -EINVAL;
162         }
163
164         memcpy(addr, rp->ai_addr, rp->ai_addrlen);
165         freeaddrinfo(result);
166
167         return 0;
168 }
169
170 static int parse_address(const char *address, const char *gateway,
171                 struct connman_ipaddress **ipaddress)
172 {
173         char buf[INET6_ADDRSTRLEN];
174         unsigned char prefixlen;
175         char **tokens;
176         char *end, *netmask;
177         int err;
178
179         tokens = g_strsplit(address, "/", -1);
180         if (g_strv_length(tokens) != 2) {
181                 g_strfreev(tokens);
182                 return -EINVAL;
183         }
184
185         prefixlen = g_ascii_strtoull(tokens[1], &end, 10);
186
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);
193
194                 *ipaddress = connman_ipaddress_alloc(AF_INET);
195                 err = connman_ipaddress_set_ipv4(*ipaddress, tokens[0],
196                                                 netmask, gateway);
197                 g_free(netmask);
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],
201                                                 prefixlen, gateway);
202         } else {
203                 DBG("Invalid Wireguard.Address value");
204                 err = -EINVAL;
205         }
206
207         g_strfreev(tokens);
208         if (err)
209                 connman_ipaddress_free(*ipaddress);
210
211         return err;
212 }
213
214 struct ifname_data {
215         char *ifname;
216         bool found;
217 };
218
219 static void ifname_check_cb(int index, void *user_data)
220 {
221         struct ifname_data *data = (struct ifname_data *)user_data;
222         char *ifname;
223
224         ifname = connman_inet_ifname(index);
225
226         if (!g_strcmp0(ifname, data->ifname))
227                 data->found = true;
228 }
229
230 static char *get_ifname(void)
231 {
232         struct ifname_data data;
233         int i;
234
235         for (i = 0; i < 256; i++) {
236                 data.ifname = g_strdup_printf("wg%d", i);
237                 data.found = false;
238                 __vpn_ipconfig_foreach(ifname_check_cb, &data);
239
240                 if (!data.found)
241                         return data.ifname;
242
243                 g_free(data.ifname);
244         }
245
246         return NULL;
247 }
248
249 static bool sockaddr_cmp_addr(struct sockaddr *a, struct sockaddr *b)
250 {
251         if (a->sa_family != b->sa_family)
252                 return false;
253
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;
257
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;
262
263                 return !memcmp(a6->sin6_addr.s6_addr,
264                                 b6->sin6_addr.s6_addr,
265                                 sizeof(a6->sin6_addr.s6_addr));
266         }
267
268         return false;
269 }
270
271 static gboolean wg_dns_reresolve_cb(gpointer user_data)
272 {
273         struct wireguard_info *info = user_data;
274         int err;
275         struct sockaddr addr;
276
277         DBG("");
278
279         err = parse_endpoint(info->endpoint_fqdn,
280                         info->port, &addr);
281         if (err)
282                 return TRUE;
283
284         if (sockaddr_cmp_addr(&addr, &info->peer.endpoint.addr))
285                 return TRUE;
286
287         if (addr.sa_family == AF_INET)
288                 memcpy(&info->peer.endpoint.addr, &addr,
289                         sizeof(info->peer.endpoint.addr4));
290         else
291                 memcpy(&info->peer.endpoint.addr, &addr,
292                         sizeof(info->peer.endpoint.addr6));
293
294         DBG("Endpoint address has changed, udpate WireGuard device");
295         err = wg_set_device(&info->device);
296         if (err)
297                 DBG("Failed to update Endpoint address for WireGuard device %s",
298                         info->device.name);
299
300         return TRUE;
301 }
302
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)
307 {
308         struct connman_ipaddress *ipaddress = NULL;
309         struct wireguard_info *info;
310         const char *option, *gateway;
311         char *ifname;
312         int err = -EINVAL;
313
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;
319
320         vpn_provider_set_plugin_data(provider, info);
321
322         option = vpn_provider_get_string(provider, "WireGuard.ListenPort");
323         if (option) {
324                 char *end;
325                 info->device.listen_port = g_ascii_strtoull(option, &end, 10);
326                 info->device.flags |= WGDEVICE_HAS_LISTEN_PORT;
327         }
328
329         option = vpn_provider_get_string(provider, "WireGuard.DNS");
330         if (option) {
331                 err = vpn_provider_set_nameservers(provider, option);
332                 if (err)
333                         goto done;
334         }
335
336         option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
337         if (!option) {
338                 DBG("WireGuard.PrivateKey is missing");
339                 goto done;
340         }
341         err = parse_key(option, info->device.private_key);
342         if (err)
343                 goto done;
344
345         option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
346         if (!option) {
347                 DBG("WireGuard.PublicKey is missing");
348                 goto done;
349         }
350         err = parse_key(option, info->peer.public_key);
351         if (err)
352                 goto done;
353
354         option = vpn_provider_get_string(provider, "WireGuard.PresharedKey");
355         if (option) {
356                 info->peer.flags |= WGPEER_HAS_PRESHARED_KEY;
357                 err = parse_key(option, info->peer.preshared_key);
358                 if (err)
359                         goto done;
360         }
361
362         option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
363         if (!option) {
364                 DBG("WireGuard.AllowedIPs is missing");
365                 goto done;
366         }
367         err = parse_allowed_ips(option, &info->peer);
368         if (err)
369                 goto done;
370
371         option = vpn_provider_get_string(provider,
372                                         "WireGuard.PersistentKeepalive");
373         if (option) {
374                 char *end;
375                 info->peer.persistent_keepalive_interval =
376                         g_ascii_strtoull(option, &end, 10);
377                 info->peer.flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
378         }
379
380         option = vpn_provider_get_string(provider, "WireGuard.EndpointPort");
381         if (!option)
382                 option = "51820";
383
384         gateway = vpn_provider_get_string(provider, "Host");
385         err = parse_endpoint(gateway, option, &info->peer.endpoint.addr);
386         if (err)
387                 goto done;
388
389         info->endpoint_fqdn = g_strdup(gateway);
390         info->port = g_strdup(option);
391
392         option = vpn_provider_get_string(provider, "WireGuard.Address");
393         if (!option) {
394                 DBG("Missing WireGuard.Address configuration");
395                 goto done;
396         }
397         err = parse_address(option, gateway, &ipaddress);
398         if (err)
399                 goto done;
400
401         ifname = get_ifname();
402         if (!ifname) {
403                 DBG("Failed to find an usable device name");
404                 err = -ENOENT;
405                 goto done;
406         }
407         stpncpy(info->device.name, ifname, sizeof(info->device.name));
408         g_free(ifname);
409
410         err = wg_add_device(info->device.name);
411         if (err) {
412                 DBG("Failed to creating WireGuard device %s", info->device.name);
413                 goto done;
414         }
415
416         err = wg_set_device(&info->device);
417         if (err) {
418                 DBG("Failed to configure WireGuard device %s", info->device.name);
419                 wg_del_device(info->device.name);
420         }
421
422         vpn_set_ifname(provider, info->device.name);
423         if (ipaddress)
424                 vpn_provider_set_ipaddress(provider, ipaddress);
425
426 done:
427         if (cb)
428                 cb(provider, user_data, err);
429
430         connman_ipaddress_free(ipaddress);
431
432         if (!err)
433                 info->reresolve_id =
434                         g_timeout_add_seconds(DNS_RERESOLVE_TIMEOUT,
435                                                 wg_dns_reresolve_cb, info);
436
437         return err;
438 }
439
440 static void wg_disconnect(struct vpn_provider *provider)
441 {
442         struct wireguard_info *info;
443
444         info = vpn_provider_get_plugin_data(provider);
445         if (!info)
446                 return;
447
448         if (info->reresolve_id > 0)
449                 g_source_remove(info->reresolve_id);
450
451         vpn_provider_set_plugin_data(provider, NULL);
452
453         wg_del_device(info->device.name);
454
455         g_free(info->endpoint_fqdn);
456         g_free(info->port);
457         g_free(info);
458 }
459
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,
464 };
465
466 static int wg_init(void)
467 {
468         return vpn_register("wireguard", &vpn_driver, NULL);
469 }
470
471 static void wg_exit(void)
472 {
473         vpn_unregister("wireguard");
474 }
475
476 CONNMAN_PLUGIN_DEFINE(wireguard, "WireGuard VPN plugin", VERSION,
477         CONNMAN_PLUGIN_PRIORITY_DEFAULT, wg_init, wg_exit)