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