unet-cli: strip initial newline in usage message
[project/unetd.git] / wg-user.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
4 *
5 * Based on wireguard-tools:
6 * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
7 */
8
9 #include <stdbool.h>
10 #include <stddef.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <dirent.h>
15 #include <errno.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <sys/stat.h>
19 #include <sys/un.h>
20 #include <arpa/inet.h>
21 #include <time.h>
22 #include <netdb.h>
23 #include "unetd.h"
24
25 #define SOCK_PATH RUNSTATEDIR "/wireguard/"
26 #define SOCK_SUFFIX ".sock"
27
28 struct wg_req {
29 FILE *f;
30
31 char *buf;
32 size_t buf_len;
33
34 char *key, *value;
35
36 int ret;
37 };
38
39 static void
40 key_to_hex(char hex[static WG_KEY_LEN_HEX], const uint8_t key[static WG_KEY_LEN])
41 {
42 unsigned int i;
43
44 for (i = 0; i < WG_KEY_LEN; ++i) {
45 hex[i * 2] = 87U + (key[i] >> 4) + ((((key[i] >> 4) - 10U) >> 8) & ~38U);
46 hex[i * 2 + 1] = 87U + (key[i] & 0xf) + ((((key[i] & 0xf) - 10U) >> 8) & ~38U);
47 }
48
49 hex[i * 2] = '\0';
50 }
51
52 static bool
53 key_from_hex(uint8_t key[static WG_KEY_LEN], const char *hex)
54 {
55 uint8_t c, c_acc, c_alpha0, c_alpha, c_num0, c_num, c_val;
56 volatile uint8_t ret = 0;
57
58 if (strlen(hex) != WG_KEY_LEN_HEX - 1)
59 return false;
60
61 for (unsigned int i = 0; i < WG_KEY_LEN_HEX - 1; i += 2) {
62 c = (uint8_t)hex[i];
63 c_num = c ^ 48U;
64 c_num0 = (c_num - 10U) >> 8;
65 c_alpha = (c & ~32U) - 55U;
66 c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8;
67 ret |= ((c_num0 | c_alpha0) - 1) >> 8;
68 c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
69 c_acc = c_val * 16U;
70
71 c = (uint8_t)hex[i + 1];
72 c_num = c ^ 48U;
73 c_num0 = (c_num - 10U) >> 8;
74 c_alpha = (c & ~32U) - 55U;
75 c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8;
76 ret |= ((c_num0 | c_alpha0) - 1) >> 8;
77 c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
78 key[i / 2] = c_acc | c_val;
79 }
80
81 return 1 & ((ret - 1) >> 8);
82 }
83
84 static bool wg_user_check(struct network *net)
85 {
86 struct sockaddr_un addr = { .sun_family = AF_UNIX };
87 struct stat sbuf;
88 int fd, ret;
89
90 if (snprintf(addr.sun_path, sizeof(addr.sun_path), SOCK_PATH "%s" SOCK_SUFFIX, network_name(net)) < 0)
91 return false;
92 if (stat(addr.sun_path, &sbuf) < 0)
93 return false;
94 if (!S_ISSOCK(sbuf.st_mode))
95 return false;
96 ret = fd = socket(AF_UNIX, SOCK_STREAM, 0);
97 if (ret < 0)
98 return false;
99 ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
100 if (ret < 0 && errno == ECONNREFUSED) { /* If the process is gone, we try to clean up the socket. */
101 close(fd);
102 unlink(addr.sun_path);
103 return false;
104 }
105 close(fd);
106 return true;
107 }
108
109 static FILE *wg_user_file(struct network *net)
110 {
111 struct stat sbuf;
112 struct sockaddr_un addr = { .sun_family = AF_UNIX };
113 int fd = -1, ret;
114 FILE *f = NULL;
115
116 errno = EINVAL;
117 ret = snprintf(addr.sun_path, sizeof(addr.sun_path), SOCK_PATH "%s" SOCK_SUFFIX, network_name(net));
118 if (ret < 0)
119 goto out;
120 ret = stat(addr.sun_path, &sbuf);
121 if (ret < 0)
122 goto out;
123 errno = EBADF;
124 if (!S_ISSOCK(sbuf.st_mode))
125 goto out;
126
127 ret = fd = socket(AF_UNIX, SOCK_STREAM, 0);
128 if (ret < 0)
129 goto out;
130
131 ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
132 if (ret < 0) {
133 if (errno == ECONNREFUSED) /* If the process is gone, we try to clean up the socket. */
134 unlink(addr.sun_path);
135 goto out;
136 }
137 f = fdopen(fd, "r+");
138 if (f)
139 errno = 0;
140 out:
141 ret = -errno;
142 if (ret) {
143 if (fd >= 0)
144 close(fd);
145 errno = -ret;
146 return NULL;
147 }
148 return f;
149 }
150
151 static void wg_req_set(struct wg_req *req, const char *key, const char *value)
152 {
153 fprintf(req->f, "%s=%s\n", key, value);
154 }
155
156 static void wg_req_set_int(struct wg_req *req, const char *key, int value)
157 {
158 fprintf(req->f, "%s=%d\n", key, value);
159 }
160
161 #define wg_req_printf(req, name, format, ...) fprintf((req)->f, "%s=" format "\n", name, ##__VA_ARGS__)
162
163 static int wg_req_init(struct wg_req *req, struct network *net, bool set)
164 {
165 memset(req, 0, sizeof(*req));
166 req->ret = -1;
167 req->f = wg_user_file(net);
168 if (!req->f)
169 return -1;
170
171 wg_req_set(req, set ? "set" : "get", "1");
172
173 return 0;
174 }
175
176 static bool wg_req_fetch(struct wg_req *req)
177 {
178 int len;
179
180 if (!req->buf) {
181 fprintf(req->f, "\n");
182 fflush(req->f);
183 }
184
185 if (getline(&req->buf, &req->buf_len, req->f) <= 0)
186 return false;
187
188 req->key = req->buf;
189 len = strlen(req->key);
190 if (len == 1 && req->key[0] == '\n')
191 return false;
192
193 req->value = strchr(req->key, '=');
194 if (!req->value || !len || req->key[len - 1] != '\n')
195 return false;
196
197 *(req->value++) = req->key[--len] = 0;
198 if (!strcmp(req->key, "errno"))
199 req->ret = atoi(req->value);
200
201 return true;
202 }
203
204 static void wg_req_complete(struct wg_req *req)
205 {
206 while (wg_req_fetch(req));
207 }
208
209 static int wg_req_done(struct wg_req *req)
210 {
211 if (!req->buf)
212 wg_req_complete(req);
213
214 if (req->f)
215 fclose(req->f);
216 free(req->buf);
217
218 return -req->ret;
219 }
220
221 static int
222 wg_user_test(struct network *net)
223 {
224 struct wg_req req;
225
226 if (wg_req_init(&req, net, false))
227 return -1;
228
229 return wg_req_done(&req);
230 }
231
232 static int
233 wg_network_reset(struct network *net, uint8_t *key)
234 {
235 struct wg_req req;
236 char key_str[WG_KEY_LEN_HEX];
237
238 if (wg_req_init(&req, net, true))
239 return -1;
240
241 wg_req_set(&req, "replace_peers", "true");
242
243 key_to_hex(key_str, key);
244 wg_req_set(&req, "private_key", key_str);
245
246 return wg_req_done(&req);
247 }
248
249 static int
250 wg_user_init(struct network *net)
251 {
252 int err;
253
254 err = wg_user_test(net);
255 if (err)
256 return err;
257
258 return wg_network_reset(net, net->config.key);
259 }
260
261 static void
262 wg_user_cleanup(struct network *net)
263 {
264 uint8_t key[WG_KEY_LEN] = {};
265
266 wg_network_reset(net, key);
267 }
268
269 static int
270 wg_user_init_local(struct network *net, struct network_peer *peer)
271 {
272 struct wg_req req;
273
274 if (wg_req_init(&req, net, true))
275 return -1;
276
277 wg_req_set_int(&req, "listen_port", peer ? peer->port : 0);
278
279 return wg_req_done(&req);
280 }
281
282 static void
283 wg_user_peer_req_add_allowed_ip(struct wg_req *req, struct network_peer *peer)
284 {
285 char addr[INET6_ADDRSTRLEN];
286 struct blob_attr *cur;
287 int rem;
288
289 inet_ntop(AF_INET6, &peer->local_addr.in6, addr, sizeof(addr));
290 wg_req_printf(req, "allowed_ip", "%s/128", addr);
291
292 blobmsg_for_each_attr(cur, peer->ipaddr, rem) {
293 const char *str = blobmsg_get_string(cur);
294 struct in6_addr in6;
295 int af, mask;
296
297 if (strchr(str, ':')) {
298 af = AF_INET6;
299 mask = 128;
300 } else {
301 af = AF_INET;
302 mask = 32;
303 }
304
305 if (inet_pton(af, str, &in6) != 1)
306 continue;
307
308 wg_req_printf(req, "allowed_ip", "%s/%d", str, mask);
309 }
310
311 blobmsg_for_each_attr(cur, peer->subnet, rem) {
312 const char *str = blobmsg_get_string(cur);
313 char buf[INET6_ADDRSTRLEN];
314 union network_addr addr;
315 int mask;
316 int af;
317
318 af = strchr(str, ':') ? AF_INET6 : AF_INET;
319 if (network_get_subnet(af, &addr, &mask, str))
320 continue;
321
322 inet_ntop(af, &addr, buf, sizeof(buf));
323 wg_req_printf(req, "allowed_ip", "%s/%d", buf, mask);
324 }
325 }
326
327 static int
328 wg_user_peer_update(struct network *net, struct network_peer *peer, enum wg_update_cmd cmd)
329 {
330 struct network_host *host;
331 struct wg_req req;
332 char key[WG_KEY_LEN_HEX];
333
334 if (wg_req_init(&req, net, true))
335 return -1;
336
337 key_to_hex(key, peer->key);
338 wg_req_set(&req, "public_key", key);
339
340 if (cmd == WG_PEER_DELETE) {
341 wg_req_set(&req, "remove", "true");
342 goto out;
343 }
344
345 wg_req_set(&req, "replace_allowed_ips", "true");
346 wg_user_peer_req_add_allowed_ip(&req, peer);
347 for_each_routed_host(host, net, peer)
348 wg_user_peer_req_add_allowed_ip(&req, &host->peer);
349
350 out:
351 return wg_req_done(&req);
352 }
353
354 static int
355 wg_user_peer_refresh(struct network *net)
356 {
357 struct network_peer *peer = NULL;
358 struct wg_req req;
359 uint8_t key[WG_KEY_LEN];
360 time_t now = time(NULL);
361
362 if (wg_req_init(&req, net, false))
363 return -1;
364
365 while (wg_req_fetch(&req)) {
366 if (!strcmp(req.key, "public_key")) {
367 if (peer)
368 wg_peer_update_done(net, peer);
369 if (key_from_hex(key, req.value))
370 peer = wg_peer_update_start(net, key);
371 else
372 peer = NULL;
373 continue;
374 }
375
376 if (!peer)
377 continue;
378
379 if (!strcmp(req.key, "last_handshake_time_sec")) {
380 uint64_t sec = strtoull(req.value, NULL, 0);
381
382 wg_peer_set_last_handshake(net, peer, now, sec);
383 continue;
384 }
385
386 if (!strcmp(req.key, "rx_bytes")) {
387 uint64_t bytes = strtoull(req.value, NULL, 0);
388
389 wg_peer_set_rx_bytes(net, peer, bytes);
390 continue;
391 }
392
393 if (!strcmp(req.key, "endpoint")) {
394 struct addrinfo *resolved;
395 struct addrinfo hints = {
396 .ai_family = AF_UNSPEC,
397 .ai_socktype = SOCK_DGRAM,
398 .ai_protocol = IPPROTO_UDP,
399 };
400 char *port;
401
402 if (!strlen(req.value))
403 continue;
404
405 if (req.value[0] == '[') {
406 req.value++;
407 port = strchr(req.value, ']');
408 if (!port)
409 continue;
410
411 *port++ = 0;
412 if (*port++ != ':')
413 continue;
414 } else {
415 port = strchr(req.value, ':');
416 if (!port)
417 continue;
418
419 *port++ = 0;
420 }
421
422 if (!*port)
423 continue;
424
425 if (getaddrinfo(req.value, port, &hints, &resolved) != 0)
426 continue;
427
428 if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) ||
429 (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)))
430 wg_peer_set_endpoint(net, peer, resolved->ai_addr, resolved->ai_addrlen);
431
432 freeaddrinfo(resolved);
433 continue;
434 }
435 }
436
437 if (peer)
438 wg_peer_update_done(net, peer);
439
440 return wg_req_done(&req);
441 }
442
443 static int
444 wg_user_peer_connect(struct network *net, struct network_peer *peer,
445 union network_endpoint *ep)
446 {
447 struct wg_req req;
448 char addr[INET6_ADDRSTRLEN];
449 char key[WG_KEY_LEN_HEX];
450 const void *ip;
451 int port;
452
453 if (wg_req_init(&req, net, true))
454 return -1;
455
456 key_to_hex(key, peer->key);
457 wg_req_set(&req, "public_key", key);
458
459 if (ep->in.sin_family == AF_INET6)
460 ip = &ep->in6.sin6_addr;
461 else
462 ip = &ep->in.sin_addr;
463
464 inet_ntop(ep->in.sin_family, ip, addr, sizeof(addr));
465 port = ntohs(ep->in.sin_port);
466
467 if (ep->in.sin_family == AF_INET6)
468 wg_req_printf(&req, "endpoint", "[%s]:%d", addr, port);
469 else
470 wg_req_printf(&req, "endpoint", "%s:%d", addr, port);
471
472 if (net->net_config.keepalive) {
473 wg_req_set_int(&req, "persistent_keepalive_interval", 0);
474 wg_req_set_int(&req, "persistent_keepalive_interval",
475 net->net_config.keepalive);
476 }
477
478 return wg_req_done(&req);
479 }
480
481 const struct wg_ops wg_user_ops = {
482 .name = "user",
483 .check = wg_user_check,
484 .init = wg_user_init,
485 .cleanup = wg_user_cleanup,
486 .init_local = wg_user_init_local,
487 .peer_update = wg_user_peer_update,
488 .peer_refresh = wg_user_peer_refresh,
489 .peer_connect = wg_user_peer_connect,
490 };