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)
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", __func__, slot, keyid, peerid,
497 ciphername);
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
567int
569{
570 struct ifdrv drv;
571 uint8_t buf[4096];
572 nvlist_t *nvl;
573 enum ovpn_notif_type type;
574 int ret;
575
576 /* Flush any pending data from the pipe. */
577 (void)read(dco->pipefd[1], buf, sizeof(buf));
578
579 CLEAR(drv);
580 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
581 drv.ifd_cmd = OVPN_GET_PKT;
582 drv.ifd_data = buf;
583 drv.ifd_len = sizeof(buf);
584
585 ret = ioctl(dco->fd, SIOCGDRVSPEC, &drv);
586 if (ret)
587 {
588 msg(M_WARN | M_ERRNO, "Failed to read control packet");
589 return -errno;
590 }
591
592 nvl = nvlist_unpack(buf, drv.ifd_len, 0);
593 if (!nvl)
594 {
595 msg(M_WARN, "Failed to unpack nvlist");
596 return -EINVAL;
597 }
598
599 dco->dco_message_peer_id = nvlist_get_number(nvl, "peerid");
600
601 type = nvlist_get_number(nvl, "notification");
602 switch (type)
603 {
605 dco->dco_del_peer_reason = OVPN_DEL_PEER_REASON_EXPIRED;
606
607 if (nvlist_exists_number(nvl, "del_reason"))
608 {
609 uint32_t reason = nvlist_get_number(nvl, "del_reason");
610 if (reason == OVPN_DEL_REASON_TIMEOUT)
611 {
612 dco->dco_del_peer_reason = OVPN_DEL_PEER_REASON_EXPIRED;
613 }
614 else
615 {
616 dco->dco_del_peer_reason = OVPN_DEL_PEER_REASON_USERSPACE;
617 }
618 }
619
620 if (nvlist_exists_nvlist(nvl, "bytes"))
621 {
622 const nvlist_t *bytes = nvlist_get_nvlist(nvl, "bytes");
623
624 dco->dco_read_bytes = nvlist_get_number(bytes, "in");
625 dco->dco_write_bytes = nvlist_get_number(bytes, "out");
626 }
627
628 dco->dco_message_type = OVPN_CMD_DEL_PEER;
629 break;
630
632 dco->dco_message_type = OVPN_CMD_SWAP_KEYS;
633 break;
634
635 case OVPN_NOTIF_FLOAT:
636 {
637 const nvlist_t *address;
638
639 if (!nvlist_exists_nvlist(nvl, "address"))
640 {
641 msg(M_WARN, "Float notification without address");
642 break;
643 }
644
645 address = nvlist_get_nvlist(nvl, "address");
646 if (!nvlist_to_sockaddr(address, &dco->dco_float_peer_ss))
647 {
648 msg(M_WARN, "Failed to parse float notification");
649 break;
650 }
651 dco->dco_message_type = OVPN_CMD_FLOAT_PEER;
652 break;
653 }
654
655 default:
656 msg(M_WARN, "Unknown kernel notification %d", type);
657 break;
658 }
659
660 nvlist_destroy(nvl);
661
662 return 0;
663}
664
665bool
666dco_available(msglvl_t msglevel)
667{
668 struct if_clonereq ifcr;
669 char *buf = NULL;
670 int fd;
671 int ret;
672 bool available = false;
673
674 /* Attempt to load the module. Ignore errors, because it might already be
675 * loaded, or built into the kernel. */
676 (void)kldload("if_ovpn");
677
678 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
679 if (fd < 0)
680 {
681 return false;
682 }
683
684 CLEAR(ifcr);
685
686 /* List cloners and check if openvpn is there. That tells us if this kernel
687 * supports if_ovpn (i.e. DCO) or not. */
688 ret = ioctl(fd, SIOCIFGCLONERS, &ifcr);
689 if (ret != 0)
690 {
691 goto out;
692 }
693
694 buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
695 if (!buf)
696 {
697 goto out;
698 }
699
700 ifcr.ifcr_count = ifcr.ifcr_total;
701 ifcr.ifcr_buffer = buf;
702 ret = ioctl(fd, SIOCIFGCLONERS, &ifcr);
703 if (ret != 0)
704 {
705 goto out;
706 }
707
708 for (int i = 0; i < ifcr.ifcr_total; i++)
709 {
710 if (strcmp(buf + (i * IFNAMSIZ), "openvpn") == 0)
711 {
712 available = true;
713 goto out;
714 }
715 }
716
717out:
718 free(buf);
719 close(fd);
720
721 return available;
722}
723
724const char *
726{
727 struct utsname *uts;
728 ALLOC_OBJ_GC(uts, struct utsname, gc);
729
730 if (uname(uts) != 0)
731 {
732 return "N/A";
733 }
734
735 return uts->version;
736}
737
738void
739dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
740{
741 struct ifdrv drv;
742 nvlist_t *nvl;
743 uint8_t buf[128];
744 int ret;
745
746 if (!dco || !dco->open)
747 {
748 return;
749 }
750
751 CLEAR(drv);
752 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
753 drv.ifd_cmd = OVPN_POLL_PKT;
754 drv.ifd_len = sizeof(buf);
755 drv.ifd_data = buf;
756
757 ret = ioctl(dco->fd, SIOCGDRVSPEC, &drv);
758 if (ret)
759 {
760 msg(M_WARN | M_ERRNO, "Failed to poll for packets");
761 return;
762 }
763
764 nvl = nvlist_unpack(buf, drv.ifd_len, 0);
765 if (!nvl)
766 {
767 msg(M_WARN, "Failed to unpack nvlist");
768 return;
769 }
770
771 if (nvlist_get_number(nvl, "pending") > 0)
772 {
773 (void)write(dco->pipefd[0], " ", 1);
774 event_ctl(es, dco->pipefd[1], EVENT_READ, arg);
775 }
776
777 nvlist_destroy(nvl);
778}
779
780static void
781dco_update_peer_stat(struct multi_context *m, uint32_t peerid, const nvlist_t *nvl)
782{
783 if (peerid >= m->max_clients || !m->instances[peerid])
784 {
785 msg(M_WARN, "dco_update_peer_stat: invalid peer ID %d returned by kernel", peerid);
786 return;
787 }
788
789 struct multi_instance *mi = m->instances[peerid];
790
791 mi->context.c2.dco_read_bytes = nvlist_get_number(nvl, "in");
792 mi->context.c2.dco_write_bytes = nvlist_get_number(nvl, "out");
793}
794
795int
796dco_get_peer_stats_multi(dco_context_t *dco, const bool raise_sigusr1_on_err)
797{
798 struct ifdrv drv;
799 uint8_t *buf = NULL;
800 size_t buf_size = 4096;
801 nvlist_t *nvl;
802 const nvlist_t *const *nvpeers;
803 size_t npeers;
804 int ret;
805
806 if (!dco || !dco->open)
807 {
808 return 0;
809 }
810
811 CLEAR(drv);
812 snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
813 drv.ifd_cmd = OVPN_GET_PEER_STATS;
814
815retry:
816 buf = realloc(buf, buf_size);
817 drv.ifd_len = buf_size;
818 drv.ifd_data = buf;
819
820 ret = ioctl(dco->fd, SIOCGDRVSPEC, &drv);
821 if (ret && errno == ENOSPC)
822 {
823 buf_size *= 2;
824 goto retry;
825 }
826
827 if (ret)
828 {
829 free(buf);
830 msg(M_WARN | M_ERRNO, "Failed to get peer stats");
831 return -EINVAL;
832 }
833
834 nvl = nvlist_unpack(buf, drv.ifd_len, 0);
835 free(buf);
836 if (!nvl)
837 {
838 msg(M_WARN, "Failed to unpack nvlist");
839 return -EINVAL;
840 }
841
842 if (!nvlist_exists_nvlist_array(nvl, "peers"))
843 {
844 /* no peers */
845 nvlist_destroy(nvl);
846 return 0;
847 }
848
849 nvpeers = nvlist_get_nvlist_array(nvl, "peers", &npeers);
850 for (size_t i = 0; i < npeers; i++)
851 {
852 const nvlist_t *peer = nvpeers[i];
853 uint32_t peerid = nvlist_get_number(peer, "peerid");
854
855 dco_update_peer_stat(dco->c->multi, peerid, nvlist_get_nvlist(peer, "bytes"));
856 }
857
858 nvlist_destroy(nvl);
859 return 0;
860}
861
862#if defined(__GNUC__) || defined(__clang__)
863#pragma GCC diagnostic pop
864#endif
865
866int
867dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
868{
869 /* Not implemented. */
870 return 0;
871}
872
873const char *
875{
876 return "none:AES-256-GCM:AES-192-GCM:AES-128-GCM:CHACHA20-POLY1305";
877}
878
879#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 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 dco_available(msglvl_t msglevel)
Definition dco.h:264
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:578
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:586
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:534
#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: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: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:131