unet-cli: pass host object to set_host()
[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_hosts_free(net);
449 network_services_free(net);
450 wg_cleanup_network(net);
451 }
452
453 static void
454 network_destroy(struct network *net)
455 {
456 network_teardown(net);
457 avl_delete(&networks, &net->node);
458 free(net->net_data);
459 free(net->config.data);
460 free(net);
461 }
462
463 static int
464 network_set_config(struct network *net, struct blob_attr *config)
465 {
466 struct blob_attr *tb[__NETWORK_ATTR_MAX];
467 struct blob_attr *cur;
468
469 if (net->config.data && blob_attr_equal(net->config.data, config))
470 goto reload;
471
472 network_teardown(net);
473
474 free(net->config.data);
475 memset(&net->config, 0, sizeof(net->config));
476
477 net->config.data = blob_memdup(config);
478 blobmsg_parse(network_policy, __NETWORK_ATTR_MAX, tb,
479 blobmsg_data(net->config.data),
480 blobmsg_len(net->config.data));
481
482 if ((cur = tb[NETWORK_ATTR_TYPE]) == NULL ||
483 !strlen(blobmsg_get_string(cur)) ||
484 !strcmp(blobmsg_get_string(cur), "dynamic"))
485 net->config.type = NETWORK_TYPE_DYNAMIC;
486 else if (!strcmp(blobmsg_get_string(cur), "file"))
487 net->config.type = NETWORK_TYPE_FILE;
488 else if (!strcmp(blobmsg_get_string(cur), "inline"))
489 net->config.type = NETWORK_TYPE_INLINE;
490 else
491 goto invalid;
492
493 if ((cur = tb[NETWORK_ATTR_KEEPALIVE]) != NULL)
494 net->config.keepalive = blobmsg_get_u32(cur);
495 else
496 net->config.keepalive = -1;
497
498 switch (net->config.type) {
499 case NETWORK_TYPE_FILE:
500 if ((cur = tb[NETWORK_ATTR_FILE]) != NULL)
501 net->config.file = blobmsg_get_string(cur);
502 else
503 goto invalid;
504 break;
505 case NETWORK_TYPE_INLINE:
506 net->config.net_data = tb[NETWORK_ATTR_DATA];
507 if (!net->config.net_data)
508 goto invalid;
509 break;
510 case NETWORK_TYPE_DYNAMIC:
511 if ((cur = tb[NETWORK_ATTR_AUTH_KEY]) == NULL)
512 goto invalid;
513
514 if (b64_decode(blobmsg_get_string(cur), net->config.auth_key,
515 sizeof(net->config.auth_key)) != sizeof(net->config.auth_key))
516 goto invalid;
517 break;
518 }
519
520 if ((cur = tb[NETWORK_ATTR_INTERFACE]) != NULL &&
521 strlen(blobmsg_get_string(cur)) > 0)
522 net->config.interface = blobmsg_get_string(cur);
523
524 if ((cur = tb[NETWORK_ATTR_UPDATE_CMD]) != NULL &&
525 strlen(blobmsg_get_string(cur)) > 0)
526 net->config.update_cmd = blobmsg_get_string(cur);
527
528 if ((cur = tb[NETWORK_ATTR_DOMAIN]) != NULL &&
529 strlen(blobmsg_get_string(cur)) > 0)
530 net->config.domain = blobmsg_get_string(cur);
531
532 if ((cur = tb[NETWORK_ATTR_TUNNELS]) != NULL)
533 net->config.tunnels = cur;
534
535 if ((cur = tb[NETWORK_ATTR_AUTH_CONNECT]) != NULL &&
536 blobmsg_check_array(cur, BLOBMSG_TYPE_STRING) > 0)
537 net->config.auth_connect = cur;
538
539 if ((cur = tb[NETWORK_ATTR_KEY]) == NULL)
540 goto invalid;
541
542 if (b64_decode(blobmsg_get_string(cur), net->config.key, sizeof(net->config.key)) !=
543 sizeof(net->config.key))
544 goto invalid;
545
546 curve25519_generate_public(net->config.pubkey, net->config.key);
547
548 if (network_setup(net))
549 goto invalid;
550
551 reload:
552 network_reload(&net->reload_timer);
553
554 return 0;
555
556 invalid:
557 network_destroy(net);
558 return -1;
559 }
560
561 static struct network *
562 network_alloc(const char *name)
563 {
564 struct network *net;
565 char *name_buf;
566
567 net = calloc_a(sizeof(*net), &name_buf, strlen(name) + 1);
568 net->node.key = strcpy(name_buf, name);
569 net->reload_timer.cb = network_reload;
570 avl_insert(&networks, &net->node);
571
572 network_pex_init(net);
573 network_hosts_init(net);
574 network_services_init(net);
575
576 return net;
577 }
578
579 void network_fill_host_addr(union network_addr *addr, uint8_t *pubkey)
580 {
581 siphash_key_t key = {
582 .key = {
583 get_unaligned_le64(addr->network_id),
584 get_unaligned_le64(addr->network_id)
585 }
586 };
587
588 siphash_to_le64(&addr->host_addr, pubkey, CURVE25519_KEY_SIZE, &key);
589 }
590
591 int unetd_network_add(const char *name, struct blob_attr *config)
592 {
593 struct network *net;
594
595 if (strchr(name, '/'))
596 return -1;
597
598 net = avl_find_element(&networks, name, net, node);
599 if (!net)
600 net = network_alloc(name);
601
602 return network_set_config(net, config);
603 }
604
605 int unetd_network_remove(const char *name)
606 {
607 struct network *net;
608
609 net = avl_find_element(&networks, name, net, node);
610 if (!net)
611 return -1;
612
613 network_destroy(net);
614
615 return 0;
616 }
617
618 void network_free_all(void)
619 {
620 struct network *net, *tmp;
621
622 avl_for_each_element_safe(&networks, net, node, tmp)
623 network_destroy(net);
624 }