1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
6 #include <sys/socket.h>
13 #define PEX_BUF_SIZE 1024
29 uint8_t id
[PEX_ID_LEN
];
32 #define PEER_EP_F_IPV6 (1 << 0)
33 #define PEER_EP_F_LOCAL (1 << 1)
35 struct pex_peer_endpoint
{
38 uint8_t peer_id
[PEX_ID_LEN
];
44 uint8_t local_addr
[16];
47 static char tx_buf
[PEX_BUF_SIZE
];
49 static const char *pex_peer_id_str(const uint8_t *key
)
54 for (i
= 0; i
< 8; i
++)
55 sprintf(str
+ i
* 2, "%02x", key
[i
]);
61 static struct network_peer
*
62 pex_msg_peer(struct network
*net
, const uint8_t *id
)
64 struct network_peer
*peer
;
65 uint8_t key
[WG_KEY_LEN
] = {};
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
));
77 static struct pex_hdr
*pex_msg_init(struct network
*net
, uint8_t opcode
)
79 struct network_peer
*local
= &net
->net_config
.local_host
->peer
;
80 struct pex_hdr
*hdr
= (struct pex_hdr
*)tx_buf
;
85 memcpy(hdr
->id
, local
->key
, sizeof(hdr
->id
));
90 static void *pex_msg_append(size_t len
)
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
];
96 if (sizeof(tx_buf
) - ofs
< len
)
105 static void pex_msg_send(struct network
*net
, struct network_peer
*peer
)
107 struct sockaddr_in6 sin6
= {};
108 struct pex_hdr
*hdr
= (struct pex_hdr
*)tx_buf
;
109 size_t tx_len
= sizeof(*hdr
) + hdr
->len
;
112 if (peer
== &net
->net_config
.local_host
->peer
|| !peer
->state
.connected
)
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
);
123 D_PEER(net
, peer
, "pex_msg_send failed: %s", strerror(errno
));
127 pex_send_hello(struct network
*net
, struct network_peer
*peer
)
129 struct pex_hello
*data
;
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
))
138 pex_msg_send(net
, peer
);
143 pex_msg_add_peer_endpoint(struct network
*net
, struct network_peer
*peer
,
144 struct network_peer
*receiver
)
146 struct pex_peer_endpoint
*data
;
152 addr
= network_endpoint_addr(&peer
->state
.endpoint
, &len
);
153 port
= peer
->state
.endpoint
.in
.sin_port
;
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
));
164 addr
= &peer
->state
.local_ep_addr
;
165 port
= htons(peer
->port
);
166 flags
|= PEER_EP_F_LOCAL
;
169 data
= pex_msg_append(sizeof(*data
));
173 memcpy(data
->peer_id
, peer
->key
, sizeof(data
->peer_id
));
174 memcpy(data
->addr
, addr
, len
);
176 data
->flags
= htons(flags
);
177 D_PEER(net
, peer
, "send endpoint to %s", network_peer_name(receiver
));
183 network_pex_handle_endpoint_change(struct network
*net
, struct network_peer
*peer
)
185 struct network_peer
*cur
;
187 vlist_for_each_element(&net
->peers
, cur
, node
) {
188 if (cur
== peer
|| !cur
->state
.connected
)
191 pex_msg_init(net
, PEX_MSG_NOTIFY_PEERS
);
192 if (pex_msg_add_peer_endpoint(net
, peer
, cur
))
195 pex_msg_send(net
, cur
);
199 void network_pex_init(struct network
*net
)
201 struct network_pex
*pex
= &net
->pex
;
203 memset(pex
, 0, sizeof(*pex
));
208 network_pex_query_hosts(struct network
*net
)
210 struct network_host
*host
;
215 pex_msg_init(net
, PEX_MSG_QUERY
);
217 avl_for_each_element(&net
->hosts
, host
, node
) {
218 struct network_peer
*peer
= &host
->peer
;
221 if (host
== net
->net_config
.local_host
||
222 peer
->state
.connected
||
226 id
= pex_msg_append(PEX_ID_LEN
);
230 memcpy(id
, peer
->key
, PEX_ID_LEN
);
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
;
247 if (host
== net
->net_config
.local_host
)
250 if (!peer
->state
.connected
)
253 D_PEER(net
, peer
, "send query for %d hosts", hosts
);
254 pex_msg_send(net
, peer
);
262 network_pex_send_ping(struct network
*net
, struct network_peer
*peer
)
264 pex_msg_init(net
, PEX_MSG_PING
);
265 pex_msg_send(net
, peer
);
268 void network_pex_event(struct network
*net
, struct network_peer
*peer
,
271 if (!network_pex_active(&net
->pex
))
275 D_PEER(net
, peer
, "PEX event type=%d", ev
);
277 D_NET(net
, "PEX event type=%d", ev
);
280 case PEX_EV_HANDSHAKE
:
281 pex_send_hello(net
, peer
);
283 case PEX_EV_ENDPOINT_CHANGE
:
284 network_pex_handle_endpoint_change(net
, peer
);
287 network_pex_query_hosts(net
);
290 network_pex_send_ping(net
, peer
);
296 network_pex_recv_hello(struct network
*net
, struct network_peer
*peer
,
297 const struct pex_hello
*data
, size_t len
)
299 char addrstr
[INET6_ADDRSTRLEN
];
303 if (len
< sizeof(*data
))
306 if (peer
->state
.has_local_ep_addr
&&
307 !memcmp(&peer
->state
.local_ep_addr
, data
->local_addr
, sizeof(data
->local_addr
)))
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
));
319 network_pex_recv_peers(struct network
*net
, struct network_peer
*peer
,
320 const struct pex_peer_endpoint
*data
, size_t len
)
322 struct network_peer
*local
= &net
->net_config
.local_host
->peer
;
323 struct network_peer
*cur
;
325 for (; len
>= sizeof(*data
); len
-= sizeof(*data
), data
++) {
326 union network_endpoint
*ep
;
331 cur
= pex_msg_peer(net
, data
->peer_id
);
335 if (cur
== peer
|| cur
== local
)
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
;
350 network_pex_recv_query(struct network
*net
, struct network_peer
*peer
,
351 const uint8_t *data
, size_t len
)
353 struct network_peer
*cur
;
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
)
362 if (!pex_msg_add_peer_endpoint(net
, cur
, peer
))
369 D_PEER(net
, peer
, "send query response with %d hosts", resp
);
370 pex_msg_send(net
, peer
);
374 network_pex_recv_ping(struct network
*net
, struct network_peer
*peer
)
376 time_t now
= time(NULL
);
378 if (peer
->state
.last_request
== now
)
381 peer
->state
.last_request
= now
;
382 pex_msg_init(net
, PEX_MSG_PONG
);
383 pex_msg_send(net
, peer
);
387 network_pex_recv(struct network
*net
, struct network_peer
*peer
, struct pex_hdr
*hdr
)
389 const void *data
= hdr
+ 1;
391 if (hdr
->version
!= 0)
394 D_PEER(net
, peer
, "PEX rx op=%d", hdr
->opcode
);
395 switch (hdr
->opcode
) {
397 network_pex_recv_hello(net
, peer
, data
, hdr
->len
);
399 case PEX_MSG_NOTIFY_PEERS
:
400 network_pex_recv_peers(net
, peer
, data
, hdr
->len
);
403 network_pex_recv_query(net
, peer
, data
, hdr
->len
);
406 network_pex_recv_ping(net
, peer
);
414 network_pex_fd_cb(struct uloop_fd
*fd
, unsigned int events
)
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
;
425 socklen_t slen
= sizeof(sin6
);
427 len
= recvfrom(fd
->fd
, buf
, sizeof(buf
), 0, (struct sockaddr
*)&sin6
, &slen
);
435 D_NET(net
, "recvfrom failed: %s", strerror(errno
));
436 network_pex_close(net
);
443 if (len
< sizeof(*hdr
))
446 hdr
->len
= ntohs(hdr
->len
);
447 if (len
- sizeof(hdr
) < hdr
->len
)
450 peer
= pex_msg_peer(net
, hdr
->id
);
454 if (memcmp(&sin6
.sin6_addr
, &peer
->local_addr
.in6
, sizeof(sin6
.sin6_addr
)) != 0)
460 network_pex_recv(net
, peer
, hdr
);
464 int network_pex_open(struct network
*net
)
466 struct network_peer
*local
= &net
->net_config
.local_host
->peer
;
467 struct network_pex
*pex
= &net
->pex
;
468 struct sockaddr_in6 sin6
= {};
472 if (!local
|| !net
->net_config
.pex_port
)
475 fd
= socket(PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
479 fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
) | O_NONBLOCK
);
480 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
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
);
487 if (bind(fd
, (struct sockaddr
*)&sin6
, sizeof(sin6
)) < 0) {
492 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
));
493 setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &yes
, sizeof(yes
));
495 setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
,
496 network_name(net
), strlen(network_name(net
)));
500 pex
->fd
.cb
= network_pex_fd_cb
;
501 uloop_fd_add(&pex
->fd
, ULOOP_READ
);
510 void network_pex_close(struct network
*net
)
512 struct network_pex
*pex
= &net
->pex
;
517 uloop_fd_delete(&pex
->fd
);
519 network_pex_init(net
);