38d314d0d188827f06d3f776c6b772806af1a494
1 // SPDX-License-Identifier: GPL-2.0-or-later
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 pex_hdr
*hdr
= (struct pex_hdr
*)tx_buf
;
84 memcpy(hdr
->id
, net
->config
.pubkey
, sizeof(hdr
->id
));
89 static void *pex_msg_append(size_t len
)
91 struct pex_hdr
*hdr
= (struct pex_hdr
*)tx_buf
;
92 int ofs
= hdr
->len
+ sizeof(struct pex_hdr
);
93 void *buf
= &tx_buf
[ofs
];
95 if (sizeof(tx_buf
) - ofs
< len
)
104 static void pex_msg_send(struct network
*net
, struct network_peer
*peer
)
106 struct sockaddr_in6 sin6
= {};
107 struct pex_hdr
*hdr
= (struct pex_hdr
*)tx_buf
;
108 size_t tx_len
= sizeof(*hdr
) + hdr
->len
;
111 if (peer
== &net
->net_config
.local_host
->peer
|| !peer
->state
.connected
)
114 sin6
.sin6_family
= AF_INET6
;
115 memcpy(&sin6
.sin6_addr
, &peer
->local_addr
.in6
,
116 sizeof(peer
->local_addr
.in6
));
117 sin6
.sin6_port
= htons(net
->net_config
.pex_port
);
118 hdr
->len
= htons(hdr
->len
);
119 ret
= sendto(net
->pex
.fd
.fd
, tx_buf
, tx_len
, 0, (struct sockaddr
*)&sin6
, sizeof(sin6
));
120 hdr
->len
= ntohs(hdr
->len
);
122 D_PEER(net
, peer
, "pex_msg_send failed: %s", strerror(errno
));
126 pex_send_hello(struct network
*net
, struct network_peer
*peer
)
128 struct pex_hello
*data
;
130 pex_msg_init(net
, PEX_MSG_HELLO
);
131 data
= pex_msg_append(sizeof(*data
));
132 if (peer
->state
.endpoint
.sa
.sa_family
== AF_INET6
)
133 data
->flags
|= htons(PEER_EP_F_IPV6
);
134 if (network_get_local_addr(&data
->local_addr
, &peer
->state
.endpoint
))
137 pex_msg_send(net
, peer
);
142 pex_msg_add_peer_endpoint(struct network
*net
, struct network_peer
*peer
,
143 struct network_peer
*receiver
)
145 struct pex_peer_endpoint
*data
;
151 addr
= network_endpoint_addr(&peer
->state
.endpoint
, &len
);
152 port
= peer
->state
.endpoint
.in
.sin_port
;
154 flags
|= PEER_EP_F_IPV6
;
155 if (network_endpoint_addr_equal(&peer
->state
.endpoint
,
156 &receiver
->state
.endpoint
)) {
157 if (!peer
->state
.has_local_ep_addr
) {
158 D_PEER(net
, peer
, "can't send peer to %s, missing local address",
159 network_peer_name(receiver
));
163 addr
= &peer
->state
.local_ep_addr
;
164 port
= htons(peer
->port
);
165 flags
|= PEER_EP_F_LOCAL
;
168 data
= pex_msg_append(sizeof(*data
));
172 memcpy(data
->peer_id
, peer
->key
, sizeof(data
->peer_id
));
173 memcpy(data
->addr
, addr
, len
);
175 data
->flags
= htons(flags
);
176 D_PEER(net
, peer
, "send endpoint to %s", network_peer_name(receiver
));
182 network_pex_handle_endpoint_change(struct network
*net
, struct network_peer
*peer
)
184 struct network_peer
*cur
;
186 vlist_for_each_element(&net
->peers
, cur
, node
) {
187 if (cur
== peer
|| !cur
->state
.connected
)
190 pex_msg_init(net
, PEX_MSG_NOTIFY_PEERS
);
191 if (pex_msg_add_peer_endpoint(net
, peer
, cur
))
194 pex_msg_send(net
, cur
);
198 void network_pex_init(struct network
*net
)
200 struct network_pex
*pex
= &net
->pex
;
202 memset(pex
, 0, sizeof(*pex
));
207 network_pex_query_hosts(struct network
*net
)
209 struct network_host
*host
;
214 pex_msg_init(net
, PEX_MSG_QUERY
);
216 avl_for_each_element(&net
->hosts
, host
, node
) {
217 struct network_peer
*peer
= &host
->peer
;
220 if (host
== net
->net_config
.local_host
||
221 peer
->state
.connected
||
225 id
= pex_msg_append(PEX_ID_LEN
);
229 memcpy(id
, peer
->key
, PEX_ID_LEN
);
236 rv
%= net
->hosts
.count
;
237 for (i
= 0; i
< 2; i
++) {
238 avl_for_each_element(&net
->hosts
, host
, node
) {
239 struct network_peer
*peer
= &host
->peer
;
246 if (host
== net
->net_config
.local_host
)
249 if (!peer
->state
.connected
)
252 D_PEER(net
, peer
, "send query for %d hosts", hosts
);
253 pex_msg_send(net
, peer
);
261 network_pex_send_ping(struct network
*net
, struct network_peer
*peer
)
263 pex_msg_init(net
, PEX_MSG_PING
);
264 pex_msg_send(net
, peer
);
267 void network_pex_event(struct network
*net
, struct network_peer
*peer
,
270 if (!network_pex_active(&net
->pex
))
274 D_PEER(net
, peer
, "PEX event type=%d", ev
);
276 D_NET(net
, "PEX event type=%d", ev
);
279 case PEX_EV_HANDSHAKE
:
280 pex_send_hello(net
, peer
);
282 case PEX_EV_ENDPOINT_CHANGE
:
283 network_pex_handle_endpoint_change(net
, peer
);
286 network_pex_query_hosts(net
);
289 network_pex_send_ping(net
, peer
);
295 network_pex_recv_hello(struct network
*net
, struct network_peer
*peer
,
296 const struct pex_hello
*data
, size_t len
)
298 char addrstr
[INET6_ADDRSTRLEN
];
302 if (len
< sizeof(*data
))
305 if (peer
->state
.has_local_ep_addr
&&
306 !memcmp(&peer
->state
.local_ep_addr
, data
->local_addr
, sizeof(data
->local_addr
)))
309 flags
= ntohs(data
->flags
);
310 af
= (flags
& PEER_EP_F_IPV6
) ? AF_INET6
: AF_INET
;
311 D_PEER(net
, peer
, "set local endpoint address to %s",
312 inet_ntop(af
, data
->local_addr
, addrstr
, sizeof(addrstr
)));
313 peer
->state
.has_local_ep_addr
= true;
314 memcpy(&peer
->state
.local_ep_addr
, data
->local_addr
, sizeof(data
->local_addr
));
318 network_pex_recv_peers(struct network
*net
, struct network_peer
*peer
,
319 const struct pex_peer_endpoint
*data
, size_t len
)
321 struct network_peer
*local
= &net
->net_config
.local_host
->peer
;
322 struct network_peer
*cur
;
324 for (; len
>= sizeof(*data
); len
-= sizeof(*data
), data
++) {
325 union network_endpoint
*ep
;
330 cur
= pex_msg_peer(net
, data
->peer_id
);
334 if (cur
== peer
|| cur
== local
)
337 D_PEER(net
, peer
, "received peer address for %s\n",
338 network_peer_name(cur
));
339 flags
= ntohs(data
->flags
);
340 ep
= &cur
->state
.next_endpoint
;
341 ep
->sa
.sa_family
= (flags
& PEER_EP_F_IPV6
) ? AF_INET6
: AF_INET
;
342 addr
= network_endpoint_addr(ep
, &len
);
343 memcpy(addr
, data
->addr
, len
);
344 ep
->in
.sin_port
= data
->port
;
349 network_pex_recv_query(struct network
*net
, struct network_peer
*peer
,
350 const uint8_t *data
, size_t len
)
352 struct network_peer
*cur
;
355 pex_msg_init(net
, PEX_MSG_NOTIFY_PEERS
);
356 for (; len
>= 8; data
+= 8, len
-= 8) {
357 cur
= pex_msg_peer(net
, data
);
358 if (!cur
|| !cur
->state
.connected
)
361 if (!pex_msg_add_peer_endpoint(net
, cur
, peer
))
368 D_PEER(net
, peer
, "send query response with %d hosts", resp
);
369 pex_msg_send(net
, peer
);
373 network_pex_recv_ping(struct network
*net
, struct network_peer
*peer
)
375 time_t now
= time(NULL
);
377 if (peer
->state
.last_request
== now
)
380 peer
->state
.last_request
= now
;
381 pex_msg_init(net
, PEX_MSG_PONG
);
382 pex_msg_send(net
, peer
);
386 network_pex_recv(struct network
*net
, struct network_peer
*peer
, struct pex_hdr
*hdr
)
388 const void *data
= hdr
+ 1;
390 if (hdr
->version
!= 0)
393 D_PEER(net
, peer
, "PEX rx op=%d", hdr
->opcode
);
394 switch (hdr
->opcode
) {
396 network_pex_recv_hello(net
, peer
, data
, hdr
->len
);
398 case PEX_MSG_NOTIFY_PEERS
:
399 network_pex_recv_peers(net
, peer
, data
, hdr
->len
);
402 network_pex_recv_query(net
, peer
, data
, hdr
->len
);
405 network_pex_recv_ping(net
, peer
);
413 network_pex_fd_cb(struct uloop_fd
*fd
, unsigned int events
)
415 struct network
*net
= container_of(fd
, struct network
, pex
.fd
);
416 struct network_peer
*local
= &net
->net_config
.local_host
->peer
;
417 struct network_peer
*peer
;
418 struct sockaddr_in6 sin6
;
419 static char buf
[PEX_BUF_SIZE
];
420 struct pex_hdr
*hdr
= (struct pex_hdr
*)buf
;
424 socklen_t slen
= sizeof(sin6
);
426 len
= recvfrom(fd
->fd
, buf
, sizeof(buf
), 0, (struct sockaddr
*)&sin6
, &slen
);
434 D_NET(net
, "recvfrom failed: %s", strerror(errno
));
435 network_pex_close(net
);
442 if (len
< sizeof(*hdr
))
445 hdr
->len
= ntohs(hdr
->len
);
446 if (len
- sizeof(hdr
) < hdr
->len
)
449 peer
= pex_msg_peer(net
, hdr
->id
);
453 if (memcmp(&sin6
.sin6_addr
, &peer
->local_addr
.in6
, sizeof(sin6
.sin6_addr
)) != 0)
459 network_pex_recv(net
, peer
, hdr
);
463 int network_pex_open(struct network
*net
)
465 struct network_peer
*local
= &net
->net_config
.local_host
->peer
;
466 struct network_pex
*pex
= &net
->pex
;
467 struct sockaddr_in6 sin6
= {};
471 if (!local
|| !net
->net_config
.pex_port
)
474 fd
= socket(PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
478 fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
) | O_NONBLOCK
);
479 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
481 sin6
.sin6_family
= AF_INET6
;
482 memcpy(&sin6
.sin6_addr
, &local
->local_addr
.in6
,
483 sizeof(local
->local_addr
.in6
));
484 sin6
.sin6_port
= htons(net
->net_config
.pex_port
);
486 if (bind(fd
, (struct sockaddr
*)&sin6
, sizeof(sin6
)) < 0) {
491 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
));
492 setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &yes
, sizeof(yes
));
494 setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
,
495 network_name(net
), strlen(network_name(net
)));
499 pex
->fd
.cb
= network_pex_fd_cb
;
500 uloop_fd_add(&pex
->fd
, ULOOP_READ
);
509 void network_pex_close(struct network
*net
)
511 struct network_pex
*pex
= &net
->pex
;
516 uloop_fd_delete(&pex
->fd
);
518 network_pex_init(net
);