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