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_FAMILY_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, int 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_A_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_PEER_NEW);
235 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_A_PEER);
236 int ret = -EMSGSIZE;
237
238 NLA_PUT_U32(nl_msg, OVPN_A_PEER_ID, peerid);
239 NLA_PUT_U32(nl_msg, OVPN_A_PEER_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
246 if (remoteaddr->sa_family == AF_INET)
247 {
248 NLA_PUT(nl_msg, OVPN_A_PEER_REMOTE_IPV4, sizeof(struct in_addr),
249 &((struct sockaddr_in *)remoteaddr)->sin_addr);
250 NLA_PUT_U16(nl_msg, OVPN_A_PEER_REMOTE_PORT, ((struct sockaddr_in *)remoteaddr)->sin_port);
251 }
252 else if (remoteaddr->sa_family == AF_INET6)
253 {
254 NLA_PUT(nl_msg, OVPN_A_PEER_REMOTE_IPV6, sizeof(struct in6_addr),
255 &((struct sockaddr_in6 *)remoteaddr)->sin6_addr);
256 NLA_PUT_U16(nl_msg, OVPN_A_PEER_REMOTE_PORT, ((struct sockaddr_in6 *)remoteaddr)->sin6_port);
257 NLA_PUT_U32(nl_msg, OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID, ((struct sockaddr_in6 *)remoteaddr)->sin6_scope_id);
258 }
259 }
260
261 if (localaddr)
262 {
263 localaddr = mapped_v4_to_v6(localaddr, &gc);
264 if (localaddr->sa_family == AF_INET)
265 {
266 NLA_PUT(nl_msg, OVPN_A_PEER_LOCAL_IPV4, sizeof(struct in_addr),
267 &((struct sockaddr_in *)localaddr)->sin_addr);
268 NLA_PUT_U16(nl_msg, OVPN_A_PEER_LOCAL_PORT, ((struct sockaddr_in *)localaddr)->sin_port);
269 }
270 else if (localaddr->sa_family == AF_INET6)
271 {
272 NLA_PUT(nl_msg, OVPN_A_PEER_LOCAL_IPV6, sizeof(struct in6_addr),
273 &((struct sockaddr_in6 *)localaddr)->sin6_addr);
274 NLA_PUT_U16(nl_msg, OVPN_A_PEER_LOCAL_PORT, ((struct sockaddr_in6 *)localaddr)->sin6_port);
275 }
276 }
277
278 /* Set the primary VPN IP addresses of the peer */
279 if (vpn_ipv4)
280 {
281 NLA_PUT_U32(nl_msg, OVPN_A_PEER_VPN_IPV4, vpn_ipv4->s_addr);
282 }
283 if (vpn_ipv6)
284 {
285 NLA_PUT(nl_msg, OVPN_A_PEER_VPN_IPV6, sizeof(struct in6_addr),
286 vpn_ipv6);
287 }
288 nla_nest_end(nl_msg, attr);
289
290 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
291
292nla_put_failure:
293 nlmsg_free(nl_msg);
294 gc_free(&gc);
295 return ret;
296}
297
298static int
299ovpn_nl_cb_finish(struct nl_msg (*msg) __attribute__ ((unused)), void *arg)
300{
301 int *status = arg;
302
303 *status = 0;
304 return NL_SKIP;
305}
306
307/* The following enum members exist in netlink.h since linux-6.1.
308 * However, some distro we support still ship an old header, thus
309 * failing the OpenVPN compilation.
310 *
311 * For the time being we add the needed defines manually.
312 * We will drop this definition once we stop supporting those old
313 * distros.
314 *
315 * @NLMSGERR_ATTR_MISS_TYPE: type of a missing required attribute,
316 * %NLMSGERR_ATTR_MISS_NEST will not be present if the attribute was
317 * missing at the message level
318 * @NLMSGERR_ATTR_MISS_NEST: offset of the nest where attribute was missing
319 */
320enum ovpn_nlmsgerr_attrs {
321 OVPN_NLMSGERR_ATTR_MISS_TYPE = 5,
322 OVPN_NLMSGERR_ATTR_MISS_NEST = 6,
323 OVPN_NLMSGERR_ATTR_MAX = 6,
324};
325
326/* This function is used as error callback on the netlink socket.
327 * When something goes wrong and the kernel returns an error, this function is
328 * invoked.
329 *
330 * We pass the error code to the user by means of a variable pointed by *arg
331 * (supplied by the user when setting this callback) and we parse the kernel
332 * reply to see if it contains a human-readable error. If found, it is printed.
333 */
334static int
335ovpn_nl_cb_error(struct sockaddr_nl (*nla) __attribute__ ((unused)),
336 struct nlmsgerr *err, void *arg)
337{
338 struct nlmsghdr *nlh = (struct nlmsghdr *)err - 1;
339 struct nlattr *tb_msg[OVPN_NLMSGERR_ATTR_MAX + 1];
340 int len = nlh->nlmsg_len;
341 struct nlattr *attrs;
342 int *ret = arg;
343 int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
344
345 *ret = err->error;
346
347 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
348 {
349 return NL_STOP;
350 }
351
352 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
353 {
354 ack_len += err->msg.nlmsg_len - sizeof(*nlh);
355 }
356
357 if (len <= ack_len)
358 {
359 return NL_STOP;
360 }
361
362 attrs = (void *)((unsigned char *)nlh + ack_len);
363 len -= ack_len;
364
365 nla_parse(tb_msg, OVPN_NLMSGERR_ATTR_MAX, attrs, len, NULL);
366 if (tb_msg[NLMSGERR_ATTR_MSG])
367 {
368 len = strnlen((char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG]),
369 nla_len(tb_msg[NLMSGERR_ATTR_MSG]));
370 msg(M_WARN, "kernel error: %*s\n", len,
371 (char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG]));
372 }
373
374 if (tb_msg[OVPN_NLMSGERR_ATTR_MISS_NEST])
375 {
376 msg(M_WARN, "kernel error: missing required nesting type %u\n",
377 nla_get_u32(tb_msg[OVPN_NLMSGERR_ATTR_MISS_NEST]));
378 }
379
380 if (tb_msg[OVPN_NLMSGERR_ATTR_MISS_TYPE])
381 {
382 msg(M_WARN, "kernel error: missing required attribute type %u\n",
383 nla_get_u32(tb_msg[OVPN_NLMSGERR_ATTR_MISS_TYPE]));
384 }
385
386 return NL_STOP;
387}
388
389static void
390ovpn_dco_init_netlink(dco_context_t *dco)
391{
392 dco->ovpn_dco_id = resolve_ovpn_netlink_id(M_ERR);
393
394 dco->nl_sock = nl_socket_alloc();
395
396 if (!dco->nl_sock)
397 {
398 msg(M_ERR, "Cannot create netlink socket");
399 }
400
401 int ret = genl_connect(dco->nl_sock);
402 if (ret)
403 {
404 msg(M_ERR, "Cannot connect to generic netlink: %s",
405 nl_geterror(ret));
406 }
407
408 /* set close on exec and non-block on the netlink socket */
409 set_cloexec(nl_socket_get_fd(dco->nl_sock));
410 set_nonblock(nl_socket_get_fd(dco->nl_sock));
411
412 dco->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
413 if (!dco->nl_cb)
414 {
415 msg(M_ERR, "failed to allocate netlink callback");
416 }
417
418 nl_socket_set_cb(dco->nl_sock, dco->nl_cb);
419
420 nl_cb_err(dco->nl_cb, NL_CB_CUSTOM, ovpn_nl_cb_error, &dco->status);
421 nl_cb_set(dco->nl_cb, NL_CB_FINISH, NL_CB_CUSTOM, ovpn_nl_cb_finish,
422 &dco->status);
423 nl_cb_set(dco->nl_cb, NL_CB_ACK, NL_CB_CUSTOM, ovpn_nl_cb_finish,
424 &dco->status);
425
426 /* The async PACKET messages confuse libnl and it will drop them with
427 * wrong sequence numbers (NLE_SEQ_MISMATCH), so disable libnl's sequence
428 * number check */
429 nl_socket_disable_seq_check(dco->nl_sock);
430
431 /* nl library sets the buffer size to 32k/32k by default which is sometimes
432 * overrun with very fast connecting/disconnecting clients.
433 * TODO: fix this in a better and more reliable way */
434 ASSERT(!nl_socket_set_buffer_size(dco->nl_sock, 1024*1024, 1024*1024));
435}
436
437bool
438ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node)
439{
440 switch (mode)
441 {
442 case CM_TOP:
443 dco->ifmode = OVPN_MODE_MP;
444 break;
445
446 case CM_P2P:
447 dco->ifmode = OVPN_MODE_P2P;
448 break;
449
450 default:
451 ASSERT(false);
452 }
453
454 ovpn_dco_init_netlink(dco);
455 return true;
456}
457
458static void
459ovpn_dco_uninit_netlink(dco_context_t *dco)
460{
461 nl_socket_free(dco->nl_sock);
462 dco->nl_sock = NULL;
463
464 /* Decrease reference count */
465 nl_cb_put(dco->nl_cb);
466
467 CLEAR(dco);
468}
469
470static void
471ovpn_dco_register(dco_context_t *dco)
472{
473 msg(D_DCO_DEBUG, __func__);
474 ovpn_get_mcast_id(dco);
475
476 if (dco->ovpn_dco_mcast_id < 0)
477 {
478 msg(M_ERR, "cannot get mcast group: %s", nl_geterror(dco->ovpn_dco_mcast_id));
479 }
480
481 /* Register for ovpn-dco specific multicast messages that the kernel may
482 * send
483 */
484 int ret = nl_socket_add_membership(dco->nl_sock, dco->ovpn_dco_mcast_id);
485 if (ret)
486 {
487 msg(M_ERR, "%s: failed to join groups: %d", __func__, ret);
488 }
489}
490
491int
492open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
493{
494 msg(D_DCO_DEBUG, "%s: %s", __func__, dev);
495 ASSERT(tt->type == DEV_TYPE_TUN);
496
497 int ret = net_iface_new(ctx, dev, OVPN_FAMILY_NAME, &tt->dco);
498 if (ret < 0)
499 {
500 msg(D_DCO_DEBUG, "Cannot create DCO interface %s: %d", dev, ret);
501 return ret;
502 }
503
504 tt->dco.ifindex = if_nametoindex(dev);
505 if (!tt->dco.ifindex)
506 {
507 msg(M_FATAL, "DCO: cannot retrieve ifindex for interface %s", dev);
508 }
509
510 tt->dco.dco_message_peer_id = -1;
511
512 ovpn_dco_register(&tt->dco);
513
514 return 0;
515}
516
517void
518close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx)
519{
520 msg(D_DCO_DEBUG, __func__);
521
522 net_iface_del(ctx, tt->actual_name);
523 ovpn_dco_uninit_netlink(&tt->dco);
524}
525
526int
527dco_swap_keys(dco_context_t *dco, unsigned int peerid)
528{
529 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
530
531 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_KEY_SWAP);
532 if (!nl_msg)
533 {
534 return -ENOMEM;
535 }
536
537 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_A_KEYCONF);
538 int ret = -EMSGSIZE;
539 NLA_PUT_U32(nl_msg, OVPN_A_KEYCONF_PEER_ID, peerid);
540 nla_nest_end(nl_msg, attr);
541
542 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
543
544nla_put_failure:
545 nlmsg_free(nl_msg);
546 return ret;
547}
548
549
550int
551dco_del_peer(dco_context_t *dco, unsigned int peerid)
552{
553 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
554
555 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_PEER_DEL);
556 if (!nl_msg)
557 {
558 return -ENOMEM;
559 }
560
561 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_A_PEER);
562 int ret = -EMSGSIZE;
563 NLA_PUT_U32(nl_msg, OVPN_A_PEER_ID, peerid);
564 nla_nest_end(nl_msg, attr);
565
566 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
567
568nla_put_failure:
569 nlmsg_free(nl_msg);
570 return ret;
571}
572
573
574int
575dco_del_key(dco_context_t *dco, unsigned int peerid,
576 dco_key_slot_t slot)
577{
578 int ret = -EMSGSIZE;
579 msg(D_DCO_DEBUG, "%s: peer-id %d, slot %d", __func__, peerid, slot);
580
581 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_KEY_DEL);
582 if (!nl_msg)
583 {
584 return -ENOMEM;
585 }
586
587 struct nlattr *keyconf = nla_nest_start(nl_msg, OVPN_A_KEYCONF);
588 NLA_PUT_U32(nl_msg, OVPN_A_KEYCONF_PEER_ID, peerid);
589 NLA_PUT_U32(nl_msg, OVPN_A_KEYCONF_SLOT, slot);
590 nla_nest_end(nl_msg, keyconf);
591
592 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
593
594nla_put_failure:
595 nlmsg_free(nl_msg);
596 return ret;
597}
598
599int
600dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid,
601 dco_key_slot_t slot,
602 const uint8_t *encrypt_key, const uint8_t *encrypt_iv,
603 const uint8_t *decrypt_key, const uint8_t *decrypt_iv,
604 const char *ciphername)
605{
606 msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s",
607 __func__, slot, keyid, peerid, ciphername);
608
609 const size_t key_len = cipher_kt_key_size(ciphername);
610 const int nonce_tail_len = 8;
611
612 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_KEY_NEW);
613 if (!nl_msg)
614 {
615 return -ENOMEM;
616 }
617
618 dco_cipher_t dco_cipher = dco_get_cipher(ciphername);
619
620 int ret = -EMSGSIZE;
621
622 struct nlattr *key_conf = nla_nest_start(nl_msg, OVPN_A_KEYCONF);
623 NLA_PUT_U32(nl_msg, OVPN_A_KEYCONF_PEER_ID, peerid);
624 NLA_PUT_U32(nl_msg, OVPN_A_KEYCONF_SLOT, slot);
625 NLA_PUT_U32(nl_msg, OVPN_A_KEYCONF_KEY_ID, keyid);
626 NLA_PUT_U32(nl_msg, OVPN_A_KEYCONF_CIPHER_ALG, dco_cipher);
627
628 struct nlattr *key_enc = nla_nest_start(nl_msg,
630 if (dco_cipher != OVPN_CIPHER_ALG_NONE)
631 {
632 NLA_PUT(nl_msg, OVPN_A_KEYDIR_CIPHER_KEY, key_len, encrypt_key);
633 NLA_PUT(nl_msg, OVPN_A_KEYDIR_NONCE_TAIL, nonce_tail_len,
634 encrypt_iv);
635 }
636 nla_nest_end(nl_msg, key_enc);
637
638 struct nlattr *key_dec = nla_nest_start(nl_msg,
640 if (dco_cipher != OVPN_CIPHER_ALG_NONE)
641 {
642 NLA_PUT(nl_msg, OVPN_A_KEYDIR_CIPHER_KEY, key_len, decrypt_key);
643 NLA_PUT(nl_msg, OVPN_A_KEYDIR_NONCE_TAIL, nonce_tail_len,
644 decrypt_iv);
645 }
646 nla_nest_end(nl_msg, key_dec);
647
648 nla_nest_end(nl_msg, key_conf);
649
650
651 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
652
653nla_put_failure:
654 nlmsg_free(nl_msg);
655 return ret;
656}
657
658int
659dco_set_peer(dco_context_t *dco, unsigned int peerid,
660 int keepalive_interval, int keepalive_timeout, int mss)
661{
662 msg(D_DCO_DEBUG, "%s: peer-id %d, keepalive %d/%d, mss %d", __func__,
663 peerid, keepalive_interval, keepalive_timeout, mss);
664
665 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_PEER_SET);
666 if (!nl_msg)
667 {
668 return -ENOMEM;
669 }
670
671 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_A_PEER);
672 int ret = -EMSGSIZE;
673 NLA_PUT_U32(nl_msg, OVPN_A_PEER_ID, peerid);
674 NLA_PUT_U32(nl_msg, OVPN_A_PEER_KEEPALIVE_INTERVAL,
675 keepalive_interval);
676 NLA_PUT_U32(nl_msg, OVPN_A_PEER_KEEPALIVE_TIMEOUT,
677 keepalive_timeout);
678 nla_nest_end(nl_msg, attr);
679
680 ret = ovpn_nl_msg_send(dco, nl_msg, NULL, NULL, __func__);
681
682nla_put_failure:
683 nlmsg_free(nl_msg);
684 return ret;
685}
686
687/* This function parses the reply provided by the kernel to the CTRL_CMD_GETFAMILY
688 * message. We parse the reply and we retrieve the multicast group ID associated
689 * with the "ovpn-dco" netlink family.
690 *
691 * The ID is later used to subscribe to the multicast group and be notified
692 * about any multicast message sent by the ovpn-dco kernel module.
693 */
694static int
695mcast_family_handler(struct nl_msg *msg, void *arg)
696{
697 dco_context_t *dco = arg;
698 struct nlattr *tb[CTRL_ATTR_MAX + 1];
699 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
700
701 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
702 genlmsg_attrlen(gnlh, 0), NULL);
703
704 if (!tb[CTRL_ATTR_MCAST_GROUPS])
705 {
706 return NL_SKIP;
707 }
708
709 struct nlattr *mcgrp;
710 int rem_mcgrp;
711 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp)
712 {
713 struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
714
715 nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
716 nla_data(mcgrp), nla_len(mcgrp), NULL);
717
718 if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]
719 || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
720 {
721 continue;
722 }
723
724 if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
726 nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
727 {
728 continue;
729 }
730 dco->ovpn_dco_mcast_id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
731 break;
732 }
733
734 return NL_SKIP;
735}
741static int
742ovpn_get_mcast_id(dco_context_t *dco)
743{
744 dco->ovpn_dco_mcast_id = -ENOENT;
745
746 /* Even though 'nlctrl' is a constant, there seem to be no library
747 * provided define for it */
748 int ctrlid = genl_ctrl_resolve(dco->nl_sock, "nlctrl");
749
750 struct nl_msg *nl_msg = nlmsg_alloc();
751 if (!nl_msg)
752 {
753 return -ENOMEM;
754 }
755
756 genlmsg_put(nl_msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
757
758 int ret = -EMSGSIZE;
759 NLA_PUT_STRING(nl_msg, CTRL_ATTR_FAMILY_NAME, OVPN_FAMILY_NAME);
760
761 ret = ovpn_nl_msg_send(dco, nl_msg, mcast_family_handler, dco, __func__);
762
763nla_put_failure:
764 nlmsg_free(nl_msg);
765 return ret;
766}
767
768/* This function parses any netlink message sent by ovpn-dco to userspace */
769static int
770ovpn_handle_msg(struct nl_msg *msg, void *arg)
771{
772 dco_context_t *dco = arg;
773
774 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
775 struct nlattr *attrs[OVPN_A_MAX + 1];
776 struct nlmsghdr *nlh = nlmsg_hdr(msg);
777
778 if (!genlmsg_valid_hdr(nlh, 0))
779 {
780 msg(D_DCO, "ovpn-dco: invalid header");
781 return NL_STOP;
782 }
783
784 if (nla_parse(attrs, OVPN_A_MAX, genlmsg_attrdata(gnlh, 0),
785 genlmsg_attrlen(gnlh, 0), NULL))
786 {
787 msg(D_DCO, "received bogus data from ovpn-dco");
788 return NL_STOP;
789 }
790
791 /* we must know which interface this message is referring to in order to
792 * avoid mixing messages for other instances
793 */
794 if (!attrs[OVPN_A_IFINDEX])
795 {
796 msg(D_DCO, "ovpn-dco: Received message without ifindex");
797 return NL_STOP;
798 }
799
800 uint32_t ifindex = nla_get_u32(attrs[OVPN_A_IFINDEX]);
801 if (ifindex != dco->ifindex)
802 {
804 "ovpn-dco: ignoring message (type=%d) for foreign ifindex %d",
805 gnlh->cmd, ifindex);
806 return NL_STOP;
807 }
808
809 /* based on the message type, we parse the subobject contained in the
810 * message, that stores the type-specific attributes.
811 *
812 * the "dco" object is then filled accordingly with the information
813 * retrieved from the message, so that the rest of the OpenVPN code can
814 * react as need be.
815 */
816 switch (gnlh->cmd)
817 {
819 {
820 if (!attrs[OVPN_A_PEER])
821 {
822 msg(D_DCO, "ovpn-dco: no peer in PEER_DEL_NTF message");
823 return NL_STOP;
824 }
825
826 struct nlattr *dp_attrs[OVPN_A_PEER_MAX + 1];
827 if (nla_parse_nested(dp_attrs, OVPN_A_PEER_MAX, attrs[OVPN_A_PEER],
828 NULL))
829 {
830 msg(D_DCO, "ovpn-dco: can't parse peer in PEER_DEL_NTF messsage");
831 return NL_STOP;
832 }
833
834 if (!dp_attrs[OVPN_A_PEER_DEL_REASON])
835 {
836 msg(D_DCO, "ovpn-dco: no reason in PEER_DEL_NTF message");
837 return NL_STOP;
838 }
839 if (!dp_attrs[OVPN_A_PEER_ID])
840 {
841 msg(D_DCO, "ovpn-dco: no peer-id in PEER_DEL_NTF message");
842 return NL_STOP;
843 }
844
845 int reason = nla_get_u32(dp_attrs[OVPN_A_PEER_DEL_REASON]);
846 unsigned int peerid = nla_get_u32(dp_attrs[OVPN_A_PEER_ID]);
847
848 msg(D_DCO_DEBUG, "ovpn-dco: received CMD_PEER_DEL_NTF, ifindex: %d, peer-id %u, reason: %d",
849 ifindex, peerid, reason);
850 dco->dco_message_peer_id = peerid;
851 dco->dco_del_peer_reason = reason;
852 dco->dco_message_type = OVPN_CMD_PEER_DEL_NTF;
853 break;
854 }
855
857 {
858 if (!attrs[OVPN_A_KEYCONF])
859 {
860 msg(D_DCO, "ovpn-dco: no keyconf in KEY_SWAP_NTF message");
861 return NL_STOP;
862 }
863
864 struct nlattr *dp_attrs[OVPN_A_KEYCONF_MAX + 1];
865 if (nla_parse_nested(dp_attrs, OVPN_A_KEYCONF_MAX,
866 attrs[OVPN_A_KEYCONF], NULL))
867 {
868 msg(D_DCO, "ovpn-dco: can't parse keyconf in KEY_SWAP_NTF message");
869 return NL_STOP;
870 }
871 if (!dp_attrs[OVPN_A_KEYCONF_PEER_ID])
872 {
873 msg(D_DCO, "ovpn-dco: no peer-id in KEY_SWAP_NTF message");
874 return NL_STOP;
875 }
876 if (!dp_attrs[OVPN_A_KEYCONF_KEY_ID])
877 {
878 msg(D_DCO, "ovpn-dco: no key-id in KEY_SWAP_NTF message");
879 return NL_STOP;
880 }
881
882 int key_id = nla_get_u16(dp_attrs[OVPN_A_KEYCONF_KEY_ID]);
883 unsigned int peer_id = nla_get_u32(dp_attrs[OVPN_A_KEYCONF_PEER_ID]);
884
885 msg(D_DCO_DEBUG, "ovpn-dco: received CMD_KEY_SWAP_NTF, ifindex: %d, peer-id %u, key-id: %d",
886 ifindex, peer_id, key_id);
887 dco->dco_message_peer_id = peer_id;
888 dco->dco_message_key_id = key_id;
889 dco->dco_message_type = OVPN_CMD_KEY_SWAP_NTF;
890 break;
891 }
892
893 default:
894 msg(D_DCO, "ovpn-dco: received unknown command: %d", gnlh->cmd);
895 dco->dco_message_type = 0;
896 return NL_STOP;
897 }
898
899 return NL_OK;
900}
901
902int
904{
905 msg(D_DCO_DEBUG, __func__);
906 nl_cb_set(dco->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ovpn_handle_msg, dco);
907
908 return ovpn_nl_recvmsgs(dco, __func__);
909}
910
911static void
912dco_update_peer_stat(struct context_2 *c2, struct nlattr *tb[], uint32_t id)
913{
915 {
916 c2->dco_read_bytes = nla_get_u64(tb[OVPN_A_PEER_LINK_RX_BYTES]);
917 msg(D_DCO_DEBUG, "%s / dco_read_bytes: " counter_format, __func__,
918 c2->dco_read_bytes);
919 }
920 else
921 {
922 msg(M_WARN, "%s: no link RX bytes provided in reply for peer %u",
923 __func__, id);
924 }
925
927 {
928 c2->dco_write_bytes = nla_get_u64(tb[OVPN_A_PEER_LINK_TX_BYTES]);
929 msg(D_DCO_DEBUG, "%s / dco_write_bytes: " counter_format, __func__,
930 c2->dco_write_bytes);
931 }
932 else
933 {
934 msg(M_WARN, "%s: no link TX bytes provided in reply for peer %u",
935 __func__, id);
936 }
937
939 {
940 c2->tun_read_bytes = nla_get_u64(tb[OVPN_A_PEER_VPN_RX_BYTES]);
941 msg(D_DCO_DEBUG, "%s / tun_read_bytes: " counter_format, __func__,
942 c2->tun_read_bytes);
943 }
944 else
945 {
946 msg(M_WARN, "%s: no VPN RX bytes provided in reply for peer %u",
947 __func__, id);
948 }
949
951 {
952 c2->tun_write_bytes = nla_get_u64(tb[OVPN_A_PEER_VPN_TX_BYTES]);
953 msg(D_DCO_DEBUG, "%s / tun_write_bytes: " counter_format, __func__,
954 c2->tun_write_bytes);
955 }
956 else
957 {
958 msg(M_WARN, "%s: no VPN TX bytes provided in reply for peer %u",
959 __func__, id);
960 }
961}
962
963int
964dco_parse_peer_multi(struct nl_msg *msg, void *arg)
965{
966 struct nlattr *tb[OVPN_A_MAX + 1];
967 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
968
969 msg(D_DCO_DEBUG, "%s: parsing message...", __func__);
970
971 nla_parse(tb, OVPN_A_MAX, genlmsg_attrdata(gnlh, 0),
972 genlmsg_attrlen(gnlh, 0), NULL);
973
974 if (!tb[OVPN_A_PEER])
975 {
976 return NL_SKIP;
977 }
978
979 struct nlattr *tb_peer[OVPN_A_PEER_MAX + 1];
980 nla_parse_nested(tb_peer, OVPN_A_PEER_MAX, tb[OVPN_A_PEER], NULL);
981
982 if (!tb_peer[OVPN_A_PEER_ID])
983 {
984 msg(M_WARN, "%s: no peer-id provided in reply", __func__);
985 return NL_SKIP;
986 }
987
988 struct multi_context *m = arg;
989 uint32_t peer_id = nla_get_u32(tb_peer[OVPN_A_PEER_ID]);
990
991 if (peer_id >= m->max_clients || !m->instances[peer_id])
992 {
993 msg(M_WARN, "%s: cannot store DCO stats for peer %u", __func__,
994 peer_id);
995 return NL_SKIP;
996 }
997
998 dco_update_peer_stat(&m->instances[peer_id]->context.c2, tb_peer, peer_id);
999
1000 return NL_OK;
1001}
1002
1003int
1005 const bool raise_sigusr1_on_err)
1006{
1007 msg(D_DCO_DEBUG, "%s", __func__);
1008
1009 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_PEER_GET);
1010
1011 nlmsg_hdr(nl_msg)->nlmsg_flags |= NLM_F_DUMP;
1012
1013 int ret = ovpn_nl_msg_send(dco, nl_msg, dco_parse_peer_multi, m, __func__);
1014
1015 nlmsg_free(nl_msg);
1016
1017 if (raise_sigusr1_on_err && ret < 0)
1018 {
1019 msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer"
1020 "may have been deleted from the kernel without notifying "
1021 "userspace. Restarting the session");
1022 register_signal(m->top.sig, SIGUSR1, "dco peer stats error");
1023 }
1024 return ret;
1025}
1026
1027static int
1028dco_parse_peer(struct nl_msg *msg, void *arg)
1029{
1030 struct context *c = arg;
1031 struct nlattr *tb[OVPN_A_MAX];
1032 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1033
1034 msg(D_DCO_DEBUG, "%s: parsing message...", __func__);
1035
1036 nla_parse(tb, OVPN_A_PEER_MAX, genlmsg_attrdata(gnlh, 0),
1037 genlmsg_attrlen(gnlh, 0), NULL);
1038
1039 if (!tb[OVPN_A_PEER])
1040 {
1041 msg(D_DCO_DEBUG, "%s: malformed reply", __func__);
1042 return NL_SKIP;
1043 }
1044
1045 struct nlattr *tb_peer[OVPN_A_PEER_MAX + 1];
1046
1047 nla_parse(tb_peer, OVPN_A_PEER,
1048 nla_data(tb[OVPN_A_PEER]),
1049 nla_len(tb[OVPN_A_PEER]), NULL);
1050
1051 if (!tb_peer[OVPN_A_PEER_ID])
1052 {
1053 msg(M_WARN, "%s: no peer-id provided in reply", __func__);
1054 return NL_SKIP;
1055 }
1056
1057 uint32_t peer_id = nla_get_u32(tb_peer[OVPN_A_PEER_ID]);
1058 if (c->c2.tls_multi->dco_peer_id != peer_id)
1059 {
1060 return NL_SKIP;
1061 }
1062
1063 dco_update_peer_stat(&c->c2, tb_peer, peer_id);
1064
1065 return NL_OK;
1066}
1067
1068int
1069dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
1070{
1071 int peer_id = c->c2.tls_multi->dco_peer_id;
1072 if (peer_id == -1)
1073 {
1074 return 0;
1075 }
1076
1077 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id);
1078
1079 if (!c->c1.tuntap)
1080 {
1081 return 0;
1082 }
1083
1084 dco_context_t *dco = &c->c1.tuntap->dco;
1085 struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_PEER_GET);
1086 struct nlattr *attr = nla_nest_start(nl_msg, OVPN_A_PEER);
1087 int ret = -EMSGSIZE;
1088
1089 NLA_PUT_U32(nl_msg, OVPN_A_PEER_ID, peer_id);
1090 nla_nest_end(nl_msg, attr);
1091
1092 ret = ovpn_nl_msg_send(dco, nl_msg, dco_parse_peer, c, __func__);
1093
1094nla_put_failure:
1095 nlmsg_free(nl_msg);
1096
1097 if (raise_sigusr1_on_err && ret < 0)
1098 {
1099 msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer"
1100 "may have been deleted from the kernel without notifying "
1101 "userspace. Restarting the session");
1102 register_signal(c->sig, SIGUSR1, "dco peer stats error");
1103 }
1104 return ret;
1105}
1106
1107bool
1108dco_available(int msglevel)
1109{
1110 if (resolve_ovpn_netlink_id(D_DCO_DEBUG) < 0)
1111 {
1112 msg(msglevel,
1113 "Note: Kernel support for ovpn-dco missing, disabling data channel offload.");
1114 return false;
1115 }
1116
1117 return true;
1118}
1119
1120const char *
1122{
1123 return "Unknown";
1124}
1125
1126void
1127dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
1128{
1129 if (dco && dco->nl_sock)
1130 {
1131 event_ctl(es, nl_socket_get_fd(dco->nl_sock), EVENT_READ, arg);
1132 }
1133}
1134
1135const char *
1137{
1138 return "AES-128-GCM:AES-256-GCM:AES-192-GCM:CHACHA20-POLY1305";
1139}
1140
1141#endif /* defined(ENABLE_DCO) && defined(TARGET_LINUX) */
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition buffer.h:1097
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_A_KEYCONF
@ OVPN_A_MAX
@ OVPN_A_PEER
@ OVPN_A_IFINDEX
@ OVPN_CMD_KEY_DEL
@ OVPN_CMD_PEER_NEW
@ OVPN_CMD_PEER_GET
@ OVPN_CMD_KEY_SWAP
@ OVPN_CMD_KEY_SWAP_NTF
@ OVPN_CMD_PEER_DEL_NTF
@ OVPN_CMD_PEER_SET
@ OVPN_CMD_KEY_NEW
@ OVPN_CMD_PEER_DEL
@ OVPN_A_PEER_LINK_RX_BYTES
@ OVPN_A_PEER_VPN_IPV6
@ OVPN_A_PEER_LINK_TX_BYTES
@ OVPN_A_PEER_VPN_IPV4
@ OVPN_A_PEER_KEEPALIVE_TIMEOUT
@ OVPN_A_PEER_LOCAL_PORT
@ OVPN_A_PEER_VPN_TX_BYTES
@ OVPN_A_PEER_LOCAL_IPV6
@ OVPN_A_PEER_REMOTE_IPV6
@ OVPN_A_PEER_VPN_RX_BYTES
@ OVPN_A_PEER_MAX
@ OVPN_A_PEER_LOCAL_IPV4
@ OVPN_A_PEER_DEL_REASON
@ OVPN_A_PEER_ID
@ OVPN_A_PEER_SOCKET
@ OVPN_A_PEER_REMOTE_IPV4
@ OVPN_A_PEER_KEEPALIVE_INTERVAL
@ OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID
@ OVPN_A_PEER_REMOTE_PORT
#define OVPN_FAMILY_NAME
#define OVPN_MCGRP_PEERS
@ OVPN_A_KEYCONF_SLOT
@ OVPN_A_KEYCONF_PEER_ID
@ OVPN_A_KEYCONF_MAX
@ OVPN_A_KEYCONF_DECRYPT_DIR
@ OVPN_A_KEYCONF_CIPHER_ALG
@ OVPN_A_KEYCONF_ENCRYPT_DIR
@ OVPN_A_KEYCONF_KEY_ID
@ OVPN_A_KEYDIR_CIPHER_KEY
@ OVPN_A_KEYDIR_NONCE_TAIL
@ OVPN_MODE_MP
@ OVPN_MODE_P2P
#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
Control Channel SSL/Data channel negotiation module.
Control Channel Verification Module.
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:716
Definition tun.h:181
int type
Definition tun.h:183
dco_context_t dco
Definition tun.h:250
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