pex-msg: fix siphash key initializer
[project/unetd.git] / pex-msg.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
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 <errno.h>
9 #include <fcntl.h>
10 #include <libubox/list.h>
11 #include <libubox/uloop.h>
12 #include "pex-msg.h"
13 #include "chacha20.h"
14 #include "auth-data.h"
15
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;
21
22 static pex_recv_cb_t pex_recv_cb;
23
24 struct pex_msg_update_recv_ctx {
25 struct list_head list;
26
27 union network_endpoint addr;
28
29 uint8_t priv_key[CURVE25519_KEY_SIZE];
30 uint8_t auth_key[CURVE25519_KEY_SIZE];
31 uint8_t e_key[CURVE25519_KEY_SIZE];
32
33 uint64_t req_id;
34
35 void *data;
36 int data_len;
37 int data_ofs;
38
39 int idle;
40 };
41
42 uint64_t pex_network_hash(const uint8_t *auth_key, uint64_t req_id)
43 {
44 siphash_key_t key = {
45 .key = {
46 be64_to_cpu(req_id),
47 be64_to_cpu(req_id)
48 }
49 };
50 uint64_t hash;
51
52 siphash_to_be64(&hash, auth_key, CURVE25519_KEY_SIZE, &key);
53
54 return hash;
55 }
56
57
58 struct pex_hdr *__pex_msg_init(const uint8_t *pubkey, uint8_t opcode)
59 {
60 struct pex_hdr *hdr = (struct pex_hdr *)pex_tx_buf;
61
62 hdr->version = 0;
63 hdr->opcode = opcode;
64 hdr->len = 0;
65 memcpy(hdr->id, pubkey, sizeof(hdr->id));
66
67 return hdr;
68 }
69
70 struct pex_hdr *__pex_msg_init_ext(const uint8_t *pubkey, const uint8_t *auth_key,
71 uint8_t opcode, bool ext)
72 {
73 struct pex_hdr *hdr = __pex_msg_init(pubkey, opcode);
74 struct pex_ext_hdr *ehdr = (struct pex_ext_hdr *)(hdr + 1);
75 uint64_t hash;
76
77 if (!ext)
78 return hdr;
79
80 hdr->len = sizeof(*ehdr);
81
82 if (fread(&ehdr->nonce, sizeof(ehdr->nonce), 1, pex_urandom) != 1)
83 return NULL;
84
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));
88
89 return hdr;
90 }
91
92 void *pex_msg_append(size_t len)
93 {
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];
97
98 if (sizeof(pex_tx_buf) - ofs < len)
99 return NULL;
100
101 hdr->len += len;
102 memset(buf, 0, len);
103
104 return buf;
105 }
106
107 static void
108 pex_fd_cb(struct uloop_fd *fd, unsigned int events)
109 {
110 struct sockaddr_in6 sin6;
111 static char buf[PEX_BUF_SIZE];
112 struct pex_hdr *hdr = (struct pex_hdr *)buf;
113 ssize_t len;
114
115 while (1) {
116 socklen_t slen = sizeof(sin6);
117
118 len = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6, &slen);
119 if (len < 0) {
120 if (errno == EINTR)
121 continue;
122
123 if (errno == EAGAIN)
124 break;
125
126 pex_close();
127 return;
128 }
129
130 if (!len)
131 continue;
132
133 if (len < sizeof(*hdr) + sizeof(struct pex_ext_hdr))
134 continue;
135
136 hdr->len = ntohs(hdr->len);
137 if (len - sizeof(hdr) - sizeof(struct pex_ext_hdr) < hdr->len)
138 continue;
139
140 pex_recv_cb(hdr, &sin6);
141 }
142 }
143
144 int __pex_msg_send(int fd, const void *addr)
145 {
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;
150 size_t addr_len;
151 int ret;
152
153 if (fd < 0) {
154 hdr->len -= sizeof(struct pex_ext_hdr);
155 fd = pex_fd.fd;
156 }
157
158 hdr->len = htons(hdr->len);
159 if (addr) {
160 if (sa->sa_family == AF_INET6)
161 addr_len = sizeof(struct sockaddr_in6);
162 else
163 addr_len = sizeof(struct sockaddr_in);
164 ret = sendto(fd, pex_tx_buf, tx_len, 0, sa, addr_len);
165 } else {
166 ret = send(fd, pex_tx_buf, tx_len, 0);
167 }
168 hdr->len = orig_len;
169
170 return ret;
171 }
172
173 static void
174 pex_msg_update_response_fill(struct pex_msg_update_send_ctx *ctx)
175 {
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;
179
180 if (cur_len > PEX_BUF_SIZE - ofs)
181 cur_len = PEX_BUF_SIZE - ofs;
182
183 memcpy(pex_msg_append(cur_len), ctx->cur, cur_len);
184 ctx->cur += cur_len;
185 ctx->rem -= cur_len;
186 }
187
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)
193 {
194 uint8_t e_key_priv[CURVE25519_KEY_SIZE];
195 uint8_t enc_key[CURVE25519_KEY_SIZE];
196 struct pex_update_response *res;
197
198 ctx->pubkey = pubkey;
199 ctx->auth_key = auth_key;
200 ctx->ext = ext;
201 ctx->req_id = req->req_id;
202
203 if (!__pex_msg_init_ext(pubkey, auth_key, PEX_MSG_UPDATE_RESPONSE, ext))
204 return;
205
206 res = pex_msg_append(sizeof(*res));
207 res->req_id = req->req_id;
208 res->data_len = len;
209
210 if (!fread(e_key_priv, sizeof(e_key_priv), 1, pex_urandom))
211 return;
212
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);
216
217 ctx->data = ctx->cur = malloc(len);
218 ctx->rem = len;
219
220 memcpy(ctx->data, data, len);
221 chacha20_encrypt_msg(ctx->data, len, &req->req_id, enc_key);
222
223 pex_msg_update_response_fill(ctx);
224 }
225
226 bool pex_msg_update_response_continue(struct pex_msg_update_send_ctx *ctx)
227 {
228 struct pex_update_response_data *res_ext;
229
230 if (ctx->rem <= 0) {
231 free(ctx->data);
232 ctx->data = NULL;
233
234 return false;
235 }
236
237 if (!__pex_msg_init_ext(ctx->pubkey, ctx->auth_key,
238 PEX_MSG_UPDATE_RESPONSE_DATA, ctx->ext))
239 return false;
240
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);
245
246 return true;
247 }
248
249
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)
254 {
255 struct pex_update_request *req;
256 struct pex_msg_update_recv_ctx *ctx;
257
258 list_for_each_entry(ctx, &requests, list) {
259 if (!memcmp(&ctx->addr, addr, sizeof(ctx->addr)))
260 return NULL;
261 }
262
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))
268 return NULL;
269 list_add_tail(&ctx->list, &requests);
270 if (!gc_timer.pending)
271 uloop_timeout_set(&gc_timer, 1000);
272
273 if (!__pex_msg_init_ext(pubkey, auth_key, PEX_MSG_UPDATE_REQUEST, ext)) {
274 free(ctx);
275 return NULL;
276 }
277
278 req = pex_msg_append(sizeof(*req));
279 req->cur_version = cpu_to_be64(cur_version);
280 req->req_id = ctx->req_id;
281
282 return req;
283 }
284
285 static struct pex_msg_update_recv_ctx *
286 pex_msg_update_recv_ctx_get(uint64_t req_id)
287 {
288 struct pex_msg_update_recv_ctx *ctx;
289
290 list_for_each_entry(ctx, &requests, list) {
291 if (ctx->req_id == req_id) {
292 ctx->idle = 0;
293 return ctx;
294 }
295 }
296
297 return NULL;
298 }
299
300 static void pex_msg_update_ctx_free(struct pex_msg_update_recv_ctx *ctx)
301 {
302 list_del(&ctx->list);
303 free(ctx->data);
304 free(ctx);
305 }
306
307 void *pex_msg_update_response_recv(const void *data, int len, enum pex_opcode op,
308 int *data_len, uint64_t *timestamp)
309 {
310 struct pex_msg_update_recv_ctx *ctx;
311 uint8_t enc_key[CURVE25519_KEY_SIZE];
312 void *ret;
313
314 *data_len = 0;
315 if (op == PEX_MSG_UPDATE_RESPONSE) {
316 const struct pex_update_response *res = data;
317
318 if (len < sizeof(*res))
319 return NULL;
320
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)
324 return NULL;
325
326 data += sizeof(*res);
327 len -= sizeof(*res);
328
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;
334
335 if (len <= sizeof(*res))
336 return NULL;
337
338 ctx = pex_msg_update_recv_ctx_get(res->req_id);
339 if (!ctx || ctx->data_ofs != res->offset)
340 return NULL;
341
342 data += sizeof(*res);
343 len -= sizeof(*res);
344 } else if (op == PEX_MSG_UPDATE_RESPONSE_NO_DATA) {
345 const struct pex_update_response_no_data *res = data;
346
347 if (len < sizeof(*res))
348 return NULL;
349
350 ctx = pex_msg_update_recv_ctx_get(res->req_id);
351 if (!ctx)
352 return NULL;
353
354 goto error;
355 } else {
356 return NULL;
357 }
358
359 if (ctx->data_ofs + len > ctx->data_len)
360 goto error;
361
362 memcpy(ctx->data + ctx->data_ofs, data, len);
363 ctx->data_ofs += len;
364 if (ctx->data_ofs < ctx->data_len)
365 return NULL;
366
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))
370 goto error;
371
372 *data_len = ctx->data_len;
373 ret = ctx->data;
374 ctx->data = NULL;
375 pex_msg_update_ctx_free(ctx);
376
377 return ret;
378
379 error:
380 pex_msg_update_ctx_free(ctx);
381 *data_len = -1;
382 return NULL;
383 }
384
385 static void
386 pex_gc_cb(struct uloop_timeout *t)
387 {
388 struct pex_msg_update_recv_ctx *ctx, *tmp;
389
390 list_for_each_entry_safe(ctx, tmp, &requests, list) {
391 if (++ctx->idle <= 3)
392 continue;
393
394 pex_msg_update_ctx_free(ctx);
395 }
396
397 if (!list_empty(&requests))
398 uloop_timeout_set(t, 1000);
399 }
400
401 int pex_open(void *addr, size_t addr_len, pex_recv_cb_t cb, bool server)
402 {
403 struct sockaddr *sa = addr;
404 int yes = 1, no = 0;
405 int fd;
406
407 pex_recv_cb = cb;
408
409 pex_urandom = fopen("/dev/urandom", "r");
410 if (!pex_urandom)
411 return -1;
412
413 fd = socket(sa->sa_family == AF_INET ? PF_INET : PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
414 if (fd < 0)
415 goto close_urandom;
416
417 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
418 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
419
420 if (server) {
421 if (bind(fd, addr, addr_len) < 0) {
422 perror("bind");
423 goto close_socket;
424 }
425
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));
429 } else {
430 if (connect(fd, addr, addr_len) < 0) {
431 perror("connect");
432 goto close_socket;
433 }
434 }
435
436 pex_fd.fd = fd;
437 pex_fd.cb = pex_fd_cb;
438 uloop_fd_add(&pex_fd, ULOOP_READ);
439
440 gc_timer.cb = pex_gc_cb;
441
442 return 0;
443
444 close_socket:
445 close(fd);
446 close_urandom:
447 fclose(pex_urandom);
448 return -1;
449 }
450
451 void pex_close(void)
452 {
453 if (!pex_fd.cb)
454 return;
455
456 fclose(pex_urandom);
457 uloop_fd_delete(&pex_fd);
458 close(pex_fd.fd);
459 pex_fd.cb = NULL;
460 pex_urandom = NULL;
461 }