27#if defined(ENABLE_DCO) && defined(TARGET_LINUX)
46#include <netlink/socket.h>
47#include <netlink/netlink.h>
48#include <netlink/genl/genl.h>
49#include <netlink/genl/family.h>
50#include <netlink/genl/ctrl.h>
60static bool __is_locked =
false;
66#define nla_nest_start(_msg, _type) nla_nest_start(_msg, (_type) | NLA_F_NESTED)
72typedef int (*ovpn_nl_cb)(
struct nl_msg *
msg,
void *arg);
86resolve_ovpn_netlink_id(
msglvl_t msglevel)
89 struct nl_sock *nl_sock = nl_socket_alloc();
93 msg(msglevel,
"Allocating net link socket failed");
97 ret = genl_connect(nl_sock);
100 msg(msglevel,
"Cannot connect to generic netlink: %s", nl_geterror(ret));
108 msg(msglevel,
"Cannot find ovpn_dco netlink component: %s", nl_geterror(ret));
112 nl_socket_free(nl_sock);
116static struct nl_msg *
119 struct nl_msg *nl_msg = nlmsg_alloc();
122 msg(
M_FATAL,
"cannot allocate netlink message");
126 genlmsg_put(nl_msg, 0, 0, dco->ovpn_dco_id, 0, 0, cmd, 0);
132 msg(
M_INFO,
"cannot put into netlink message");
140 int ret = nl_recvmsgs(dco->nl_sock, dco->nl_cb);
146 msg(
M_WARN,
"%s: netlink received interrupt due to signal - ignoring", prefix);
150 msg(
M_FATAL,
"%s: netlink out of memory error", prefix);
154 msg(
M_WARN,
"%s: netlink reports blocking read - aborting wait", prefix);
158 msg(
M_FATAL,
"%s: netlink reports device not found:", prefix);
161 case -NLE_OBJ_NOTFOUND:
162 msg(
M_INFO,
"%s: netlink reports object not found, ovpn kernel module unloaded?", prefix);
168 msg(
M_NONFATAL,
"%s: netlink reports error (%d): %s", prefix, ret,
187ovpn_nl_msg_send(
dco_context_t *dco,
struct nl_msg *nl_msg,
const char *prefix)
191 nl_send_auto(dco->nl_sock, nl_msg);
193 while (dco->status == 1)
195 ovpn_nl_recvmsgs(dco, prefix);
200 msg(
M_INFO,
"%s: failed to send netlink message: %s (%d)", prefix, strerror(-dco->status),
208mapped_v4_to_v6(
struct sockaddr *sock,
struct gc_arena *
gc)
210 struct sockaddr_in6 *sock6 = (
struct sockaddr_in6 *)sock;
211 if (sock->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sock6->sin6_addr))
213 struct sockaddr_in *sock4;
215 memcpy(&sock4->sin_addr, sock6->sin6_addr.s6_addr + 12, 4);
216 sock4->sin_port = sock6->sin6_port;
217 sock4->sin_family = AF_INET;
218 return (
struct sockaddr *)sock4;
225 struct sockaddr *remoteaddr,
const struct in_addr *vpn_ipv4,
226 const struct in6_addr *vpn_ipv6)
229 const char *remotestr =
"[undefined]";
234 msg(
D_DCO_DEBUG,
"%s: peer-id %d, fd %d, remote addr: %s", __func__, peerid, sd, remotestr);
237 struct nlattr *attr = nla_nest_start(nl_msg,
OVPN_A_PEER);
246 remoteaddr = mapped_v4_to_v6(remoteaddr, &
gc);
248 if (remoteaddr->sa_family == AF_INET)
251 &((
struct sockaddr_in *)remoteaddr)->sin_addr);
253 ((
struct sockaddr_in *)remoteaddr)->sin_port);
255 else if (remoteaddr->sa_family == AF_INET6)
258 &((
struct sockaddr_in6 *)remoteaddr)->sin6_addr);
260 ((
struct sockaddr_in6 *)remoteaddr)->sin6_port);
262 ((
struct sockaddr_in6 *)remoteaddr)->sin6_scope_id);
268 localaddr = mapped_v4_to_v6(localaddr, &
gc);
269 if (localaddr->sa_family == AF_INET)
272 &((
struct sockaddr_in *)localaddr)->sin_addr);
274 else if (localaddr->sa_family == AF_INET6)
277 &((
struct sockaddr_in6 *)localaddr)->sin6_addr);
290 nla_nest_end(nl_msg, attr);
292 ret = ovpn_nl_msg_send(dco, nl_msg, __func__);
322enum ovpn_nlmsgerr_attrs
324 OVPN_NLMSGERR_ATTR_MISS_TYPE = 5,
325 OVPN_NLMSGERR_ATTR_MISS_NEST = 6,
326 OVPN_NLMSGERR_ATTR_MAX = 6,
338ovpn_nl_cb_error(
struct sockaddr_nl(*nla)
__attribute__((unused)),
struct nlmsgerr *err,
void *arg)
340 struct nlmsghdr *nlh = (
struct nlmsghdr *)err - 1;
341 struct nlattr *tb_msg[OVPN_NLMSGERR_ATTR_MAX + 1];
342 int len = nlh->nlmsg_len;
343 struct nlattr *attrs;
345 int ack_len =
sizeof(*nlh) +
sizeof(int) +
sizeof(*nlh);
349 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
354 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
356 ack_len += err->msg.nlmsg_len - (int)
sizeof(*nlh);
364 attrs = (
void *)((
unsigned char *)nlh + ack_len);
367 nla_parse(tb_msg, OVPN_NLMSGERR_ATTR_MAX, attrs, len, NULL);
368 if (tb_msg[NLMSGERR_ATTR_MSG])
370 len = (int)strnlen((
char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG]),
371 nla_len(tb_msg[NLMSGERR_ATTR_MSG]));
372 msg(
M_WARN,
"kernel error: %*s", len, (
char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG]));
375 if (tb_msg[OVPN_NLMSGERR_ATTR_MISS_NEST])
377 msg(
M_WARN,
"kernel error: missing required nesting type %u",
378 nla_get_u32(tb_msg[OVPN_NLMSGERR_ATTR_MISS_NEST]));
381 if (tb_msg[OVPN_NLMSGERR_ATTR_MISS_TYPE])
383 msg(
M_WARN,
"kernel error: missing required attribute type %u",
384 nla_get_u32(tb_msg[OVPN_NLMSGERR_ATTR_MISS_TYPE]));
394 ovpn_get_mcast_id(dco);
396 if (dco->ovpn_dco_mcast_id < 0)
398 msg(
M_FATAL,
"cannot get mcast group: %s", nl_geterror(dco->ovpn_dco_mcast_id));
404 int ret = nl_socket_add_membership(dco->nl_sock, dco->ovpn_dco_mcast_id);
407 msg(
M_FATAL,
"%s: failed to join groups: %d", __func__, ret);
411static int ovpn_handle_msg(
struct nl_msg *
msg,
void *arg);
416 dco->ovpn_dco_id = resolve_ovpn_netlink_id(
M_FATAL);
418 dco->nl_sock = nl_socket_alloc();
425 int ret = genl_connect(dco->nl_sock);
428 msg(
M_FATAL,
"Cannot connect to generic netlink: %s", nl_geterror(ret));
433 setsockopt(nl_socket_get_fd(dco->nl_sock), SOL_NETLINK, NETLINK_EXT_ACK, &ret,
sizeof(ret));
439 dco->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
442 msg(
M_FATAL,
"failed to allocate netlink callback");
445 nl_socket_set_cb(dco->nl_sock, dco->nl_cb);
447 dco->dco_message_peer_id = -1;
448 nl_cb_err(dco->nl_cb, NL_CB_CUSTOM, ovpn_nl_cb_error, &dco->status);
449 nl_cb_set(dco->nl_cb, NL_CB_FINISH, NL_CB_CUSTOM, ovpn_nl_cb_finish, &dco->status);
450 nl_cb_set(dco->nl_cb, NL_CB_ACK, NL_CB_CUSTOM, ovpn_nl_cb_finish, &dco->status);
451 nl_cb_set(dco->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ovpn_handle_msg, dco);
453 ovpn_dco_register(dco);
458 nl_socket_disable_seq_check(dco->nl_sock);
463 ASSERT(!nl_socket_set_buffer_size(dco->nl_sock, 1024 * 1024, 1024 * 1024));
489 ovpn_dco_init_netlink(dco);
496 nl_socket_free(dco->nl_sock);
500 nl_cb_put(dco->nl_cb);
518 tt->
dco.ifindex = if_nametoindex(dev);
519 if (!tt->
dco.ifindex)
521 msg(
M_FATAL,
"DCO: cannot retrieve ifindex for interface %s", dev);
533 ovpn_dco_uninit_netlink(&tt->
dco);
550 nla_nest_end(nl_msg, attr);
552 ret = ovpn_nl_msg_send(dco, nl_msg, __func__);
571 struct nlattr *attr = nla_nest_start(nl_msg,
OVPN_A_PEER);
574 nla_nest_end(nl_msg, attr);
576 ret = ovpn_nl_msg_send(dco, nl_msg, __func__);
588 msg(
D_DCO_DEBUG,
"%s: peer-id %d, slot %d", __func__, peerid, slot);
599 nla_nest_end(nl_msg, keyconf);
601 ret = ovpn_nl_msg_send(dco, nl_msg, __func__);
610 const uint8_t *encrypt_key,
const uint8_t *encrypt_iv,
const uint8_t *decrypt_key,
611 const uint8_t *decrypt_iv,
const char *ciphername,
bool epoch)
613 msg(
D_DCO_DEBUG,
"%s: slot %d, key-id %d, peer-id %d, cipher %s, epoch %d", __func__, slot, keyid, peerid,
617 ASSERT(key_len <= INT_MAX);
618 const int nonce_tail_len = 8;
626 dco_cipher_t dco_cipher = dco_get_cipher(ciphername);
642 nla_nest_end(nl_msg, key_enc);
650 nla_nest_end(nl_msg, key_dec);
652 nla_nest_end(nl_msg, key_conf);
655 ret = ovpn_nl_msg_send(dco, nl_msg, __func__);
666 msg(
D_DCO_DEBUG,
"%s: peer-id %d, keepalive %d/%d, mss %d", __func__, peerid,
667 keepalive_interval, keepalive_timeout, mss);
675 struct nlattr *attr = nla_nest_start(nl_msg,
OVPN_A_PEER);
680 nla_nest_end(nl_msg, attr);
682 ret = ovpn_nl_msg_send(dco, nl_msg, __func__);
697mcast_family_handler(
struct nl_msg *
msg,
void *arg)
700 struct nlattr *tb[CTRL_ATTR_MAX + 1];
701 const struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(
msg));
703 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
705 if (!tb[CTRL_ATTR_MCAST_GROUPS])
710 const struct nlattr *mcgrp;
712 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp)
714 struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
716 nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp), nla_len(mcgrp), NULL);
718 if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
724 nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]))
729 dco->ovpn_dco_mcast_id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
743 dco->ovpn_dco_mcast_id = -ENOENT;
747 dco->ctrlid = genl_ctrl_resolve(dco->nl_sock,
"nlctrl");
749 struct nl_msg *nl_msg = nlmsg_alloc();
755 genlmsg_put(nl_msg, 0, 0, dco->ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
760 ret = ovpn_nl_msg_send(dco, nl_msg, __func__);
768ovpn_parse_float_addr(
struct nlattr **attrs,
struct sockaddr *out)
772 msg(
D_DCO,
"ovpn-dco: no remote port in PEER_FLOAT_NTF message");
778 struct sockaddr_in *addr4 = (
struct sockaddr_in *)out;
780 addr4->sin_family = AF_INET;
788 struct sockaddr_in6 *addr6 = (
struct sockaddr_in6 *)out;
790 addr6->sin6_family = AF_INET6;
793 sizeof(addr6->sin6_addr));
801 msg(
D_DCO,
"ovpn-dco: no valid remote IP address in PEER_FLOAT_NTF message");
807ovpn_nla_get_uint(
struct nlattr *attr)
809 if (nla_len(attr) ==
sizeof(uint32_t))
811 return nla_get_u32(attr);
815 return nla_get_u64(attr);
820dco_update_peer_stat(
struct context_2 *c2,
struct nlattr *tb[], uint32_t
id)
829 msg(
M_WARN,
"%s: no link RX bytes provided in reply for peer %u", __func__,
id);
839 msg(
M_WARN,
"%s: no link TX bytes provided in reply for peer %u", __func__,
id);
849 msg(
M_WARN,
"%s: no VPN RX bytes provided in reply for peer %u", __func__,
id);
859 msg(
M_WARN,
"%s: no VPN TX bytes provided in reply for peer %u", __func__,
id);
877 msg(
M_WARN,
"ovpn-dco: no peer-id provided in PEER_GET reply");
896 if (peer_id >= dco->c->multi->max_clients)
898 msg(
M_WARN,
"%s: received out of bound peer_id %u (max=%u)", __func__, peer_id,
899 dco->c->multi->max_clients);
913 dco_update_peer_stat(c2, tb_peer, peer_id);
926 msg(
D_DCO,
"ovpn-dco: Received message without ifindex");
931 if (ifindex != dco->ifindex)
933 msg(
D_DCO_DEBUG,
"ovpn-dco: ignoring message for foreign ifindex %d", ifindex);
941ovpn_handle_peer_del_ntf(
dco_context_t *dco,
struct nlattr *attrs[])
943 if (!ovpn_iface_check(dco, attrs))
976 dco->ifindex, peerid, reason);
977 dco->dco_message_peer_id = peerid;
978 dco->dco_del_peer_reason = reason;
985ovpn_handle_peer_float_ntf(
dco_context_t *dco,
struct nlattr *attrs[])
987 if (!ovpn_iface_check(dco, attrs))
994 msg(
D_DCO,
"ovpn-dco: no peer in PEER_FLOAT_NTF message");
1001 msg(
D_DCO,
"ovpn-dco: can't parse peer in PEER_FLOAT_NTF messsage");
1007 msg(
D_DCO,
"ovpn-dco: no peer-id in PEER_FLOAT_NTF message");
1012 if (!ovpn_parse_float_addr(fp_attrs, (
struct sockaddr *)&dco->dco_float_peer_ss))
1018 msg(
D_DCO_DEBUG,
"ovpn-dco: received CMD_PEER_FLOAT_NTF, ifindex: %u, peer-id %u, address: %s",
1019 dco->ifindex, peerid,
print_sockaddr((
struct sockaddr *)&dco->dco_float_peer_ss, &
gc));
1020 dco->dco_message_peer_id = (int)peerid;
1029ovpn_handle_key_swap_ntf(
dco_context_t *dco,
struct nlattr *attrs[])
1031 if (!ovpn_iface_check(dco, attrs))
1038 msg(
D_DCO,
"ovpn-dco: no keyconf in KEY_SWAP_NTF message");
1045 msg(
D_DCO,
"ovpn-dco: can't parse keyconf in KEY_SWAP_NTF message");
1050 msg(
D_DCO,
"ovpn-dco: no peer-id in KEY_SWAP_NTF message");
1055 msg(
D_DCO,
"ovpn-dco: no key-id in KEY_SWAP_NTF message");
1062 msg(
D_DCO_DEBUG,
"ovpn-dco: received CMD_KEY_SWAP_NTF, ifindex: %d, peer-id %u, key-id: %d",
1063 dco->ifindex, peer_id, key_id);
1064 dco->dco_message_peer_id = peer_id;
1065 dco->dco_message_key_id = key_id;
1073ovpn_handle_msg(
struct nl_msg *
msg,
void *arg)
1078 struct nlmsghdr *nlh = nlmsg_hdr(
msg);
1079 struct genlmsghdr *gnlh = genlmsg_hdr(nlh);
1082 nlh->nlmsg_type, gnlh->cmd, nlh->nlmsg_flags);
1088 if (nlh->nlmsg_type == dco->ctrlid)
1091 return mcast_family_handler(
msg, dco);
1094 if (!genlmsg_valid_hdr(nlh, 0))
1096 msg(
D_DCO,
"ovpn-dco: invalid header");
1100 if (nla_parse(attrs,
OVPN_A_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL))
1102 msg(
D_DCO,
"received bogus data from ovpn-dco");
1119 return ovpn_handle_peer(dco, attrs);
1124 ret = ovpn_handle_peer_del_ntf(dco, attrs);
1130 ret = ovpn_handle_peer_float_ntf(dco, attrs);
1136 ret = ovpn_handle_key_swap_ntf(dco, attrs);
1141 msg(
D_DCO,
"ovpn-dco: received unknown command: %d", gnlh->cmd);
1142 dco->dco_message_type = 0;
1151 if (dco->c->mode ==
CM_TOP)
1168 return ovpn_nl_recvmsgs(dco, __func__);
1172dco_get_peer(
dco_context_t *dco,
int peer_id,
const bool raise_sigusr1_on_err)
1178 msg(
D_DCO_DEBUG,
"%s: cannot request peer stats while parsing other messages", __func__);
1194 struct nlattr *attr = nla_nest_start(nl_msg,
OVPN_A_PEER);
1195 int ret = -EMSGSIZE;
1203 nlmsg_hdr(nl_msg)->nlmsg_flags |= NLM_F_DUMP;
1205 nla_nest_end(nl_msg, attr);
1207 ret = ovpn_nl_msg_send(dco, nl_msg, __func__);
1212 if (raise_sigusr1_on_err && ret < 0)
1214 msg(
M_WARN,
"Error retrieving DCO peer stats: the underlying DCO peer"
1215 "may have been deleted from the kernel without notifying "
1216 "userspace. Restarting the session");
1236 return dco_get_peer(dco, -1, raise_sigusr1_on_err);
1244 msg(msglevel,
"Note: Kernel support for ovpn interfaces missing, "
1245 "disabling data channel offload. Use Linux 6.16.0 or "
1246 "newer with ovpn support or use ovpn-backports for "
1247 "interface support.");
1259dco_version_string_in_tree(
struct gc_arena *
gc)
1262 struct utsname system;
1282dco_version_string_backports(FILE *fp,
struct gc_arena *
gc)
1286 if (!fgets(str, PATH_MAX, fp))
1292 char *nl = strchr(str,
'\n');
1304 const char *version;
1308 if (stat(
"/sys/module/ovpn", &sb) != 0 || !S_ISDIR(sb.st_mode))
1316 fp = fopen(
"/sys/module/ovpn/version",
"r");
1319 return dco_version_string_in_tree(
gc);
1321 version = dco_version_string_backports(fp,
gc);
1330 if (dco && dco->nl_sock)
1339 return "AES-128-GCM:AES-256-GCM:AES-192-GCM:CHACHA20-POLY1305";
bool buf_puts(struct buffer *buf, const char *str)
Append a string to a buffer with overflow check.
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Allocate memory and, optionally, zero it.
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Allocate a buffer of the given size under garbage collection.
Buffer management functions and garbage collection.
#define BSTR(buf)
Return the buffer content pointer cast to char *.
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Allocate and zero-initialise a garbage-collected object of the given type.
static void gc_free(struct gc_arena *a)
Free all allocations in a garbage collection arena.
static struct gc_arena gc_new(void)
Allocate and return a new, empty garbage collection arena.
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)
static int dco_set_peer(dco_context_t *dco, unsigned int peerid, int keepalive_interval, int keepalive_timeout, int mss)
static const char * dco_get_supported_ciphers(void)
static bool dco_supports_epoch_data(struct context *c)
static void dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
static int open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
static int dco_read_and_process(dco_context_t *dco)
static bool dco_available(msglvl_t msglevel)
static bool ovpn_dco_init(struct context *c)
static const char * dco_version_string(struct gc_arena *gc)
static void close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx)
static int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
int dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
int dco_del_peer(dco_context_t *dco, unsigned int peerid)
int dco_swap_keys(dco_context_t *dco, unsigned int peer_id)
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)
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)
static void event_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg)
void set_nonblock(socket_descriptor_t fd)
void set_cloexec(socket_descriptor_t fd)
void process_incoming_dco(dco_context_t *dco)
Process an incoming DCO message (from kernel space).
static SERVICE_STATUS status
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).
@ OVPN_CMD_PEER_FLOAT_NTF
@ OVPN_A_PEER_LINK_RX_BYTES
@ OVPN_A_PEER_LINK_TX_BYTES
@ OVPN_A_PEER_KEEPALIVE_TIMEOUT
@ OVPN_A_PEER_VPN_TX_BYTES
@ OVPN_A_PEER_REMOTE_IPV6
@ OVPN_A_PEER_VPN_RX_BYTES
@ OVPN_A_PEER_REMOTE_IPV4
@ OVPN_A_PEER_KEEPALIVE_INTERVAL
@ OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID
@ OVPN_A_PEER_REMOTE_PORT
@ OVPN_A_KEYCONF_DECRYPT_DIR
@ OVPN_A_KEYCONF_CIPHER_ALG
@ OVPN_A_KEYCONF_ENCRYPT_DIR
@ OVPN_A_KEYDIR_CIPHER_KEY
@ OVPN_A_KEYDIR_NONCE_TAIL
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.
static const char * print_sockaddr(const struct sockaddr *addr, struct gc_arena *gc)
Control Channel SSL/Data channel negotiation module.
Control Channel Verification Module.
Wrapper structure for dynamically allocated memory.
struct tuntap * tuntap
Tun/tap virtual network interface.
Level 2 context containing state that is reset on both SIGHUP and SIGUSR1 restarts.
counter_type dco_read_bytes
counter_type tun_read_bytes
counter_type dco_write_bytes
struct tls_multi * tls_multi
TLS state structure for this VPN tunnel.
counter_type tun_write_bytes
Contains all state information for one tunnel.
int mode
Role of this context within the OpenVPN process.
struct context_2 c2
Level 2 context.
struct context_1 c1
Level 1 context.
Garbage collection arena used to keep track of dynamically allocated memory.
Container for two sets of OpenSSL cipher and/or HMAC contexts for both sending and receiving directio...
Container for unidirectional cipher and HMAC key material.
Server-mode state structure for one single VPN tunnel.
struct context context
The context structure storing state for this VPN tunnel.
int dco_peer_id
This is the handle that DCO uses to identify this session with the kernel.