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