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
))
44 ret
= wg_peer_update(net
, h_new
, h_old
? WG_PEER_UPDATE
: WG_PEER_CREATE
);
46 ret
= wg_peer_update(net
, h_old
, WG_PEER_DELETE
);
49 fprintf(stderr
, "Failed to %s peer on network %s: %s\n",
50 h_new
? "update" : "delete", network_name(net
),
54 static struct network_group
*
55 network_group_get(struct network
*net
, const char *name
)
57 struct network_group
*group
;
60 group
= avl_find_element(&net
->groups
, name
, group
, node
);
64 group
= calloc_a(sizeof(*group
), &name_buf
, strlen(name
) + 1);
65 group
->node
.key
= strcpy(name_buf
, name
);
66 avl_insert(&net
->groups
, &group
->node
);
72 network_host_add_group(struct network
*net
, struct network_host
*host
,
75 struct network_group
*group
;
78 group
= network_group_get(net
, name
);
79 for (i
= 0; i
< group
->n_members
; i
++)
80 if (group
->members
[i
] == host
)
84 group
->members
= realloc(group
->members
, group
->n_members
* sizeof(*group
->members
));
85 group
->members
[group
->n_members
- 1] = host
;
94 NETWORK_HOST_PEX_PORT
,
95 NETWORK_HOST_ENDPOINT
,
100 static const struct blobmsg_policy host_policy
[__NETWORK_HOST_MAX
] = {
101 [NETWORK_HOST_KEY
] = { "key", BLOBMSG_TYPE_STRING
},
102 [NETWORK_HOST_GROUPS
] = { "groups", BLOBMSG_TYPE_ARRAY
},
103 [NETWORK_HOST_IPADDR
] = { "ipaddr", BLOBMSG_TYPE_ARRAY
},
104 [NETWORK_HOST_SUBNET
] = { "subnet", BLOBMSG_TYPE_ARRAY
},
105 [NETWORK_HOST_PORT
] = { "port", BLOBMSG_TYPE_INT32
},
106 [NETWORK_HOST_PEX_PORT
] = { "peer-exchange-port", BLOBMSG_TYPE_INT32
},
107 [NETWORK_HOST_ENDPOINT
] = { "endpoint", BLOBMSG_TYPE_STRING
},
108 [NETWORK_HOST_GATEWAY
] = { "gateway", BLOBMSG_TYPE_STRING
},
112 network_host_create(struct network
*net
, struct blob_attr
*attr
, bool dynamic
)
114 struct blob_attr
*tb
[__NETWORK_HOST_MAX
];
115 struct blob_attr
*cur
, *ipaddr
, *subnet
;
116 uint8_t key
[CURVE25519_KEY_SIZE
];
117 struct network_host
*host
= NULL
;
118 struct network_peer
*peer
;
119 int ipaddr_len
, subnet_len
;
120 const char *endpoint
, *gateway
;
121 char *endpoint_buf
, *gateway_buf
;
124 blobmsg_parse(host_policy
, __NETWORK_HOST_MAX
, tb
, blobmsg_data(attr
), blobmsg_len(attr
));
126 if (!tb
[NETWORK_HOST_KEY
])
129 ipaddr_len
= tb
[NETWORK_HOST_IPADDR
] ? blob_pad_len(tb
[NETWORK_HOST_IPADDR
]) : 0;
131 blobmsg_check_array(tb
[NETWORK_HOST_IPADDR
], BLOBMSG_TYPE_STRING
) < 0)
134 subnet_len
= tb
[NETWORK_HOST_SUBNET
] ? blob_pad_len(tb
[NETWORK_HOST_SUBNET
]) : 0;
136 blobmsg_check_array(tb
[NETWORK_HOST_SUBNET
], BLOBMSG_TYPE_STRING
) < 0)
139 if ((cur
= tb
[NETWORK_HOST_ENDPOINT
]) != NULL
)
140 endpoint
= blobmsg_get_string(cur
);
144 if (!dynamic
&& (cur
= tb
[NETWORK_HOST_GATEWAY
]) != NULL
)
145 gateway
= blobmsg_get_string(cur
);
149 if (b64_decode(blobmsg_get_string(tb
[NETWORK_HOST_KEY
]), key
,
150 sizeof(key
)) != sizeof(key
))
154 struct network_dynamic_peer
*dyn_peer
;
156 /* don't override/alter hosts configured via network data */
157 peer
= vlist_find(&net
->peers
, key
, peer
, node
);
158 if (peer
&& !peer
->dynamic
&&
159 peer
->node
.version
== net
->peers
.version
)
162 dyn_peer
= calloc_a(sizeof(*dyn_peer
),
165 &endpoint_buf
, endpoint
? strlen(endpoint
) + 1 : 0);
166 list_add_tail(&dyn_peer
->list
, &net
->dynamic_peers
);
167 peer
= &dyn_peer
->peer
;
172 name
= blobmsg_name(attr
);
173 host
= avl_find_element(&net
->hosts
, name
, host
, node
);
177 host
= calloc_a(sizeof(*host
),
178 &name_buf
, strlen(name
) + 1,
181 &endpoint_buf
, endpoint
? strlen(endpoint
) + 1 : 0,
182 &gateway_buf
, gateway
? strlen(gateway
) + 1 : 0);
183 host
->node
.key
= strcpy(name_buf
, name
);
187 peer
->dynamic
= dynamic
;
188 if ((cur
= tb
[NETWORK_HOST_IPADDR
]) != NULL
&& ipaddr_len
)
189 peer
->ipaddr
= memcpy(ipaddr
, cur
, ipaddr_len
);
190 if ((cur
= tb
[NETWORK_HOST_SUBNET
]) != NULL
&& subnet_len
)
191 peer
->subnet
= memcpy(subnet
, cur
, subnet_len
);
192 if ((cur
= tb
[NETWORK_HOST_PORT
]) != NULL
)
193 peer
->port
= blobmsg_get_u32(cur
);
195 peer
->port
= net
->net_config
.port
;
196 if ((cur
= tb
[NETWORK_HOST_PEX_PORT
]) != NULL
)
197 peer
->pex_port
= blobmsg_get_u32(cur
);
199 peer
->pex_port
= net
->net_config
.pex_port
;
201 peer
->endpoint
= strcpy(endpoint_buf
, endpoint
);
202 memcpy(peer
->key
, key
, sizeof(key
));
204 memcpy(&peer
->local_addr
.network_id
,
205 &net
->net_config
.addr
.network_id
,
206 sizeof(peer
->local_addr
.network_id
));
207 network_fill_host_addr(&peer
->local_addr
, peer
->key
);
213 host
->gateway
= strcpy(gateway_buf
, gateway
);
215 blobmsg_for_each_attr(cur
, tb
[NETWORK_HOST_GROUPS
], rem
) {
216 if (!blobmsg_check_attr(cur
, false) ||
217 blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
220 network_host_add_group(net
, host
, blobmsg_get_string(cur
));
223 avl_insert(&net
->hosts
, &host
->node
);
224 if (!memcmp(peer
->key
, net
->config
.pubkey
, sizeof(key
))) {
225 if (!net
->prev_local_host
||
226 !network_peer_equal(&net
->prev_local_host
->peer
, &host
->peer
))
227 net
->net_config
.local_host_changed
= true;
229 net
->net_config
.local_host
= host
;
234 network_hosts_load_dynamic_file(struct network
*net
, const char *file
)
236 struct blob_attr
*cur
;
239 blob_buf_init(&b
, 0);
241 if (!blobmsg_add_json_from_file(&b
, file
))
244 blob_for_each_attr(cur
, b
.head
, rem
)
245 network_host_create(net
, cur
, true);
249 network_hosts_load_dynamic_peers(struct network
*net
)
251 struct network_dynamic_peer
*dyn
;
252 struct blob_attr
*cur
;
255 if (!net
->config
.peer_data
)
258 blobmsg_for_each_attr(cur
, net
->config
.peer_data
, rem
)
259 network_hosts_load_dynamic_file(net
, blobmsg_get_string(cur
));
263 list_for_each_entry(dyn
, &net
->dynamic_peers
, list
)
264 vlist_add(&net
->peers
, &dyn
->peer
.node
, &dyn
->peer
.key
);
268 network_host_free_dynamic_peers(struct list_head
*list
)
270 struct network_dynamic_peer
*dyn
, *dyn_tmp
;
272 list_for_each_entry_safe(dyn
, dyn_tmp
, list
, list
) {
273 list_del(&dyn
->list
);
278 void network_hosts_reload_dynamic_peers(struct network
*net
)
280 struct network_peer
*peer
;
281 LIST_HEAD(old_entries
);
283 if (!net
->config
.peer_data
)
286 list_splice_init(&net
->dynamic_peers
, &old_entries
);
288 vlist_for_each_element(&net
->peers
, peer
, node
)
290 peer
->node
.version
= net
->peers
.version
- 1;
292 network_hosts_load_dynamic_peers(net
);
294 vlist_flush(&net
->peers
);
296 network_host_free_dynamic_peers(&old_entries
);
299 void network_hosts_update_start(struct network
*net
)
301 struct network_host
*host
, *htmp
;
302 struct network_group
*group
, *gtmp
;
304 avl_remove_all_elements(&net
->hosts
, host
, node
, htmp
)
305 list_add_tail(&host
->node
.list
, &old_hosts
);
307 avl_remove_all_elements(&net
->groups
, group
, node
, gtmp
) {
308 free(group
->members
);
312 vlist_update(&net
->peers
);
316 __network_hosts_update_done(struct network
*net
, bool free_net
)
318 struct network_host
*local
, *host
, *tmp
;
319 LIST_HEAD(old_dynamic
);
320 const char *local_name
;
322 list_splice_init(&net
->dynamic_peers
, &old_dynamic
);
326 local
= net
->net_config
.local_host
;
330 local_name
= network_host_name(local
);
332 if (net
->net_config
.local_host_changed
)
333 wg_init_local(net
, &local
->peer
);
335 avl_for_each_element(&net
->hosts
, host
, node
) {
338 if (host
->gateway
&& strcmp(host
->gateway
, local_name
) != 0)
340 if (local
->gateway
&& strcmp(local
->gateway
, network_host_name(host
)) != 0)
342 vlist_add(&net
->peers
, &host
->peer
.node
, host
->peer
.key
);
345 network_hosts_load_dynamic_peers(net
);
348 vlist_flush(&net
->peers
);
350 network_host_free_dynamic_peers(&old_dynamic
);
352 list_for_each_entry_safe(host
, tmp
, &old_hosts
, node
.list
) {
353 list_del(&host
->node
.list
);
358 void network_hosts_update_done(struct network
*net
)
360 return __network_hosts_update_done(net
, false);
363 static union network_endpoint
*
364 network_peer_next_endpoint(struct network_peer
*peer
)
366 union network_endpoint
*ep
;
369 for (i
= 0; i
< __ENDPOINT_TYPE_MAX
; i
++) {
370 int cur
= peer
->state
.next_endpoint_idx
;
372 if (++peer
->state
.next_endpoint_idx
== __ENDPOINT_TYPE_MAX
)
373 peer
->state
.next_endpoint_idx
= 0;
375 ep
= &peer
->state
.next_endpoint
[cur
];
376 if (cur
== ENDPOINT_TYPE_STATIC
&&
378 network_get_endpoint(ep
, AF_UNSPEC
, peer
->endpoint
, peer
->port
,
379 peer
->state
.connect_attempt
++)))
382 if (!ep
->sa
.sa_family
)
393 network_hosts_connect_cb(struct uloop_timeout
*t
)
395 struct network
*net
= container_of(t
, struct network
, connect_timer
);
396 struct network_host
*host
;
397 struct network_peer
*peer
;
398 union network_endpoint
*ep
;
400 avl_for_each_element(&net
->hosts
, host
, node
)
401 host
->peer
.state
.num_net_queries
= 0;
402 net
->num_net_queries
= 0;
404 if (!net
->net_config
.keepalive
|| !net
->net_config
.local_host
)
407 wg_peer_refresh(net
);
409 vlist_for_each_element(&net
->peers
, peer
, node
) {
410 if (peer
->state
.connected
)
413 ep
= network_peer_next_endpoint(peer
);
417 if (memcmp(ep
, &peer
->state
.endpoint
, sizeof(*ep
)) != 0 &&
418 !network_skip_endpoint_route(net
, ep
))
419 unetd_ubus_netifd_add_route(net
, ep
);
421 wg_peer_connect(net
, peer
, ep
);
424 network_pex_event(net
, NULL
, PEX_EV_QUERY
);
426 uloop_timeout_set(t
, 1000);
429 void network_hosts_add(struct network
*net
, struct blob_attr
*hosts
)
431 struct blob_attr
*cur
;
434 blobmsg_for_each_attr(cur
, hosts
, rem
)
435 network_host_create(net
, cur
, false);
438 void network_hosts_init(struct network
*net
)
440 INIT_LIST_HEAD(&net
->dynamic_peers
);
441 avl_init(&net
->hosts
, avl_strcmp
, false, NULL
);
442 vlist_init(&net
->peers
, avl_key_cmp
, network_peer_update
);
443 avl_init(&net
->groups
, avl_strcmp
, false, NULL
);
444 net
->connect_timer
.cb
= network_hosts_connect_cb
;
447 void network_hosts_free(struct network
*net
)
449 uloop_timeout_cancel(&net
->connect_timer
);
450 network_hosts_update_start(net
);
451 __network_hosts_update_done(net
, true);