ubus: add reload command
[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 <netinet/in.h>
13 #include <netinet/ip.h>
14 #include <netinet/ip6.h>
15 #include <netinet/udp.h>
16 #include "pex-msg.h"
17 #include "chacha20.h"
18 #include "auth-data.h"
19
20 static char pex_tx_buf[PEX_BUF_SIZE];
21 static FILE *pex_urandom;
22 static struct uloop_fd pex_fd;
23 static LIST_HEAD(requests);
24 static struct uloop_timeout gc_timer;
25 static int pex_raw_v4_fd = -1, pex_raw_v6_fd = -1;
26
27 static pex_recv_cb_t pex_recv_cb;
28
29 struct pex_msg_update_recv_ctx {
30 struct list_head list;
31
32 union network_endpoint addr;
33
34 uint8_t priv_key[CURVE25519_KEY_SIZE];
35 uint8_t auth_key[CURVE25519_KEY_SIZE];
36 uint8_t e_key[CURVE25519_KEY_SIZE];
37
38 uint64_t req_id;
39
40 void *data;
41 int data_len;
42 int data_ofs;
43
44 int idle;
45 };
46
47 uint64_t pex_network_hash(const uint8_t *auth_key, uint64_t req_id)
48 {
49 siphash_key_t key = {
50 .key = {
51 be64_to_cpu(req_id),
52 be64_to_cpu(req_id)
53 }
54 };
55 uint64_t hash;
56
57 siphash_to_be64(&hash, auth_key, CURVE25519_KEY_SIZE, &key);
58
59 return hash;
60 }
61
62
63 struct pex_hdr *__pex_msg_init(const uint8_t *pubkey, uint8_t opcode)
64 {
65 struct pex_hdr *hdr = (struct pex_hdr *)pex_tx_buf;
66
67 hdr->version = 0;
68 hdr->opcode = opcode;
69 hdr->len = 0;
70 memcpy(hdr->id, pubkey, sizeof(hdr->id));
71
72 return hdr;
73 }
74
75 struct pex_hdr *__pex_msg_init_ext(const uint8_t *pubkey, const uint8_t *auth_key,
76 uint8_t opcode, bool ext)
77 {
78 struct pex_hdr *hdr = __pex_msg_init(pubkey, opcode);
79 struct pex_ext_hdr *ehdr = (struct pex_ext_hdr *)(hdr + 1);
80 uint64_t hash;
81
82 if (!ext)
83 return hdr;
84
85 hdr->len = sizeof(*ehdr);
86
87 if (fread(&ehdr->nonce, sizeof(ehdr->nonce), 1, pex_urandom) != 1)
88 return NULL;
89
90 hash = pex_network_hash(auth_key, ehdr->nonce);
91 *(uint64_t *)hdr->id ^= hash;
92 memcpy(ehdr->auth_id, auth_key, sizeof(ehdr->auth_id));
93
94 return hdr;
95 }
96
97 void *pex_msg_append(size_t len)
98 {
99 struct pex_hdr *hdr = (struct pex_hdr *)pex_tx_buf;
100 int ofs = hdr->len + sizeof(struct pex_hdr);
101 void *buf = &pex_tx_buf[ofs];
102
103 if (sizeof(pex_tx_buf) - ofs < len)
104 return NULL;
105
106 hdr->len += len;
107 memset(buf, 0, len);
108
109 return buf;
110 }
111
112 static void
113 pex_fd_cb(struct uloop_fd *fd, unsigned int events)
114 {
115 struct sockaddr_in6 sin6;
116 static char buf[PEX_BUF_SIZE];
117 struct pex_hdr *hdr = (struct pex_hdr *)buf;
118 ssize_t len;
119
120 while (1) {
121 socklen_t slen = sizeof(sin6);
122
123 len = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6, &slen);
124 if (len < 0) {
125 if (errno == EINTR)
126 continue;
127
128 if (errno == EAGAIN)
129 break;
130
131 pex_close();
132 return;
133 }
134
135 if (!len)
136 continue;
137
138 if (len < sizeof(*hdr) + sizeof(struct pex_ext_hdr))
139 continue;
140
141 hdr->len = ntohs(hdr->len);
142 if (len - sizeof(hdr) - sizeof(struct pex_ext_hdr) < hdr->len)
143 continue;
144
145 pex_recv_cb(hdr, &sin6);
146 }
147 }
148
149 static inline uint32_t
150 csum_tcpudp_nofold(uint32_t saddr, uint32_t daddr, uint32_t len, uint8_t proto)
151 {
152 uint64_t sum = 0;
153
154 sum += saddr;
155 sum += daddr;
156 #if __BYTE_ORDER == __LITTLE_ENDIAN
157 sum += (proto + len) << 8;
158 #else
159 sum += proto + len;
160 #endif
161
162 sum = (sum & 0xffffffff) + (sum >> 32);
163 sum = (sum & 0xffffffff) + (sum >> 32);
164
165 return (uint32_t)sum;
166 }
167
168 static inline uint32_t csum_add(uint32_t sum, uint32_t addend)
169 {
170 sum += addend;
171 return sum + (sum < addend);
172 }
173
174 static inline uint16_t csum_fold(uint32_t sum)
175 {
176 sum = (sum & 0xffff) + (sum >> 16);
177 sum = (sum & 0xffff) + (sum >> 16);
178
179 return (uint16_t)~sum;
180 }
181
182 static uint32_t csum_partial(const void *buf, int len)
183 {
184 const uint16_t *data = buf;
185 uint32_t sum = 0;
186
187 while (len > 1) {
188 sum += *data++;
189 len -= 2;
190 }
191
192 if (len == 1)
193 #if __BYTE_ORDER == __LITTLE_ENDIAN
194 sum += *(uint8_t *)data;
195 #else
196 sum += *(uint8_t *)data << 8;
197 #endif
198
199 sum = (sum & 0xffff) + (sum >> 16);
200 sum = (sum & 0xffff) + (sum >> 16);
201
202 return sum;
203 }
204
205 static void pex_fixup_udpv4(void *hdr, size_t hdrlen, const void *data, size_t len)
206 {
207 struct ip *ip = hdr;
208 struct udphdr *udp = hdr + ip->ip_hl * 4;
209 uint16_t udp_len = sizeof(*udp) + len;
210 uint32_t sum;
211
212 if ((void *)&udp[1] > hdr + hdrlen)
213 return;
214
215 udp->uh_sum = 0;
216 udp->uh_ulen = htons(udp_len);
217 sum = csum_tcpudp_nofold(*(uint32_t *)&ip->ip_src, *(uint32_t *)&ip->ip_dst,
218 ip->ip_p, udp_len);
219 sum = csum_add(sum, csum_partial(udp, sizeof(*udp)));
220 sum = csum_add(sum, csum_partial(data, len));
221 udp->uh_sum = csum_fold(sum);
222
223 ip->ip_len = htons(hdrlen + len);
224 ip->ip_sum = 0;
225 ip->ip_sum = csum_fold(csum_partial(ip, sizeof(*ip)));
226
227 #ifdef __APPLE__
228 ip->ip_len = hdrlen + len;
229 #endif
230 }
231
232 static void pex_fixup_udpv6(void *hdr, size_t hdrlen, const void *data, size_t len)
233 {
234 struct ip6_hdr *ip = hdr;
235 struct udphdr *udp = hdr + sizeof(*ip);
236 uint16_t udp_len = htons(sizeof(*udp) + len);
237
238 if ((void *)&udp[1] > hdr + hdrlen)
239 return;
240
241 ip->ip6_plen = htons(sizeof(*udp) + len);
242 udp->uh_sum = 0;
243 udp->uh_ulen = udp_len;
244 udp->uh_sum = csum_fold(csum_partial(hdr, sizeof(*ip) + sizeof(*udp)));
245
246 #ifdef __APPLE__
247 ip->ip6_plen = sizeof(*udp) + len;
248 #endif
249 }
250
251 static void pex_fixup_header(void *hdr, size_t hdrlen, const void *data, size_t len)
252 {
253 if (hdrlen >= sizeof(struct ip6_hdr) + sizeof(struct udphdr))
254 pex_fixup_udpv6(hdr, hdrlen, data, len);
255 else if (hdrlen >= sizeof(struct ip) + sizeof(struct udphdr))
256 pex_fixup_udpv4(hdr, hdrlen, data, len);
257 }
258
259 int __pex_msg_send(int fd, const void *addr, void *ip_hdr, size_t ip_hdrlen)
260 {
261 struct pex_hdr *hdr = (struct pex_hdr *)pex_tx_buf;
262 const struct sockaddr *sa = addr;
263 size_t tx_len = sizeof(*hdr) + hdr->len;
264 uint16_t orig_len = hdr->len;
265 int ret;
266
267 if (fd < 0) {
268 hdr->len -= sizeof(struct pex_ext_hdr);
269 if (ip_hdrlen)
270 fd = sa->sa_family == AF_INET6 ? pex_raw_v6_fd : pex_raw_v4_fd;
271 else
272 fd = pex_fd.fd;
273
274 if (fd < 0)
275 return -1;
276 }
277
278 hdr->len = htons(hdr->len);
279 if (addr) {
280 struct iovec iov[2] = {
281 { .iov_base = (void *)ip_hdr, .iov_len = ip_hdrlen },
282 { .iov_base = pex_tx_buf, .iov_len = tx_len }
283 };
284 struct msghdr msg = {
285 .msg_name = (void *)addr,
286 .msg_iov = iov,
287 .msg_iovlen = ARRAY_SIZE(iov),
288 };
289
290 if (sa->sa_family == AF_INET6)
291 msg.msg_namelen = sizeof(struct sockaddr_in6);
292 else
293 msg.msg_namelen = sizeof(struct sockaddr_in);
294
295 if (ip_hdrlen) {
296 pex_fixup_header(ip_hdr, ip_hdrlen, pex_tx_buf, tx_len);
297 } else {
298 msg.msg_iov++;
299 msg.msg_iovlen--;
300 }
301
302 ret = sendmsg(fd, &msg, 0);
303 } else {
304 ret = send(fd, pex_tx_buf, tx_len, 0);
305 }
306 hdr->len = orig_len;
307
308 return ret;
309 }
310
311 static void
312 pex_msg_update_response_fill(struct pex_msg_update_send_ctx *ctx)
313 {
314 struct pex_hdr *hdr = (struct pex_hdr *)pex_tx_buf;
315 int ofs = hdr->len + sizeof(struct pex_hdr);
316 int cur_len = ctx->rem;
317
318 if (cur_len > PEX_BUF_SIZE - ofs)
319 cur_len = PEX_BUF_SIZE - ofs;
320
321 memcpy(pex_msg_append(cur_len), ctx->cur, cur_len);
322 ctx->cur += cur_len;
323 ctx->rem -= cur_len;
324 }
325
326 void pex_msg_update_response_init(struct pex_msg_update_send_ctx *ctx,
327 const uint8_t *pubkey, const uint8_t *auth_key,
328 const uint8_t *peer_key, bool ext,
329 struct pex_update_request *req,
330 const void *data, int len)
331 {
332 uint8_t e_key_priv[CURVE25519_KEY_SIZE];
333 uint8_t enc_key[CURVE25519_KEY_SIZE];
334 struct pex_update_response *res;
335
336 ctx->pubkey = pubkey;
337 ctx->auth_key = auth_key;
338 ctx->ext = ext;
339 ctx->req_id = req->req_id;
340
341 if (!__pex_msg_init_ext(pubkey, auth_key, PEX_MSG_UPDATE_RESPONSE, ext))
342 return;
343
344 res = pex_msg_append(sizeof(*res));
345 res->req_id = req->req_id;
346 res->data_len = len;
347
348 if (!fread(e_key_priv, sizeof(e_key_priv), 1, pex_urandom))
349 return;
350
351 curve25519_clamp_secret(e_key_priv);
352 curve25519_generate_public(res->e_key, e_key_priv);
353 curve25519(enc_key, e_key_priv, peer_key);
354
355 ctx->data = ctx->cur = malloc(len);
356 ctx->rem = len;
357
358 memcpy(ctx->data, data, len);
359 chacha20_encrypt_msg(ctx->data, len, &req->req_id, enc_key);
360
361 pex_msg_update_response_fill(ctx);
362 }
363
364 bool pex_msg_update_response_continue(struct pex_msg_update_send_ctx *ctx)
365 {
366 struct pex_update_response_data *res_ext;
367
368 if (ctx->rem <= 0) {
369 free(ctx->data);
370 ctx->data = NULL;
371
372 return false;
373 }
374
375 if (!__pex_msg_init_ext(ctx->pubkey, ctx->auth_key,
376 PEX_MSG_UPDATE_RESPONSE_DATA, ctx->ext))
377 return false;
378
379 res_ext = pex_msg_append(sizeof(*res_ext));
380 res_ext->req_id = ctx->req_id;
381 res_ext->offset = ctx->cur - ctx->data;
382 pex_msg_update_response_fill(ctx);
383
384 return true;
385 }
386
387
388 struct pex_update_request *
389 pex_msg_update_request_init(const uint8_t *pubkey, const uint8_t *priv_key,
390 const uint8_t *auth_key, union network_endpoint *addr,
391 uint64_t cur_version, bool ext)
392 {
393 struct pex_update_request *req;
394 struct pex_msg_update_recv_ctx *ctx;
395
396 list_for_each_entry(ctx, &requests, list) {
397 if (!memcmp(&ctx->addr, addr, sizeof(ctx->addr)))
398 return NULL;
399 }
400
401 ctx = calloc(1, sizeof(*ctx));
402 memcpy(&ctx->addr, addr, sizeof(ctx->addr));
403 memcpy(ctx->auth_key, auth_key, sizeof(ctx->auth_key));
404 memcpy(ctx->priv_key, priv_key, sizeof(ctx->priv_key));
405 if (!fread(&ctx->req_id, sizeof(ctx->req_id), 1, pex_urandom))
406 return NULL;
407 list_add_tail(&ctx->list, &requests);
408 if (!gc_timer.pending)
409 uloop_timeout_set(&gc_timer, 1000);
410
411 if (!__pex_msg_init_ext(pubkey, auth_key, PEX_MSG_UPDATE_REQUEST, ext)) {
412 free(ctx);
413 return NULL;
414 }
415
416 req = pex_msg_append(sizeof(*req));
417 req->cur_version = cpu_to_be64(cur_version);
418 req->req_id = ctx->req_id;
419
420 return req;
421 }
422
423 static struct pex_msg_update_recv_ctx *
424 pex_msg_update_recv_ctx_get(uint64_t req_id)
425 {
426 struct pex_msg_update_recv_ctx *ctx;
427
428 list_for_each_entry(ctx, &requests, list) {
429 if (ctx->req_id == req_id) {
430 ctx->idle = 0;
431 return ctx;
432 }
433 }
434
435 return NULL;
436 }
437
438 static void pex_msg_update_ctx_free(struct pex_msg_update_recv_ctx *ctx)
439 {
440 list_del(&ctx->list);
441 free(ctx->data);
442 free(ctx);
443 }
444
445 void *pex_msg_update_response_recv(const void *data, int len, enum pex_opcode op,
446 int *data_len, uint64_t *timestamp)
447 {
448 struct pex_msg_update_recv_ctx *ctx;
449 uint8_t enc_key[CURVE25519_KEY_SIZE];
450 void *ret;
451
452 *data_len = 0;
453 if (op == PEX_MSG_UPDATE_RESPONSE) {
454 const struct pex_update_response *res = data;
455
456 if (len < sizeof(*res))
457 return NULL;
458
459 ctx = pex_msg_update_recv_ctx_get(res->req_id);
460 if (!ctx || ctx->data_len || !res->data_len ||
461 res->data_len > UNETD_NET_DATA_SIZE_MAX)
462 return NULL;
463
464 data += sizeof(*res);
465 len -= sizeof(*res);
466
467 ctx->data_len = res->data_len;
468 memcpy(ctx->e_key, res->e_key, sizeof(ctx->e_key));
469 ctx->data = malloc(ctx->data_len);
470 } else if (op == PEX_MSG_UPDATE_RESPONSE_DATA) {
471 const struct pex_update_response_data *res = data;
472
473 if (len <= sizeof(*res))
474 return NULL;
475
476 ctx = pex_msg_update_recv_ctx_get(res->req_id);
477 if (!ctx || ctx->data_ofs != res->offset)
478 return NULL;
479
480 data += sizeof(*res);
481 len -= sizeof(*res);
482 } else if (op == PEX_MSG_UPDATE_RESPONSE_NO_DATA) {
483 const struct pex_update_response_no_data *res = data;
484
485 if (len < sizeof(*res))
486 return NULL;
487
488 ctx = pex_msg_update_recv_ctx_get(res->req_id);
489 if (!ctx)
490 return NULL;
491
492 goto error;
493 } else {
494 return NULL;
495 }
496
497 if (ctx->data_ofs + len > ctx->data_len)
498 goto error;
499
500 memcpy(ctx->data + ctx->data_ofs, data, len);
501 ctx->data_ofs += len;
502 if (ctx->data_ofs < ctx->data_len)
503 return NULL;
504
505 curve25519(enc_key, ctx->priv_key, ctx->e_key);
506 chacha20_encrypt_msg(ctx->data, ctx->data_len, &ctx->req_id, enc_key);
507 if (unet_auth_data_validate(ctx->auth_key, ctx->data, ctx->data_len, timestamp, NULL))
508 goto error;
509
510 *data_len = ctx->data_len;
511 ret = ctx->data;
512 ctx->data = NULL;
513 pex_msg_update_ctx_free(ctx);
514
515 return ret;
516
517 error:
518 pex_msg_update_ctx_free(ctx);
519 *data_len = -1;
520 return NULL;
521 }
522
523 static void
524 pex_gc_cb(struct uloop_timeout *t)
525 {
526 struct pex_msg_update_recv_ctx *ctx, *tmp;
527
528 list_for_each_entry_safe(ctx, tmp, &requests, list) {
529 if (++ctx->idle <= 3)
530 continue;
531
532 pex_msg_update_ctx_free(ctx);
533 }
534
535 if (!list_empty(&requests))
536 uloop_timeout_set(t, 1000);
537 }
538
539 int pex_open(void *addr, size_t addr_len, pex_recv_cb_t cb, bool server)
540 {
541 struct sockaddr *sa = addr;
542 int yes = 1, no = 0;
543 int fd;
544
545 pex_recv_cb = cb;
546
547 if (server) {
548 pex_raw_v4_fd = fd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
549 if (fd < 0)
550 return -1;
551
552 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
553 setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &yes, sizeof(yes));
554
555 #ifdef linux
556 pex_raw_v6_fd = fd = socket(PF_INET6, SOCK_RAW, IPPROTO_UDP);
557 if (fd < 0)
558 goto close_raw;
559
560 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
561 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
562 setsockopt(fd, IPPROTO_IPV6, IPV6_HDRINCL, &yes, sizeof(yes));
563 #endif
564 }
565
566 pex_urandom = fopen("/dev/urandom", "r");
567 if (!pex_urandom)
568 goto close_raw;
569
570 fd = socket(sa->sa_family == AF_INET ? PF_INET : PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
571 if (fd < 0)
572 goto close_urandom;
573
574 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
575 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
576
577 if (server) {
578 if (bind(fd, addr, addr_len) < 0) {
579 perror("bind");
580 goto close_socket;
581 }
582
583 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
584 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes));
585 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
586 } else {
587 if (connect(fd, addr, addr_len) < 0) {
588 perror("connect");
589 goto close_socket;
590 }
591 }
592
593 pex_fd.fd = fd;
594 pex_fd.cb = pex_fd_cb;
595 uloop_fd_add(&pex_fd, ULOOP_READ);
596
597 gc_timer.cb = pex_gc_cb;
598
599 return 0;
600
601 close_socket:
602 close(fd);
603 close_urandom:
604 fclose(pex_urandom);
605 close_raw:
606 if (pex_raw_v4_fd >= 0)
607 close(pex_raw_v4_fd);
608 if (pex_raw_v6_fd >= 0)
609 close(pex_raw_v6_fd);
610 pex_raw_v4_fd = -1;
611 pex_raw_v6_fd = -1;
612 return -1;
613 }
614
615 void pex_close(void)
616 {
617 if (!pex_fd.cb)
618 return;
619
620 if (pex_raw_v4_fd >= 0)
621 close(pex_raw_v4_fd);
622 if (pex_raw_v6_fd >= 0)
623 close(pex_raw_v6_fd);
624 pex_raw_v4_fd = -1;
625 pex_raw_v6_fd = -1;
626
627 fclose(pex_urandom);
628 uloop_fd_delete(&pex_fd);
629 close(pex_fd.fd);
630 pex_fd.cb = NULL;
631 pex_urandom = NULL;
632 }