1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
7 #include <libubox/avl-cmp.h>
8 #include <libubox/utils.h>
9 #include <libubox/blobmsg_json.h>
16 NETDATA_ATTR_SERVICES
,
20 static const struct blobmsg_policy netdata_policy
[__NETDATA_ATTR_MAX
] = {
21 [NETDATA_ATTR_CONFIG
] = { "config", BLOBMSG_TYPE_TABLE
},
22 [NETDATA_ATTR_HOSTS
] = { "hosts", BLOBMSG_TYPE_TABLE
},
23 [NETDATA_ATTR_SERVICES
] = { "services", BLOBMSG_TYPE_TABLE
},
29 NETCONF_ATTR_PEX_PORT
,
30 NETCONF_ATTR_KEEPALIVE
,
34 static const struct blobmsg_policy netconf_policy
[__NETCONF_ATTR_MAX
] = {
35 [NETCONF_ATTR_ID
] = { "id", BLOBMSG_TYPE_STRING
},
36 [NETCONF_ATTR_PORT
] = { "port", BLOBMSG_TYPE_INT32
},
37 [NETCONF_ATTR_PEX_PORT
] = { "peer-exchange-port", BLOBMSG_TYPE_INT32
},
38 [NETCONF_ATTR_KEEPALIVE
] = { "keepalive", BLOBMSG_TYPE_INT32
},
41 const struct blobmsg_policy network_policy
[__NETWORK_ATTR_MAX
] = {
42 [NETWORK_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
43 [NETWORK_ATTR_TYPE
] = { "type", BLOBMSG_TYPE_STRING
},
44 [NETWORK_ATTR_KEY
] = { "key", BLOBMSG_TYPE_STRING
},
45 [NETWORK_ATTR_FILE
] = { "file", BLOBMSG_TYPE_STRING
},
46 [NETWORK_ATTR_DATA
] = { "data", BLOBMSG_TYPE_TABLE
},
47 [NETWORK_ATTR_INTERFACE
] = { "interface", BLOBMSG_TYPE_STRING
},
48 [NETWORK_ATTR_KEEPALIVE
] = { "keepalive", BLOBMSG_TYPE_INT32
},
49 [NETWORK_ATTR_DOMAIN
] = { "domain", BLOBMSG_TYPE_STRING
},
50 [NETWORK_ATTR_UPDATE_CMD
] = { "update-cmd", BLOBMSG_TYPE_STRING
},
53 AVL_TREE(networks
, avl_strcmp
, false, NULL
);
54 static struct blob_buf b
;
56 static void network_load_config_data(struct network
*net
, struct blob_attr
*data
)
58 struct blob_attr
*tb
[__NETCONF_ATTR_MAX
];
59 struct blob_attr
*cur
;
60 siphash_key_t key
= {};
62 blobmsg_parse(netconf_policy
, __NETCONF_ATTR_MAX
, tb
,
63 blobmsg_data(data
), blobmsg_len(data
));
65 if ((cur
= tb
[NETCONF_ATTR_PORT
]) != NULL
)
66 net
->net_config
.port
= blobmsg_get_u32(cur
);
68 net
->net_config
.port
= 51820;
70 if ((cur
= tb
[NETCONF_ATTR_PEX_PORT
]) != NULL
)
71 net
->net_config
.pex_port
= blobmsg_get_u32(cur
);
73 if ((cur
= tb
[NETCONF_ATTR_ID
]) != NULL
) {
74 const char *id
= blobmsg_get_string(cur
);
75 siphash_to_le64(&net
->net_config
.addr
.network_id
, id
, strlen(id
), &key
);
77 siphash_to_le64(&net
->net_config
.addr
.network_id
, &net
->net_config
.port
,
78 sizeof(net
->net_config
.port
), &key
);
81 net
->net_config
.addr
.network_id
[0] = 0xfd;
82 network_fill_host_addr(&net
->net_config
.addr
, net
->config
.pubkey
);
84 if (net
->config
.keepalive
>= 0)
85 net
->net_config
.keepalive
= net
->config
.keepalive
;
86 else if ((cur
= tb
[NETCONF_ATTR_KEEPALIVE
]) != NULL
)
87 net
->net_config
.keepalive
= blobmsg_get_u32(cur
);
89 net
->net_config
.keepalive
= 0;
92 static int network_load_data(struct network
*net
, struct blob_attr
*data
)
94 struct blob_attr
*tb
[__NETDATA_ATTR_MAX
];
96 blobmsg_parse(netdata_policy
, __NETDATA_ATTR_MAX
, tb
,
97 blobmsg_data(data
), blobmsg_len(data
));
99 network_load_config_data(net
, tb
[NETDATA_ATTR_CONFIG
]);
100 network_hosts_add(net
, tb
[NETDATA_ATTR_HOSTS
]);
101 network_services_add(net
, tb
[NETDATA_ATTR_SERVICES
]);
106 static int network_load_file(struct network
*net
)
108 blob_buf_init(&b
, 0);
110 if (!blobmsg_add_json_from_file(&b
, net
->config
.file
))
113 return network_load_data(net
, b
.head
);
117 network_fill_ip(struct blob_buf
*buf
, int af
, union network_addr
*addr
, int mask
)
122 c
= blobmsg_open_table(buf
, NULL
);
124 blobmsg_printf(buf
, "mask", "%d", mask
);
126 str
= blobmsg_alloc_string_buffer(buf
, "ipaddr", INET6_ADDRSTRLEN
);
127 inet_ntop(af
, addr
, str
, INET6_ADDRSTRLEN
);
128 blobmsg_add_string_buffer(buf
);
130 blobmsg_close_table(buf
, c
);
134 network_fill_ipaddr_list(struct network_host
*host
, struct blob_buf
*b
, bool ipv6
)
136 union network_addr addr
= {};
137 struct blob_attr
*cur
;
142 af
= ipv6
? AF_INET6
: AF_INET
;
143 blobmsg_for_each_attr(cur
, host
->peer
.ipaddr
, rem
) {
144 const char *str
= blobmsg_get_string(cur
);
146 if (!!strchr(str
, ':') != ipv6
)
149 if (inet_pton(af
, str
, &addr
) != 1)
152 c
= blobmsg_open_table(b
, NULL
);
153 blobmsg_add_string(b
, "ipaddr", str
);
154 blobmsg_add_string(b
, "mask", ipv6
? "128" : "32");
155 blobmsg_close_table(b
, c
);
160 network_fill_ip_settings(struct network
*net
, struct blob_buf
*buf
)
162 struct network_host
*host
= net
->net_config
.local_host
;
165 c
= blobmsg_open_array(buf
, "ipaddr");
166 network_fill_ipaddr_list(host
, buf
, false);
167 blobmsg_close_array(buf
, c
);
169 c
= blobmsg_open_array(buf
, "ip6addr");
170 network_fill_ip(buf
, AF_INET6
, &host
->peer
.local_addr
, 64);
171 network_fill_ipaddr_list(host
, buf
, true);
172 blobmsg_close_array(buf
, c
);
176 __network_fill_host_subnets(struct network_host
*host
, struct blob_buf
*b
, bool ipv6
)
178 union network_addr addr
= {};
179 struct blob_attr
*cur
;
185 af
= ipv6
? AF_INET6
: AF_INET
;
186 blobmsg_for_each_attr(cur
, host
->peer
.subnet
, rem
) {
187 const char *str
= blobmsg_get_string(cur
);
190 if (!!strchr(str
, ':') != ipv6
)
193 if (network_get_subnet(af
, &addr
, &mask
, str
))
196 c
= blobmsg_open_table(b
, NULL
);
198 buf
= blobmsg_alloc_string_buffer(b
, "target", INET6_ADDRSTRLEN
);
199 inet_ntop(af
, &addr
, buf
, INET6_ADDRSTRLEN
);
200 blobmsg_add_string_buffer(b
);
202 blobmsg_printf(b
, "netmask", "%d", mask
);
204 blobmsg_close_table(b
, c
);
207 blobmsg_for_each_attr(cur
, host
->peer
.ipaddr
, rem
) {
208 const char *str
= blobmsg_get_string(cur
);
210 if (!!strchr(str
, ':') != ipv6
)
213 if (inet_pton(af
, str
, &addr
) != 1)
216 c
= blobmsg_open_table(b
, NULL
);
217 blobmsg_add_string(b
, "target", str
);
218 blobmsg_add_string(b
, "netmask", ipv6
? "128" : "32");
219 blobmsg_close_table(b
, c
);
224 __network_fill_subnets(struct network
*net
, struct blob_buf
*buf
, bool ipv6
)
226 struct network_host
*host
;
229 c
= blobmsg_open_array(buf
, ipv6
? "routes6": "routes");
230 avl_for_each_element(&net
->hosts
, host
, node
) {
231 if (host
== net
->net_config
.local_host
)
233 __network_fill_host_subnets(host
, buf
, ipv6
);
235 blobmsg_close_array(buf
, c
);
240 network_fill_subnets(struct network
*net
, struct blob_buf
*buf
)
242 __network_fill_subnets(net
, buf
, false);
243 __network_fill_subnets(net
, buf
, true);
247 network_do_update(struct network
*net
, bool up
)
249 if (!net
->net_config
.local_host
)
252 blob_buf_init(&b
, 0);
253 blobmsg_add_u32(&b
, "action", 0);
254 blobmsg_add_string(&b
, "ifname", network_name(net
));
255 blobmsg_add_u8(&b
, "link-up", up
);
258 network_fill_ip_settings(net
, &b
);
259 network_fill_subnets(net
, &b
);
263 char *s
= blobmsg_format_json(b
.head
, true);
264 D_NET(net
, "update: %s", s
);
268 if (net
->config
.update_cmd
) {
269 const char *argv
[] = { net
->config
.update_cmd
, NULL
, NULL
};
274 argv
[1] = blobmsg_format_json(b
.head
, true);
275 execvp(argv
[0], (char **)argv
);
278 waitpid(pid
, &stat
, 0);
281 if (!net
->config
.interface
)
284 blobmsg_add_string(&b
, "interface", net
->config
.interface
);
285 unetd_ubus_netifd_update(b
.head
);
288 static int network_reload(struct network
*net
)
292 net
->prev_local_host
= net
->net_config
.local_host
;
294 memset(&net
->net_config
, 0, sizeof(net
->net_config
));
296 network_pex_close(net
);
297 network_services_free(net
);
298 network_hosts_update_start(net
);
299 network_services_update_start(net
);
301 switch (net
->config
.type
) {
302 case NETWORK_TYPE_FILE
:
303 ret
= network_load_file(net
);
305 case NETWORK_TYPE_INLINE
:
306 ret
= network_load_data(net
, net
->config
.net_data
);
310 network_services_update_done(net
);
311 network_hosts_update_done(net
);
312 uloop_timeout_set(&net
->connect_timer
, 10);
314 net
->prev_local_host
= NULL
;
317 network_do_update(net
, true);
318 network_pex_open(net
);
323 static int network_setup(struct network
*net
)
325 if (wg_init_network(net
)) {
326 fprintf(stderr
, "Setup failed for network %s\n", network_name(net
));
333 static void network_teardown(struct network
*net
)
335 network_do_update(net
, false);
336 network_pex_close(net
);
337 network_hosts_free(net
);
338 network_services_free(net
);
339 wg_cleanup_network(net
);
343 network_destroy(struct network
*net
)
345 network_teardown(net
);
346 avl_delete(&networks
, &net
->node
);
347 free(net
->config
.data
);
352 network_set_config(struct network
*net
, struct blob_attr
*config
)
354 struct blob_attr
*tb
[__NETWORK_ATTR_MAX
];
355 struct blob_attr
*cur
;
357 if (net
->config
.data
&& blob_attr_equal(net
->config
.data
, config
))
360 network_teardown(net
);
362 free(net
->config
.data
);
363 memset(&net
->config
, 0, sizeof(net
->config
));
365 net
->config
.data
= blob_memdup(config
);
366 blobmsg_parse(network_policy
, __NETWORK_ATTR_MAX
, tb
,
367 blobmsg_data(net
->config
.data
),
368 blobmsg_len(net
->config
.data
));
370 if ((cur
= tb
[NETWORK_ATTR_TYPE
]) == NULL
)
373 if (!strcmp(blobmsg_get_string(cur
), "file"))
374 net
->config
.type
= NETWORK_TYPE_FILE
;
375 else if (!strcmp(blobmsg_get_string(cur
), "inline"))
376 net
->config
.type
= NETWORK_TYPE_INLINE
;
380 if ((cur
= tb
[NETWORK_ATTR_KEEPALIVE
]) != NULL
)
381 net
->config
.keepalive
= blobmsg_get_u32(cur
);
383 net
->config
.keepalive
= -1;
385 switch (net
->config
.type
) {
386 case NETWORK_TYPE_FILE
:
387 if ((cur
= tb
[NETWORK_ATTR_FILE
]) != NULL
)
388 net
->config
.file
= blobmsg_get_string(cur
);
392 case NETWORK_TYPE_INLINE
:
393 net
->config
.net_data
= tb
[NETWORK_ATTR_DATA
];
394 if (!net
->config
.net_data
)
399 if ((cur
= tb
[NETWORK_ATTR_INTERFACE
]) != NULL
)
400 net
->config
.interface
= blobmsg_get_string(cur
);
402 if ((cur
= tb
[NETWORK_ATTR_UPDATE_CMD
]) != NULL
)
403 net
->config
.update_cmd
= blobmsg_get_string(cur
);
405 if ((cur
= tb
[NETWORK_ATTR_DOMAIN
]) != NULL
)
406 net
->config
.domain
= blobmsg_get_string(cur
);
408 if ((cur
= tb
[NETWORK_ATTR_KEY
]) == NULL
)
411 if (b64_decode(blobmsg_get_string(cur
), net
->config
.key
, sizeof(net
->config
.key
)) !=
412 sizeof(net
->config
.key
))
415 curve25519_generate_public(net
->config
.pubkey
, net
->config
.key
);
417 if (network_setup(net
))
426 network_destroy(net
);
430 static struct network
*
431 network_alloc(const char *name
)
436 net
= calloc_a(sizeof(*net
), &name_buf
, strlen(name
) + 1);
437 net
->node
.key
= strcpy(name_buf
, name
);
438 avl_insert(&networks
, &net
->node
);
440 network_pex_init(net
);
441 network_hosts_init(net
);
442 network_services_init(net
);
447 void network_fill_host_addr(union network_addr
*addr
, uint8_t *pubkey
)
449 siphash_key_t key
= {
451 get_unaligned_le64(addr
->network_id
),
452 get_unaligned_le64(addr
->network_id
)
456 siphash_to_le64(&addr
->host_addr
, pubkey
, CURVE25519_KEY_SIZE
, &key
);
459 int unetd_network_add(const char *name
, struct blob_attr
*config
)
463 if (strchr(name
, '/'))
466 net
= avl_find_element(&networks
, name
, net
, node
);
468 net
= network_alloc(name
);
470 return network_set_config(net
, config
);
473 int unetd_network_remove(const char *name
)
477 net
= avl_find_element(&networks
, name
, net
, node
);
481 network_destroy(net
);
486 void network_free_all(void)
488 struct network
*net
, *tmp
;
490 avl_for_each_element_safe(&networks
, net
, node
, tmp
)
491 network_destroy(net
);