1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
5 #include <libubox/avl-cmp.h>
8 static LIST_HEAD(old_hosts
);
10 static int avl_key_cmp(const void *k1
, const void *k2
, void *ptr
)
12 return memcmp(k1
, k2
, CURVE25519_KEY_SIZE
);
16 network_peer_equal(struct network_peer
*p1
, struct network_peer
*p2
)
18 return !memcmp(&p1
->local_addr
, &p2
->local_addr
, sizeof(p1
->local_addr
)) &&
19 blob_attr_equal(p1
->ipaddr
, p2
->ipaddr
) &&
20 blob_attr_equal(p1
->subnet
, p2
->subnet
) &&
25 network_peer_update(struct vlist_tree
*tree
,
26 struct vlist_node
*node_new
,
27 struct vlist_node
*node_old
)
29 struct network
*net
= container_of(tree
, struct network
, peers
);
30 struct network_peer
*h_new
= container_of_safe(node_new
, struct network_peer
, node
);
31 struct network_peer
*h_old
= container_of_safe(node_old
, struct network_peer
, node
);
35 memcpy(&h_new
->state
, &h_old
->state
, sizeof(h_new
->state
));
37 if (network_peer_equal(h_new
, h_old
))
42 ret
= wg_peer_update(net
, h_new
, h_old
? WG_PEER_UPDATE
: WG_PEER_CREATE
);
44 ret
= wg_peer_update(net
, h_old
, WG_PEER_DELETE
);
47 fprintf(stderr
, "Failed to %s peer on network %s: %s\n",
48 h_new
? "update" : "delete", network_name(net
),
52 static struct network_group
*
53 network_group_get(struct network
*net
, const char *name
)
55 struct network_group
*group
;
58 group
= avl_find_element(&net
->groups
, name
, group
, node
);
62 group
= calloc_a(sizeof(*group
), &name_buf
, strlen(name
) + 1);
63 group
->node
.key
= strcpy(name_buf
, name
);
64 avl_insert(&net
->groups
, &group
->node
);
70 network_host_add_group(struct network
*net
, struct network_host
*host
,
73 struct network_group
*group
;
76 group
= network_group_get(net
, name
);
77 for (i
= 0; i
< group
->n_members
; i
++)
78 if (group
->members
[i
] == host
)
82 group
->members
= realloc(group
->members
, group
->n_members
* sizeof(*group
->members
));
83 group
->members
[group
->n_members
- 1] = host
;
87 network_host_create(struct network
*net
, struct blob_attr
*attr
)
95 NETWORK_HOST_ENDPOINT
,
98 static const struct blobmsg_policy policy
[__NETWORK_HOST_MAX
] = {
99 [NETWORK_HOST_KEY
] = { "key", BLOBMSG_TYPE_STRING
},
100 [NETWORK_HOST_GROUPS
] = { "groups", BLOBMSG_TYPE_ARRAY
},
101 [NETWORK_HOST_IPADDR
] = { "ipaddr", BLOBMSG_TYPE_ARRAY
},
102 [NETWORK_HOST_SUBNET
] = { "subnet", BLOBMSG_TYPE_ARRAY
},
103 [NETWORK_HOST_PORT
] = { "port", BLOBMSG_TYPE_INT32
},
104 [NETWORK_HOST_ENDPOINT
] = { "endpoint", BLOBMSG_TYPE_STRING
},
106 struct blob_attr
*tb
[__NETWORK_HOST_MAX
];
107 struct blob_attr
*cur
, *ipaddr
, *subnet
;
108 uint8_t key
[CURVE25519_KEY_SIZE
];
109 struct network_host
*host
;
110 struct network_peer
*peer
;
111 int ipaddr_len
, subnet_len
;
112 const char *name
, *endpoint
;
113 char *name_buf
, *endpoint_buf
;
116 blobmsg_parse(policy
, __NETWORK_HOST_MAX
, tb
, blobmsg_data(attr
), blobmsg_len(attr
));
118 if (!tb
[NETWORK_HOST_KEY
])
121 ipaddr_len
= tb
[NETWORK_HOST_IPADDR
] ? blob_pad_len(tb
[NETWORK_HOST_IPADDR
]) : 0;
123 blobmsg_check_array(tb
[NETWORK_HOST_IPADDR
], BLOBMSG_TYPE_STRING
) < 0)
126 subnet_len
= tb
[NETWORK_HOST_SUBNET
] ? blob_pad_len(tb
[NETWORK_HOST_SUBNET
]) : 0;
128 blobmsg_check_array(tb
[NETWORK_HOST_SUBNET
], BLOBMSG_TYPE_STRING
) < 0)
131 if ((cur
= tb
[NETWORK_HOST_ENDPOINT
]) != NULL
)
132 endpoint
= blobmsg_get_string(cur
);
136 if (b64_decode(blobmsg_get_string(tb
[NETWORK_HOST_KEY
]), key
,
137 sizeof(key
)) != sizeof(key
))
140 name
= blobmsg_name(attr
);
141 host
= avl_find_element(&net
->hosts
, name
, host
, node
);
145 host
= calloc_a(sizeof(*host
),
146 &name_buf
, strlen(name
) + 1,
149 &endpoint_buf
, endpoint
? strlen(endpoint
) + 1 : 0);
151 if ((cur
= tb
[NETWORK_HOST_IPADDR
]) != NULL
&& ipaddr_len
)
152 peer
->ipaddr
= memcpy(ipaddr
, cur
, ipaddr_len
);
153 if ((cur
= tb
[NETWORK_HOST_SUBNET
]) != NULL
&& subnet_len
)
154 peer
->subnet
= memcpy(subnet
, cur
, subnet_len
);
155 if ((cur
= tb
[NETWORK_HOST_PORT
]) != NULL
)
156 peer
->port
= blobmsg_get_u32(cur
);
158 peer
->port
= net
->net_config
.port
;
160 peer
->endpoint
= strcpy(endpoint_buf
, endpoint
);
161 memcpy(peer
->key
, key
, sizeof(key
));
162 host
->node
.key
= strcpy(name_buf
, name
);
164 memcpy(&peer
->local_addr
.network_id
,
165 &net
->net_config
.addr
.network_id
,
166 sizeof(peer
->local_addr
.network_id
));
167 network_fill_host_addr(&peer
->local_addr
, peer
->key
);
169 blobmsg_for_each_attr(cur
, tb
[NETWORK_HOST_GROUPS
], rem
) {
170 if (!blobmsg_check_attr(cur
, false) ||
171 blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
174 network_host_add_group(net
, host
, blobmsg_get_string(cur
));
177 avl_insert(&net
->hosts
, &host
->node
);
178 if (!memcmp(peer
->key
, net
->config
.pubkey
, sizeof(key
))) {
179 if (!net
->prev_local_host
||
180 !network_peer_equal(&net
->prev_local_host
->peer
, &host
->peer
))
181 net
->net_config
.local_host_changed
= true;
183 net
->net_config
.local_host
= host
;
187 void network_hosts_update_start(struct network
*net
)
189 struct network_host
*host
, *htmp
;
190 struct network_group
*group
, *gtmp
;
192 avl_remove_all_elements(&net
->hosts
, host
, node
, htmp
)
193 list_add_tail(&host
->node
.list
, &old_hosts
);
195 avl_remove_all_elements(&net
->groups
, group
, node
, gtmp
) {
196 free(group
->members
);
200 vlist_update(&net
->peers
);
203 void network_hosts_update_done(struct network
*net
)
205 struct network_host
*host
, *tmp
;
207 if (!net
->net_config
.local_host
)
210 if (net
->net_config
.local_host_changed
)
211 wg_init_local(net
, &net
->net_config
.local_host
->peer
);
213 avl_for_each_element(&net
->hosts
, host
, node
)
214 if (host
!= net
->net_config
.local_host
)
215 vlist_add(&net
->peers
, &host
->peer
.node
, host
->peer
.key
);
218 vlist_flush(&net
->peers
);
220 list_for_each_entry_safe(host
, tmp
, &old_hosts
, node
.list
) {
221 list_del(&host
->node
.list
);
227 network_hosts_connect_cb(struct uloop_timeout
*t
)
229 struct network
*net
= container_of(t
, struct network
, connect_timer
);
230 struct network_host
*host
;
231 union network_endpoint
*ep
;
233 if (!net
->net_config
.keepalive
)
236 wg_peer_refresh(net
);
238 avl_for_each_element(&net
->hosts
, host
, node
) {
239 struct network_peer
*peer
= &host
->peer
;
241 if (host
== net
->net_config
.local_host
)
244 if (peer
->state
.connected
)
247 ep
= &peer
->state
.next_endpoint
;
248 if (peer
->endpoint
&&
249 network_get_endpoint(ep
, peer
->endpoint
, peer
->port
,
250 peer
->state
.connect_attempt
++))
253 if (!ep
->sa
.sa_family
)
256 if (memcmp(ep
, &peer
->state
.endpoint
, sizeof(*ep
)) != 0)
257 unetd_ubus_netifd_add_route(net
, ep
);
259 wg_peer_connect(net
, peer
, ep
);
262 network_pex_event(net
, NULL
, PEX_EV_QUERY
);
264 uloop_timeout_set(t
, 1000);
267 void network_hosts_add(struct network
*net
, struct blob_attr
*hosts
)
269 struct blob_attr
*cur
;
272 blobmsg_for_each_attr(cur
, hosts
, rem
)
273 network_host_create(net
, cur
);
276 void network_hosts_init(struct network
*net
)
278 avl_init(&net
->hosts
, avl_strcmp
, false, NULL
);
279 vlist_init(&net
->peers
, avl_key_cmp
, network_peer_update
);
280 avl_init(&net
->groups
, avl_strcmp
, false, NULL
);
281 net
->connect_timer
.cb
= network_hosts_connect_cb
;
284 void network_hosts_free(struct network
*net
)
286 uloop_timeout_cancel(&net
->connect_timer
);
287 network_hosts_update_start(net
);
288 network_hosts_update_done(net
);