unet-cli: strip initial newline in usage message
[project/unetd.git] / host.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
4 */
5 #include <libubox/avl-cmp.h>
6 #include <libubox/blobmsg_json.h>
7 #include "unetd.h"
8
9 static LIST_HEAD(old_hosts);
10 static struct blob_buf b;
11
12 static int avl_key_cmp(const void *k1, const void *k2, void *ptr)
13 {
14 return memcmp(k1, k2, CURVE25519_KEY_SIZE);
15 }
16
17 static bool
18 network_peer_equal(struct network_peer *p1, struct network_peer *p2)
19 {
20 return !memcmp(&p1->local_addr, &p2->local_addr, sizeof(p1->local_addr)) &&
21 blob_attr_equal(p1->ipaddr, p2->ipaddr) &&
22 blob_attr_equal(p1->subnet, p2->subnet) &&
23 p1->port == p2->port;
24 }
25
26 static void
27 network_peer_update(struct vlist_tree *tree,
28 struct vlist_node *node_new,
29 struct vlist_node *node_old)
30 {
31 struct network *net = container_of(tree, struct network, peers);
32 struct network_peer *h_new = container_of_safe(node_new, struct network_peer, node);
33 struct network_peer *h_old = container_of_safe(node_old, struct network_peer, node);
34 int ret;
35
36 if (h_new && h_old) {
37 memcpy(&h_new->state, &h_old->state, sizeof(h_new->state));
38
39 if (network_peer_equal(h_new, h_old))
40 return;
41 }
42
43 if ((h_new ? h_new : h_old)->indirect)
44 return;
45
46 if (h_new)
47 ret = wg_peer_update(net, h_new, h_old ? WG_PEER_UPDATE : WG_PEER_CREATE);
48 else
49 ret = wg_peer_update(net, h_old, WG_PEER_DELETE);
50
51 if (ret)
52 fprintf(stderr, "Failed to %s peer on network %s: %s\n",
53 h_new ? "update" : "delete", network_name(net),
54 strerror(-ret));
55 }
56
57 static struct network_group *
58 network_group_get(struct network *net, const char *name)
59 {
60 struct network_group *group;
61 char *name_buf;
62
63 group = avl_find_element(&net->groups, name, group, node);
64 if (group)
65 return group;
66
67 group = calloc_a(sizeof(*group), &name_buf, strlen(name) + 1);
68 group->node.key = strcpy(name_buf, name);
69 avl_insert(&net->groups, &group->node);
70
71 return group;
72 }
73
74 static void
75 network_host_add_group(struct network *net, struct network_host *host,
76 const char *name)
77 {
78 struct network_group *group;
79 int i;
80
81 group = network_group_get(net, name);
82 for (i = 0; i < group->n_members; i++)
83 if (group->members[i] == host)
84 return;
85
86 group->n_members++;
87 group->members = realloc(group->members, group->n_members * sizeof(*group->members));
88 group->members[group->n_members - 1] = host;
89 }
90
91 enum {
92 NETWORK_HOST_KEY,
93 NETWORK_HOST_GROUPS,
94 NETWORK_HOST_IPADDR,
95 NETWORK_HOST_SUBNET,
96 NETWORK_HOST_PORT,
97 NETWORK_HOST_PEX_PORT,
98 NETWORK_HOST_ENDPOINT,
99 NETWORK_HOST_GATEWAY,
100 __NETWORK_HOST_MAX
101 };
102
103 static const struct blobmsg_policy host_policy[__NETWORK_HOST_MAX] = {
104 [NETWORK_HOST_KEY] = { "key", BLOBMSG_TYPE_STRING },
105 [NETWORK_HOST_GROUPS] = { "groups", BLOBMSG_TYPE_ARRAY },
106 [NETWORK_HOST_IPADDR] = { "ipaddr", BLOBMSG_TYPE_ARRAY },
107 [NETWORK_HOST_SUBNET] = { "subnet", BLOBMSG_TYPE_ARRAY },
108 [NETWORK_HOST_PORT] = { "port", BLOBMSG_TYPE_INT32 },
109 [NETWORK_HOST_PEX_PORT] = { "peer-exchange-port", BLOBMSG_TYPE_INT32 },
110 [NETWORK_HOST_ENDPOINT] = { "endpoint", BLOBMSG_TYPE_STRING },
111 [NETWORK_HOST_GATEWAY] = { "gateway", BLOBMSG_TYPE_STRING },
112 };
113
114 static void
115 network_host_create(struct network *net, struct blob_attr *attr, bool dynamic)
116 {
117 struct blob_attr *tb[__NETWORK_HOST_MAX];
118 struct blob_attr *cur, *ipaddr, *subnet;
119 uint8_t key[CURVE25519_KEY_SIZE];
120 struct network_host *host = NULL;
121 struct network_peer *peer;
122 int ipaddr_len, subnet_len;
123 const char *endpoint, *gateway;
124 char *endpoint_buf, *gateway_buf;
125 int rem;
126
127 blobmsg_parse(host_policy, __NETWORK_HOST_MAX, tb, blobmsg_data(attr), blobmsg_len(attr));
128
129 if (!tb[NETWORK_HOST_KEY])
130 return;
131
132 ipaddr_len = tb[NETWORK_HOST_IPADDR] ? blob_pad_len(tb[NETWORK_HOST_IPADDR]) : 0;
133 if (ipaddr_len &&
134 blobmsg_check_array(tb[NETWORK_HOST_IPADDR], BLOBMSG_TYPE_STRING) < 0)
135 ipaddr_len = 0;
136
137 subnet_len = tb[NETWORK_HOST_SUBNET] ? blob_pad_len(tb[NETWORK_HOST_SUBNET]) : 0;
138 if (subnet_len &&
139 blobmsg_check_array(tb[NETWORK_HOST_SUBNET], BLOBMSG_TYPE_STRING) < 0)
140 subnet_len = 0;
141
142 if ((cur = tb[NETWORK_HOST_ENDPOINT]) != NULL)
143 endpoint = blobmsg_get_string(cur);
144 else
145 endpoint = NULL;
146
147 if (!dynamic && (cur = tb[NETWORK_HOST_GATEWAY]) != NULL)
148 gateway = blobmsg_get_string(cur);
149 else
150 gateway = NULL;
151
152 if (b64_decode(blobmsg_get_string(tb[NETWORK_HOST_KEY]), key,
153 sizeof(key)) != sizeof(key))
154 return;
155
156 if (dynamic) {
157 struct network_dynamic_peer *dyn_peer;
158
159 /* don't override/alter hosts configured via network data */
160 peer = vlist_find(&net->peers, key, peer, node);
161 if (peer && !peer->dynamic &&
162 peer->node.version == net->peers.version)
163 return;
164
165 dyn_peer = calloc_a(sizeof(*dyn_peer),
166 &ipaddr, ipaddr_len,
167 &subnet, subnet_len,
168 &endpoint_buf, endpoint ? strlen(endpoint) + 1 : 0);
169 list_add_tail(&dyn_peer->list, &net->dynamic_peers);
170 peer = &dyn_peer->peer;
171 } else {
172 const char *name;
173 char *name_buf;
174
175 name = blobmsg_name(attr);
176 host = avl_find_element(&net->hosts, name, host, node);
177 if (host)
178 return;
179
180 host = calloc_a(sizeof(*host),
181 &name_buf, strlen(name) + 1,
182 &ipaddr, ipaddr_len,
183 &subnet, subnet_len,
184 &endpoint_buf, endpoint ? strlen(endpoint) + 1 : 0,
185 &gateway_buf, gateway ? strlen(gateway) + 1 : 0);
186 host->node.key = strcpy(name_buf, name);
187 peer = &host->peer;
188 }
189
190 peer->dynamic = dynamic;
191 if ((cur = tb[NETWORK_HOST_IPADDR]) != NULL && ipaddr_len)
192 peer->ipaddr = memcpy(ipaddr, cur, ipaddr_len);
193 if ((cur = tb[NETWORK_HOST_SUBNET]) != NULL && subnet_len)
194 peer->subnet = memcpy(subnet, cur, subnet_len);
195 if ((cur = tb[NETWORK_HOST_PORT]) != NULL)
196 peer->port = blobmsg_get_u32(cur);
197 else
198 peer->port = net->net_config.port;
199 if ((cur = tb[NETWORK_HOST_PEX_PORT]) != NULL)
200 peer->pex_port = blobmsg_get_u32(cur);
201 else
202 peer->pex_port = net->net_config.pex_port;
203 if (endpoint)
204 peer->endpoint = strcpy(endpoint_buf, endpoint);
205 memcpy(peer->key, key, sizeof(key));
206
207 memcpy(&peer->local_addr.network_id,
208 &net->net_config.addr.network_id,
209 sizeof(peer->local_addr.network_id));
210 network_fill_host_addr(&peer->local_addr, peer->key);
211
212 if (!host)
213 return;
214
215 if (gateway)
216 host->gateway = strcpy(gateway_buf, gateway);
217
218 blobmsg_for_each_attr(cur, tb[NETWORK_HOST_GROUPS], rem) {
219 if (!blobmsg_check_attr(cur, false) ||
220 blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
221 continue;
222
223 network_host_add_group(net, host, blobmsg_get_string(cur));
224 }
225
226 avl_insert(&net->hosts, &host->node);
227 if (!memcmp(peer->key, net->config.pubkey, sizeof(key))) {
228 if (!net->prev_local_host ||
229 !network_peer_equal(&net->prev_local_host->peer, &host->peer))
230 net->net_config.local_host_changed = true;
231
232 net->net_config.local_host = host;
233 }
234 }
235
236 static void
237 network_hosts_load_dynamic_file(struct network *net, const char *file)
238 {
239 struct blob_attr *cur;
240 int rem;
241
242 blob_buf_init(&b, 0);
243
244 if (!blobmsg_add_json_from_file(&b, file))
245 return;
246
247 blob_for_each_attr(cur, b.head, rem)
248 network_host_create(net, cur, true);
249 }
250
251 static void
252 network_hosts_load_dynamic_peers(struct network *net)
253 {
254 struct network_dynamic_peer *dyn;
255 struct blob_attr *cur;
256 int rem;
257
258 if (!net->config.peer_data)
259 return;
260
261 blobmsg_for_each_attr(cur, net->config.peer_data, rem)
262 network_hosts_load_dynamic_file(net, blobmsg_get_string(cur));
263
264 blob_buf_free(&b);
265
266 list_for_each_entry(dyn, &net->dynamic_peers, list)
267 vlist_add(&net->peers, &dyn->peer.node, &dyn->peer.key);
268 }
269
270 static void
271 network_host_free_dynamic_peers(struct list_head *list)
272 {
273 struct network_dynamic_peer *dyn, *dyn_tmp;
274
275 list_for_each_entry_safe(dyn, dyn_tmp, list, list) {
276 list_del(&dyn->list);
277 free(dyn);
278 }
279 }
280
281 void network_hosts_reload_dynamic_peers(struct network *net)
282 {
283 struct network_peer *peer;
284 LIST_HEAD(old_entries);
285
286 if (!net->config.peer_data)
287 return;
288
289 list_splice_init(&net->dynamic_peers, &old_entries);
290
291 vlist_for_each_element(&net->peers, peer, node)
292 if (peer->dynamic)
293 peer->node.version = net->peers.version - 1;
294
295 network_hosts_load_dynamic_peers(net);
296
297 vlist_flush(&net->peers);
298
299 network_host_free_dynamic_peers(&old_entries);
300 }
301
302 void network_hosts_update_start(struct network *net)
303 {
304 struct network_host *host, *htmp;
305 struct network_group *group, *gtmp;
306
307 avl_remove_all_elements(&net->hosts, host, node, htmp)
308 list_add_tail(&host->node.list, &old_hosts);
309
310 avl_remove_all_elements(&net->groups, group, node, gtmp) {
311 free(group->members);
312 free(group);
313 }
314
315 vlist_update(&net->peers);
316 }
317
318 static void
319 __network_hosts_update_done(struct network *net, bool free_net)
320 {
321 struct network_host *local, *host, *tmp;
322 LIST_HEAD(old_dynamic);
323 const char *local_name;
324
325 list_splice_init(&net->dynamic_peers, &old_dynamic);
326 if (free_net)
327 goto out;
328
329 local = net->net_config.local_host;
330 if (!local)
331 goto out;
332
333 local_name = network_host_name(local);
334
335 if (net->net_config.local_host_changed)
336 wg_init_local(net, &local->peer);
337
338 avl_for_each_element(&net->hosts, host, node) {
339 if (host == local)
340 continue;
341 host->peer.indirect = false;
342 if (host->gateway && strcmp(host->gateway, local_name) != 0)
343 host->peer.indirect = true;
344 if (local->gateway && strcmp(local->gateway, network_host_name(host)) != 0)
345 host->peer.indirect = true;
346 vlist_add(&net->peers, &host->peer.node, host->peer.key);
347 }
348
349 network_hosts_load_dynamic_peers(net);
350
351 out:
352 vlist_flush(&net->peers);
353
354 network_host_free_dynamic_peers(&old_dynamic);
355
356 list_for_each_entry_safe(host, tmp, &old_hosts, node.list) {
357 list_del(&host->node.list);
358 free(host);
359 }
360 }
361
362 void network_hosts_update_done(struct network *net)
363 {
364 return __network_hosts_update_done(net, false);
365 }
366
367 static union network_endpoint *
368 network_peer_next_endpoint(struct network_peer *peer)
369 {
370 union network_endpoint *ep;
371 int i;
372
373 for (i = 0; i < __ENDPOINT_TYPE_MAX; i++) {
374 int cur = peer->state.next_endpoint_idx;
375
376 if (++peer->state.next_endpoint_idx == __ENDPOINT_TYPE_MAX)
377 peer->state.next_endpoint_idx = 0;
378
379 ep = &peer->state.next_endpoint[cur];
380 if (cur == ENDPOINT_TYPE_STATIC &&
381 (!peer->endpoint ||
382 network_get_endpoint(ep, AF_UNSPEC, peer->endpoint, peer->port,
383 peer->state.connect_attempt++)))
384 continue;
385
386 if (!ep->sa.sa_family)
387 continue;
388
389 return ep;
390 }
391
392 return NULL;
393 }
394
395
396 static void
397 network_hosts_connect_cb(struct uloop_timeout *t)
398 {
399 struct network *net = container_of(t, struct network, connect_timer);
400 struct network_host *host;
401 struct network_peer *peer;
402 union network_endpoint *ep;
403
404 avl_for_each_element(&net->hosts, host, node)
405 host->peer.state.num_net_queries = 0;
406 net->num_net_queries = 0;
407
408 if (!net->net_config.keepalive || !net->net_config.local_host)
409 return;
410
411 wg_peer_refresh(net);
412
413 vlist_for_each_element(&net->peers, peer, node) {
414 if (peer->state.connected || peer->indirect)
415 continue;
416
417 ep = network_peer_next_endpoint(peer);
418 if (!ep)
419 continue;
420
421 if (memcmp(ep, &peer->state.endpoint, sizeof(*ep)) != 0 &&
422 !network_skip_endpoint_route(net, ep))
423 unetd_ubus_netifd_add_route(net, ep);
424
425 wg_peer_connect(net, peer, ep);
426 }
427
428 network_pex_event(net, NULL, PEX_EV_QUERY);
429
430 uloop_timeout_set(t, 1000);
431 }
432
433 void network_hosts_add(struct network *net, struct blob_attr *hosts)
434 {
435 struct blob_attr *cur;
436 int rem;
437
438 blobmsg_for_each_attr(cur, hosts, rem)
439 network_host_create(net, cur, false);
440 }
441
442 void network_hosts_init(struct network *net)
443 {
444 INIT_LIST_HEAD(&net->dynamic_peers);
445 avl_init(&net->hosts, avl_strcmp, false, NULL);
446 vlist_init(&net->peers, avl_key_cmp, network_peer_update);
447 avl_init(&net->groups, avl_strcmp, false, NULL);
448 net->connect_timer.cb = network_hosts_connect_cb;
449 }
450
451 void network_hosts_free(struct network *net)
452 {
453 uloop_timeout_cancel(&net->connect_timer);
454 network_hosts_update_start(net);
455 __network_hosts_update_done(net, true);
456 }