1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
6 #include <sys/socket.h>
10 #include <libubox/list.h>
11 #include <libubox/uloop.h>
14 #include "auth-data.h"
16 static char pex_tx_buf
[PEX_BUF_SIZE
];
17 static FILE *pex_urandom
;
18 static struct uloop_fd pex_fd
;
19 static LIST_HEAD(requests
);
20 static struct uloop_timeout gc_timer
;
22 static pex_recv_cb_t pex_recv_cb
;
24 struct pex_msg_update_recv_ctx
{
25 struct list_head list
;
27 union network_endpoint addr
;
29 uint8_t priv_key
[CURVE25519_KEY_SIZE
];
30 uint8_t auth_key
[CURVE25519_KEY_SIZE
];
31 uint8_t e_key
[CURVE25519_KEY_SIZE
];
42 uint64_t pex_network_hash(const uint8_t *auth_key
, uint64_t req_id
)
52 siphash_to_be64(&hash
, auth_key
, CURVE25519_KEY_SIZE
, &key
);
58 struct pex_hdr
*__pex_msg_init(const uint8_t *pubkey
, uint8_t opcode
)
60 struct pex_hdr
*hdr
= (struct pex_hdr
*)pex_tx_buf
;
65 memcpy(hdr
->id
, pubkey
, sizeof(hdr
->id
));
70 struct pex_hdr
*__pex_msg_init_ext(const uint8_t *pubkey
, const uint8_t *auth_key
,
71 uint8_t opcode
, bool ext
)
73 struct pex_hdr
*hdr
= __pex_msg_init(pubkey
, opcode
);
74 struct pex_ext_hdr
*ehdr
= (struct pex_ext_hdr
*)(hdr
+ 1);
80 hdr
->len
= sizeof(*ehdr
);
82 if (fread(&ehdr
->nonce
, sizeof(ehdr
->nonce
), 1, pex_urandom
) != 1)
85 hash
= pex_network_hash(auth_key
, ehdr
->nonce
);
86 *(uint64_t *)hdr
->id
^= hash
;
87 memcpy(ehdr
->auth_id
, auth_key
, sizeof(ehdr
->auth_id
));
92 void *pex_msg_append(size_t len
)
94 struct pex_hdr
*hdr
= (struct pex_hdr
*)pex_tx_buf
;
95 int ofs
= hdr
->len
+ sizeof(struct pex_hdr
);
96 void *buf
= &pex_tx_buf
[ofs
];
98 if (sizeof(pex_tx_buf
) - ofs
< len
)
108 pex_fd_cb(struct uloop_fd
*fd
, unsigned int events
)
110 struct sockaddr_in6 sin6
;
111 static char buf
[PEX_BUF_SIZE
];
112 struct pex_hdr
*hdr
= (struct pex_hdr
*)buf
;
116 socklen_t slen
= sizeof(sin6
);
118 len
= recvfrom(fd
->fd
, buf
, sizeof(buf
), 0, (struct sockaddr
*)&sin6
, &slen
);
133 if (len
< sizeof(*hdr
) + sizeof(struct pex_ext_hdr
))
136 hdr
->len
= ntohs(hdr
->len
);
137 if (len
- sizeof(hdr
) - sizeof(struct pex_ext_hdr
) < hdr
->len
)
140 pex_recv_cb(hdr
, &sin6
);
144 int __pex_msg_send(int fd
, const void *addr
)
146 struct pex_hdr
*hdr
= (struct pex_hdr
*)pex_tx_buf
;
147 const struct sockaddr
*sa
= addr
;
148 size_t tx_len
= sizeof(*hdr
) + hdr
->len
;
149 uint16_t orig_len
= hdr
->len
;
154 hdr
->len
-= sizeof(struct pex_ext_hdr
);
158 hdr
->len
= htons(hdr
->len
);
160 if (sa
->sa_family
== AF_INET6
)
161 addr_len
= sizeof(struct sockaddr_in6
);
163 addr_len
= sizeof(struct sockaddr_in
);
164 ret
= sendto(fd
, pex_tx_buf
, tx_len
, 0, sa
, addr_len
);
166 ret
= send(fd
, pex_tx_buf
, tx_len
, 0);
174 pex_msg_update_response_fill(struct pex_msg_update_send_ctx
*ctx
)
176 struct pex_hdr
*hdr
= (struct pex_hdr
*)pex_tx_buf
;
177 int ofs
= hdr
->len
+ sizeof(struct pex_hdr
);
178 int cur_len
= ctx
->rem
;
180 if (cur_len
> PEX_BUF_SIZE
- ofs
)
181 cur_len
= PEX_BUF_SIZE
- ofs
;
183 memcpy(pex_msg_append(cur_len
), ctx
->cur
, cur_len
);
188 void pex_msg_update_response_init(struct pex_msg_update_send_ctx
*ctx
,
189 const uint8_t *pubkey
, const uint8_t *auth_key
,
190 const uint8_t *peer_key
, bool ext
,
191 struct pex_update_request
*req
,
192 const void *data
, int len
)
194 uint8_t e_key_priv
[CURVE25519_KEY_SIZE
];
195 uint8_t enc_key
[CURVE25519_KEY_SIZE
];
196 struct pex_update_response
*res
;
198 ctx
->pubkey
= pubkey
;
199 ctx
->auth_key
= auth_key
;
201 ctx
->req_id
= req
->req_id
;
203 if (!__pex_msg_init_ext(pubkey
, auth_key
, PEX_MSG_UPDATE_RESPONSE
, ext
))
206 res
= pex_msg_append(sizeof(*res
));
207 res
->req_id
= req
->req_id
;
210 if (!fread(e_key_priv
, sizeof(e_key_priv
), 1, pex_urandom
))
213 curve25519_clamp_secret(e_key_priv
);
214 curve25519_generate_public(res
->e_key
, e_key_priv
);
215 curve25519(enc_key
, e_key_priv
, peer_key
);
217 ctx
->data
= ctx
->cur
= malloc(len
);
220 memcpy(ctx
->data
, data
, len
);
221 chacha20_encrypt_msg(ctx
->data
, len
, &req
->req_id
, enc_key
);
223 pex_msg_update_response_fill(ctx
);
226 bool pex_msg_update_response_continue(struct pex_msg_update_send_ctx
*ctx
)
228 struct pex_update_response_data
*res_ext
;
237 if (!__pex_msg_init_ext(ctx
->pubkey
, ctx
->auth_key
,
238 PEX_MSG_UPDATE_RESPONSE_DATA
, ctx
->ext
))
241 res_ext
= pex_msg_append(sizeof(*res_ext
));
242 res_ext
->req_id
= ctx
->req_id
;
243 res_ext
->offset
= ctx
->cur
- ctx
->data
;
244 pex_msg_update_response_fill(ctx
);
250 struct pex_update_request
*
251 pex_msg_update_request_init(const uint8_t *pubkey
, const uint8_t *priv_key
,
252 const uint8_t *auth_key
, union network_endpoint
*addr
,
253 uint64_t cur_version
, bool ext
)
255 struct pex_update_request
*req
;
256 struct pex_msg_update_recv_ctx
*ctx
;
258 list_for_each_entry(ctx
, &requests
, list
) {
259 if (!memcmp(&ctx
->addr
, addr
, sizeof(ctx
->addr
)))
263 ctx
= calloc(1, sizeof(*ctx
));
264 memcpy(&ctx
->addr
, addr
, sizeof(ctx
->addr
));
265 memcpy(ctx
->auth_key
, auth_key
, sizeof(ctx
->auth_key
));
266 memcpy(ctx
->priv_key
, priv_key
, sizeof(ctx
->priv_key
));
267 if (!fread(&ctx
->req_id
, sizeof(ctx
->req_id
), 1, pex_urandom
))
269 list_add_tail(&ctx
->list
, &requests
);
270 if (!gc_timer
.pending
)
271 uloop_timeout_set(&gc_timer
, 1000);
273 if (!__pex_msg_init_ext(pubkey
, auth_key
, PEX_MSG_UPDATE_REQUEST
, ext
)) {
278 req
= pex_msg_append(sizeof(*req
));
279 req
->cur_version
= cpu_to_be64(cur_version
);
280 req
->req_id
= ctx
->req_id
;
285 static struct pex_msg_update_recv_ctx
*
286 pex_msg_update_recv_ctx_get(uint64_t req_id
)
288 struct pex_msg_update_recv_ctx
*ctx
;
290 list_for_each_entry(ctx
, &requests
, list
) {
291 if (ctx
->req_id
== req_id
) {
300 static void pex_msg_update_ctx_free(struct pex_msg_update_recv_ctx
*ctx
)
302 list_del(&ctx
->list
);
307 void *pex_msg_update_response_recv(const void *data
, int len
, enum pex_opcode op
,
308 int *data_len
, uint64_t *timestamp
)
310 struct pex_msg_update_recv_ctx
*ctx
;
311 uint8_t enc_key
[CURVE25519_KEY_SIZE
];
315 if (op
== PEX_MSG_UPDATE_RESPONSE
) {
316 const struct pex_update_response
*res
= data
;
318 if (len
< sizeof(*res
))
321 ctx
= pex_msg_update_recv_ctx_get(res
->req_id
);
322 if (!ctx
|| ctx
->data_len
|| !res
->data_len
||
323 res
->data_len
> UNETD_NET_DATA_SIZE_MAX
)
326 data
+= sizeof(*res
);
329 ctx
->data_len
= res
->data_len
;
330 memcpy(ctx
->e_key
, res
->e_key
, sizeof(ctx
->e_key
));
331 ctx
->data
= malloc(ctx
->data_len
);
332 } else if (op
== PEX_MSG_UPDATE_RESPONSE_DATA
) {
333 const struct pex_update_response_data
*res
= data
;
335 if (len
<= sizeof(*res
))
338 ctx
= pex_msg_update_recv_ctx_get(res
->req_id
);
339 if (!ctx
|| ctx
->data_ofs
!= res
->offset
)
342 data
+= sizeof(*res
);
344 } else if (op
== PEX_MSG_UPDATE_RESPONSE_NO_DATA
) {
345 const struct pex_update_response_no_data
*res
= data
;
347 if (len
< sizeof(*res
))
350 ctx
= pex_msg_update_recv_ctx_get(res
->req_id
);
359 if (ctx
->data_ofs
+ len
> ctx
->data_len
)
362 memcpy(ctx
->data
+ ctx
->data_ofs
, data
, len
);
363 ctx
->data_ofs
+= len
;
364 if (ctx
->data_ofs
< ctx
->data_len
)
367 curve25519(enc_key
, ctx
->priv_key
, ctx
->e_key
);
368 chacha20_encrypt_msg(ctx
->data
, ctx
->data_len
, &ctx
->req_id
, enc_key
);
369 if (unet_auth_data_validate(ctx
->auth_key
, ctx
->data
, ctx
->data_len
, timestamp
, NULL
))
372 *data_len
= ctx
->data_len
;
375 pex_msg_update_ctx_free(ctx
);
380 pex_msg_update_ctx_free(ctx
);
386 pex_gc_cb(struct uloop_timeout
*t
)
388 struct pex_msg_update_recv_ctx
*ctx
, *tmp
;
390 list_for_each_entry_safe(ctx
, tmp
, &requests
, list
) {
391 if (++ctx
->idle
<= 3)
394 pex_msg_update_ctx_free(ctx
);
397 if (!list_empty(&requests
))
398 uloop_timeout_set(t
, 1000);
401 int pex_open(void *addr
, size_t addr_len
, pex_recv_cb_t cb
, bool server
)
403 struct sockaddr
*sa
= addr
;
409 pex_urandom
= fopen("/dev/urandom", "r");
413 fd
= socket(sa
->sa_family
== AF_INET
? PF_INET
: PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
417 fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
) | O_NONBLOCK
);
418 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
421 if (bind(fd
, addr
, addr_len
) < 0) {
426 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
));
427 setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &yes
, sizeof(yes
));
428 setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &no
, sizeof(no
));
430 if (connect(fd
, addr
, addr_len
) < 0) {
437 pex_fd
.cb
= pex_fd_cb
;
438 uloop_fd_add(&pex_fd
, ULOOP_READ
);
440 gc_timer
.cb
= pex_gc_cb
;
457 uloop_fd_delete(&pex_fd
);