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