OpenVPN
dco_linux.c
Go to the documentation of this file.
1/*
2 * Interface to linux dco networking code
3 *
4 * Copyright (C) 2020-2024 Antonio Quartulli <a@unstable.cc>
5 * Copyright (C) 2020-2024 Arne Schwabe <arne@rfc2549.org>
6 * Copyright (C) 2020-2024 OpenVPN Inc <sales@openvpn.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program (see the file COPYING included with this
19 * distribution); if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#if defined(ENABLE_DCO) && defined(TARGET_LINUX)
29
30#include "syshead.h"
31
32#include "dco_linux.h"
33#include "errlevel.h"
34#include "buffer.h"
35#include "networking.h"
36#include "openvpn.h"
37
38#include "socket.h"
39#include "tun.h"
40#include "ssl.h"
41#include "fdmisc.h"
42#include "multi.h"
43#include "ssl_verify.h"
44
45#include "ovpn_dco_linux.h"
46
47#include <netlink/socket.h>
48#include <netlink/netlink.h>
49#include <netlink/genl/genl.h>
50#include <netlink/genl/family.h>
51#include <netlink/genl/ctrl.h>
52
53
54/* libnl < 3.5.0 does not set the NLA_F_NESTED on its own, therefore we
55 * have to explicitly do it to prevent the kernel from failing upon
56 * parsing of the message
57 */
58#define nla_nest_start(_msg, _type) \
59 nla_nest_start(_msg, (_type) | NLA_F_NESTED)
60
61static int ovpn_get_mcast_id(dco_context_t *dco);
62
63void dco_check_key_ctx(const struct key_ctx_bi *key);
64
65typedef int (*ovpn_nl_cb)(struct nl_msg *msg, void *arg);
66
78static int
79resolve_ovpn_netlink_id(int msglevel)
80{
81 int ret;
82 struct nl_sock *nl_sock = nl_socket_alloc();
83
84 if (!nl_sock)
85 {
86 msg(msglevel, "Allocating net link socket failed");
87 return -ENOMEM;
88 }
89
90 ret = genl_connect(nl_sock);
91 if (ret)
92 {
93 msg(msglevel, "Cannot connect to generic netlink: %s",
94 nl_geterror(ret));
95 goto err_sock;
96 }
97 set_cloexec(nl_socket_get_fd(nl_sock));
98
99 ret = genl_ctrl_resolve(nl_sock, OVPN_NL_NAME);
100 if (ret < 0)
101 {
102 msg(msglevel, "Cannot find ovpn_dco netlink component: %s",
103 nl_geterror(ret));
104 }
105
106err_sock:
107 nl_socket_free(nl_sock);
108 return ret;
109}
110
111static struct nl_msg *
112ovpn_dco_nlmsg_create(dco_context_t *dco, enum ovpn_nl_commands cmd)
113{
114 struct nl_msg *nl_msg = nlmsg_alloc();
115 if (!nl_msg)
116 {
117 msg(M_ERR, "cannot allocate netlink message");
118 return NULL;
119 }
120
121 genlmsg_put(nl_msg, 0, 0, dco->ovpn_dco_id, 0, 0, cmd, 0);
122 NLA_PUT_U32(nl_msg, OVPN_ATTR_IFINDEX, dco->ifindex);
123
124 return nl_msg;
125nla_put_failure:
126 nlmsg_free(nl_msg);
127 msg(M_INFO, "cannot put into netlink message");
128 return NULL;
129}
130
131static int
132ovpn_nl_recvmsgs(dco_context_t *dco, const char *prefix)
133{
134 int ret = nl_recvmsgs(dco->nl_sock, dco->nl_cb);
135
136 switch (ret)
137 {
138 case -NLE_INTR:
139 msg(M_WARN, "%s: netlink received interrupt due to signal - ignoring", prefix);
140 break;
141
142 case -NLE_NOMEM:
143 msg(M_ERR, "%s: netlink out of memory error", prefix);
144 break;
145
146 case -M_ERR:
147 msg(M_WARN, "%s: netlink reports blocking read - aborting wait", prefix);
148 break;
149
150 case -NLE_NODEV:
151 msg(M_ERR, "%s: netlink reports device not found:", prefix);
152 break;
153
154 case -NLE_OBJ_NOTFOUND:
155 msg(M_INFO, "%s: netlink reports object not found, ovpn-dco unloaded?", prefix);
156 break;
157
158 default:
159 if (ret)
160 {
161 msg(M_NONFATAL, "%s: netlink reports error (%d): %s", prefix, ret, nl_geterror(-ret));
162 }
163 break;
164 }
165
166 return ret;
167}
168
180static int
181ovpn_nl_msg_send(dco_context_t *dco, struct nl_msg *nl_msg, ovpn_nl_cb cb,
182 void *cb_arg, const char *prefix)
183{
184 dco->status = 1;
185
186 nl_cb_set(dco->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, cb, cb_arg);
187 nl_send_auto(dco->nl_sock, nl_msg);
188
189 while (dco->status == 1)
190 {
191 ovpn_nl_recvmsgs(dco, prefix);
192 }
193
194 if (dco->status < 0)
195 {
196 msg(M_INFO, "%s: failed to send netlink message: %s (%d)",
197 prefix, strerror(-dco->status), dco->status);
198 }
199
200 return dco->status;
201}
202
203struct sockaddr *
204mapped_v4_to_v6(struct sockaddr *sock, struct gc_arena *gc)
205{
206 struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)sock;
207 if (sock->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sock6->sin6_addr))
208 {
209
210 struct sockaddr_in *sock4;
211 ALLOC_OBJ_CLEAR_GC(sock4, struct sockaddr_in, gc);
212 memcpy(&sock4->sin_addr, sock6->sin6_addr.s6_addr + 12, 4);
213 sock4->sin_port = sock6->sin6_port;
214 sock4->sin_family = AF_INET;
215 return (struct sockaddr *)sock4;
216 }
217 return sock;
218}
219
220int
221dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd,
222 struct sockaddr *localaddr, struct sockaddr *remoteaddr,
223 struct in_addr *vpn_ipv4, struct in6_addr *vpn_ipv6)
224{
225 struct gc_arena gc = gc_new();
226 const char *remotestr = "[undefined]";
227 if (remoteaddr)
228 {
229 remotestr = print_sockaddr(remoteaddr, &gc);
230 }
231 msg(D_DCO_DEBUG, "%s: peer-id %d, fd %d, remote addr: %s", __func__,
232 peerid, sd, remotestr);
233
234 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_NEW_PEER);
235 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_NEW_PEER);
236 int ret = -EMSGSIZE;
237
238 NLA_PUT_U32(nl_msg, OVPN_NEW_PEER_ATTR_PEER_ID, peerid);
239 NLA_PUT_U32(nl_msg, OVPN_NEW_PEER_ATTR_SOCKET, sd);
240
241 /* Set the remote endpoint if defined (for UDP) */
242 if (remoteaddr)
243 {
244 remoteaddr = mapped_v4_to_v6(remoteaddr, &gc);
245 int alen = af_addr_size(remoteaddr->sa_family);
246
247 NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_SOCKADDR_REMOTE, alen, remoteaddr);
248 }
249
250 if (localaddr)
251 {
252 localaddr = mapped_v4_to_v6(localaddr, &gc);
253 if (localaddr->sa_family == AF_INET)
254 {
255 NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_LOCAL_IP, sizeof(struct in_addr),
256 &((struct sockaddr_in *)localaddr)->sin_addr);
257 }
258 else if (localaddr->sa_family == AF_INET6)
259 {
260 NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_LOCAL_IP, sizeof(struct in6_addr),
261 &((struct sockaddr_in6 *)localaddr)->sin6_addr);
262 }
263 }
264
265 /* Set the primary VPN IP addresses of the peer */
266 if (vpn_ipv4)
267 {
268 NLA_PUT_U32(nl_msg, OVPN_NEW_PEER_ATTR_IPV4, vpn_ipv4->s_addr);
269 }
270 if (vpn_ipv6)
271 {
272 NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_IPV6, sizeof(struct in6_addr),
273 vpn_ipv6);
274 }
275 nla_nest_end(nl_msg, attr);
276
277 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
278
279nla_put_failure:
280 nlmsg_free(nl_msg);
281 gc_free(&gc);
282 return ret;
283}
284
285static int
286ovpn_nl_cb_finish(struct nl_msg (*msg) __attribute__ ((unused)), void *arg)
287{
288 int *status = arg;
289
290 *status = 0;
291 return NL_SKIP;
292}
293
294/* The following enum members exist in netlink.h since linux-6.1.
295 * However, some distro we support still ship an old header, thus
296 * failing the OpenVPN compilation.
297 *
298 * For the time being we add the needed defines manually.
299 * We will drop this definition once we stop supporting those old
300 * distros.
301 *
302 * @NLMSGERR_ATTR_MISS_TYPE: type of a missing required attribute,
303 * %NLMSGERR_ATTR_MISS_NEST will not be present if the attribute was
304 * missing at the message level
305 * @NLMSGERR_ATTR_MISS_NEST: offset of the nest where attribute was missing
306 */
307enum ovpn_nlmsgerr_attrs {
308 OVPN_NLMSGERR_ATTR_MISS_TYPE = 5,
309 OVPN_NLMSGERR_ATTR_MISS_NEST = 6,
310 OVPN_NLMSGERR_ATTR_MAX = 6,
311};
312
313/* This function is used as error callback on the netlink socket.
314 * When something goes wrong and the kernel returns an error, this function is
315 * invoked.
316 *
317 * We pass the error code to the user by means of a variable pointed by *arg
318 * (supplied by the user when setting this callback) and we parse the kernel
319 * reply to see if it contains a human-readable error. If found, it is printed.
320 */
321static int
322ovpn_nl_cb_error(struct sockaddr_nl (*nla) __attribute__ ((unused)),
323 struct nlmsgerr *err, void *arg)
324{
325 struct nlmsghdr *nlh = (struct nlmsghdr *)err - 1;
326 struct nlattr *tb_msg[OVPN_NLMSGERR_ATTR_MAX + 1];
327 int len = nlh->nlmsg_len;
328 struct nlattr *attrs;
329 int *ret = arg;
330 int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
331
332 *ret = err->error;
333
334 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
335 {
336 return NL_STOP;
337 }
338
339 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
340 {
341 ack_len += err->msg.nlmsg_len - sizeof(*nlh);
342 }
343
344 if (len <= ack_len)
345 {
346 return NL_STOP;
347 }
348
349 attrs = (void *)((unsigned char *)nlh + ack_len);
350 len -= ack_len;
351
352 nla_parse(tb_msg, OVPN_NLMSGERR_ATTR_MAX, attrs, len, NULL);
353 if (tb_msg[NLMSGERR_ATTR_MSG])
354 {
355 len = strnlen((char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG]),
356 nla_len(tb_msg[NLMSGERR_ATTR_MSG]));
357 msg(M_WARN, "kernel error: %*s\n", len,
358 (char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG]));
359 }
360
361 if (tb_msg[OVPN_NLMSGERR_ATTR_MISS_NEST])
362 {
363 msg(M_WARN, "kernel error: missing required nesting type %u\n",
364 nla_get_u32(tb_msg[OVPN_NLMSGERR_ATTR_MISS_NEST]));
365 }
366
367 if (tb_msg[OVPN_NLMSGERR_ATTR_MISS_TYPE])
368 {
369 msg(M_WARN, "kernel error: missing required attribute type %u\n",
370 nla_get_u32(tb_msg[OVPN_NLMSGERR_ATTR_MISS_TYPE]));
371 }
372
373 return NL_STOP;
374}
375
376static void
377ovpn_dco_init_netlink(dco_context_t *dco)
378{
379 dco->ovpn_dco_id = resolve_ovpn_netlink_id(M_ERR);
380
381 dco->nl_sock = nl_socket_alloc();
382
383 if (!dco->nl_sock)
384 {
385 msg(M_ERR, "Cannot create netlink socket");
386 }
387
388 int ret = genl_connect(dco->nl_sock);
389 if (ret)
390 {
391 msg(M_ERR, "Cannot connect to generic netlink: %s",
392 nl_geterror(ret));
393 }
394
395 /* set close on exec and non-block on the netlink socket */
396 set_cloexec(nl_socket_get_fd(dco->nl_sock));
397 set_nonblock(nl_socket_get_fd(dco->nl_sock));
398
399 dco->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
400 if (!dco->nl_cb)
401 {
402 msg(M_ERR, "failed to allocate netlink callback");
403 }
404
405 nl_socket_set_cb(dco->nl_sock, dco->nl_cb);
406
407 nl_cb_err(dco->nl_cb, NL_CB_CUSTOM, ovpn_nl_cb_error, &dco->status);
408 nl_cb_set(dco->nl_cb, NL_CB_FINISH, NL_CB_CUSTOM, ovpn_nl_cb_finish,
409 &dco->status);
410 nl_cb_set(dco->nl_cb, NL_CB_ACK, NL_CB_CUSTOM, ovpn_nl_cb_finish,
411 &dco->status);
412
413 /* The async PACKET messages confuse libnl and it will drop them with
414 * wrong sequence numbers (NLE_SEQ_MISMATCH), so disable libnl's sequence
415 * number check */
416 nl_socket_disable_seq_check(dco->nl_sock);
417
418 /* nl library sets the buffer size to 32k/32k by default which is sometimes
419 * overrun with very fast connecting/disconnecting clients.
420 * TODO: fix this in a better and more reliable way */
421 ASSERT(!nl_socket_set_buffer_size(dco->nl_sock, 1024*1024, 1024*1024));
422}
423
424bool
425ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node)
426{
427 switch (mode)
428 {
429 case CM_TOP:
430 dco->ifmode = OVPN_MODE_MP;
431 break;
432
433 case CM_P2P:
434 dco->ifmode = OVPN_MODE_P2P;
435 break;
436
437 default:
438 ASSERT(false);
439 }
440
441 ovpn_dco_init_netlink(dco);
442 return true;
443}
444
445static void
446ovpn_dco_uninit_netlink(dco_context_t *dco)
447{
448 nl_socket_free(dco->nl_sock);
449 dco->nl_sock = NULL;
450
451 /* Decrease reference count */
452 nl_cb_put(dco->nl_cb);
453
454 CLEAR(dco);
455}
456
457static void
458ovpn_dco_register(dco_context_t *dco)
459{
460 msg(D_DCO_DEBUG, __func__);
461 ovpn_get_mcast_id(dco);
462
463 if (dco->ovpn_dco_mcast_id < 0)
464 {
465 msg(M_ERR, "cannot get mcast group: %s", nl_geterror(dco->ovpn_dco_mcast_id));
466 }
467
468 /* Register for ovpn-dco specific multicast messages that the kernel may
469 * send
470 */
471 int ret = nl_socket_add_membership(dco->nl_sock, dco->ovpn_dco_mcast_id);
472 if (ret)
473 {
474 msg(M_ERR, "%s: failed to join groups: %d", __func__, ret);
475 }
476}
477
478int
479open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
480{
481 msg(D_DCO_DEBUG, "%s: %s", __func__, dev);
482 ASSERT(tt->type == DEV_TYPE_TUN);
483
484 int ret = net_iface_new(ctx, dev, "ovpn-dco", &tt->dco);
485 if (ret < 0)
486 {
487 msg(D_DCO_DEBUG, "Cannot create DCO interface %s: %d", dev, ret);
488 return ret;
489 }
490
491 tt->dco.ifindex = if_nametoindex(dev);
492 if (!tt->dco.ifindex)
493 {
494 msg(M_FATAL, "DCO: cannot retrieve ifindex for interface %s", dev);
495 }
496
497 tt->dco.dco_message_peer_id = -1;
498
499 ovpn_dco_register(&tt->dco);
500
501 return 0;
502}
503
504void
505close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx)
506{
507 msg(D_DCO_DEBUG, __func__);
508
509 net_iface_del(ctx, tt->actual_name);
510 ovpn_dco_uninit_netlink(&tt->dco);
511}
512
513int
514dco_swap_keys(dco_context_t *dco, unsigned int peerid)
515{
516 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
517
518 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_SWAP_KEYS);
519 if (!nl_msg)
520 {
521 return -ENOMEM;
522 }
523
524 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_SWAP_KEYS);
525 int ret = -EMSGSIZE;
526 NLA_PUT_U32(nl_msg, OVPN_SWAP_KEYS_ATTR_PEER_ID, peerid);
527 nla_nest_end(nl_msg, attr);
528
529 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
530
531nla_put_failure:
532 nlmsg_free(nl_msg);
533 return ret;
534}
535
536
537int
538dco_del_peer(dco_context_t *dco, unsigned int peerid)
539{
540 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
541
542 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_DEL_PEER);
543 if (!nl_msg)
544 {
545 return -ENOMEM;
546 }
547
548 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_DEL_PEER);
549 int ret = -EMSGSIZE;
550 NLA_PUT_U32(nl_msg, OVPN_DEL_PEER_ATTR_PEER_ID, peerid);
551 nla_nest_end(nl_msg, attr);
552
553 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
554
555nla_put_failure:
556 nlmsg_free(nl_msg);
557 return ret;
558}
559
560
561int
562dco_del_key(dco_context_t *dco, unsigned int peerid,
563 dco_key_slot_t slot)
564{
565 msg(D_DCO_DEBUG, "%s: peer-id %d, slot %d", __func__, peerid, slot);
566
567 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_DEL_KEY);
568 if (!nl_msg)
569 {
570 return -ENOMEM;
571 }
572
573 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_DEL_KEY);
574 int ret = -EMSGSIZE;
575 NLA_PUT_U32(nl_msg, OVPN_DEL_KEY_ATTR_PEER_ID, peerid);
576 NLA_PUT_U8(nl_msg, OVPN_DEL_KEY_ATTR_KEY_SLOT, slot);
577 nla_nest_end(nl_msg, attr);
578
579 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
580
581nla_put_failure:
582 nlmsg_free(nl_msg);
583 return ret;
584}
585
586int
587dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid,
588 dco_key_slot_t slot,
589 const uint8_t *encrypt_key, const uint8_t *encrypt_iv,
590 const uint8_t *decrypt_key, const uint8_t *decrypt_iv,
591 const char *ciphername)
592{
593 msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s",
594 __func__, slot, keyid, peerid, ciphername);
595
596 const size_t key_len = cipher_kt_key_size(ciphername);
597 const int nonce_tail_len = 8;
598
599 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_NEW_KEY);
600 if (!nl_msg)
601 {
602 return -ENOMEM;
603 }
604
605 dco_cipher_t dco_cipher = dco_get_cipher(ciphername);
606
607 int ret = -EMSGSIZE;
608 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_NEW_KEY);
609 NLA_PUT_U32(nl_msg, OVPN_NEW_KEY_ATTR_PEER_ID, peerid);
610 NLA_PUT_U8(nl_msg, OVPN_NEW_KEY_ATTR_KEY_SLOT, slot);
611 NLA_PUT_U8(nl_msg, OVPN_NEW_KEY_ATTR_KEY_ID, keyid);
612 NLA_PUT_U16(nl_msg, OVPN_NEW_KEY_ATTR_CIPHER_ALG, dco_cipher);
613
614 struct nlattr *key_enc = nla_nest_start(nl_msg,
616 if (dco_cipher != OVPN_CIPHER_ALG_NONE)
617 {
618 NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_CIPHER_KEY, key_len, encrypt_key);
619 NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_NONCE_TAIL, nonce_tail_len,
620 encrypt_iv);
621 }
622 nla_nest_end(nl_msg, key_enc);
623
624 struct nlattr *key_dec = nla_nest_start(nl_msg,
626 if (dco_cipher != OVPN_CIPHER_ALG_NONE)
627 {
628 NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_CIPHER_KEY, key_len, decrypt_key);
629 NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_NONCE_TAIL, nonce_tail_len,
630 decrypt_iv);
631 }
632 nla_nest_end(nl_msg, key_dec);
633
634 nla_nest_end(nl_msg, attr);
635
636 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
637
638nla_put_failure:
639 nlmsg_free(nl_msg);
640 return ret;
641}
642
643int
644dco_set_peer(dco_context_t *dco, unsigned int peerid,
645 int keepalive_interval, int keepalive_timeout, int mss)
646{
647 msg(D_DCO_DEBUG, "%s: peer-id %d, keepalive %d/%d, mss %d", __func__,
648 peerid, keepalive_interval, keepalive_timeout, mss);
649
650 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_SET_PEER);
651 if (!nl_msg)
652 {
653 return -ENOMEM;
654 }
655
656 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_SET_PEER);
657 int ret = -EMSGSIZE;
658 NLA_PUT_U32(nl_msg, OVPN_SET_PEER_ATTR_PEER_ID, peerid);
659 NLA_PUT_U32(nl_msg, OVPN_SET_PEER_ATTR_KEEPALIVE_INTERVAL,
660 keepalive_interval);
661 NLA_PUT_U32(nl_msg, OVPN_SET_PEER_ATTR_KEEPALIVE_TIMEOUT,
662 keepalive_timeout);
663 nla_nest_end(nl_msg, attr);
664
665 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
666
667nla_put_failure:
668 nlmsg_free(nl_msg);
669 return ret;
670}
671
672/* This function parses the reply provided by the kernel to the CTRL_CMD_GETFAMILY
673 * message. We parse the reply and we retrieve the multicast group ID associated
674 * with the "ovpn-dco" netlink family.
675 *
676 * The ID is later used to subscribe to the multicast group and be notified
677 * about any multicast message sent by the ovpn-dco kernel module.
678 */
679static int
680mcast_family_handler(struct nl_msg *msg, void *arg)
681{
682 dco_context_t *dco = arg;
683 struct nlattr *tb[CTRL_ATTR_MAX + 1];
684 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
685
686 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
687 genlmsg_attrlen(gnlh, 0), NULL);
688
689 if (!tb[CTRL_ATTR_MCAST_GROUPS])
690 {
691 return NL_SKIP;
692 }
693
694 struct nlattr *mcgrp;
695 int rem_mcgrp;
696 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp)
697 {
698 struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
699
700 nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
701 nla_data(mcgrp), nla_len(mcgrp), NULL);
702
703 if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]
704 || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
705 {
706 continue;
707 }
708
709 if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
711 nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
712 {
713 continue;
714 }
715 dco->ovpn_dco_mcast_id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
716 break;
717 }
718
719 return NL_SKIP;
720}
726static int
727ovpn_get_mcast_id(dco_context_t *dco)
728{
729 dco->ovpn_dco_mcast_id = -ENOENT;
730
731 /* Even though 'nlctrl' is a constant, there seem to be no library
732 * provided define for it */
733 int ctrlid = genl_ctrl_resolve(dco->nl_sock, "nlctrl");
734
735 struct nl_msg *nl_msg = nlmsg_alloc();
736 if (!nl_msg)
737 {
738 return -ENOMEM;
739 }
740
741 genlmsg_put(nl_msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
742
743 int ret = -EMSGSIZE;
744 NLA_PUT_STRING(nl_msg, CTRL_ATTR_FAMILY_NAME, OVPN_NL_NAME);
745
746 ret = ovpn_nl_msg_send(dco, nl_msg, mcast_family_handler, dco, __func__);
747
748nla_put_failure:
749 nlmsg_free(nl_msg);
750 return ret;
751}
752
753/* This function parses any netlink message sent by ovpn-dco to userspace */
754static int
755ovpn_handle_msg(struct nl_msg *msg, void *arg)
756{
757 dco_context_t *dco = arg;
758
759 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
760 struct nlattr *attrs[OVPN_ATTR_MAX + 1];
761 struct nlmsghdr *nlh = nlmsg_hdr(msg);
762
763 if (!genlmsg_valid_hdr(nlh, 0))
764 {
765 msg(D_DCO, "ovpn-dco: invalid header");
766 return NL_SKIP;
767 }
768
769 if (nla_parse(attrs, OVPN_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
770 genlmsg_attrlen(gnlh, 0), NULL))
771 {
772 msg(D_DCO, "received bogus data from ovpn-dco");
773 return NL_SKIP;
774 }
775
776 /* we must know which interface this message is referring to in order to
777 * avoid mixing messages for other instances
778 */
779 if (!attrs[OVPN_ATTR_IFINDEX])
780 {
781 msg(D_DCO, "ovpn-dco: Received message without ifindex");
782 return NL_SKIP;
783 }
784
785 uint32_t ifindex = nla_get_u32(attrs[OVPN_ATTR_IFINDEX]);
786 if (ifindex != dco->ifindex)
787 {
789 "ovpn-dco: ignoring message (type=%d) for foreign ifindex %d",
790 gnlh->cmd, ifindex);
791 return NL_SKIP;
792 }
793
794 /* based on the message type, we parse the subobject contained in the
795 * message, that stores the type-specific attributes.
796 *
797 * the "dco" object is then filled accordingly with the information
798 * retrieved from the message, so that the rest of the OpenVPN code can
799 * react as need be.
800 */
801 switch (gnlh->cmd)
802 {
804 {
805 if (!attrs[OVPN_ATTR_DEL_PEER])
806 {
807 msg(D_DCO, "ovpn-dco: no attributes in OVPN_DEL_PEER message");
808 return NL_SKIP;
809 }
810
811 struct nlattr *dp_attrs[OVPN_DEL_PEER_ATTR_MAX + 1];
812 if (nla_parse_nested(dp_attrs, OVPN_DEL_PEER_ATTR_MAX,
813 attrs[OVPN_ATTR_DEL_PEER], NULL))
814 {
815 msg(D_DCO, "received bogus del peer packet data from ovpn-dco");
816 return NL_SKIP;
817 }
818
819 if (!dp_attrs[OVPN_DEL_PEER_ATTR_REASON])
820 {
821 msg(D_DCO, "ovpn-dco: no reason in DEL_PEER message");
822 return NL_SKIP;
823 }
824 if (!dp_attrs[OVPN_DEL_PEER_ATTR_PEER_ID])
825 {
826 msg(D_DCO, "ovpn-dco: no peer-id in DEL_PEER message");
827 return NL_SKIP;
828 }
829 int reason = nla_get_u8(dp_attrs[OVPN_DEL_PEER_ATTR_REASON]);
830 unsigned int peerid = nla_get_u32(dp_attrs[OVPN_DEL_PEER_ATTR_PEER_ID]);
831
832 msg(D_DCO_DEBUG, "ovpn-dco: received CMD_DEL_PEER, ifindex: %d, peer-id %d, reason: %d",
833 ifindex, peerid, reason);
834 dco->dco_message_peer_id = peerid;
835 dco->dco_del_peer_reason = reason;
836 dco->dco_message_type = OVPN_CMD_DEL_PEER;
837
838 break;
839 }
840
841 default:
842 msg(D_DCO, "ovpn-dco: received unknown command: %d", gnlh->cmd);
843 dco->dco_message_type = 0;
844 return NL_SKIP;
845 }
846
847 return NL_OK;
848}
849
850int
852{
853 msg(D_DCO_DEBUG, __func__);
854 nl_cb_set(dco->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ovpn_handle_msg, dco);
855
856 return ovpn_nl_recvmsgs(dco, __func__);
857}
858
859static void
860dco_update_peer_stat(struct context_2 *c2, struct nlattr *tb[], uint32_t id)
861{
863 {
865 msg(D_DCO_DEBUG, "%s / dco_read_bytes: " counter_format, __func__,
866 c2->dco_read_bytes);
867 }
868 else
869 {
870 msg(M_WARN, "%s: no link RX bytes provided in reply for peer %u",
871 __func__, id);
872 }
873
875 {
877 msg(D_DCO_DEBUG, "%s / dco_write_bytes: " counter_format, __func__,
878 c2->dco_write_bytes);
879 }
880 else
881 {
882 msg(M_WARN, "%s: no link TX bytes provided in reply for peer %u",
883 __func__, id);
884 }
885
887 {
889 msg(D_DCO_DEBUG, "%s / tun_read_bytes: " counter_format, __func__,
890 c2->tun_read_bytes);
891 }
892 else
893 {
894 msg(M_WARN, "%s: no VPN RX bytes provided in reply for peer %u",
895 __func__, id);
896 }
897
899 {
901 msg(D_DCO_DEBUG, "%s / tun_write_bytes: " counter_format, __func__,
902 c2->tun_write_bytes);
903 }
904 else
905 {
906 msg(M_WARN, "%s: no VPN TX bytes provided in reply for peer %u",
907 __func__, id);
908 }
909}
910
911int
912dco_parse_peer_multi(struct nl_msg *msg, void *arg)
913{
914 struct nlattr *tb[OVPN_ATTR_MAX + 1];
915 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
916
917 msg(D_DCO_DEBUG, "%s: parsing message...", __func__);
918
919 nla_parse(tb, OVPN_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
920 genlmsg_attrlen(gnlh, 0), NULL);
921
922 if (!tb[OVPN_ATTR_GET_PEER])
923 {
924 return NL_SKIP;
925 }
926
927 struct nlattr *tb_peer[OVPN_GET_PEER_RESP_ATTR_MAX + 1];
928
929 nla_parse(tb_peer, OVPN_GET_PEER_RESP_ATTR_MAX,
930 nla_data(tb[OVPN_ATTR_GET_PEER]),
931 nla_len(tb[OVPN_ATTR_GET_PEER]), NULL);
932
934 {
935 msg(M_WARN, "%s: no peer-id provided in reply", __func__);
936 return NL_SKIP;
937 }
938
939 struct multi_context *m = arg;
940 uint32_t peer_id = nla_get_u32(tb_peer[OVPN_GET_PEER_RESP_ATTR_PEER_ID]);
941
942 if (peer_id >= m->max_clients || !m->instances[peer_id])
943 {
944 msg(M_WARN, "%s: cannot store DCO stats for peer %u", __func__,
945 peer_id);
946 return NL_SKIP;
947 }
948
949 dco_update_peer_stat(&m->instances[peer_id]->context.c2, tb_peer, peer_id);
950
951 return NL_OK;
952}
953
954int
956 const bool raise_sigusr1_on_err)
957{
958 msg(D_DCO_DEBUG, "%s", __func__);
959
960 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_GET_PEER);
961
962 nlmsg_hdr(nl_msg)->nlmsg_flags |= NLM_F_DUMP;
963
964 int ret = ovpn_nl_msg_send(dco, nl_msg, dco_parse_peer_multi, m, __func__);
965
966 nlmsg_free(nl_msg);
967
968 if (raise_sigusr1_on_err && ret < 0)
969 {
970 msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer"
971 "may have been deleted from the kernel without notifying "
972 "userspace. Restarting the session");
973 register_signal(m->top.sig, SIGUSR1, "dco peer stats error");
974 }
975 return ret;
976}
977
978static int
979dco_parse_peer(struct nl_msg *msg, void *arg)
980{
981 struct context *c = arg;
982 struct nlattr *tb[OVPN_ATTR_MAX + 1];
983 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
984
985 msg(D_DCO_DEBUG, "%s: parsing message...", __func__);
986
987 nla_parse(tb, OVPN_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
988 genlmsg_attrlen(gnlh, 0), NULL);
989
990 if (!tb[OVPN_ATTR_GET_PEER])
991 {
992 msg(D_DCO_DEBUG, "%s: malformed reply", __func__);
993 return NL_SKIP;
994 }
995
996 struct nlattr *tb_peer[OVPN_GET_PEER_RESP_ATTR_MAX + 1];
997
998 nla_parse(tb_peer, OVPN_GET_PEER_RESP_ATTR_MAX,
999 nla_data(tb[OVPN_ATTR_GET_PEER]),
1000 nla_len(tb[OVPN_ATTR_GET_PEER]), NULL);
1001
1002 if (!tb_peer[OVPN_GET_PEER_RESP_ATTR_PEER_ID])
1003 {
1004 msg(M_WARN, "%s: no peer-id provided in reply", __func__);
1005 return NL_SKIP;
1006 }
1007
1008 uint32_t peer_id = nla_get_u32(tb_peer[OVPN_GET_PEER_RESP_ATTR_PEER_ID]);
1009 if (c->c2.tls_multi->dco_peer_id != peer_id)
1010 {
1011 return NL_SKIP;
1012 }
1013
1014 dco_update_peer_stat(&c->c2, tb_peer, peer_id);
1015
1016 return NL_OK;
1017}
1018
1019int
1020dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
1021{
1022 int peer_id = c->c2.tls_multi->dco_peer_id;
1023 if (peer_id == -1)
1024 {
1025 return 0;
1026 }
1027
1028 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id);
1029
1030 if (!c->c1.tuntap)
1031 {
1032 return 0;
1033 }
1034
1035 dco_context_t *dco = &c->c1.tuntap->dco;
1036 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_GET_PEER);
1037 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_GET_PEER);
1038 int ret = -EMSGSIZE;
1039
1040 NLA_PUT_U32(nl_msg, OVPN_GET_PEER_ATTR_PEER_ID, peer_id);
1041 nla_nest_end(nl_msg, attr);
1042
1043 ret = ovpn_nl_msg_send(dco, nl_msg, dco_parse_peer, c, __func__);
1044
1045nla_put_failure:
1046 nlmsg_free(nl_msg);
1047
1048 if (raise_sigusr1_on_err && ret < 0)
1049 {
1050 msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer"
1051 "may have been deleted from the kernel without notifying "
1052 "userspace. Restarting the session");
1053 register_signal(c->sig, SIGUSR1, "dco peer stats error");
1054 }
1055 return ret;
1056}
1057
1058bool
1059dco_available(int msglevel)
1060{
1061 if (resolve_ovpn_netlink_id(D_DCO_DEBUG) < 0)
1062 {
1063 msg(msglevel,
1064 "Note: Kernel support for ovpn-dco missing, disabling data channel offload.");
1065 return false;
1066 }
1067
1068 return true;
1069}
1070
1071const char *
1073{
1074 struct buffer out = alloc_buf_gc(256, gc);
1075 FILE *fp = fopen("/sys/module/ovpn_dco_v2/version", "r");
1076 if (!fp)
1077 {
1078 return "N/A";
1079 }
1080
1081 if (!fgets(BSTR(&out), BCAP(&out), fp))
1082 {
1083 fclose(fp);
1084 return "ERR";
1085 }
1086
1087 /* remove potential newline at the end of the string */
1088 char *str = BSTR(&out);
1089 char *nl = strchr(str, '\n');
1090 if (nl)
1091 {
1092 *nl = '\0';
1093 }
1094
1095 fclose(fp);
1096 return BSTR(&out);
1097}
1098
1099void
1100dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
1101{
1102 if (dco && dco->nl_sock)
1103 {
1104 event_ctl(es, nl_socket_get_fd(dco->nl_sock), EVENT_READ, arg);
1105 }
1106}
1107
1108const char *
1110{
1111 return "AES-128-GCM:AES-256-GCM:AES-192-GCM:CHACHA20-POLY1305";
1112}
1113
1114#endif /* defined(ENABLE_DCO) && defined(TARGET_LINUX) */
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
#define BSTR(buf)
Definition buffer.h:129
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition buffer.h:1097
#define BCAP(buf)
Definition buffer.h:130
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
static struct gc_arena gc_new(void)
Definition buffer.h:1025
#define counter_format
Definition common.h:31
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:270
static int dco_set_peer(dco_context_t *dco, unsigned int peerid, int keepalive_interval, int keepalive_timeout, int mss)
Definition dco.h:350
static const char * dco_get_supported_ciphers(void)
Definition dco.h:392
static int dco_do_read(dco_context_t *dco)
Definition dco.h:317
static void dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
Definition dco.h:324
static int open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
Definition dco.h:306
static int dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m, const bool raise_sigusr1_on_err)
Definition dco.h:379
static bool ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node)
Definition dco.h:300
void * dco_context_t
Definition dco.h:267
static const char * dco_version_string(struct gc_arena *gc)
Definition dco.h:276
static void close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx)
Definition dco.h:312
static int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
Definition dco.h:386
int dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
Definition dco_win.c:566
int dco_del_peer(dco_context_t *dco, unsigned int peerid)
Definition dco_win.c:465
int dco_swap_keys(dco_context_t *dco, unsigned int peer_id)
Definition dco_win.c:575
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:414
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:525
#define D_DCO
Definition errlevel.h:94
#define D_DCO_DEBUG
Definition errlevel.h:118
#define M_INFO
Definition errlevel.h:55
#define EVENT_READ
Definition event.h:39
static void event_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg)
Definition event.h:181
void set_nonblock(socket_descriptor_t fd)
Definition fdmisc.c:69
void set_cloexec(socket_descriptor_t fd)
Definition fdmisc.c:79
static SERVICE_STATUS status
Definition interactive.c:53
Header file for server-mode related structures and functions.
void * openvpn_net_ctx_t
Definition networking.h:39
#define CLEAR(x)
Definition basic.h:33
#define M_FATAL
Definition error.h:89
#define M_NONFATAL
Definition error.h:90
#define M_ERR
Definition error.h:105
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
#define CM_P2P
Definition openvpn.h:482
#define CM_TOP
Definition openvpn.h:483
@ OVPN_CIPHER_ALG_NONE
@ OVPN_DEL_PEER_ATTR_REASON
@ OVPN_DEL_PEER_ATTR_PEER_ID
@ OVPN_DEL_PEER_ATTR_MAX
@ OVPN_GET_PEER_RESP_ATTR_PEER_ID
@ OVPN_GET_PEER_RESP_ATTR_VPN_TX_BYTES
@ OVPN_GET_PEER_RESP_ATTR_LINK_RX_BYTES
@ OVPN_GET_PEER_RESP_ATTR_LINK_TX_BYTES
@ OVPN_GET_PEER_RESP_ATTR_VPN_RX_BYTES
@ OVPN_GET_PEER_RESP_ATTR_MAX
@ OVPN_NEW_KEY_ATTR_DECRYPT_KEY
@ OVPN_NEW_KEY_ATTR_KEY_ID
@ OVPN_NEW_KEY_ATTR_ENCRYPT_KEY
@ OVPN_NEW_KEY_ATTR_PEER_ID
@ OVPN_NEW_KEY_ATTR_CIPHER_ALG
@ OVPN_NEW_KEY_ATTR_KEY_SLOT
ovpn_nl_commands
enum ovpn_nl_commands - supported netlink commands
@ OVPN_CMD_SET_PEER
@OVPN_CMD_SET_PEER: Tweak parameters for an existing peer
@ OVPN_CMD_SWAP_KEYS
@ OVPN_CMD_DEL_PEER
@OVPN_CMD_DEL_PEER: Remove peer from internal table
@ OVPN_CMD_NEW_PEER
@OVPN_CMD_NEW_PEER: Configure peer with its crypto keys
@ OVPN_CMD_NEW_KEY
@ OVPN_CMD_DEL_KEY
@ OVPN_CMD_GET_PEER
@OVPN_CMD_GET_PEER: Retrieve the status of a peer or all peers
@ OVPN_SET_PEER_ATTR_KEEPALIVE_INTERVAL
@ OVPN_SET_PEER_ATTR_KEEPALIVE_TIMEOUT
@ OVPN_SET_PEER_ATTR_PEER_ID
#define OVPN_NL_MULTICAST_GROUP_PEERS
@ OVPN_GET_PEER_ATTR_PEER_ID
@ OVPN_DEL_KEY_ATTR_PEER_ID
@ OVPN_DEL_KEY_ATTR_KEY_SLOT
@ OVPN_MODE_MP
@ OVPN_MODE_P2P
@ OVPN_SWAP_KEYS_ATTR_PEER_ID
@ OVPN_NEW_PEER_ATTR_SOCKADDR_REMOTE
@ OVPN_NEW_PEER_ATTR_IPV4
@ OVPN_NEW_PEER_ATTR_PEER_ID
@ OVPN_NEW_PEER_ATTR_LOCAL_IP
@ OVPN_NEW_PEER_ATTR_SOCKET
@ OVPN_NEW_PEER_ATTR_IPV6
@ OVPN_KEY_DIR_ATTR_CIPHER_KEY
@ OVPN_KEY_DIR_ATTR_NONCE_TAIL
#define OVPN_NL_NAME
@ OVPN_ATTR_DEL_KEY
@ OVPN_ATTR_SWAP_KEYS
@ OVPN_ATTR_SET_PEER
@ OVPN_ATTR_MAX
@ OVPN_ATTR_GET_PEER
@ OVPN_ATTR_DEL_PEER
@ OVPN_ATTR_NEW_PEER
@ OVPN_ATTR_IFINDEX
@ OVPN_ATTR_NEW_KEY
#define DEV_TYPE_TUN
Definition proto.h:36
void register_signal(struct signal_info *si, int signum, const char *signal_text)
Register a soft signal in the signal_info struct si respecting priority.
Definition sig.c:231
static const char * print_sockaddr(const struct sockaddr *addr, struct gc_arena *gc)
Definition socket.h:384
static int af_addr_size(sa_family_t af)
Definition socket.h:864
Control Channel SSL/Data channel negotiation module.
Control Channel Verification Module.
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
struct tuntap * tuntap
Tun/tap virtual network interface.
Definition openvpn.h:171
Level 2 context containing state that is reset on both SIGHUP and SIGUSR1 restarts.
Definition openvpn.h:224
counter_type dco_read_bytes
Definition openvpn.h:267
counter_type tun_read_bytes
Definition openvpn.h:264
counter_type dco_write_bytes
Definition openvpn.h:270
struct tls_multi * tls_multi
TLS state structure for this VPN tunnel.
Definition openvpn.h:323
counter_type tun_write_bytes
Definition openvpn.h:265
Contains all state information for one tunnel.
Definition openvpn.h:474
struct signal_info * sig
Internal error signaling object.
Definition openvpn.h:500
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:117
Container for two sets of OpenSSL cipher and/or HMAC contexts for both sending and receiving directio...
Definition crypto.h:279
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 context top
Storage structure for process-wide configuration.
Definition multi.h:202
struct multi_instance ** instances
Array of multi_instances.
Definition multi.h:164
struct context context
The context structure storing state for this VPN tunnel.
Definition multi.h:144
int dco_peer_id
This is the handle that DCO uses to identify this session with the kernel.
Definition ssl_common.h:696
Definition tun.h:181
int type
Definition tun.h:183
dco_context_t dco
Definition tun.h:249
char * actual_name
Definition tun.h:205
__attribute__((unused))
Definition test.c:42
struct env_set * es
struct gc_arena gc
Definition test_ssl.c:155