OpenVPN
dco_freebsd.c
Go to the documentation of this file.
1/*
2 * Interface to FreeBSD dco networking code
3 *
4 * Copyright (C) 2022 Rubicon Communications, LLC (Netgate). All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program (see the file COPYING included with this
17 * distribution); if not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#if defined(ENABLE_DCO) && defined(TARGET_FREEBSD)
25
26#include "syshead.h"
27
28#include <sys/param.h>
29#include <sys/linker.h>
30#include <sys/nv.h>
31#include <sys/utsname.h>
32
33#include <netinet/in.h>
34
35#include "dco_freebsd.h"
36#include "dco.h"
37#include "tun.h"
38#include "crypto.h"
39#include "multi.h"
40#include "ssl_common.h"
41
42static nvlist_t *
43sockaddr_to_nvlist(const struct sockaddr *sa)
44{
45 nvlist_t *nvl = nvlist_create(0);
46
47 nvlist_add_number(nvl, "af", sa->sa_family);
48
49 switch (sa->sa_family)
50 {
51 case AF_INET:
52 {
53 const struct sockaddr_in *in = (const struct sockaddr_in *)sa;
54 nvlist_add_binary(nvl, "address", &in->sin_addr, sizeof(in->sin_addr));
55 nvlist_add_number(nvl, "port", in->sin_port);
56 break;
57 }
58
59 case AF_INET6:
60 {
61 const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)sa;
62 nvlist_add_binary(nvl, "address", &in6->sin6_addr, sizeof(in6->sin6_addr));
63 nvlist_add_number(nvl, "port", in6->sin6_port);
64 nvlist_add_number(nvl, "scopeid", in6->sin6_scope_id);
65 break;
66 }
67
68 default:
69 ASSERT(0);
70 }
71
72 return (nvl);
73}
74
75static bool
76nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *ss)
77{
78 if (!nvlist_exists_number(nvl, "af"))
79 {
80 return (false);
81 }
82 if (!nvlist_exists_binary(nvl, "address"))
83 {
84 return (false);
85 }
86 if (!nvlist_exists_number(nvl, "port"))
87 {
88 return (false);
89 }
90
91 ss->ss_family = nvlist_get_number(nvl, "af");
92
93 switch (ss->ss_family)
94 {
95 case AF_INET:
96 {
97 struct sockaddr_in *in = (struct sockaddr_in *)ss;
98 const void *data;
99 size_t len;
100
101 in->sin_len = sizeof(*in);
102 data = nvlist_get_binary(nvl, "address", &len);
103 ASSERT(len == sizeof(in->sin_addr));
104 memcpy(&in->sin_addr, data, sizeof(in->sin_addr));
105 in->sin_port = nvlist_get_number(nvl, "port");
106 break;
107 }
108
109 case AF_INET6:
110 {
111 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)ss;
112 const void *data;
113 size_t len;
114
115 in6->sin6_len = sizeof(*in6);
116 data = nvlist_get_binary(nvl, "address", &len);
117 ASSERT(len == sizeof(in6->sin6_addr));
118 memcpy(&in6->sin6_addr, data, sizeof(in6->sin6_addr));
119 in6->sin6_port = nvlist_get_number(nvl, "port");
120
121 if (nvlist_exists_number(nvl, "scopeid"))
122 {
123 in6->sin6_scope_id = nvlist_get_number(nvl, "scopeid");
124 }
125 break;
126 }
127
128 default:
129 return (false);
130 }
131
132 return (true);
133}
134
135int
136dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd, struct sockaddr *localaddr,
137 struct sockaddr *remoteaddr, struct in_addr *vpn_ipv4, struct in6_addr *vpn_ipv6)
138{
139 struct ifdrv drv;
140 nvlist_t *nvl, *local_nvl, *remote_nvl;
141 int ret;
142
143 nvl = nvlist_create(0);
144
145 msg(D_DCO_DEBUG, "%s: peer-id %d, fd %d", __func__, peerid, sd);
146
147 if (localaddr)
148 {
149 local_nvl = sockaddr_to_nvlist(localaddr);
150 nvlist_add_nvlist(nvl, "local", local_nvl);
151 }
152
153 if (remoteaddr)
154 {
155 remote_nvl = sockaddr_to_nvlist(remoteaddr);
156 nvlist_add_nvlist(nvl, "remote", remote_nvl);
157 }
158
159 if (vpn_ipv4)
160 {
161 nvlist_add_binary(nvl, "vpn_ipv4", &vpn_ipv4->s_addr, sizeof(vpn_ipv4->s_addr));
162 }
163
164 if (vpn_ipv6)
165 {
166 nvlist_add_binary(nvl, "vpn_ipv6", vpn_ipv6, sizeof(*vpn_ipv6));
167 }
168
169 nvlist_add_number(nvl, "fd", sd);
170 nvlist_add_number(nvl, "peerid", peerid);
171
172 CLEAR(drv);
173 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
174 drv.ifd_cmd = OVPN_NEW_PEER;
175 drv.ifd_data = nvlist_pack(nvl, &drv.ifd_len);
176
177 ret = ioctl(dco->fd, SIOCSDRVSPEC, &drv);
178 if (ret)
179 {
180 msg(M_ERR | M_ERRNO, "Failed to create new peer");
181 }
182
183 free(drv.ifd_data);
184 if (localaddr)
185 {
186 nvlist_destroy(local_nvl);
187 }
188 if (remoteaddr)
189 {
190 nvlist_destroy(remote_nvl);
191 }
192 nvlist_destroy(nvl);
193
194 return ret;
195}
196
197static int
198open_fd(dco_context_t *dco)
199{
200 int ret;
201
202 ret = pipe2(dco->pipefd, O_CLOEXEC | O_NONBLOCK);
203 if (ret != 0)
204 {
205 return -1;
206 }
207
208 dco->fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
209 if (dco->fd != -1)
210 {
211 dco->open = true;
212 }
213
214 return dco->fd;
215}
216
217static void
218close_fd(dco_context_t *dco)
219{
220 close(dco->pipefd[0]);
221 close(dco->pipefd[1]);
222 close(dco->fd);
223}
224
225bool
226ovpn_dco_init(struct context *c)
227{
228 c->c1.tuntap->dco.c = c;
229
230 if (open_fd(&c->c1.tuntap->dco) < 0)
231 {
232 msg(M_ERR, "Failed to open socket");
233 return false;
234 }
235 return true;
236}
237
238static int
239dco_set_ifmode(dco_context_t *dco, int ifmode)
240{
241 struct ifdrv drv;
242 nvlist_t *nvl;
243 int ret;
244
245 nvl = nvlist_create(0);
246 nvlist_add_number(nvl, "ifmode", ifmode);
247
248 CLEAR(drv);
249 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
250 drv.ifd_cmd = OVPN_SET_IFMODE;
251 drv.ifd_data = nvlist_pack(nvl, &drv.ifd_len);
252
253 ret = ioctl(dco->fd, SIOCSDRVSPEC, &drv);
254 if (ret)
255 {
256 msg(M_WARN | M_ERRNO, "dco_set_ifmode: failed to set ifmode=%08x", ifmode);
257 }
258
259 free(drv.ifd_data);
260 nvlist_destroy(nvl);
261
262 return ret;
263}
264
265static int
266create_interface(struct tuntap *tt, const char *dev)
267{
268 int ret;
269 struct ifreq ifr;
270
271 CLEAR(ifr);
272
273 /* Create ovpnx first, then rename it. */
274 snprintf(ifr.ifr_name, IFNAMSIZ, "ovpn");
275 ret = ioctl(tt->dco.fd, SIOCIFCREATE2, &ifr);
276 if (ret)
277 {
278 ret = -errno;
279 msg(M_WARN | M_ERRNO, "Failed to create interface %s (SIOCIFCREATE2)", ifr.ifr_name);
280 return ret;
281 }
282
283 /* Rename */
284 if (!strcmp(dev, "tun"))
285 {
286 ifr.ifr_data = "ovpn";
287 }
288 else
289 {
290 ifr.ifr_data = (char *)dev;
291 }
292
293 snprintf(tt->dco.ifname, IFNAMSIZ, "%s", ifr.ifr_data);
294
295 ret = ioctl(tt->dco.fd, SIOCSIFNAME, &ifr);
296 if (ret)
297 {
298 ret = -errno;
299 /* Delete the created interface again. */
300 (void)ioctl(tt->dco.fd, SIOCIFDESTROY, &ifr);
301 msg(M_WARN | M_ERRNO, "Failed to create interface %s (SIOCSIFNAME)", ifr.ifr_data);
302 return ret;
303 }
304
305 return 0;
306}
307
308static int
309remove_interface(struct tuntap *tt)
310{
311 int ret;
312 struct ifreq ifr;
313
314 CLEAR(ifr);
315 snprintf(ifr.ifr_name, IFNAMSIZ, "%s", tt->dco.ifname);
316
317 ret = ioctl(tt->dco.fd, SIOCIFDESTROY, &ifr);
318 if (ret)
319 {
320 msg(M_ERR | M_ERRNO, "Failed to remove interface %s", ifr.ifr_name);
321 }
322
323 tt->dco.ifname[0] = 0;
324
325 return ret;
326}
327
328int
329open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
330{
331 int ret = create_interface(tt, dev);
332
333 if (ret >= 0 || ret == -EEXIST)
334 {
335 /* see "Interface Flags" in ifnet(9) */
336 int i = IFF_POINTOPOINT | IFF_MULTICAST;
337 if (tt->topology == TOP_SUBNET)
338 {
339 i = IFF_BROADCAST | IFF_MULTICAST;
340 }
341 dco_set_ifmode(&tt->dco, i);
342 }
343
344 return ret;
345}
346
347void
348close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx)
349{
350 remove_interface(tt);
351 close_fd(&tt->dco);
352}
353
354int
355dco_swap_keys(dco_context_t *dco, unsigned int peerid)
356{
357 struct ifdrv drv;
358 nvlist_t *nvl;
359 int ret;
360
361 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
362
363 nvl = nvlist_create(0);
364 nvlist_add_number(nvl, "peerid", peerid);
365
366 CLEAR(drv);
367 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
368 drv.ifd_cmd = OVPN_SWAP_KEYS;
369 drv.ifd_data = nvlist_pack(nvl, &drv.ifd_len);
370
371 ret = ioctl(dco->fd, SIOCSDRVSPEC, &drv);
372 if (ret)
373 {
374 msg(M_WARN | M_ERRNO, "Failed to swap keys");
375 }
376
377 free(drv.ifd_data);
378 nvlist_destroy(nvl);
379
380 return ret;
381}
382
383int
384dco_del_peer(dco_context_t *dco, unsigned int peerid)
385{
386 struct ifdrv drv;
387 nvlist_t *nvl;
388 int ret;
389
390 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
391
392 nvl = nvlist_create(0);
393 nvlist_add_number(nvl, "peerid", peerid);
394
395 CLEAR(drv);
396 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
397 drv.ifd_cmd = OVPN_DEL_PEER;
398 drv.ifd_data = nvlist_pack(nvl, &drv.ifd_len);
399
400 ret = ioctl(dco->fd, SIOCSDRVSPEC, &drv);
401 if (ret)
402 {
403 msg(M_WARN | M_ERRNO, "Failed to delete peer");
404 }
405
406 free(drv.ifd_data);
407 nvlist_destroy(nvl);
408
409 return ret;
410}
411
412int
413dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
414{
415 struct ifdrv drv;
416 nvlist_t *nvl;
417 int ret;
418
419 msg(D_DCO_DEBUG, "%s: peer-id %d, slot %d", __func__, peerid, slot);
420
421 nvl = nvlist_create(0);
422 nvlist_add_number(nvl, "slot", slot);
423 nvlist_add_number(nvl, "peerid", peerid);
424
425 CLEAR(drv);
426 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
427 drv.ifd_cmd = OVPN_DEL_KEY;
428 drv.ifd_data = nvlist_pack(nvl, &drv.ifd_len);
429
430 ret = ioctl(dco->fd, SIOCSDRVSPEC, &drv);
431 if (ret)
432 {
433 msg(M_WARN | M_ERRNO, "Failed to delete key");
434 }
435
436 free(drv.ifd_data);
437 nvlist_destroy(nvl);
438
439 return ret;
440}
441
442static nvlist_t *
443key_to_nvlist(const uint8_t *key, const uint8_t *implicit_iv, const char *ciphername)
444{
445 nvlist_t *nvl;
446 size_t key_len;
447
448 nvl = nvlist_create(0);
449
450 nvlist_add_string(nvl, "cipher", ciphername);
451
452 if (strcmp(ciphername, "none") != 0)
453 {
454 key_len = cipher_kt_key_size(ciphername);
455
456 nvlist_add_binary(nvl, "key", key, key_len);
457 nvlist_add_binary(nvl, "iv", implicit_iv, 8);
458 }
459
460 return (nvl);
461}
462
463static int
464start_tun(dco_context_t *dco)
465{
466 struct ifdrv drv;
467 int ret;
468
469 CLEAR(drv);
470 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
471 drv.ifd_cmd = OVPN_START_VPN;
472
473 ret = ioctl(dco->fd, SIOCSDRVSPEC, &drv);
474 if (ret)
475 {
476 msg(M_ERR | M_ERRNO, "Failed to start vpn");
477 }
478
479 return ret;
480}
481
482int
483dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid, dco_key_slot_t slot,
484 const uint8_t *encrypt_key, const uint8_t *encrypt_iv, const uint8_t *decrypt_key,
485 const uint8_t *decrypt_iv, const char *ciphername)
486{
487 struct ifdrv drv;
488 nvlist_t *nvl, *encrypt_nvl, *decrypt_nvl;
489 int ret;
490
491 msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s", __func__, slot, keyid, peerid,
492 ciphername);
493
494 nvl = nvlist_create(0);
495
496 nvlist_add_number(nvl, "slot", slot);
497 nvlist_add_number(nvl, "keyid", keyid);
498 nvlist_add_number(nvl, "peerid", peerid);
499
500 encrypt_nvl = key_to_nvlist(encrypt_key, encrypt_iv, ciphername);
501 decrypt_nvl = key_to_nvlist(decrypt_key, decrypt_iv, ciphername);
502
503 nvlist_add_nvlist(nvl, "encrypt", encrypt_nvl);
504 nvlist_add_nvlist(nvl, "decrypt", decrypt_nvl);
505
506 CLEAR(drv);
507 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
508 drv.ifd_cmd = OVPN_NEW_KEY;
509 drv.ifd_data = nvlist_pack(nvl, &drv.ifd_len);
510
511 ret = ioctl(dco->fd, SIOCSDRVSPEC, &drv);
512 if (ret)
513 {
514 msg(M_ERR | M_ERRNO, "Failed to set key");
515 }
516 else
517 {
518 ret = start_tun(dco);
519 }
520
521 free(drv.ifd_data);
522 nvlist_destroy(encrypt_nvl);
523 nvlist_destroy(decrypt_nvl);
524 nvlist_destroy(nvl);
525
526 return ret;
527}
528
529int
530dco_set_peer(dco_context_t *dco, unsigned int peerid, int keepalive_interval, int keepalive_timeout,
531 int mss)
532{
533 struct ifdrv drv;
534 nvlist_t *nvl;
535 int ret;
536
537 msg(D_DCO_DEBUG, "%s: peer-id %d, ping interval %d, ping timeout %d", __func__, peerid,
538 keepalive_interval, keepalive_timeout);
539
540 nvl = nvlist_create(0);
541 nvlist_add_number(nvl, "peerid", peerid);
542 nvlist_add_number(nvl, "interval", keepalive_interval);
543 nvlist_add_number(nvl, "timeout", keepalive_timeout);
544
545 CLEAR(drv);
546 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
547 drv.ifd_cmd = OVPN_SET_PEER;
548 drv.ifd_data = nvlist_pack(nvl, &drv.ifd_len);
549
550 ret = ioctl(dco->fd, SIOCSDRVSPEC, &drv);
551 if (ret)
552 {
553 msg(M_WARN | M_ERRNO, "Failed to set keepalive");
554 }
555
556 free(drv.ifd_data);
557 nvlist_destroy(nvl);
558
559 return ret;
560}
561
562int
564{
565 struct ifdrv drv;
566 uint8_t buf[4096];
567 nvlist_t *nvl;
568 enum ovpn_notif_type type;
569 int ret;
570
571 /* Flush any pending data from the pipe. */
572 (void)read(dco->pipefd[1], buf, sizeof(buf));
573
574 CLEAR(drv);
575 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
576 drv.ifd_cmd = OVPN_GET_PKT;
577 drv.ifd_data = buf;
578 drv.ifd_len = sizeof(buf);
579
580 ret = ioctl(dco->fd, SIOCGDRVSPEC, &drv);
581 if (ret)
582 {
583 msg(M_WARN | M_ERRNO, "Failed to read control packet");
584 return -errno;
585 }
586
587 nvl = nvlist_unpack(buf, drv.ifd_len, 0);
588 if (!nvl)
589 {
590 msg(M_WARN, "Failed to unpack nvlist");
591 return -EINVAL;
592 }
593
594 dco->dco_message_peer_id = nvlist_get_number(nvl, "peerid");
595
596 type = nvlist_get_number(nvl, "notification");
597 switch (type)
598 {
600 dco->dco_del_peer_reason = OVPN_DEL_PEER_REASON_EXPIRED;
601
602 if (nvlist_exists_number(nvl, "del_reason"))
603 {
604 uint32_t reason = nvlist_get_number(nvl, "del_reason");
605 if (reason == OVPN_DEL_REASON_TIMEOUT)
606 {
607 dco->dco_del_peer_reason = OVPN_DEL_PEER_REASON_EXPIRED;
608 }
609 else
610 {
611 dco->dco_del_peer_reason = OVPN_DEL_PEER_REASON_USERSPACE;
612 }
613 }
614
615 if (nvlist_exists_nvlist(nvl, "bytes"))
616 {
617 const nvlist_t *bytes = nvlist_get_nvlist(nvl, "bytes");
618
619 dco->dco_read_bytes = nvlist_get_number(bytes, "in");
620 dco->dco_write_bytes = nvlist_get_number(bytes, "out");
621 }
622
623 dco->dco_message_type = OVPN_CMD_DEL_PEER;
624 break;
625
627 dco->dco_message_type = OVPN_CMD_SWAP_KEYS;
628 break;
629
630 case OVPN_NOTIF_FLOAT:
631 {
632 const nvlist_t *address;
633
634 if (!nvlist_exists_nvlist(nvl, "address"))
635 {
636 msg(M_WARN, "Float notification without address");
637 break;
638 }
639
640 address = nvlist_get_nvlist(nvl, "address");
641 if (!nvlist_to_sockaddr(address, &dco->dco_float_peer_ss))
642 {
643 msg(M_WARN, "Failed to parse float notification");
644 break;
645 }
646 dco->dco_message_type = OVPN_CMD_FLOAT_PEER;
647 break;
648 }
649
650 default:
651 msg(M_WARN, "Unknown kernel notification %d", type);
652 break;
653 }
654
655 nvlist_destroy(nvl);
656
657 return 0;
658}
659
660bool
661dco_available(int msglevel)
662{
663 struct if_clonereq ifcr;
664 char *buf = NULL;
665 int fd;
666 int ret;
667 bool available = false;
668
669 /* Attempt to load the module. Ignore errors, because it might already be
670 * loaded, or built into the kernel. */
671 (void)kldload("if_ovpn");
672
673 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
674 if (fd < 0)
675 {
676 return false;
677 }
678
679 CLEAR(ifcr);
680
681 /* List cloners and check if openvpn is there. That tells us if this kernel
682 * supports if_ovpn (i.e. DCO) or not. */
683 ret = ioctl(fd, SIOCIFGCLONERS, &ifcr);
684 if (ret != 0)
685 {
686 goto out;
687 }
688
689 buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
690 if (!buf)
691 {
692 goto out;
693 }
694
695 ifcr.ifcr_count = ifcr.ifcr_total;
696 ifcr.ifcr_buffer = buf;
697 ret = ioctl(fd, SIOCIFGCLONERS, &ifcr);
698 if (ret != 0)
699 {
700 goto out;
701 }
702
703 for (int i = 0; i < ifcr.ifcr_total; i++)
704 {
705 if (strcmp(buf + (i * IFNAMSIZ), "openvpn") == 0)
706 {
707 available = true;
708 goto out;
709 }
710 }
711
712out:
713 free(buf);
714 close(fd);
715
716 return available;
717}
718
719const char *
721{
722 struct utsname *uts;
723 ALLOC_OBJ_GC(uts, struct utsname, gc);
724
725 if (uname(uts) != 0)
726 {
727 return "N/A";
728 }
729
730 return uts->version;
731}
732
733void
734dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
735{
736 struct ifdrv drv;
737 nvlist_t *nvl;
738 uint8_t buf[128];
739 int ret;
740
741 if (!dco || !dco->open)
742 {
743 return;
744 }
745
746 CLEAR(drv);
747 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
748 drv.ifd_cmd = OVPN_POLL_PKT;
749 drv.ifd_len = sizeof(buf);
750 drv.ifd_data = buf;
751
752 ret = ioctl(dco->fd, SIOCGDRVSPEC, &drv);
753 if (ret)
754 {
755 msg(M_WARN | M_ERRNO, "Failed to poll for packets");
756 return;
757 }
758
759 nvl = nvlist_unpack(buf, drv.ifd_len, 0);
760 if (!nvl)
761 {
762 msg(M_WARN, "Failed to unpack nvlist");
763 return;
764 }
765
766 if (nvlist_get_number(nvl, "pending") > 0)
767 {
768 (void)write(dco->pipefd[0], " ", 1);
769 event_ctl(es, dco->pipefd[1], EVENT_READ, arg);
770 }
771
772 nvlist_destroy(nvl);
773}
774
775static void
776dco_update_peer_stat(struct multi_context *m, uint32_t peerid, const nvlist_t *nvl)
777{
778 if (peerid >= m->max_clients || !m->instances[peerid])
779 {
780 msg(M_WARN, "dco_update_peer_stat: invalid peer ID %d returned by kernel", peerid);
781 return;
782 }
783
784 struct multi_instance *mi = m->instances[peerid];
785
786 mi->context.c2.dco_read_bytes = nvlist_get_number(nvl, "in");
787 mi->context.c2.dco_write_bytes = nvlist_get_number(nvl, "out");
788}
789
790int
791dco_get_peer_stats_multi(dco_context_t *dco, const bool raise_sigusr1_on_err)
792{
793 struct ifdrv drv;
794 uint8_t *buf = NULL;
795 size_t buf_size = 4096;
796 nvlist_t *nvl;
797 const nvlist_t *const *nvpeers;
798 size_t npeers;
799 int ret;
800
801 if (!dco || !dco->open)
802 {
803 return 0;
804 }
805
806 CLEAR(drv);
807 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
808 drv.ifd_cmd = OVPN_GET_PEER_STATS;
809
810retry:
811 buf = realloc(buf, buf_size);
812 drv.ifd_len = buf_size;
813 drv.ifd_data = buf;
814
815 ret = ioctl(dco->fd, SIOCGDRVSPEC, &drv);
816 if (ret && errno == ENOSPC)
817 {
818 buf_size *= 2;
819 goto retry;
820 }
821
822 if (ret)
823 {
824 free(buf);
825 msg(M_WARN | M_ERRNO, "Failed to get peer stats");
826 return -EINVAL;
827 }
828
829 nvl = nvlist_unpack(buf, drv.ifd_len, 0);
830 free(buf);
831 if (!nvl)
832 {
833 msg(M_WARN, "Failed to unpack nvlist");
834 return -EINVAL;
835 }
836
837 if (!nvlist_exists_nvlist_array(nvl, "peers"))
838 {
839 /* no peers */
840 nvlist_destroy(nvl);
841 return 0;
842 }
843
844 nvpeers = nvlist_get_nvlist_array(nvl, "peers", &npeers);
845 for (size_t i = 0; i < npeers; i++)
846 {
847 const nvlist_t *peer = nvpeers[i];
848 uint32_t peerid = nvlist_get_number(peer, "peerid");
849
850 dco_update_peer_stat(dco->c->multi, peerid, nvlist_get_nvlist(peer, "bytes"));
851 }
852
853 nvlist_destroy(nvl);
854 return 0;
855}
856
857int
858dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
859{
860 /* Not implemented. */
861 return 0;
862}
863
864const char *
866{
867 return "none:AES-256-GCM:AES-192-GCM:AES-128-GCM:CHACHA20-POLY1305";
868}
869
870#endif /* defined(ENABLE_DCO) && defined(TARGET_FREEBSD) */
#define ALLOC_OBJ_GC(dptr, type, gc)
Definition buffer.h:1074
Data Channel Cryptography Module.
int cipher_kt_key_size(const char *ciphername)
Returns the size of keys used by the cipher, in bytes.
static bool dco_available(int msglevel)
Definition dco.h:264
static int dco_get_peer_stats_multi(dco_context_t *dco, const bool raise_sigusr1_on_err)
Definition dco.h:371
static int dco_set_peer(dco_context_t *dco, unsigned int peerid, int keepalive_interval, int keepalive_timeout, int mss)
Definition dco.h:343
static const char * dco_get_supported_ciphers(void)
Definition dco.h:383
static int dco_do_read(dco_context_t *dco)
Definition dco.h:311
static void dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
Definition dco.h:318
static int open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
Definition dco.h:300
static bool ovpn_dco_init(struct context *c)
Definition dco.h:294
void * dco_context_t
Definition dco.h:261
static const char * dco_version_string(struct gc_arena *gc)
Definition dco.h:270
static void close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx)
Definition dco.h:306
static int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
Definition dco.h:377
int dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
Definition dco_win.c:568
int dco_del_peer(dco_context_t *dco, unsigned int peerid)
Definition dco_win.c:469
int dco_swap_keys(dco_context_t *dco, unsigned int peer_id)
Definition dco_win.c:576
int dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd, struct sockaddr *localaddr, struct sockaddr *remoteaddr, struct in_addr *vpn_ipv4, struct in6_addr *vpn_ipv6)
Definition dco_win.c:418
int dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid, dco_key_slot_t slot, const uint8_t *encrypt_key, const uint8_t *encrypt_iv, const uint8_t *decrypt_key, const uint8_t *decrypt_iv, const char *ciphername)
Definition dco_win.c:529
#define D_DCO_DEBUG
Definition errlevel.h:117
#define EVENT_READ
Definition event.h:38
static void event_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg)
Definition event.h:183
@ address
Definition interactive.c:84
@ write
@ read
Header file for server-mode related structures and functions.
void * openvpn_net_ctx_t
Definition networking.h:38
#define CLEAR(x)
Definition basic.h:32
#define M_ERR
Definition error.h:104
#define msg(flags,...)
Definition error.h:150
#define ASSERT(x)
Definition error.h:217
#define M_WARN
Definition error.h:90
#define M_ERRNO
Definition error.h:93
#define OVPN_SET_IFMODE
#define OVPN_SWAP_KEYS
#define OVPN_POLL_PKT
#define OVPN_DEL_PEER
@ OVPN_DEL_REASON_TIMEOUT
#define OVPN_GET_PKT
#define OVPN_GET_PEER_STATS
#define OVPN_START_VPN
#define OVPN_NEW_KEY
#define OVPN_NEW_PEER
ovpn_notif_type
@ OVPN_NOTIF_DEL_PEER
@ OVPN_NOTIF_ROTATE_KEY
@ OVPN_NOTIF_FLOAT
#define OVPN_SET_PEER
#define OVPN_DEL_KEY
@ OVPN_DEL_PEER_REASON_EXPIRED
@ OVPN_DEL_PEER_REASON_USERSPACE
@ OVPN_CMD_FLOAT_PEER
@ OVPN_CMD_SWAP_KEYS
@ OVPN_CMD_DEL_PEER
#define TOP_SUBNET
Definition proto.h:43
Control Channel Common Data Structures.
struct tuntap * tuntap
Tun/tap virtual network interface.
Definition openvpn.h:172
counter_type dco_read_bytes
Definition openvpn.h:267
counter_type dco_write_bytes
Definition openvpn.h:270
Contains all state information for one tunnel.
Definition openvpn.h:474
struct context_2 c2
Level 2 context.
Definition openvpn.h:517
struct context_1 c1
Level 1 context.
Definition openvpn.h:516
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:116
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
Main OpenVPN server state structure.
Definition multi.h:164
int max_clients
Definition multi.h:187
struct multi_instance ** instances
Array of multi_instances.
Definition multi.h:165
Server-mode state structure for one single VPN tunnel.
Definition multi.h:103
struct context context
The context structure storing state for this VPN tunnel.
Definition multi.h:144
Definition tun.h:183
int topology
Definition tun.h:188
dco_context_t dco
Definition tun.h:249
struct env_set * es
struct gc_arena gc
Definition test_ssl.c:154