44defdc56b750f98fcea634e841c9a4dc2444257
[project/unetd.git] / network.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
4 */
5 #define _GNU_SOURCE
6 #include <arpa/inet.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <sys/wait.h>
10 #include <net/if.h>
11 #include <libubox/avl-cmp.h>
12 #include <libubox/utils.h>
13 #include <libubox/blobmsg_json.h>
14 #include "unetd.h"
15
16 enum {
17 NETDATA_ATTR_CONFIG,
18 NETDATA_ATTR_HOSTS,
19 NETDATA_ATTR_GROUPS,
20 NETDATA_ATTR_SERVICES,
21 __NETDATA_ATTR_MAX,
22 };
23
24 static const struct blobmsg_policy netdata_policy[__NETDATA_ATTR_MAX] = {
25 [NETDATA_ATTR_CONFIG] = { "config", BLOBMSG_TYPE_TABLE },
26 [NETDATA_ATTR_HOSTS] = { "hosts", BLOBMSG_TYPE_TABLE },
27 [NETDATA_ATTR_SERVICES] = { "services", BLOBMSG_TYPE_TABLE },
28 };
29
30 enum {
31 NETCONF_ATTR_ID,
32 NETCONF_ATTR_PORT,
33 NETCONF_ATTR_PEX_PORT,
34 NETCONF_ATTR_KEEPALIVE,
35 __NETCONF_ATTR_MAX
36 };
37
38 static const struct blobmsg_policy netconf_policy[__NETCONF_ATTR_MAX] = {
39 [NETCONF_ATTR_ID] = { "id", BLOBMSG_TYPE_STRING },
40 [NETCONF_ATTR_PORT] = { "port", BLOBMSG_TYPE_INT32 },
41 [NETCONF_ATTR_PEX_PORT] = { "peer-exchange-port", BLOBMSG_TYPE_INT32 },
42 [NETCONF_ATTR_KEEPALIVE] = { "keepalive", BLOBMSG_TYPE_INT32 },
43 };
44
45 const struct blobmsg_policy network_policy[__NETWORK_ATTR_MAX] = {
46 [NETWORK_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
47 [NETWORK_ATTR_TYPE] = { "type", BLOBMSG_TYPE_STRING },
48 [NETWORK_ATTR_AUTH_KEY] = { "auth_key", BLOBMSG_TYPE_STRING },
49 [NETWORK_ATTR_KEY] = { "key", BLOBMSG_TYPE_STRING },
50 [NETWORK_ATTR_FILE] = { "file", BLOBMSG_TYPE_STRING },
51 [NETWORK_ATTR_DATA] = { "data", BLOBMSG_TYPE_TABLE },
52 [NETWORK_ATTR_INTERFACE] = { "interface", BLOBMSG_TYPE_STRING },
53 [NETWORK_ATTR_KEEPALIVE] = { "keepalive", BLOBMSG_TYPE_INT32 },
54 [NETWORK_ATTR_DOMAIN] = { "domain", BLOBMSG_TYPE_STRING },
55 [NETWORK_ATTR_UPDATE_CMD] = { "update-cmd", BLOBMSG_TYPE_STRING },
56 [NETWORK_ATTR_TUNNELS] = { "tunnels", BLOBMSG_TYPE_TABLE },
57 [NETWORK_ATTR_AUTH_CONNECT] = { "auth_connect", BLOBMSG_TYPE_ARRAY },
58 [NETWORK_ATTR_PEER_DATA] = { "peer_data", BLOBMSG_TYPE_ARRAY },
59 };
60
61 AVL_TREE(networks, avl_strcmp, false, NULL);
62 static struct blob_buf b;
63
64 static void network_load_config_data(struct network *net, struct blob_attr *data)
65 {
66 struct blob_attr *tb[__NETCONF_ATTR_MAX];
67 struct blob_attr *cur;
68 siphash_key_t key = {};
69
70 blobmsg_parse(netconf_policy, __NETCONF_ATTR_MAX, tb,
71 blobmsg_data(data), blobmsg_len(data));
72
73 if ((cur = tb[NETCONF_ATTR_PORT]) != NULL)
74 net->net_config.port = blobmsg_get_u32(cur);
75 else
76 net->net_config.port = 51820;
77
78 if ((cur = tb[NETCONF_ATTR_PEX_PORT]) != NULL)
79 net->net_config.pex_port = blobmsg_get_u32(cur);
80
81 if ((cur = tb[NETCONF_ATTR_ID]) != NULL) {
82 const char *id = blobmsg_get_string(cur);
83 siphash_to_le64(&net->net_config.addr.network_id, id, strlen(id), &key);
84 } else {
85 siphash_to_le64(&net->net_config.addr.network_id, &net->net_config.port,
86 sizeof(net->net_config.port), &key);
87 }
88
89 net->net_config.addr.network_id[0] = 0xfd;
90 network_fill_host_addr(&net->net_config.addr, net->config.pubkey);
91
92 if (net->config.keepalive >= 0)
93 net->net_config.keepalive = net->config.keepalive;
94 else if ((cur = tb[NETCONF_ATTR_KEEPALIVE]) != NULL)
95 net->net_config.keepalive = blobmsg_get_u32(cur);
96 else
97 net->net_config.keepalive = 0;
98 }
99
100 static int network_load_data(struct network *net, struct blob_attr *data)
101 {
102 struct blob_attr *tb[__NETDATA_ATTR_MAX];
103 siphash_key_t key = {};
104
105 net->net_config.hash = siphash(data, blob_raw_len(data), &key);
106 blobmsg_parse(netdata_policy, __NETDATA_ATTR_MAX, tb,
107 blobmsg_data(data), blobmsg_len(data));
108
109 network_load_config_data(net, tb[NETDATA_ATTR_CONFIG]);
110 network_hosts_add(net, tb[NETDATA_ATTR_HOSTS]);
111 network_services_add(net, tb[NETDATA_ATTR_SERVICES]);
112
113 return 0;
114 }
115
116 static int network_load_file(struct network *net)
117 {
118 blob_buf_init(&b, 0);
119
120 if (!blobmsg_add_json_from_file(&b, net->config.file))
121 return -1;
122
123 return network_load_data(net, b.head);
124 }
125
126 static int network_load_dynamic(struct network *net)
127 {
128 const char *json = NULL;
129 char *fname = NULL;
130 struct stat st;
131 FILE *f = NULL;
132 int ret = -1;
133
134 if (asprintf(&fname, "%s/%s.bin", data_dir, network_name(net)) < 0)
135 return -1;
136
137 f = fopen(fname, "r");
138 free(fname);
139
140 if (!f) {
141 D_NET(net, "failed to open %s/%s.bin\n", data_dir, network_name(net));
142 return -1;
143 }
144
145 if (fstat(fileno(f), &st) < 0)
146 goto out;
147
148 net->net_data_len = st.st_size;
149 net->net_data = realloc(net->net_data, net->net_data_len + 1);
150 memset(net->net_data + net->net_data_len, 0, 1);
151 if (fread(net->net_data, 1, net->net_data_len, f) != net->net_data_len ||
152 unet_auth_data_validate(net->config.auth_key, net->net_data,
153 net->net_data_len, &net->net_data_version, &json)) {
154 net->net_data_len = 0;
155 goto out;
156 }
157
158 fclose(f);
159 blob_buf_init(&b, 0);
160 if (!blobmsg_add_json_from_string(&b, json)) {
161 net->net_data_len = 0;
162 return -1;
163 }
164
165 return network_load_data(net, b.head);
166
167 out:
168 fclose(f);
169 return ret;
170 }
171
172 int network_save_dynamic(struct network *net)
173 {
174 char *fname = NULL, *fname2;
175 size_t len;
176 FILE *f;
177 int fd, ret;
178
179 if (net->config.type != NETWORK_TYPE_DYNAMIC ||
180 !net->net_data_len)
181 return -1;
182
183 if (asprintf(&fname, "%s/%s.bin.XXXXXXXX", data_dir, network_name(net)) < 0)
184 return -1;
185
186 fd = mkstemp(fname);
187 if (fd < 0)
188 goto error;
189
190 f = fdopen(fd, "w");
191 if (!f) {
192 close(fd);
193 goto error;
194 }
195
196 len = fwrite(net->net_data, 1, net->net_data_len, f);
197 fflush(f);
198 fdatasync(fd);
199 fclose(f);
200
201 if (len != net->net_data_len)
202 goto error;
203
204 fname2 = strdup(fname);
205 *strrchr(fname2, '.') = 0;
206 ret = rename(fname, fname2);
207 free(fname2);
208
209 if (ret)
210 unlink(fname);
211 free(fname);
212
213 return ret;
214
215 error:
216 free(fname);
217 return -1;
218 }
219
220
221 static void
222 network_fill_ip(struct blob_buf *buf, int af, union network_addr *addr, int mask)
223 {
224 char *str;
225 void *c;
226
227 c = blobmsg_open_table(buf, NULL);
228
229 blobmsg_printf(buf, "mask", "%d", mask);
230
231 str = blobmsg_alloc_string_buffer(buf, "ipaddr", INET6_ADDRSTRLEN);
232 inet_ntop(af, addr, str, INET6_ADDRSTRLEN);
233 blobmsg_add_string_buffer(buf);
234
235 blobmsg_close_table(buf, c);
236 }
237
238 static void
239 network_fill_ipaddr_list(struct network_host *host, struct blob_buf *b, bool ipv6)
240 {
241 union network_addr addr = {};
242 struct blob_attr *cur;
243 void *c;
244 int rem;
245 int af;
246
247 af = ipv6 ? AF_INET6 : AF_INET;
248 blobmsg_for_each_attr(cur, host->peer.ipaddr, rem) {
249 const char *str = blobmsg_get_string(cur);
250
251 if (!!strchr(str, ':') != ipv6)
252 continue;
253
254 if (inet_pton(af, str, &addr) != 1)
255 continue;
256
257 c = blobmsg_open_table(b, NULL);
258 blobmsg_add_string(b, "ipaddr", str);
259 blobmsg_add_string(b, "mask", ipv6 ? "128" : "32");
260 blobmsg_close_table(b, c);
261 }
262 }
263
264 static void
265 network_fill_ip_settings(struct network *net, struct blob_buf *buf)
266 {
267 struct network_host *host = net->net_config.local_host;
268 void *c;
269
270 c = blobmsg_open_array(buf, "ipaddr");
271 network_fill_ipaddr_list(host, buf, false);
272 blobmsg_close_array(buf, c);
273
274 c = blobmsg_open_array(buf, "ip6addr");
275 network_fill_ip(buf, AF_INET6, &host->peer.local_addr, 64);
276 network_fill_ipaddr_list(host, buf, true);
277 blobmsg_close_array(buf, c);
278 }
279
280 static void
281 __network_fill_host_subnets(struct network_host *host, struct blob_buf *b, bool ipv6)
282 {
283 union network_addr addr = {};
284 struct blob_attr *cur;
285 void *c;
286 int af;
287 int mask;
288 int rem;
289
290 af = ipv6 ? AF_INET6 : AF_INET;
291 blobmsg_for_each_attr(cur, host->peer.subnet, rem) {
292 const char *str = blobmsg_get_string(cur);
293 char *buf;
294
295 if (!!strchr(str, ':') != ipv6)
296 continue;
297
298 if (network_get_subnet(af, &addr, &mask, str))
299 continue;
300
301 c = blobmsg_open_table(b, NULL);
302
303 buf = blobmsg_alloc_string_buffer(b, "target", INET6_ADDRSTRLEN);
304 inet_ntop(af, &addr, buf, INET6_ADDRSTRLEN);
305 blobmsg_add_string_buffer(b);
306
307 blobmsg_printf(b, "netmask", "%d", mask);
308
309 blobmsg_close_table(b, c);
310 }
311
312 blobmsg_for_each_attr(cur, host->peer.ipaddr, rem) {
313 const char *str = blobmsg_get_string(cur);
314
315 if (!!strchr(str, ':') != ipv6)
316 continue;
317
318 if (inet_pton(af, str, &addr) != 1)
319 continue;
320
321 c = blobmsg_open_table(b, NULL);
322 blobmsg_add_string(b, "target", str);
323 blobmsg_add_string(b, "netmask", ipv6 ? "128" : "32");
324 blobmsg_close_table(b, c);
325 }
326 }
327
328 static void
329 __network_fill_subnets(struct network *net, struct blob_buf *buf, bool ipv6)
330 {
331 struct network_host *host;
332 void *c;
333
334 c = blobmsg_open_array(buf, ipv6 ? "routes6": "routes");
335 avl_for_each_element(&net->hosts, host, node) {
336 if (host == net->net_config.local_host)
337 continue;
338 __network_fill_host_subnets(host, buf, ipv6);
339 }
340 blobmsg_close_array(buf, c);
341 }
342
343
344 static void
345 network_fill_subnets(struct network *net, struct blob_buf *buf)
346 {
347 __network_fill_subnets(net, buf, false);
348 __network_fill_subnets(net, buf, true);
349 }
350
351 static void
352 network_do_update(struct network *net, bool up)
353 {
354 if (!net->net_config.local_host)
355 up = false;
356
357 blob_buf_init(&b, 0);
358 blobmsg_add_u32(&b, "action", 0);
359 blobmsg_add_string(&b, "ifname", network_name(net));
360 blobmsg_add_u8(&b, "link-up", up);
361
362 if (up) {
363 network_fill_ip_settings(net, &b);
364 network_fill_subnets(net, &b);
365 }
366
367 if (debug) {
368 char *s = blobmsg_format_json(b.head, true);
369 D_NET(net, "update: %s", s);
370 free(s);
371 }
372
373 if (net->config.update_cmd) {
374 const char *argv[] = { net->config.update_cmd, NULL, NULL };
375 int pid, stat;
376
377 pid = fork();
378 if (pid == 0) {
379 argv[1] = blobmsg_format_json(b.head, true);
380 execvp(argv[0], (char **)argv);
381 exit(1);
382 }
383 waitpid(pid, &stat, 0);
384 }
385
386 if (!net->config.interface)
387 return;
388
389 blobmsg_add_string(&b, "interface", net->config.interface);
390 unetd_ubus_netifd_update(b.head);
391 }
392
393 static void network_reload(struct uloop_timeout *t)
394 {
395 struct network *net = container_of(t, struct network, reload_timer);
396
397 net->prev_local_host = net->net_config.local_host;
398
399 memset(&net->net_config, 0, sizeof(net->net_config));
400
401 network_pex_close(net);
402 network_services_free(net);
403 network_hosts_update_start(net);
404 network_services_update_start(net);
405
406 switch (net->config.type) {
407 case NETWORK_TYPE_FILE:
408 network_load_file(net);
409 break;
410 case NETWORK_TYPE_INLINE:
411 network_load_data(net, net->config.net_data);
412 break;
413 case NETWORK_TYPE_DYNAMIC:
414 network_load_dynamic(net);
415 break;
416 }
417
418 network_services_update_done(net);
419 network_hosts_update_done(net);
420 uloop_timeout_set(&net->connect_timer, 10);
421
422 net->prev_local_host = NULL;
423
424 unetd_write_hosts();
425 network_do_update(net, true);
426 network_pex_open(net);
427 unetd_ubus_notify(net);
428 }
429
430 void network_soft_reload(struct network *net)
431 {
432 siphash_key_t key = {};
433 uint64_t hash;
434
435 if (net->config.type == NETWORK_TYPE_FILE) {
436 blob_buf_init(&b, 0);
437
438 if (!blobmsg_add_json_from_file(&b, net->config.file))
439 return;
440
441 hash = siphash(b.head, blob_raw_len(b.head), &key);
442 if (hash != net->net_config.hash) {
443 uloop_timeout_set(&net->reload_timer, 1);
444 return;
445 }
446 }
447
448 network_hosts_reload_dynamic_peers(net);
449 }
450
451 static int network_setup(struct network *net)
452 {
453 if (wg_init_network(net)) {
454 fprintf(stderr, "Setup failed for network %s\n", network_name(net));
455 return -1;
456 }
457
458 net->ifindex = if_nametoindex(network_name(net));
459 if (!net->ifindex) {
460 fprintf(stderr, "Could not get ifindex for network %s\n", network_name(net));
461 return -1;
462 }
463
464 return 0;
465 }
466
467 static void network_teardown(struct network *net)
468 {
469 uloop_timeout_cancel(&net->connect_timer);
470 uloop_timeout_cancel(&net->reload_timer);
471 network_do_update(net, false);
472 network_pex_close(net);
473 network_pex_free(net);
474 network_hosts_free(net);
475 network_services_free(net);
476 wg_cleanup_network(net);
477 }
478
479 static void
480 network_destroy(struct network *net)
481 {
482 network_teardown(net);
483 avl_delete(&networks, &net->node);
484 free(net->net_data);
485 free(net->config.data);
486 free(net);
487 }
488
489 static int
490 network_set_config(struct network *net, struct blob_attr *config)
491 {
492 struct blob_attr *tb[__NETWORK_ATTR_MAX];
493 struct blob_attr *cur;
494
495 if (net->config.data && blob_attr_equal(net->config.data, config))
496 goto reload;
497
498 network_teardown(net);
499
500 free(net->config.data);
501 memset(&net->config, 0, sizeof(net->config));
502
503 net->config.data = blob_memdup(config);
504 blobmsg_parse(network_policy, __NETWORK_ATTR_MAX, tb,
505 blobmsg_data(net->config.data),
506 blobmsg_len(net->config.data));
507
508 if ((cur = tb[NETWORK_ATTR_TYPE]) == NULL ||
509 !strlen(blobmsg_get_string(cur)) ||
510 !strcmp(blobmsg_get_string(cur), "dynamic"))
511 net->config.type = NETWORK_TYPE_DYNAMIC;
512 else if (!strcmp(blobmsg_get_string(cur), "file"))
513 net->config.type = NETWORK_TYPE_FILE;
514 else if (!strcmp(blobmsg_get_string(cur), "inline"))
515 net->config.type = NETWORK_TYPE_INLINE;
516 else
517 goto invalid;
518
519 if ((cur = tb[NETWORK_ATTR_KEEPALIVE]) != NULL)
520 net->config.keepalive = blobmsg_get_u32(cur);
521 else
522 net->config.keepalive = -1;
523
524 switch (net->config.type) {
525 case NETWORK_TYPE_FILE:
526 if ((cur = tb[NETWORK_ATTR_FILE]) != NULL)
527 net->config.file = blobmsg_get_string(cur);
528 else
529 goto invalid;
530 break;
531 case NETWORK_TYPE_INLINE:
532 net->config.net_data = tb[NETWORK_ATTR_DATA];
533 if (!net->config.net_data)
534 goto invalid;
535 break;
536 case NETWORK_TYPE_DYNAMIC:
537 if ((cur = tb[NETWORK_ATTR_AUTH_KEY]) == NULL)
538 goto invalid;
539
540 if (b64_decode(blobmsg_get_string(cur), net->config.auth_key,
541 sizeof(net->config.auth_key)) != sizeof(net->config.auth_key))
542 goto invalid;
543 break;
544 }
545
546 if ((cur = tb[NETWORK_ATTR_INTERFACE]) != NULL &&
547 strlen(blobmsg_get_string(cur)) > 0)
548 net->config.interface = blobmsg_get_string(cur);
549
550 if ((cur = tb[NETWORK_ATTR_UPDATE_CMD]) != NULL &&
551 strlen(blobmsg_get_string(cur)) > 0)
552 net->config.update_cmd = blobmsg_get_string(cur);
553
554 if ((cur = tb[NETWORK_ATTR_DOMAIN]) != NULL &&
555 strlen(blobmsg_get_string(cur)) > 0)
556 net->config.domain = blobmsg_get_string(cur);
557
558 if ((cur = tb[NETWORK_ATTR_TUNNELS]) != NULL)
559 net->config.tunnels = cur;
560
561 if ((cur = tb[NETWORK_ATTR_AUTH_CONNECT]) != NULL &&
562 blobmsg_check_array(cur, BLOBMSG_TYPE_STRING) > 0)
563 net->config.auth_connect = cur;
564
565 if ((cur = tb[NETWORK_ATTR_PEER_DATA]) != NULL &&
566 blobmsg_check_array(cur, BLOBMSG_TYPE_STRING) > 0)
567 net->config.peer_data = cur;
568
569 if ((cur = tb[NETWORK_ATTR_KEY]) == NULL)
570 goto invalid;
571
572 if (b64_decode(blobmsg_get_string(cur), net->config.key, sizeof(net->config.key)) !=
573 sizeof(net->config.key))
574 goto invalid;
575
576 curve25519_generate_public(net->config.pubkey, net->config.key);
577
578 if (network_setup(net))
579 goto invalid;
580
581 reload:
582 network_reload(&net->reload_timer);
583
584 return 0;
585
586 invalid:
587 network_destroy(net);
588 return -1;
589 }
590
591 static struct network *
592 network_alloc(const char *name)
593 {
594 struct network *net;
595 char *name_buf;
596
597 net = calloc_a(sizeof(*net), &name_buf, strlen(name) + 1);
598 net->node.key = strcpy(name_buf, name);
599 net->reload_timer.cb = network_reload;
600 avl_insert(&networks, &net->node);
601
602 network_pex_init(net);
603 network_hosts_init(net);
604 network_services_init(net);
605
606 return net;
607 }
608
609 void network_fill_host_addr(union network_addr *addr, uint8_t *pubkey)
610 {
611 siphash_key_t key = {
612 .key = {
613 get_unaligned_le64(addr->network_id),
614 get_unaligned_le64(addr->network_id)
615 }
616 };
617
618 siphash_to_le64(&addr->host_addr, pubkey, CURVE25519_KEY_SIZE, &key);
619 }
620
621 int unetd_network_add(const char *name, struct blob_attr *config)
622 {
623 struct network *net;
624
625 if (strchr(name, '/'))
626 return -1;
627
628 net = avl_find_element(&networks, name, net, node);
629 if (!net)
630 net = network_alloc(name);
631
632 return network_set_config(net, config);
633 }
634
635 int unetd_network_remove(const char *name)
636 {
637 struct network *net;
638
639 net = avl_find_element(&networks, name, net, node);
640 if (!net)
641 return -1;
642
643 network_destroy(net);
644
645 return 0;
646 }
647
648 void network_free_all(void)
649 {
650 struct network *net, *tmp;
651
652 avl_for_each_element_safe(&networks, net, node, tmp)
653 network_destroy(net);
654 }