vxlan: add bpf program to fix up tcp mss values
[project/unetd.git] / network.c
1 // SPDX-License-Identifier: GPL-2.0+
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_KEY] = { "key", BLOBMSG_TYPE_STRING },
48 [NETWORK_ATTR_FILE] = { "file", BLOBMSG_TYPE_STRING },
49 [NETWORK_ATTR_DATA] = { "data", BLOBMSG_TYPE_TABLE },
50 [NETWORK_ATTR_INTERFACE] = { "interface", BLOBMSG_TYPE_STRING },
51 [NETWORK_ATTR_KEEPALIVE] = { "keepalive", BLOBMSG_TYPE_INT32 },
52 [NETWORK_ATTR_DOMAIN] = { "domain", BLOBMSG_TYPE_STRING },
53 [NETWORK_ATTR_UPDATE_CMD] = { "update-cmd", BLOBMSG_TYPE_STRING },
54 [NETWORK_ATTR_TUNNELS] = { "tunnels", BLOBMSG_TYPE_TABLE },
55 };
56
57 AVL_TREE(networks, avl_strcmp, false, NULL);
58 static struct blob_buf b;
59
60 static void network_load_config_data(struct network *net, struct blob_attr *data)
61 {
62 struct blob_attr *tb[__NETCONF_ATTR_MAX];
63 struct blob_attr *cur;
64 siphash_key_t key = {};
65
66 blobmsg_parse(netconf_policy, __NETCONF_ATTR_MAX, tb,
67 blobmsg_data(data), blobmsg_len(data));
68
69 if ((cur = tb[NETCONF_ATTR_PORT]) != NULL)
70 net->net_config.port = blobmsg_get_u32(cur);
71 else
72 net->net_config.port = 51820;
73
74 if ((cur = tb[NETCONF_ATTR_PEX_PORT]) != NULL)
75 net->net_config.pex_port = blobmsg_get_u32(cur);
76
77 if ((cur = tb[NETCONF_ATTR_ID]) != NULL) {
78 const char *id = blobmsg_get_string(cur);
79 siphash_to_le64(&net->net_config.addr.network_id, id, strlen(id), &key);
80 } else {
81 siphash_to_le64(&net->net_config.addr.network_id, &net->net_config.port,
82 sizeof(net->net_config.port), &key);
83 }
84
85 net->net_config.addr.network_id[0] = 0xfd;
86 network_fill_host_addr(&net->net_config.addr, net->config.pubkey);
87
88 if (net->config.keepalive >= 0)
89 net->net_config.keepalive = net->config.keepalive;
90 else if ((cur = tb[NETCONF_ATTR_KEEPALIVE]) != NULL)
91 net->net_config.keepalive = blobmsg_get_u32(cur);
92 else
93 net->net_config.keepalive = 0;
94 }
95
96 static int network_load_data(struct network *net, struct blob_attr *data)
97 {
98 struct blob_attr *tb[__NETDATA_ATTR_MAX];
99
100 blobmsg_parse(netdata_policy, __NETDATA_ATTR_MAX, tb,
101 blobmsg_data(data), blobmsg_len(data));
102
103 network_load_config_data(net, tb[NETDATA_ATTR_CONFIG]);
104 network_hosts_add(net, tb[NETDATA_ATTR_HOSTS]);
105 network_services_add(net, tb[NETDATA_ATTR_SERVICES]);
106
107 return 0;
108 }
109
110 static int network_load_file(struct network *net)
111 {
112 blob_buf_init(&b, 0);
113
114 if (!blobmsg_add_json_from_file(&b, net->config.file))
115 return -1;
116
117 return network_load_data(net, b.head);
118 }
119
120 static void
121 network_fill_ip(struct blob_buf *buf, int af, union network_addr *addr, int mask)
122 {
123 char *str;
124 void *c;
125
126 c = blobmsg_open_table(buf, NULL);
127
128 blobmsg_printf(buf, "mask", "%d", mask);
129
130 str = blobmsg_alloc_string_buffer(buf, "ipaddr", INET6_ADDRSTRLEN);
131 inet_ntop(af, addr, str, INET6_ADDRSTRLEN);
132 blobmsg_add_string_buffer(buf);
133
134 blobmsg_close_table(buf, c);
135 }
136
137 static void
138 network_fill_ipaddr_list(struct network_host *host, struct blob_buf *b, bool ipv6)
139 {
140 union network_addr addr = {};
141 struct blob_attr *cur;
142 void *c;
143 int rem;
144 int af;
145
146 af = ipv6 ? AF_INET6 : AF_INET;
147 blobmsg_for_each_attr(cur, host->peer.ipaddr, rem) {
148 const char *str = blobmsg_get_string(cur);
149
150 if (!!strchr(str, ':') != ipv6)
151 continue;
152
153 if (inet_pton(af, str, &addr) != 1)
154 continue;
155
156 c = blobmsg_open_table(b, NULL);
157 blobmsg_add_string(b, "ipaddr", str);
158 blobmsg_add_string(b, "mask", ipv6 ? "128" : "32");
159 blobmsg_close_table(b, c);
160 }
161 }
162
163 static void
164 network_fill_ip_settings(struct network *net, struct blob_buf *buf)
165 {
166 struct network_host *host = net->net_config.local_host;
167 void *c;
168
169 c = blobmsg_open_array(buf, "ipaddr");
170 network_fill_ipaddr_list(host, buf, false);
171 blobmsg_close_array(buf, c);
172
173 c = blobmsg_open_array(buf, "ip6addr");
174 network_fill_ip(buf, AF_INET6, &host->peer.local_addr, 64);
175 network_fill_ipaddr_list(host, buf, true);
176 blobmsg_close_array(buf, c);
177 }
178
179 static void
180 __network_fill_host_subnets(struct network_host *host, struct blob_buf *b, bool ipv6)
181 {
182 union network_addr addr = {};
183 struct blob_attr *cur;
184 void *c;
185 int af;
186 int mask;
187 int rem;
188
189 af = ipv6 ? AF_INET6 : AF_INET;
190 blobmsg_for_each_attr(cur, host->peer.subnet, rem) {
191 const char *str = blobmsg_get_string(cur);
192 char *buf;
193
194 if (!!strchr(str, ':') != ipv6)
195 continue;
196
197 if (network_get_subnet(af, &addr, &mask, str))
198 continue;
199
200 c = blobmsg_open_table(b, NULL);
201
202 buf = blobmsg_alloc_string_buffer(b, "target", INET6_ADDRSTRLEN);
203 inet_ntop(af, &addr, buf, INET6_ADDRSTRLEN);
204 blobmsg_add_string_buffer(b);
205
206 blobmsg_printf(b, "netmask", "%d", mask);
207
208 blobmsg_close_table(b, c);
209 }
210
211 blobmsg_for_each_attr(cur, host->peer.ipaddr, rem) {
212 const char *str = blobmsg_get_string(cur);
213
214 if (!!strchr(str, ':') != ipv6)
215 continue;
216
217 if (inet_pton(af, str, &addr) != 1)
218 continue;
219
220 c = blobmsg_open_table(b, NULL);
221 blobmsg_add_string(b, "target", str);
222 blobmsg_add_string(b, "netmask", ipv6 ? "128" : "32");
223 blobmsg_close_table(b, c);
224 }
225 }
226
227 static void
228 __network_fill_subnets(struct network *net, struct blob_buf *buf, bool ipv6)
229 {
230 struct network_host *host;
231 void *c;
232
233 c = blobmsg_open_array(buf, ipv6 ? "routes6": "routes");
234 avl_for_each_element(&net->hosts, host, node) {
235 if (host == net->net_config.local_host)
236 continue;
237 __network_fill_host_subnets(host, buf, ipv6);
238 }
239 blobmsg_close_array(buf, c);
240 }
241
242
243 static void
244 network_fill_subnets(struct network *net, struct blob_buf *buf)
245 {
246 __network_fill_subnets(net, buf, false);
247 __network_fill_subnets(net, buf, true);
248 }
249
250 static void
251 network_do_update(struct network *net, bool up)
252 {
253 if (!net->net_config.local_host)
254 up = false;
255
256 blob_buf_init(&b, 0);
257 blobmsg_add_u32(&b, "action", 0);
258 blobmsg_add_string(&b, "ifname", network_name(net));
259 blobmsg_add_u8(&b, "link-up", up);
260
261 if (up) {
262 network_fill_ip_settings(net, &b);
263 network_fill_subnets(net, &b);
264 }
265
266 if (debug) {
267 char *s = blobmsg_format_json(b.head, true);
268 D_NET(net, "update: %s", s);
269 free(s);
270 }
271
272 if (net->config.update_cmd) {
273 const char *argv[] = { net->config.update_cmd, NULL, NULL };
274 int pid, stat;
275
276 pid = fork();
277 if (pid == 0) {
278 argv[1] = blobmsg_format_json(b.head, true);
279 execvp(argv[0], (char **)argv);
280 exit(1);
281 }
282 waitpid(pid, &stat, 0);
283 }
284
285 if (!net->config.interface)
286 return;
287
288 blobmsg_add_string(&b, "interface", net->config.interface);
289 unetd_ubus_netifd_update(b.head);
290 }
291
292 static int network_reload(struct network *net)
293 {
294 int ret;
295
296 net->prev_local_host = net->net_config.local_host;
297
298 memset(&net->net_config, 0, sizeof(net->net_config));
299
300 network_pex_close(net);
301 network_services_free(net);
302 network_hosts_update_start(net);
303 network_services_update_start(net);
304
305 switch (net->config.type) {
306 case NETWORK_TYPE_FILE:
307 ret = network_load_file(net);
308 break;
309 case NETWORK_TYPE_INLINE:
310 ret = network_load_data(net, net->config.net_data);
311 break;
312 }
313
314 network_services_update_done(net);
315 network_hosts_update_done(net);
316 uloop_timeout_set(&net->connect_timer, 10);
317
318 net->prev_local_host = NULL;
319
320 unetd_write_hosts();
321 network_do_update(net, true);
322 network_pex_open(net);
323
324 return ret;
325 }
326
327 static int network_setup(struct network *net)
328 {
329 if (wg_init_network(net)) {
330 fprintf(stderr, "Setup failed for network %s\n", network_name(net));
331 return -1;
332 }
333
334 net->ifindex = if_nametoindex(network_name(net));
335 if (!net->ifindex) {
336 fprintf(stderr, "Could not get ifindex for network %s\n", network_name(net));
337 return -1;
338 }
339
340 return 0;
341 }
342
343 static void network_teardown(struct network *net)
344 {
345 network_do_update(net, false);
346 network_pex_close(net);
347 network_hosts_free(net);
348 network_services_free(net);
349 wg_cleanup_network(net);
350 }
351
352 static void
353 network_destroy(struct network *net)
354 {
355 network_teardown(net);
356 avl_delete(&networks, &net->node);
357 free(net->config.data);
358 free(net);
359 }
360
361 static int
362 network_set_config(struct network *net, struct blob_attr *config)
363 {
364 struct blob_attr *tb[__NETWORK_ATTR_MAX];
365 struct blob_attr *cur;
366
367 if (net->config.data && blob_attr_equal(net->config.data, config))
368 goto reload;
369
370 network_teardown(net);
371
372 free(net->config.data);
373 memset(&net->config, 0, sizeof(net->config));
374
375 net->config.data = blob_memdup(config);
376 blobmsg_parse(network_policy, __NETWORK_ATTR_MAX, tb,
377 blobmsg_data(net->config.data),
378 blobmsg_len(net->config.data));
379
380 if ((cur = tb[NETWORK_ATTR_TYPE]) == NULL)
381 goto invalid;
382
383 if (!strcmp(blobmsg_get_string(cur), "file"))
384 net->config.type = NETWORK_TYPE_FILE;
385 else if (!strcmp(blobmsg_get_string(cur), "inline"))
386 net->config.type = NETWORK_TYPE_INLINE;
387 else
388 goto invalid;
389
390 if ((cur = tb[NETWORK_ATTR_KEEPALIVE]) != NULL)
391 net->config.keepalive = blobmsg_get_u32(cur);
392 else
393 net->config.keepalive = -1;
394
395 switch (net->config.type) {
396 case NETWORK_TYPE_FILE:
397 if ((cur = tb[NETWORK_ATTR_FILE]) != NULL)
398 net->config.file = blobmsg_get_string(cur);
399 else
400 goto invalid;
401 break;
402 case NETWORK_TYPE_INLINE:
403 net->config.net_data = tb[NETWORK_ATTR_DATA];
404 if (!net->config.net_data)
405 goto invalid;
406 break;
407 }
408
409 if ((cur = tb[NETWORK_ATTR_INTERFACE]) != NULL)
410 net->config.interface = blobmsg_get_string(cur);
411
412 if ((cur = tb[NETWORK_ATTR_UPDATE_CMD]) != NULL)
413 net->config.update_cmd = blobmsg_get_string(cur);
414
415 if ((cur = tb[NETWORK_ATTR_DOMAIN]) != NULL)
416 net->config.domain = blobmsg_get_string(cur);
417
418 if ((cur = tb[NETWORK_ATTR_TUNNELS]) != NULL)
419 net->config.tunnels = cur;
420
421 if ((cur = tb[NETWORK_ATTR_KEY]) == NULL)
422 goto invalid;
423
424 if (b64_decode(blobmsg_get_string(cur), net->config.key, sizeof(net->config.key)) !=
425 sizeof(net->config.key))
426 goto invalid;
427
428 curve25519_generate_public(net->config.pubkey, net->config.key);
429
430 if (network_setup(net))
431 goto invalid;
432
433 reload:
434 network_reload(net);
435
436 return 0;
437
438 invalid:
439 network_destroy(net);
440 return -1;
441 }
442
443 static struct network *
444 network_alloc(const char *name)
445 {
446 struct network *net;
447 char *name_buf;
448
449 net = calloc_a(sizeof(*net), &name_buf, strlen(name) + 1);
450 net->node.key = strcpy(name_buf, name);
451 avl_insert(&networks, &net->node);
452
453 network_pex_init(net);
454 network_hosts_init(net);
455 network_services_init(net);
456
457 return net;
458 }
459
460 void network_fill_host_addr(union network_addr *addr, uint8_t *pubkey)
461 {
462 siphash_key_t key = {
463 .key = {
464 get_unaligned_le64(addr->network_id),
465 get_unaligned_le64(addr->network_id)
466 }
467 };
468
469 siphash_to_le64(&addr->host_addr, pubkey, CURVE25519_KEY_SIZE, &key);
470 }
471
472 int unetd_network_add(const char *name, struct blob_attr *config)
473 {
474 struct network *net;
475
476 if (strchr(name, '/'))
477 return -1;
478
479 net = avl_find_element(&networks, name, net, node);
480 if (!net)
481 net = network_alloc(name);
482
483 return network_set_config(net, config);
484 }
485
486 int unetd_network_remove(const char *name)
487 {
488 struct network *net;
489
490 net = avl_find_element(&networks, name, net, node);
491 if (!net)
492 return -1;
493
494 network_destroy(net);
495
496 return 0;
497 }
498
499 void network_free_all(void)
500 {
501 struct network *net, *tmp;
502
503 avl_for_each_element_safe(&networks, net, node, tmp)
504 network_destroy(net);
505 }