1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
8 #include <sys/socket.h>
11 #include <libubox/avl-cmp.h>
12 #include <libubox/utils.h>
13 #include <libubox/blobmsg_json.h>
20 NETDATA_ATTR_SERVICES
,
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
},
33 NETCONF_ATTR_PEX_PORT
,
34 NETCONF_ATTR_KEEPALIVE
,
35 NETCONF_ATTR_STUN_SERVERS
,
39 static const struct blobmsg_policy netconf_policy
[__NETCONF_ATTR_MAX
] = {
40 [NETCONF_ATTR_ID
] = { "id", BLOBMSG_TYPE_STRING
},
41 [NETCONF_ATTR_PORT
] = { "port", BLOBMSG_TYPE_INT32
},
42 [NETCONF_ATTR_PEX_PORT
] = { "peer-exchange-port", BLOBMSG_TYPE_INT32
},
43 [NETCONF_ATTR_KEEPALIVE
] = { "keepalive", BLOBMSG_TYPE_INT32
},
44 [NETCONF_ATTR_STUN_SERVERS
] = { "stun-servers", BLOBMSG_TYPE_ARRAY
},
47 const struct blobmsg_policy network_policy
[__NETWORK_ATTR_MAX
] = {
48 [NETWORK_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
49 [NETWORK_ATTR_TYPE
] = { "type", BLOBMSG_TYPE_STRING
},
50 [NETWORK_ATTR_AUTH_KEY
] = { "auth_key", BLOBMSG_TYPE_STRING
},
51 [NETWORK_ATTR_KEY
] = { "key", BLOBMSG_TYPE_STRING
},
52 [NETWORK_ATTR_FILE
] = { "file", BLOBMSG_TYPE_STRING
},
53 [NETWORK_ATTR_DATA
] = { "data", BLOBMSG_TYPE_TABLE
},
54 [NETWORK_ATTR_INTERFACE
] = { "interface", BLOBMSG_TYPE_STRING
},
55 [NETWORK_ATTR_KEEPALIVE
] = { "keepalive", BLOBMSG_TYPE_INT32
},
56 [NETWORK_ATTR_DOMAIN
] = { "domain", BLOBMSG_TYPE_STRING
},
57 [NETWORK_ATTR_UPDATE_CMD
] = { "update-cmd", BLOBMSG_TYPE_STRING
},
58 [NETWORK_ATTR_TUNNELS
] = { "tunnels", BLOBMSG_TYPE_TABLE
},
59 [NETWORK_ATTR_AUTH_CONNECT
] = { "auth_connect", BLOBMSG_TYPE_ARRAY
},
60 [NETWORK_ATTR_PEER_DATA
] = { "peer_data", BLOBMSG_TYPE_ARRAY
},
63 AVL_TREE(networks
, avl_strcmp
, false, NULL
);
64 static struct blob_buf b
;
66 static void network_load_stun_servers(struct network
*net
, struct blob_attr
*data
)
68 struct blob_attr
*cur
;
71 blobmsg_for_each_attr(cur
, data
, rem
)
72 network_stun_server_add(net
, blobmsg_get_string(cur
));
75 static void network_load_config_data(struct network
*net
, struct blob_attr
*data
)
77 struct blob_attr
*tb
[__NETCONF_ATTR_MAX
];
78 struct blob_attr
*cur
;
79 siphash_key_t key
= {};
81 blobmsg_parse(netconf_policy
, __NETCONF_ATTR_MAX
, tb
,
82 blobmsg_data(data
), blobmsg_len(data
));
84 if ((cur
= tb
[NETCONF_ATTR_PORT
]) != NULL
)
85 net
->net_config
.port
= blobmsg_get_u32(cur
);
87 net
->net_config
.port
= 51820;
89 if ((cur
= tb
[NETCONF_ATTR_PEX_PORT
]) != NULL
)
90 net
->net_config
.pex_port
= blobmsg_get_u32(cur
);
92 if ((cur
= tb
[NETCONF_ATTR_ID
]) != NULL
) {
93 const char *id
= blobmsg_get_string(cur
);
94 siphash_to_le64(&net
->net_config
.addr
.network_id
, id
, strlen(id
), &key
);
96 siphash_to_le64(&net
->net_config
.addr
.network_id
, &net
->net_config
.port
,
97 sizeof(net
->net_config
.port
), &key
);
100 net
->net_config
.addr
.network_id
[0] = 0xfd;
101 network_fill_host_addr(&net
->net_config
.addr
, net
->config
.pubkey
);
103 if (net
->config
.keepalive
>= 0)
104 net
->net_config
.keepalive
= net
->config
.keepalive
;
105 else if ((cur
= tb
[NETCONF_ATTR_KEEPALIVE
]) != NULL
)
106 net
->net_config
.keepalive
= blobmsg_get_u32(cur
);
108 net
->net_config
.keepalive
= 0;
110 if ((cur
= tb
[NETCONF_ATTR_STUN_SERVERS
]) != NULL
&&
111 blobmsg_check_array(cur
, BLOBMSG_TYPE_STRING
) > 0)
112 network_load_stun_servers(net
, cur
);
115 static int network_load_data(struct network
*net
, struct blob_attr
*data
)
117 struct blob_attr
*tb
[__NETDATA_ATTR_MAX
];
118 siphash_key_t key
= {};
120 net
->net_config
.hash
= siphash(data
, blob_raw_len(data
), &key
);
121 blobmsg_parse(netdata_policy
, __NETDATA_ATTR_MAX
, tb
,
122 blobmsg_data(data
), blobmsg_len(data
));
124 network_load_config_data(net
, tb
[NETDATA_ATTR_CONFIG
]);
125 network_hosts_add(net
, tb
[NETDATA_ATTR_HOSTS
]);
126 network_services_add(net
, tb
[NETDATA_ATTR_SERVICES
]);
131 static int network_load_file(struct network
*net
)
133 blob_buf_init(&b
, 0);
135 if (!blobmsg_add_json_from_file(&b
, net
->config
.file
))
138 return network_load_data(net
, b
.head
);
141 static int network_load_dynamic(struct network
*net
)
143 const char *json
= NULL
;
149 if (asprintf(&fname
, "%s/%s.bin", data_dir
, network_name(net
)) < 0)
152 f
= fopen(fname
, "r");
156 D_NET(net
, "failed to open %s/%s.bin\n", data_dir
, network_name(net
));
160 if (fstat(fileno(f
), &st
) < 0)
163 net
->net_data_len
= st
.st_size
;
164 net
->net_data
= realloc(net
->net_data
, net
->net_data_len
+ 1);
165 memset(net
->net_data
+ net
->net_data_len
, 0, 1);
166 if (fread(net
->net_data
, 1, net
->net_data_len
, f
) != net
->net_data_len
||
167 unet_auth_data_validate(net
->config
.auth_key
, net
->net_data
,
168 net
->net_data_len
, &net
->net_data_version
, &json
)) {
169 net
->net_data_len
= 0;
174 blob_buf_init(&b
, 0);
175 if (!blobmsg_add_json_from_string(&b
, json
)) {
176 net
->net_data_len
= 0;
180 return network_load_data(net
, b
.head
);
187 int network_save_dynamic(struct network
*net
)
189 char *fname
= NULL
, *fname2
;
194 if (net
->config
.type
!= NETWORK_TYPE_DYNAMIC
||
198 if (asprintf(&fname
, "%s/%s.bin.XXXXXXXX", data_dir
, network_name(net
)) < 0)
211 len
= fwrite(net
->net_data
, 1, net
->net_data_len
, f
);
216 if (len
!= net
->net_data_len
)
219 fname2
= strdup(fname
);
220 *strrchr(fname2
, '.') = 0;
221 ret
= rename(fname
, fname2
);
237 network_fill_ip(struct blob_buf
*buf
, int af
, union network_addr
*addr
, int mask
)
242 c
= blobmsg_open_table(buf
, NULL
);
244 blobmsg_printf(buf
, "mask", "%d", mask
);
246 str
= blobmsg_alloc_string_buffer(buf
, "ipaddr", INET6_ADDRSTRLEN
);
247 inet_ntop(af
, addr
, str
, INET6_ADDRSTRLEN
);
248 blobmsg_add_string_buffer(buf
);
250 blobmsg_close_table(buf
, c
);
254 network_fill_ipaddr_list(struct network_host
*host
, struct blob_buf
*b
, bool ipv6
)
256 union network_addr addr
= {};
257 struct blob_attr
*cur
;
262 af
= ipv6
? AF_INET6
: AF_INET
;
263 blobmsg_for_each_attr(cur
, host
->peer
.ipaddr
, rem
) {
264 const char *str
= blobmsg_get_string(cur
);
266 if (!!strchr(str
, ':') != ipv6
)
269 if (inet_pton(af
, str
, &addr
) != 1)
272 c
= blobmsg_open_table(b
, NULL
);
273 blobmsg_add_string(b
, "ipaddr", str
);
274 blobmsg_add_string(b
, "mask", ipv6
? "128" : "32");
275 blobmsg_close_table(b
, c
);
280 network_fill_ip_settings(struct network
*net
, struct blob_buf
*buf
)
282 struct network_host
*host
= net
->net_config
.local_host
;
285 c
= blobmsg_open_array(buf
, "ipaddr");
286 network_fill_ipaddr_list(host
, buf
, false);
287 blobmsg_close_array(buf
, c
);
289 c
= blobmsg_open_array(buf
, "ip6addr");
290 network_fill_ip(buf
, AF_INET6
, &host
->peer
.local_addr
, 64);
291 network_fill_ipaddr_list(host
, buf
, true);
292 blobmsg_close_array(buf
, c
);
296 __network_fill_host_subnets(struct network_host
*host
, struct blob_buf
*b
, bool ipv6
)
298 union network_addr addr
= {};
299 struct blob_attr
*cur
;
305 af
= ipv6
? AF_INET6
: AF_INET
;
306 blobmsg_for_each_attr(cur
, host
->peer
.subnet
, rem
) {
307 const char *str
= blobmsg_get_string(cur
);
310 if (!!strchr(str
, ':') != ipv6
)
313 if (network_get_subnet(af
, &addr
, &mask
, str
))
316 c
= blobmsg_open_table(b
, NULL
);
318 buf
= blobmsg_alloc_string_buffer(b
, "target", INET6_ADDRSTRLEN
);
319 inet_ntop(af
, &addr
, buf
, INET6_ADDRSTRLEN
);
320 blobmsg_add_string_buffer(b
);
322 blobmsg_printf(b
, "netmask", "%d", mask
);
324 blobmsg_close_table(b
, c
);
327 blobmsg_for_each_attr(cur
, host
->peer
.ipaddr
, rem
) {
328 const char *str
= blobmsg_get_string(cur
);
330 if (!!strchr(str
, ':') != ipv6
)
333 if (inet_pton(af
, str
, &addr
) != 1)
336 c
= blobmsg_open_table(b
, NULL
);
337 blobmsg_add_string(b
, "target", str
);
338 blobmsg_add_string(b
, "netmask", ipv6
? "128" : "32");
339 blobmsg_close_table(b
, c
);
344 __network_fill_subnets(struct network
*net
, struct blob_buf
*buf
, bool ipv6
)
346 struct network_host
*host
;
349 c
= blobmsg_open_array(buf
, ipv6
? "routes6": "routes");
350 avl_for_each_element(&net
->hosts
, host
, node
) {
351 if (host
== net
->net_config
.local_host
)
353 __network_fill_host_subnets(host
, buf
, ipv6
);
355 blobmsg_close_array(buf
, c
);
360 network_fill_subnets(struct network
*net
, struct blob_buf
*buf
)
362 __network_fill_subnets(net
, buf
, false);
363 __network_fill_subnets(net
, buf
, true);
367 __network_skip_endpoint_route(struct network
*net
, struct network_host
*host
,
368 union network_endpoint
*ep
)
370 bool ipv6
= ep
->sa
.sa_family
== AF_INET6
;
371 uint32_t *subnet32
, *addr32
, mask32
;
372 union network_addr addr
= {};
373 struct blob_attr
*cur
;
376 blobmsg_for_each_attr(cur
, host
->peer
.ipaddr
, rem
) {
377 const char *str
= blobmsg_get_string(cur
);
379 if (!!strchr(str
, ':') != ipv6
)
382 if (inet_pton(ep
->sa
.sa_family
, str
, &addr
) != 1)
386 if (!memcmp(&addr
.in6
, &ep
->in6
.sin6_addr
, sizeof(addr
.in6
)))
389 if (!memcmp(&addr
.in
, &ep
->in
.sin_addr
, sizeof(addr
.in
)))
395 addr32
= (uint32_t *)&ep
->in6
.sin6_addr
;
397 addr32
= (uint32_t *)&ep
->in
.sin_addr
;
399 subnet32
= (uint32_t *)&addr
;
400 blobmsg_for_each_attr(cur
, host
->peer
.subnet
, rem
) {
401 const char *str
= blobmsg_get_string(cur
);
404 if (!!strchr(str
, ':') != ipv6
)
407 if (network_get_subnet(ep
->sa
.sa_family
, &addr
, &mask
, str
))
413 for (i
= 0; i
< (ipv6
? 4 : 1); i
++) {
414 int cur_mask
= mask
> 32 ? 32 : mask
;
421 mask32
= ~0ULL << (32 - cur_mask
);
422 if (ntohl(subnet32
[i
] ^ addr32
[i
]) & mask32
)
432 bool network_skip_endpoint_route(struct network
*net
, union network_endpoint
*ep
)
434 struct network_host
*host
;
436 avl_for_each_element(&net
->hosts
, host
, node
)
437 if (__network_skip_endpoint_route(net
, host
, ep
))
445 network_do_update(struct network
*net
, bool up
)
447 if (!net
->net_config
.local_host
)
450 blob_buf_init(&b
, 0);
451 blobmsg_add_u32(&b
, "action", 0);
452 blobmsg_add_string(&b
, "ifname", network_name(net
));
453 blobmsg_add_u8(&b
, "link-up", up
);
456 network_fill_ip_settings(net
, &b
);
457 network_fill_subnets(net
, &b
);
461 char *s
= blobmsg_format_json(b
.head
, true);
462 D_NET(net
, "update: %s", s
);
466 if (net
->config
.update_cmd
) {
467 const char *argv
[] = { net
->config
.update_cmd
, NULL
, NULL
};
472 argv
[1] = blobmsg_format_json(b
.head
, true);
473 execvp(argv
[0], (char **)argv
);
476 waitpid(pid
, &stat
, 0);
479 if (!net
->config
.interface
)
482 blobmsg_add_string(&b
, "interface", net
->config
.interface
);
483 unetd_ubus_netifd_update(b
.head
);
486 static void network_reload(struct uloop_timeout
*t
)
488 struct network
*net
= container_of(t
, struct network
, reload_timer
);
490 net
->prev_local_host
= net
->net_config
.local_host
;
492 memset(&net
->net_config
, 0, sizeof(net
->net_config
));
494 network_stun_free(net
);
495 network_pex_close(net
);
496 network_services_free(net
);
497 network_hosts_update_start(net
);
498 network_services_update_start(net
);
500 switch (net
->config
.type
) {
501 case NETWORK_TYPE_FILE
:
502 network_load_file(net
);
504 case NETWORK_TYPE_INLINE
:
505 network_load_data(net
, net
->config
.net_data
);
507 case NETWORK_TYPE_DYNAMIC
:
508 network_load_dynamic(net
);
512 network_services_update_done(net
);
513 network_hosts_update_done(net
);
514 uloop_timeout_set(&net
->connect_timer
, 10);
516 net
->prev_local_host
= NULL
;
519 network_do_update(net
, true);
520 network_pex_open(net
);
521 network_stun_start(net
);
522 unetd_ubus_notify(net
);
525 void network_soft_reload(struct network
*net
)
527 siphash_key_t key
= {};
530 if (net
->config
.type
== NETWORK_TYPE_FILE
) {
531 blob_buf_init(&b
, 0);
533 if (!blobmsg_add_json_from_file(&b
, net
->config
.file
))
536 hash
= siphash(b
.head
, blob_raw_len(b
.head
), &key
);
537 if (hash
!= net
->net_config
.hash
) {
538 uloop_timeout_set(&net
->reload_timer
, 1);
543 network_hosts_reload_dynamic_peers(net
);
546 static int network_setup(struct network
*net
)
548 if (wg_init_network(net
)) {
549 fprintf(stderr
, "Setup failed for network %s\n", network_name(net
));
553 net
->ifindex
= if_nametoindex(network_name(net
));
555 fprintf(stderr
, "Could not get ifindex for network %s\n", network_name(net
));
562 static void network_teardown(struct network
*net
)
564 uloop_timeout_cancel(&net
->connect_timer
);
565 uloop_timeout_cancel(&net
->reload_timer
);
566 network_do_update(net
, false);
567 network_stun_free(net
);
568 network_pex_close(net
);
569 network_pex_free(net
);
570 network_hosts_free(net
);
571 network_services_free(net
);
572 wg_cleanup_network(net
);
576 network_destroy(struct network
*net
)
578 network_teardown(net
);
579 avl_delete(&networks
, &net
->node
);
581 free(net
->config
.data
);
586 network_set_config(struct network
*net
, struct blob_attr
*config
)
588 struct blob_attr
*tb
[__NETWORK_ATTR_MAX
];
589 struct blob_attr
*cur
;
591 if (net
->config
.data
&& blob_attr_equal(net
->config
.data
, config
))
594 network_teardown(net
);
596 free(net
->config
.data
);
597 memset(&net
->config
, 0, sizeof(net
->config
));
599 net
->config
.data
= blob_memdup(config
);
600 blobmsg_parse(network_policy
, __NETWORK_ATTR_MAX
, tb
,
601 blobmsg_data(net
->config
.data
),
602 blobmsg_len(net
->config
.data
));
604 if ((cur
= tb
[NETWORK_ATTR_TYPE
]) == NULL
||
605 !strlen(blobmsg_get_string(cur
)) ||
606 !strcmp(blobmsg_get_string(cur
), "dynamic"))
607 net
->config
.type
= NETWORK_TYPE_DYNAMIC
;
608 else if (!strcmp(blobmsg_get_string(cur
), "file"))
609 net
->config
.type
= NETWORK_TYPE_FILE
;
610 else if (!strcmp(blobmsg_get_string(cur
), "inline"))
611 net
->config
.type
= NETWORK_TYPE_INLINE
;
615 if ((cur
= tb
[NETWORK_ATTR_KEEPALIVE
]) != NULL
)
616 net
->config
.keepalive
= blobmsg_get_u32(cur
);
618 net
->config
.keepalive
= -1;
620 switch (net
->config
.type
) {
621 case NETWORK_TYPE_FILE
:
622 if ((cur
= tb
[NETWORK_ATTR_FILE
]) != NULL
)
623 net
->config
.file
= blobmsg_get_string(cur
);
627 case NETWORK_TYPE_INLINE
:
628 net
->config
.net_data
= tb
[NETWORK_ATTR_DATA
];
629 if (!net
->config
.net_data
)
632 case NETWORK_TYPE_DYNAMIC
:
633 if ((cur
= tb
[NETWORK_ATTR_AUTH_KEY
]) == NULL
)
636 if (b64_decode(blobmsg_get_string(cur
), net
->config
.auth_key
,
637 sizeof(net
->config
.auth_key
)) != sizeof(net
->config
.auth_key
))
642 if ((cur
= tb
[NETWORK_ATTR_INTERFACE
]) != NULL
&&
643 strlen(blobmsg_get_string(cur
)) > 0)
644 net
->config
.interface
= blobmsg_get_string(cur
);
646 if ((cur
= tb
[NETWORK_ATTR_UPDATE_CMD
]) != NULL
&&
647 strlen(blobmsg_get_string(cur
)) > 0)
648 net
->config
.update_cmd
= blobmsg_get_string(cur
);
650 if ((cur
= tb
[NETWORK_ATTR_DOMAIN
]) != NULL
&&
651 strlen(blobmsg_get_string(cur
)) > 0)
652 net
->config
.domain
= blobmsg_get_string(cur
);
654 if ((cur
= tb
[NETWORK_ATTR_TUNNELS
]) != NULL
)
655 net
->config
.tunnels
= cur
;
657 if ((cur
= tb
[NETWORK_ATTR_AUTH_CONNECT
]) != NULL
&&
658 blobmsg_check_array(cur
, BLOBMSG_TYPE_STRING
) > 0)
659 net
->config
.auth_connect
= cur
;
661 if ((cur
= tb
[NETWORK_ATTR_PEER_DATA
]) != NULL
&&
662 blobmsg_check_array(cur
, BLOBMSG_TYPE_STRING
) > 0)
663 net
->config
.peer_data
= cur
;
665 if ((cur
= tb
[NETWORK_ATTR_KEY
]) == NULL
)
668 if (b64_decode(blobmsg_get_string(cur
), net
->config
.key
, sizeof(net
->config
.key
)) !=
669 sizeof(net
->config
.key
))
672 curve25519_generate_public(net
->config
.pubkey
, net
->config
.key
);
674 if (network_setup(net
))
678 network_reload(&net
->reload_timer
);
683 network_destroy(net
);
687 static struct network
*
688 network_alloc(const char *name
)
693 net
= calloc_a(sizeof(*net
), &name_buf
, strlen(name
) + 1);
694 net
->node
.key
= strcpy(name_buf
, name
);
695 net
->reload_timer
.cb
= network_reload
;
696 avl_insert(&networks
, &net
->node
);
698 network_pex_init(net
);
699 network_stun_init(net
);
700 network_hosts_init(net
);
701 network_services_init(net
);
706 void network_fill_host_addr(union network_addr
*addr
, uint8_t *pubkey
)
708 siphash_key_t key
= {
710 get_unaligned_le64(addr
->network_id
),
711 get_unaligned_le64(addr
->network_id
)
715 siphash_to_le64(&addr
->host_addr
, pubkey
, CURVE25519_KEY_SIZE
, &key
);
718 int unetd_network_add(const char *name
, struct blob_attr
*config
)
722 if (strchr(name
, '/'))
725 net
= avl_find_element(&networks
, name
, net
, node
);
727 net
= network_alloc(name
);
729 return network_set_config(net
, config
);
732 int unetd_network_remove(const char *name
)
736 net
= avl_find_element(&networks
, name
, net
, node
);
740 network_destroy(net
);
745 void network_free_all(void)
747 struct network
*net
, *tmp
;
749 avl_for_each_element_safe(&networks
, net
, node
, tmp
)
750 network_destroy(net
);