1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
5 #include <libubox/avl-cmp.h>
6 #include <libubox/blobmsg_json.h>
9 static LIST_HEAD(old_hosts
);
10 static struct blob_buf b
;
12 static int avl_key_cmp(const void *k1
, const void *k2
, void *ptr
)
14 return memcmp(k1
, k2
, CURVE25519_KEY_SIZE
);
18 network_peer_equal(struct network_peer
*p1
, struct network_peer
*p2
)
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
) &&
27 network_peer_update(struct vlist_tree
*tree
,
28 struct vlist_node
*node_new
,
29 struct vlist_node
*node_old
)
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
);
37 memcpy(&h_new
->state
, &h_old
->state
, sizeof(h_new
->state
));
39 if (network_peer_equal(h_new
, h_old
))
43 if ((h_new
? h_new
: h_old
)->indirect
)
47 ret
= wg_peer_update(net
, h_new
, h_old
? WG_PEER_UPDATE
: WG_PEER_CREATE
);
49 ret
= wg_peer_update(net
, h_old
, WG_PEER_DELETE
);
52 fprintf(stderr
, "Failed to %s peer on network %s: %s\n",
53 h_new
? "update" : "delete", network_name(net
),
57 static struct network_group
*
58 network_group_get(struct network
*net
, const char *name
)
60 struct network_group
*group
;
63 group
= avl_find_element(&net
->groups
, name
, group
, node
);
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
);
75 network_host_add_group(struct network
*net
, struct network_host
*host
,
78 struct network_group
*group
;
81 group
= network_group_get(net
, name
);
82 for (i
= 0; i
< group
->n_members
; i
++)
83 if (group
->members
[i
] == host
)
87 group
->members
= realloc(group
->members
, group
->n_members
* sizeof(*group
->members
));
88 group
->members
[group
->n_members
- 1] = host
;
97 NETWORK_HOST_PEX_PORT
,
98 NETWORK_HOST_ENDPOINT
,
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
},
115 network_host_create(struct network
*net
, struct blob_attr
*attr
, bool dynamic
)
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
;
127 blobmsg_parse(host_policy
, __NETWORK_HOST_MAX
, tb
, blobmsg_data(attr
), blobmsg_len(attr
));
129 if (!tb
[NETWORK_HOST_KEY
])
132 ipaddr_len
= tb
[NETWORK_HOST_IPADDR
] ? blob_pad_len(tb
[NETWORK_HOST_IPADDR
]) : 0;
134 blobmsg_check_array(tb
[NETWORK_HOST_IPADDR
], BLOBMSG_TYPE_STRING
) < 0)
137 subnet_len
= tb
[NETWORK_HOST_SUBNET
] ? blob_pad_len(tb
[NETWORK_HOST_SUBNET
]) : 0;
139 blobmsg_check_array(tb
[NETWORK_HOST_SUBNET
], BLOBMSG_TYPE_STRING
) < 0)
142 if ((cur
= tb
[NETWORK_HOST_ENDPOINT
]) != NULL
)
143 endpoint
= blobmsg_get_string(cur
);
147 if (!dynamic
&& (cur
= tb
[NETWORK_HOST_GATEWAY
]) != NULL
)
148 gateway
= blobmsg_get_string(cur
);
152 if (b64_decode(blobmsg_get_string(tb
[NETWORK_HOST_KEY
]), key
,
153 sizeof(key
)) != sizeof(key
))
157 struct network_dynamic_peer
*dyn_peer
;
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
)
165 dyn_peer
= calloc_a(sizeof(*dyn_peer
),
168 &endpoint_buf
, endpoint
? strlen(endpoint
) + 1 : 0);
169 list_add_tail(&dyn_peer
->list
, &net
->dynamic_peers
);
170 peer
= &dyn_peer
->peer
;
175 name
= blobmsg_name(attr
);
176 host
= avl_find_element(&net
->hosts
, name
, host
, node
);
180 host
= calloc_a(sizeof(*host
),
181 &name_buf
, strlen(name
) + 1,
184 &endpoint_buf
, endpoint
? strlen(endpoint
) + 1 : 0,
185 &gateway_buf
, gateway
? strlen(gateway
) + 1 : 0);
186 host
->node
.key
= strcpy(name_buf
, name
);
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
);
198 peer
->port
= net
->net_config
.port
;
199 if ((cur
= tb
[NETWORK_HOST_PEX_PORT
]) != NULL
)
200 peer
->pex_port
= blobmsg_get_u32(cur
);
202 peer
->pex_port
= net
->net_config
.pex_port
;
204 peer
->endpoint
= strcpy(endpoint_buf
, endpoint
);
205 memcpy(peer
->key
, key
, sizeof(key
));
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
);
216 host
->gateway
= strcpy(gateway_buf
, gateway
);
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
)
223 network_host_add_group(net
, host
, blobmsg_get_string(cur
));
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;
232 net
->net_config
.local_host
= host
;
237 network_hosts_load_dynamic_file(struct network
*net
, const char *file
)
239 struct blob_attr
*cur
;
242 blob_buf_init(&b
, 0);
244 if (!blobmsg_add_json_from_file(&b
, file
))
247 blob_for_each_attr(cur
, b
.head
, rem
)
248 network_host_create(net
, cur
, true);
252 network_hosts_load_dynamic_peers(struct network
*net
)
254 struct network_dynamic_peer
*dyn
;
255 struct blob_attr
*cur
;
258 if (!net
->config
.peer_data
)
261 blobmsg_for_each_attr(cur
, net
->config
.peer_data
, rem
)
262 network_hosts_load_dynamic_file(net
, blobmsg_get_string(cur
));
266 list_for_each_entry(dyn
, &net
->dynamic_peers
, list
)
267 vlist_add(&net
->peers
, &dyn
->peer
.node
, &dyn
->peer
.key
);
271 network_host_free_dynamic_peers(struct list_head
*list
)
273 struct network_dynamic_peer
*dyn
, *dyn_tmp
;
275 list_for_each_entry_safe(dyn
, dyn_tmp
, list
, list
) {
276 list_del(&dyn
->list
);
281 void network_hosts_reload_dynamic_peers(struct network
*net
)
283 struct network_peer
*peer
;
284 LIST_HEAD(old_entries
);
286 if (!net
->config
.peer_data
)
289 list_splice_init(&net
->dynamic_peers
, &old_entries
);
291 vlist_for_each_element(&net
->peers
, peer
, node
)
293 peer
->node
.version
= net
->peers
.version
- 1;
295 network_hosts_load_dynamic_peers(net
);
297 vlist_flush(&net
->peers
);
299 network_host_free_dynamic_peers(&old_entries
);
302 void network_hosts_update_start(struct network
*net
)
304 struct network_host
*host
, *htmp
;
305 struct network_group
*group
, *gtmp
;
307 avl_remove_all_elements(&net
->hosts
, host
, node
, htmp
)
308 list_add_tail(&host
->node
.list
, &old_hosts
);
310 avl_remove_all_elements(&net
->groups
, group
, node
, gtmp
) {
311 free(group
->members
);
315 vlist_update(&net
->peers
);
319 __network_hosts_update_done(struct network
*net
, bool free_net
)
321 struct network_host
*local
, *host
, *tmp
;
322 LIST_HEAD(old_dynamic
);
323 const char *local_name
;
325 list_splice_init(&net
->dynamic_peers
, &old_dynamic
);
329 local
= net
->net_config
.local_host
;
333 local_name
= network_host_name(local
);
335 if (net
->net_config
.local_host_changed
)
336 wg_init_local(net
, &local
->peer
);
338 avl_for_each_element(&net
->hosts
, host
, node
) {
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
);
349 network_hosts_load_dynamic_peers(net
);
352 vlist_flush(&net
->peers
);
354 network_host_free_dynamic_peers(&old_dynamic
);
356 list_for_each_entry_safe(host
, tmp
, &old_hosts
, node
.list
) {
357 list_del(&host
->node
.list
);
362 void network_hosts_update_done(struct network
*net
)
364 return __network_hosts_update_done(net
, false);
367 static union network_endpoint
*
368 network_peer_next_endpoint(struct network_peer
*peer
)
370 union network_endpoint
*ep
;
373 for (i
= 0; i
< __ENDPOINT_TYPE_MAX
; i
++) {
374 int cur
= peer
->state
.next_endpoint_idx
;
376 if (++peer
->state
.next_endpoint_idx
== __ENDPOINT_TYPE_MAX
)
377 peer
->state
.next_endpoint_idx
= 0;
379 ep
= &peer
->state
.next_endpoint
[cur
];
380 if (cur
== ENDPOINT_TYPE_STATIC
&&
382 network_get_endpoint(ep
, AF_UNSPEC
, peer
->endpoint
, peer
->port
,
383 peer
->state
.connect_attempt
++)))
386 if (!ep
->sa
.sa_family
)
397 network_hosts_connect_cb(struct uloop_timeout
*t
)
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
;
404 avl_for_each_element(&net
->hosts
, host
, node
)
405 host
->peer
.state
.num_net_queries
= 0;
406 net
->num_net_queries
= 0;
408 if (!net
->net_config
.keepalive
|| !net
->net_config
.local_host
)
411 wg_peer_refresh(net
);
413 vlist_for_each_element(&net
->peers
, peer
, node
) {
414 if (peer
->state
.connected
|| peer
->indirect
)
417 ep
= network_peer_next_endpoint(peer
);
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
);
425 wg_peer_connect(net
, peer
, ep
);
428 network_pex_event(net
, NULL
, PEX_EV_QUERY
);
430 uloop_timeout_set(t
, 1000);
433 void network_hosts_add(struct network
*net
, struct blob_attr
*hosts
)
435 struct blob_attr
*cur
;
438 blobmsg_for_each_attr(cur
, hosts
, rem
)
439 network_host_create(net
, cur
, false);
442 void network_hosts_init(struct network
*net
)
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
;
451 void network_hosts_free(struct network
*net
)
453 uloop_timeout_cancel(&net
->connect_timer
);
454 network_hosts_update_start(net
);
455 __network_hosts_update_done(net
, true);