utils: fix memory leak in network_get_endpoint()
[project/unetd.git] / pex.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
4 */
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <arpa/inet.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <time.h>
11 #include "unetd.h"
12
13 #define PEX_BUF_SIZE 1024
14
15 enum pex_opcode {
16 PEX_MSG_HELLO,
17 PEX_MSG_NOTIFY_PEERS,
18 PEX_MSG_QUERY,
19 PEX_MSG_PING,
20 PEX_MSG_PONG,
21 };
22
23 #define PEX_ID_LEN 8
24
25 struct pex_hdr {
26 uint8_t version;
27 uint8_t opcode;
28 uint16_t len;
29 uint8_t id[PEX_ID_LEN];
30 };
31
32 #define PEER_EP_F_IPV6 (1 << 0)
33 #define PEER_EP_F_LOCAL (1 << 1)
34
35 struct pex_peer_endpoint {
36 uint16_t flags;
37 uint16_t port;
38 uint8_t peer_id[PEX_ID_LEN];
39 uint8_t addr[16];
40 };
41
42 struct pex_hello {
43 uint16_t flags;
44 uint8_t local_addr[16];
45 };
46
47 static char tx_buf[PEX_BUF_SIZE];
48
49 static const char *pex_peer_id_str(const uint8_t *key)
50 {
51 static char str[20];
52 int i;
53
54 for (i = 0; i < 8; i++)
55 sprintf(str + i * 2, "%02x", key[i]);
56
57 return str;
58 }
59
60
61 static struct network_peer *
62 pex_msg_peer(struct network *net, const uint8_t *id)
63 {
64 struct network_peer *peer;
65 uint8_t key[WG_KEY_LEN] = {};
66
67 memcpy(key, id, PEX_ID_LEN);
68 peer = avl_find_ge_element(&net->peers.avl, key, peer, node.avl);
69 if (!peer || memcmp(peer->key, key, PEX_ID_LEN) != 0) {
70 D_NET(net, "can't find peer %s", pex_peer_id_str(id));
71 return NULL;
72 }
73
74 return peer;
75 }
76
77 static struct pex_hdr *pex_msg_init(struct network *net, uint8_t opcode)
78 {
79 struct network_peer *local = &net->net_config.local_host->peer;
80 struct pex_hdr *hdr = (struct pex_hdr *)tx_buf;
81
82 hdr->version = 0;
83 hdr->opcode = opcode;
84 hdr->len = 0;
85 memcpy(hdr->id, local->key, sizeof(hdr->id));
86
87 return hdr;
88 }
89
90 static void *pex_msg_append(size_t len)
91 {
92 struct pex_hdr *hdr = (struct pex_hdr *)tx_buf;
93 int ofs = hdr->len + sizeof(struct pex_hdr);
94 void *buf = &tx_buf[ofs];
95
96 if (sizeof(tx_buf) - ofs < len)
97 return NULL;
98
99 hdr->len += len;
100 memset(buf, 0, len);
101
102 return buf;
103 }
104
105 static void pex_msg_send(struct network *net, struct network_peer *peer)
106 {
107 struct sockaddr_in6 sin6 = {};
108 struct pex_hdr *hdr = (struct pex_hdr *)tx_buf;
109 size_t tx_len = sizeof(*hdr) + hdr->len;
110 int ret;
111
112 if (peer == &net->net_config.local_host->peer || !peer->state.connected)
113 return;
114
115 sin6.sin6_family = AF_INET6;
116 memcpy(&sin6.sin6_addr, &peer->local_addr.in6,
117 sizeof(peer->local_addr.in6));
118 sin6.sin6_port = htons(net->net_config.pex_port);
119 hdr->len = htons(hdr->len);
120 ret = sendto(net->pex.fd.fd, tx_buf, tx_len, 0, (struct sockaddr *)&sin6, sizeof(sin6));
121 hdr->len = ntohs(hdr->len);
122 if (ret < 0)
123 D_PEER(net, peer, "pex_msg_send failed: %s", strerror(errno));
124 }
125
126 static void
127 pex_send_hello(struct network *net, struct network_peer *peer)
128 {
129 struct pex_hello *data;
130
131 pex_msg_init(net, PEX_MSG_HELLO);
132 data = pex_msg_append(sizeof(*data));
133 if (peer->state.endpoint.sa.sa_family == AF_INET6)
134 data->flags |= htons(PEER_EP_F_IPV6);
135 if (network_get_local_addr(&data->local_addr, &peer->state.endpoint))
136 return;
137
138 pex_msg_send(net, peer);
139 }
140
141
142 static int
143 pex_msg_add_peer_endpoint(struct network *net, struct network_peer *peer,
144 struct network_peer *receiver)
145 {
146 struct pex_peer_endpoint *data;
147 uint16_t flags = 0;
148 const void *addr;
149 int port;
150 int len;
151
152 addr = network_endpoint_addr(&peer->state.endpoint, &len);
153 port = peer->state.endpoint.in.sin_port;
154 if (len > 4)
155 flags |= PEER_EP_F_IPV6;
156 if (network_endpoint_addr_equal(&peer->state.endpoint,
157 &receiver->state.endpoint)) {
158 if (!peer->state.has_local_ep_addr) {
159 D_PEER(net, peer, "can't send peer to %s, missing local address",
160 network_peer_name(receiver));
161 return -1;
162 }
163
164 addr = &peer->state.local_ep_addr;
165 port = htons(peer->port);
166 flags |= PEER_EP_F_LOCAL;
167 }
168
169 data = pex_msg_append(sizeof(*data));
170 if (!data)
171 return -1;
172
173 memcpy(data->peer_id, peer->key, sizeof(data->peer_id));
174 memcpy(data->addr, addr, len);
175 data->port = port;
176 data->flags = htons(flags);
177 D_PEER(net, peer, "send endpoint to %s", network_peer_name(receiver));
178
179 return 0;
180 }
181
182 static void
183 network_pex_handle_endpoint_change(struct network *net, struct network_peer *peer)
184 {
185 struct network_peer *cur;
186
187 vlist_for_each_element(&net->peers, cur, node) {
188 if (cur == peer || !cur->state.connected)
189 continue;
190
191 pex_msg_init(net, PEX_MSG_NOTIFY_PEERS);
192 if (pex_msg_add_peer_endpoint(net, peer, cur))
193 continue;
194
195 pex_msg_send(net, cur);
196 }
197 }
198
199 void network_pex_init(struct network *net)
200 {
201 struct network_pex *pex = &net->pex;
202
203 memset(pex, 0, sizeof(*pex));
204 pex->fd.fd = -1;
205 }
206
207 static void
208 network_pex_query_hosts(struct network *net)
209 {
210 struct network_host *host;
211 int rv = rand();
212 int hosts = 0;
213 int i;
214
215 pex_msg_init(net, PEX_MSG_QUERY);
216
217 avl_for_each_element(&net->hosts, host, node) {
218 struct network_peer *peer = &host->peer;
219 void *id;
220
221 if (host == net->net_config.local_host ||
222 peer->state.connected ||
223 peer->endpoint)
224 continue;
225
226 id = pex_msg_append(PEX_ID_LEN);
227 if (!id)
228 break;
229
230 memcpy(id, peer->key, PEX_ID_LEN);
231 hosts++;
232 }
233
234 if (!hosts)
235 return;
236
237 rv %= net->hosts.count;
238 for (i = 0; i < 2; i++) {
239 avl_for_each_element(&net->hosts, host, node) {
240 struct network_peer *peer = &host->peer;
241
242 if (rv > 0) {
243 rv--;
244 continue;
245 }
246
247 if (host == net->net_config.local_host)
248 continue;
249
250 if (!peer->state.connected)
251 continue;
252
253 D_PEER(net, peer, "send query for %d hosts", hosts);
254 pex_msg_send(net, peer);
255 return;
256 }
257 }
258
259 }
260
261 static void
262 network_pex_send_ping(struct network *net, struct network_peer *peer)
263 {
264 pex_msg_init(net, PEX_MSG_PING);
265 pex_msg_send(net, peer);
266 }
267
268 void network_pex_event(struct network *net, struct network_peer *peer,
269 enum pex_event ev)
270 {
271 if (!network_pex_active(&net->pex))
272 return;
273
274 if (peer)
275 D_PEER(net, peer, "PEX event type=%d", ev);
276 else
277 D_NET(net, "PEX event type=%d", ev);
278
279 switch (ev) {
280 case PEX_EV_HANDSHAKE:
281 pex_send_hello(net, peer);
282 break;
283 case PEX_EV_ENDPOINT_CHANGE:
284 network_pex_handle_endpoint_change(net, peer);
285 break;
286 case PEX_EV_QUERY:
287 network_pex_query_hosts(net);
288 break;
289 case PEX_EV_PING:
290 network_pex_send_ping(net, peer);
291 break;
292 }
293 }
294
295 static void
296 network_pex_recv_hello(struct network *net, struct network_peer *peer,
297 const struct pex_hello *data, size_t len)
298 {
299 char addrstr[INET6_ADDRSTRLEN];
300 uint16_t flags;
301 int af;
302
303 if (len < sizeof(*data))
304 return;
305
306 if (peer->state.has_local_ep_addr &&
307 !memcmp(&peer->state.local_ep_addr, data->local_addr, sizeof(data->local_addr)))
308 return;
309
310 flags = ntohs(data->flags);
311 af = (flags & PEER_EP_F_IPV6) ? AF_INET6 : AF_INET;
312 D_PEER(net, peer, "set local endpoint address to %s",
313 inet_ntop(af, data->local_addr, addrstr, sizeof(addrstr)));
314 peer->state.has_local_ep_addr = true;
315 memcpy(&peer->state.local_ep_addr, data->local_addr, sizeof(data->local_addr));
316 }
317
318 static void
319 network_pex_recv_peers(struct network *net, struct network_peer *peer,
320 const struct pex_peer_endpoint *data, size_t len)
321 {
322 struct network_peer *local = &net->net_config.local_host->peer;
323 struct network_peer *cur;
324
325 for (; len >= sizeof(*data); len -= sizeof(*data), data++) {
326 union network_endpoint *ep;
327 uint16_t flags;
328 void *addr;
329 int len;
330
331 cur = pex_msg_peer(net, data->peer_id);
332 if (!cur)
333 continue;
334
335 if (cur == peer || cur == local)
336 continue;
337
338 D_PEER(net, peer, "received peer address for %s\n",
339 network_peer_name(cur));
340 flags = ntohs(data->flags);
341 ep = &cur->state.next_endpoint;
342 ep->sa.sa_family = (flags & PEER_EP_F_IPV6) ? AF_INET6 : AF_INET;
343 addr = network_endpoint_addr(ep, &len);
344 memcpy(addr, data->addr, len);
345 ep->in.sin_port = data->port;
346 }
347 }
348
349 static void
350 network_pex_recv_query(struct network *net, struct network_peer *peer,
351 const uint8_t *data, size_t len)
352 {
353 struct network_peer *cur;
354 int resp = 0;
355
356 pex_msg_init(net, PEX_MSG_NOTIFY_PEERS);
357 for (; len >= 8; data += 8, len -= 8) {
358 cur = pex_msg_peer(net, data);
359 if (!cur || !cur->state.connected)
360 continue;
361
362 if (!pex_msg_add_peer_endpoint(net, cur, peer))
363 resp++;
364 }
365
366 if (!resp)
367 return;
368
369 D_PEER(net, peer, "send query response with %d hosts", resp);
370 pex_msg_send(net, peer);
371 }
372
373 static void
374 network_pex_recv_ping(struct network *net, struct network_peer *peer)
375 {
376 time_t now = time(NULL);
377
378 if (peer->state.last_request == now)
379 return;
380
381 peer->state.last_request = now;
382 pex_msg_init(net, PEX_MSG_PONG);
383 pex_msg_send(net, peer);
384 }
385
386 static void
387 network_pex_recv(struct network *net, struct network_peer *peer, struct pex_hdr *hdr)
388 {
389 const void *data = hdr + 1;
390
391 if (hdr->version != 0)
392 return;
393
394 D_PEER(net, peer, "PEX rx op=%d", hdr->opcode);
395 switch (hdr->opcode) {
396 case PEX_MSG_HELLO:
397 network_pex_recv_hello(net, peer, data, hdr->len);
398 break;
399 case PEX_MSG_NOTIFY_PEERS:
400 network_pex_recv_peers(net, peer, data, hdr->len);
401 break;
402 case PEX_MSG_QUERY:
403 network_pex_recv_query(net, peer, data, hdr->len);
404 break;
405 case PEX_MSG_PING:
406 network_pex_recv_ping(net, peer);
407 break;
408 case PEX_MSG_PONG:
409 break;
410 }
411 }
412
413 static void
414 network_pex_fd_cb(struct uloop_fd *fd, unsigned int events)
415 {
416 struct network *net = container_of(fd, struct network, pex.fd);
417 struct network_peer *local = &net->net_config.local_host->peer;
418 struct network_peer *peer;
419 struct sockaddr_in6 sin6;
420 static char buf[PEX_BUF_SIZE];
421 struct pex_hdr *hdr = (struct pex_hdr *)buf;
422 ssize_t len;
423
424 while (1) {
425 socklen_t slen = sizeof(sin6);
426
427 len = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6, &slen);
428 if (len < 0) {
429 if (errno == EINTR)
430 continue;
431
432 if (errno == EAGAIN)
433 break;
434
435 D_NET(net, "recvfrom failed: %s", strerror(errno));
436 network_pex_close(net);
437 return;
438 }
439
440 if (!len)
441 continue;
442
443 if (len < sizeof(*hdr))
444 continue;
445
446 hdr->len = ntohs(hdr->len);
447 if (len - sizeof(hdr) < hdr->len)
448 continue;
449
450 peer = pex_msg_peer(net, hdr->id);
451 if (!peer)
452 continue;
453
454 if (memcmp(&sin6.sin6_addr, &peer->local_addr.in6, sizeof(sin6.sin6_addr)) != 0)
455 continue;
456
457 if (peer == local)
458 continue;
459
460 network_pex_recv(net, peer, hdr);
461 }
462 }
463
464 int network_pex_open(struct network *net)
465 {
466 struct network_peer *local = &net->net_config.local_host->peer;
467 struct network_pex *pex = &net->pex;
468 struct sockaddr_in6 sin6 = {};
469 int yes = 1;
470 int fd;
471
472 if (dummy_mode || !local || !net->net_config.pex_port)
473 return 0;
474
475 fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
476 if (fd < 0)
477 return -1;
478
479 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
480 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
481
482 sin6.sin6_family = AF_INET6;
483 memcpy(&sin6.sin6_addr, &local->local_addr.in6,
484 sizeof(local->local_addr.in6));
485 sin6.sin6_port = htons(net->net_config.pex_port);
486
487 if (bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
488 perror("bind");
489 goto close;
490 }
491
492 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
493 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes));
494 #ifdef linux
495 setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
496 network_name(net), strlen(network_name(net)));
497 #endif
498
499 pex->fd.fd = fd;
500 pex->fd.cb = network_pex_fd_cb;
501 uloop_fd_add(&pex->fd, ULOOP_READ);
502
503 return 0;
504
505 close:
506 close(fd);
507 return -1;
508 }
509
510 void network_pex_close(struct network *net)
511 {
512 struct network_pex *pex = &net->pex;
513
514 if (pex->fd.fd < 0)
515 return;
516
517 uloop_fd_delete(&pex->fd);
518 close(pex->fd.fd);
519 network_pex_init(net);
520 }