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
)
50 siphash_to_be64(&hash
, auth_key
, CURVE25519_KEY_SIZE
, &key
);
56 struct pex_hdr
*__pex_msg_init(const uint8_t *pubkey
, uint8_t opcode
)
58 struct pex_hdr
*hdr
= (struct pex_hdr
*)pex_tx_buf
;
63 memcpy(hdr
->id
, pubkey
, sizeof(hdr
->id
));
68 struct pex_hdr
*__pex_msg_init_ext(const uint8_t *pubkey
, const uint8_t *auth_key
,
69 uint8_t opcode
, bool ext
)
71 struct pex_hdr
*hdr
= __pex_msg_init(pubkey
, opcode
);
72 struct pex_ext_hdr
*ehdr
= (struct pex_ext_hdr
*)(hdr
+ 1);
78 hdr
->len
= sizeof(*ehdr
);
80 if (fread(&ehdr
->nonce
, sizeof(ehdr
->nonce
), 1, pex_urandom
) != 1)
83 hash
= pex_network_hash(auth_key
, ehdr
->nonce
);
84 *(uint64_t *)hdr
->id
^= hash
;
85 memcpy(ehdr
->auth_id
, auth_key
, sizeof(ehdr
->auth_id
));
90 void *pex_msg_append(size_t len
)
92 struct pex_hdr
*hdr
= (struct pex_hdr
*)pex_tx_buf
;
93 int ofs
= hdr
->len
+ sizeof(struct pex_hdr
);
94 void *buf
= &pex_tx_buf
[ofs
];
96 if (sizeof(pex_tx_buf
) - ofs
< len
)
106 pex_fd_cb(struct uloop_fd
*fd
, unsigned int events
)
108 struct sockaddr_in6 sin6
;
109 static char buf
[PEX_BUF_SIZE
];
110 struct pex_hdr
*hdr
= (struct pex_hdr
*)buf
;
114 socklen_t slen
= sizeof(sin6
);
116 len
= recvfrom(fd
->fd
, buf
, sizeof(buf
), 0, (struct sockaddr
*)&sin6
, &slen
);
131 if (len
< sizeof(*hdr
) + sizeof(struct pex_ext_hdr
))
134 hdr
->len
= ntohs(hdr
->len
);
135 if (len
- sizeof(hdr
) - sizeof(struct pex_ext_hdr
) < hdr
->len
)
138 pex_recv_cb(hdr
, &sin6
);
142 int __pex_msg_send(int fd
, const void *addr
)
144 struct pex_hdr
*hdr
= (struct pex_hdr
*)pex_tx_buf
;
145 const struct sockaddr
*sa
= addr
;
146 size_t tx_len
= sizeof(*hdr
) + hdr
->len
;
147 uint16_t orig_len
= hdr
->len
;
152 hdr
->len
-= sizeof(struct pex_ext_hdr
);
156 hdr
->len
= htons(hdr
->len
);
158 if (sa
->sa_family
== AF_INET6
)
159 addr_len
= sizeof(struct sockaddr_in6
);
161 addr_len
= sizeof(struct sockaddr_in
);
162 ret
= sendto(fd
, pex_tx_buf
, tx_len
, 0, sa
, addr_len
);
164 ret
= send(fd
, pex_tx_buf
, tx_len
, 0);
172 pex_msg_update_response_fill(struct pex_msg_update_send_ctx
*ctx
)
174 struct pex_hdr
*hdr
= (struct pex_hdr
*)pex_tx_buf
;
175 int ofs
= hdr
->len
+ sizeof(struct pex_hdr
);
176 int cur_len
= ctx
->rem
;
178 if (cur_len
> PEX_BUF_SIZE
- ofs
)
179 cur_len
= PEX_BUF_SIZE
- ofs
;
181 memcpy(pex_msg_append(cur_len
), ctx
->cur
, cur_len
);
186 void pex_msg_update_response_init(struct pex_msg_update_send_ctx
*ctx
,
187 const uint8_t *pubkey
, const uint8_t *auth_key
,
188 const uint8_t *peer_key
, bool ext
,
189 struct pex_update_request
*req
,
190 const void *data
, int len
)
192 uint8_t e_key_priv
[CURVE25519_KEY_SIZE
];
193 uint8_t enc_key
[CURVE25519_KEY_SIZE
];
194 struct pex_update_response
*res
;
196 ctx
->pubkey
= pubkey
;
197 ctx
->auth_key
= auth_key
;
199 ctx
->req_id
= req
->req_id
;
201 if (!__pex_msg_init_ext(pubkey
, auth_key
, PEX_MSG_UPDATE_RESPONSE
, ext
))
204 res
= pex_msg_append(sizeof(*res
));
205 res
->req_id
= req
->req_id
;
208 if (!fread(e_key_priv
, sizeof(e_key_priv
), 1, pex_urandom
))
211 curve25519_clamp_secret(e_key_priv
);
212 curve25519_generate_public(res
->e_key
, e_key_priv
);
213 curve25519(enc_key
, e_key_priv
, peer_key
);
215 ctx
->data
= ctx
->cur
= malloc(len
);
218 memcpy(ctx
->data
, data
, len
);
219 chacha20_encrypt_msg(ctx
->data
, len
, &req
->req_id
, enc_key
);
221 pex_msg_update_response_fill(ctx
);
224 bool pex_msg_update_response_continue(struct pex_msg_update_send_ctx
*ctx
)
226 struct pex_update_response_data
*res_ext
;
235 if (!__pex_msg_init_ext(ctx
->pubkey
, ctx
->auth_key
,
236 PEX_MSG_UPDATE_RESPONSE_DATA
, ctx
->ext
))
239 res_ext
= pex_msg_append(sizeof(*res_ext
));
240 res_ext
->req_id
= ctx
->req_id
;
241 res_ext
->offset
= ctx
->cur
- ctx
->data
;
242 pex_msg_update_response_fill(ctx
);
248 struct pex_update_request
*
249 pex_msg_update_request_init(const uint8_t *pubkey
, const uint8_t *priv_key
,
250 const uint8_t *auth_key
, union network_endpoint
*addr
,
251 uint64_t cur_version
, bool ext
)
253 struct pex_update_request
*req
;
254 struct pex_msg_update_recv_ctx
*ctx
;
256 list_for_each_entry(ctx
, &requests
, list
) {
257 if (!memcmp(&ctx
->addr
, addr
, sizeof(ctx
->addr
)))
261 ctx
= calloc(1, sizeof(*ctx
));
262 memcpy(&ctx
->addr
, addr
, sizeof(ctx
->addr
));
263 memcpy(ctx
->auth_key
, auth_key
, sizeof(ctx
->auth_key
));
264 memcpy(ctx
->priv_key
, priv_key
, sizeof(ctx
->priv_key
));
265 if (!fread(&ctx
->req_id
, sizeof(ctx
->req_id
), 1, pex_urandom
))
267 list_add_tail(&ctx
->list
, &requests
);
268 if (!gc_timer
.pending
)
269 uloop_timeout_set(&gc_timer
, 1000);
271 if (!__pex_msg_init_ext(pubkey
, auth_key
, PEX_MSG_UPDATE_REQUEST
, ext
)) {
276 req
= pex_msg_append(sizeof(*req
));
277 req
->cur_version
= cpu_to_be64(cur_version
);
278 req
->req_id
= ctx
->req_id
;
283 static struct pex_msg_update_recv_ctx
*
284 pex_msg_update_recv_ctx_get(uint64_t req_id
)
286 struct pex_msg_update_recv_ctx
*ctx
;
288 list_for_each_entry(ctx
, &requests
, list
) {
289 if (ctx
->req_id
== req_id
) {
298 static void pex_msg_update_ctx_free(struct pex_msg_update_recv_ctx
*ctx
)
300 list_del(&ctx
->list
);
305 void *pex_msg_update_response_recv(const void *data
, int len
, enum pex_opcode op
,
306 int *data_len
, uint64_t *timestamp
)
308 struct pex_msg_update_recv_ctx
*ctx
;
309 uint8_t enc_key
[CURVE25519_KEY_SIZE
];
313 if (op
== PEX_MSG_UPDATE_RESPONSE
) {
314 const struct pex_update_response
*res
= data
;
316 if (len
< sizeof(*res
))
319 ctx
= pex_msg_update_recv_ctx_get(res
->req_id
);
320 if (!ctx
|| ctx
->data_len
|| !res
->data_len
||
321 res
->data_len
> UNETD_NET_DATA_SIZE_MAX
)
324 data
+= sizeof(*res
);
327 ctx
->data_len
= res
->data_len
;
328 memcpy(ctx
->e_key
, res
->e_key
, sizeof(ctx
->e_key
));
329 ctx
->data
= malloc(ctx
->data_len
);
330 } else if (op
== PEX_MSG_UPDATE_RESPONSE_DATA
) {
331 const struct pex_update_response_data
*res
= data
;
333 if (len
<= sizeof(*res
))
336 ctx
= pex_msg_update_recv_ctx_get(res
->req_id
);
337 if (!ctx
|| ctx
->data_ofs
!= res
->offset
)
340 data
+= sizeof(*res
);
342 } else if (op
== PEX_MSG_UPDATE_RESPONSE_NO_DATA
) {
343 const struct pex_update_response_no_data
*res
= data
;
345 if (len
< sizeof(*res
))
348 ctx
= pex_msg_update_recv_ctx_get(res
->req_id
);
357 if (ctx
->data_ofs
+ len
> ctx
->data_len
)
360 memcpy(ctx
->data
+ ctx
->data_ofs
, data
, len
);
361 ctx
->data_ofs
+= len
;
362 if (ctx
->data_ofs
< ctx
->data_len
)
365 curve25519(enc_key
, ctx
->priv_key
, ctx
->e_key
);
366 chacha20_encrypt_msg(ctx
->data
, ctx
->data_len
, &ctx
->req_id
, enc_key
);
367 if (unet_auth_data_validate(ctx
->auth_key
, ctx
->data
, ctx
->data_len
, timestamp
, NULL
))
370 *data_len
= ctx
->data_len
;
373 pex_msg_update_ctx_free(ctx
);
378 pex_msg_update_ctx_free(ctx
);
384 pex_gc_cb(struct uloop_timeout
*t
)
386 struct pex_msg_update_recv_ctx
*ctx
, *tmp
;
388 list_for_each_entry_safe(ctx
, tmp
, &requests
, list
) {
389 if (++ctx
->idle
<= 3)
392 pex_msg_update_ctx_free(ctx
);
395 if (!list_empty(&requests
))
396 uloop_timeout_set(t
, 1000);
399 int pex_open(void *addr
, size_t addr_len
, pex_recv_cb_t cb
, bool server
)
401 struct sockaddr
*sa
= addr
;
407 pex_urandom
= fopen("/dev/urandom", "r");
411 fd
= socket(sa
->sa_family
== AF_INET
? PF_INET
: PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
415 fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
) | O_NONBLOCK
);
416 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
419 if (bind(fd
, addr
, addr_len
) < 0) {
424 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
));
425 setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &yes
, sizeof(yes
));
426 setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &no
, sizeof(no
));
428 if (connect(fd
, addr
, addr_len
) < 0) {
435 pex_fd
.cb
= pex_fd_cb
;
436 uloop_fd_add(&pex_fd
, ULOOP_READ
);
438 gc_timer
.cb
= pex_gc_cb
;
455 uloop_fd_delete(&pex_fd
);