Arne Schwabe [Thu, 13 Aug 2026 17:02:05 +0000 (19:02 +0200)]
Replace SHA256 with SIPHASH24 in HMAC cookie approach
Using SHA256 for this is overkill since we only need a 64bit hash
value that is not predictable. Siphash24 also fulfils these
requirements while being much faster.
Change-Id: I3b6bb178ffb2bb49981bc23eabf04fe8e06d6fc3 Signed-off-by: Arne Schwabe <arne-openvpn@rfc2549.org> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1827
Message-Id: <20260813170211.29576-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38316.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Gleb Pesin [Thu, 13 Aug 2026 16:32:33 +0000 (18:32 +0200)]
OpenSSL: avoid resetting the HMAC key on every packet
OpenSSL 3.0.3 and newer can reinitialize an EVP_MAC HMAC
context with its existing key when EVP_MAC_init is called without
parameters. Use that path instead of supplying the digest and key
again on every OpenVPN HMAC reset.
Retain the old parameter-based reset for OpenSSL 3.0.0 through
3.0.2, where parameterless EVP_MAC reinitialization did not reset
the underlying HMAC implementation.
Github: closes OpenVPN/openvpn#1088
Change-Id: I1913a6e64b7ce22b66d2034df2a2fac33f60ea9f Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org> Acked-by: Razvan Cojocaru <razvanc@mailbox.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1840
Message-Id: <20260813163239.26557-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38313.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Max Fillinger [Thu, 13 Aug 2026 14:51:17 +0000 (16:51 +0200)]
Fix format string specifier for size_t
size_t being the same as unsigned long is true on Linux, but this
produces a warning when cross-compiling for Windows. Replace %lu with
the correct format specifier %zu.
Change-Id: Id8524d9c36ea913d557d3f43f1f62acc4186b4eb Signed-off-by: Max Fillinger <maximilian.fillinger@sentyron.com> Acked-by: Gert Doering <gert@greenie.muc.de> Acked-by: Razvan Cojocaru <razvanc@mailbox.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1843
Message-Id: <20260813145122.14606-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38303.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
ssl: Do not queue control ciphertext while a packet is still queued
An outgoing control channel packet is handed to the link layer as a
buffer descriptor pointing into the reliable send buffer it was built
from, and the packet id sits in that buffer's headroom, right in front
of the payload. If the entry is reused before the packet has been
written out, buf_copy_n() writes the new payload and
reliable_mark_active_outgoing() prepends the new packet id exactly over
the packet id of the queued packet, while its opcode, ACK array and
length stay untouched. The queued packet then goes out with somebody
else's packet id.
Observed in a TCP p2p handshake: both peers reset simultaneously, the
peer's two HARD_RESET packets arrive back to back, so io_wait_dowork()
takes the residual data shortcut (event_set_status = SOCKET_READ) and
does not write out our already queued HARD_RESET retransmit. The ACK
in the second peer reset then purges our reset from the send window,
tls_process_state() moves to S_START and queues the ClientHello into
the very same (now inactive) entry. Result on the wire: a HARD_RESET
with the ClientHello's packet id 1, followed by the ClientHello with
the same id 1. The receiver consumes the reset, advances its receive
window, and drops the real ClientHello as a replay - the handshake
deadlocks until it times out.
The send path in tls_process_state() and the dedicated ACK path in
tls_process() are already guarded by to_link->len, only the ciphertext
queueing was not. Guard it as well. A pending to_link makes
tls_process() report itself as active, so we are called again as soon
as the packet has been written out. In the error path this can drop a
TLS alert that we would have queued, which is in line with that path
not ensuring delivery anyway.
Change-Id: Ib0e7c9d3a2f4e6b8c1d5a9f7e3b2c4d6a8f1e5b3 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1831
Message-Id: <20260805134336.163392-1-frank@lichtenheld.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38133.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Thu, 13 Aug 2026 05:58:30 +0000 (07:58 +0200)]
Fix extracting IV_MTU
Commit 06ced3fd accidentally broke extracting the MTU from the peer
info while refactoring the code. Before 06ced3fd the code used
iv_mtu as temporary string and extracted the value into client_max_mtu.
The new code never set client_max_mtu and used iv_mtu as integer instead.
Fix this by setting client_max_mtu again with the real MTU value from
the peer.
Change-Id: Ia2e238a41526ebc178c53d3807103d8b9da475a5 Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1842
Message-Id: <20260813055836.32422-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38291.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Mon, 10 Aug 2026 11:42:06 +0000 (13:42 +0200)]
Reenable xmit_hold when using p2p tcp-server and tls-server
Commit 619c3e9 changed the logic to enable xmit_hold only
when c->mode is CM_CHILD_TCP. This works for --mode server and
was probably done to allow to properly work when the server
is listening on multiple sockets and options->ce.proto cannot be used
to determine if this socket is tcp or udp.
Restore the logic for p2p to avoid both sides starting sending
resets at the same time.
In order to achieve a multipeer functionality, peers now
use separate IDs for sending (tx_peer_id) and receiving
(rx_peer_id).
Each peer announces its own ID through pushing peer-info
using 'ID=7f1' hex format so identification can still
happen even if IP/port changes.
In P2P mode, peer switch to using the announced IDs after
mutual exchange.
In P2MP mode, clients always announce their ID, and servers
can optionally respond with their own to enable the same
behavior.
Change-Id: I0a13ee90b6706acf20eabcee3bab3f2dff639bf9 Signed-off-by: Gianmarco De Gregori <gianmarco@mandelbit.com> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1089
Message-Id: <20260728122355.2566-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37944.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Thu, 6 Aug 2026 15:32:51 +0000 (17:32 +0200)]
Add aws-lc siphash implementation
AWS-LC has a siphash implementation that is just a simple function call
that also performs the same/better than the reference implementation that
it looks to be based on. AWS-lc variant seems to have come from boringssl
according to the Google copyright.
The return type of the siphash related function has been also removed as
neither the reference nor the aws-lc implementation can fail. Only the
OpenSSL based implementation needed a return type.
Change-Id: I05e20f8c82494e4abf96fe1e3a73e1c7b9101af6 Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1572
Message-Id: <20260806153251.66170-1-frank@lichtenheld.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38181.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Thu, 6 Aug 2026 15:32:30 +0000 (17:32 +0200)]
Use OpenSSL's SIPHASH implementation to double check our implementation
OpenSSL library is currently slower than the reference implementation
(about 1.5x to 2x depending of the compiler).
The OpenSSL API for using the SIPHASH MAC is different enough from using
normal HMAC or Digest that we already implement that combining them into
one API does not make sense.
SIPHASH is only available on OpenSSL 3.1 and later. We still check for
support on 3.0 and later as the whole API to allow using the SIPHASH alrady
exists in OpenSSL 3.0. Some of the later OpenSSL 3.0.x might get support
for it. Theoretically, a provider can be loaded in OpenSSL 3.0 that
implements SIPHASH.
With OpenSSL's implementation being slower, we currently only use it to
check that our reference implementation and the OpenSSL implementation
yield the same result in unit tests
Change-Id: I09aa27caa1a3aab0d1be6118b26d54a1c1bf7aa0 Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/31
Message-Id: <20260806153230.65971-1-frank@lichtenheld.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38180.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Thu, 6 Aug 2026 10:29:21 +0000 (12:29 +0200)]
Change hash iv to a be a fixed sized array
While for our own hash function, always using an uint32_t works well, it does
not work very well if we move to another hash function like siphash that
requires a larger key.
To avoid allocating a specific context, change the API to be a fixed size
array of size 4. This define allows use to easily change it to a larger
value if we use hash functions that require larger keys.
Change-Id: If47c7d920b2fa4047b7db03fcde821899839324d Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1571
Message-Id: <20260806102926.28206-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38162.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Thu, 6 Aug 2026 09:09:45 +0000 (11:09 +0200)]
Remove local get_random in test_misc.c
The get_random in test_misc.c conflicts
with the get_random function that OpenVPN defines in crypto.h
Also adjust the implementation in mock_get_random.c to match the
prototype in crypto.h
Change-Id: I3db70001be7f39cf84d562517647f1a305962b42 Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Antonio Quartulli <antonio@mandelbit.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1834
Message-Id: <20260806090951.20900-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38155.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Lev Stipakov [Wed, 5 Aug 2026 13:46:14 +0000 (15:46 +0200)]
mudp: extract send_standalone_reply() helper
Factor the synchronous, stateless "send a standalone control
packet back to the peer that just contacted us" sequence out of
send_hmac_reset_packet() into a reusable helper. No behavioural change.
This lets a following commit reuse it for the out-of-band probe reply
instead of duplicating the aux_buf / to_link / process_outgoing_link
sequence.
Change-Id: Ic75ca2ee9b59a4e11f37cd9653df268bba33889c Signed-off-by: Lev Stipakov <lev@openvpn.net> Acked-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Antonio Quartulli <antonio@mandelbit.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1743
Message-Id: <20260805134614.163847-1-frank@lichtenheld.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38134.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
interactive: forbid "--setenv opt" in startup data
CheckOption() white-lists the command line options passed to the
service by name only. As "setenv" is white-listed, a caller could
pass "--setenv opt <option>", which bypasses option validation.
Reject "--setenv opt ..." after the white-list lookup.
ssl: Ignore hard reset packets with a non-zero packet id
A hard reset is always the first packet of a session, so it always
carries reliable packet id 0. tls_process_state() relies on that when it
treats a received reset as the early negotiation packet only for packet
id 0, and the stateless three-way handshake relies on it as well (see
the comment in session_skip_to_pre_start()).
A reset claiming a different id is therefore bogus.
We had a bug that could cause hard reset replays with packet id 1 in
specific scenarios (P2P TCP). In that case we accepted the packet id
at face value and then ignored the control packet that actually had
id 1 as an replay. This caused a difficult to diagnose dead connection
that was stuck just before TLS negotiation. The check added handles
this specific scenario well in that we just ignore the bogus reset
but do not abort the connection attempt. Starting fresh might retrigger
the bug. If there would be a separate bug where the client only sends
hard resets with packet id 1 we will still get logging on the server
side now.
Change-Id: I3c7d1f9e5b2a4c6d8e1f3a5b7c9d2e4f6a8b1c3d Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1832
Message-Id: <20260731114605.11596-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38098.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Gert Doering [Thu, 30 Jul 2026 20:46:37 +0000 (22:46 +0200)]
t_server_null: run server processes with 'ulimit -t 300'
"ulimit -t" will hard limit the usable CPU time for any process started
to the specified number of seconds. So if we have a stuck-and-looping
server process (which was observed frequently) this will make sure
the situation will fix itself eventually.
Change-Id: I7e5ac9b4a8594251c3b5c4655f9d74b021950098 Signed-off-by: Gert Doering <gert@greenie.muc.de> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/777
Message-Id: <20260730204642.27250-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38088.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Wed, 29 Jul 2026 06:41:52 +0000 (08:41 +0200)]
Correctly calculate packet id size when epoch packet format is in use
The code assumed that always when tls mode (without CFB/OFB) is in use
that the packet size is 4 bytes. With epoch packet format is incorrect
as that uses 64 bit.
Even thought packet_id_long_form has a the same size (8 byte) it is not
the same header format (32 bit time + 32 bit IV) as the epoch
format (16 bit epoch + 48 IV). Use a simple sizeof(uint64_t) to
avoid suggesting that it might be the same.
Github: closes OpenVPN/openvpn#1074
Change-Id: I5b862eabe032eb4d2229ff5b2f4f6af7406f6f4e Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Antonio Quartulli <antonio@mandelbit.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1829
Message-Id: <20260729064158.15731-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37983.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
cppcheck complained about the creation of a useless
variable on Windows. With the old code this was not
fixable in a good way. So rewrite the whole code to
hopefully be much more readable.
While testing this we also found out that the old
code was not really working on Solaris, so disable
support for that.
Gert Doering contributed support for NetBSD.
Github: closes OpenVPN/openvpn#1034
Change-Id: Ibe7b3c17176c97a1cbb4d9cc87735b05e62c4f43 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1675
Message-Id: <20260724220839.26402-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37863.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
With this change, OpenVPN can be launched without specifying
any --dev option and it will start a `tun` (L3) tunnel with the
interface named `tunX`.
As before, this behaviour can be changed using --dev or --dev-type.
Existing configs won't see any behavioural change as they all
had to contain at least one --dev directive.
Change-Id: I0ca7b5b7ec1a01acaad222c99db137c94c88555a Signed-off-by: Antonio Quartulli <antonio@mandelbit.com> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1537
Message-Id: <20260724055529.1376-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37825.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
If installing a DCO key succeeds, always record the slot in the
corresponding key_state. The installed-key counter only tracks whether
the number of kernel slots grew, but a successful KEY_NEW still means
that this key_state is associated with the selected DCO slot.
Also replace DCO key-state assertions in dco_update_keys() with error
returns. This preserves the invariant checks but lets the existing
caller restart the connection instead of aborting the process if
userspace ever detects inconsistent DCO key state.
Marco Baffo [Wed, 22 Jul 2026 20:52:05 +0000 (22:52 +0200)]
options: limit ping and keepalive values to one day
A correct configuration should not require such large ping intervals or
timeouts, and an upper limit of one day is already generous.
Limit --ping, --ping-exit, --ping-restart and --keepalive values to
86400 seconds. Since --keepalive doubles the timeout in server mode,
limit its timeout argument to 43200 seconds there.
Enable TCP_NODELAY by default and push it to clients
TCP_NODELAY had to be requested explicitly via
--tcp-nodelay or "socket-flags TCP_NODELAY". Enable
it unconditionally on every TCP socket instead
(dco-win is skipped as it manages its own socket).
The socket_set_flags() and
link_socket_update_flags() plumbing that only ever
applied it is dropped; the SF_TCP_NODELAY sockflag
and "socket-flags TCP_NODELAY" become no-ops, the
latter kept for backwards compatibility.
--tcp-nodelay no longer touches the local socket
but, in --mode server, still pushes "socket-flags
TCP_NODELAY" to clients, for the benefit of clients
older than 2.7.6 that do not enable it by default.
On a client the option is deprecated and inert. It
can be dropped once such clients are gone.
Change-Id: I434a5373f77b0f7570a6a2aafe0eaf970e2eabe7 Signed-off-by: Antonio Quartulli <antonio@mandelbit.com> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1797
Message-Id: <20260721124452.27832-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37726.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Max Fillinger [Wed, 22 Jul 2026 16:37:55 +0000 (18:37 +0200)]
Remove --providers from --help output for Mbed TLS
This option is OpenSSL-only. When used with Mbed TLS, it prints warnings
and does not do anything. With this change, the option is still parsed,
to ensure compatiblity of configurations, but it is removed from the
--help text.
Change-Id: I0f56ca69efae0ca376eb9eae064a893c8768188e Signed-off-by: Max Fillinger <maximilian.fillinger@sentyron.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1799
Message-Id: <20260722163800.2474-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37781.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Max Fillinger [Wed, 22 Jul 2026 15:25:14 +0000 (17:25 +0200)]
Make --x509-username-field work with Mbed TLS
In pre-2.7 versions, this option was not available in the Mbed TLS
build. This was changed in 2.7, but the option did not do anything when
Mbed TLS was selected as the crypto library. Regardless of the field
chosen with --x509-username-field, OpenVPN would always extract the CN
as username.
This could lead to a situation where an unintended certificate gets
accepted by OpenVPN: If we run with "--x509-username-field serialNumber"
and "--verify-x509-name 0x05 name", OpenVPN would accept a certificate
with CN=0x05 and an incorrect serial number, while a certificate with
the correct serial number would be rejected. (Though note that to
exploit this, an attacker needs to make the CA sign a certificate
with a hexadecimal number in the CN.)
This commit adds code to backend_x509_get_username to extract the
correct field values from X509 certificates. It also changes the
behavior of the function to match the OpenSSL version when the output
buffer is too small. (With Mbed TLS, the function would silently
truncate the output and return SUCCESS.)
It also adds unit tests for extracting the values of different fields.
Despite this commit fixing a CVE, we have decided not to keep it under
embargo until the release of the next version because it is unlikely to
be exploitable in practice: Someone has to run OpenVPN 2.7 with Mbed
TLS, use the --x509-username-field option even though it didn't exist in
Mbed TLS builds of earlier versions, not notice that the intended
certificate is *not* accepted, and then an attacker has to get the CA to
sign a certificate with a weird common name.
CVE: 2026-63650
Github: openvpn/openvpn-private-issues#144 Reported-By: Hcamael Reported-By: 章鱼哥 (www.aipyaipy.com)
Change-Id: Ic183f1f1f90561454b7b1128c95255368427cc4a Signed-off-by: Max Fillinger <maximilian.fillinger@sentyron.com> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1801
Message-Id: <20260722152521.22272-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37773.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
This has also been reported twice as a security relevant bug, but
only later than the original finding - and it isn't.
While --client-nat would modify a 32bit integer "after the packet"
(the place where an IPv4 address would be, in a well-formed packet),
the underlying buffer is always max-frame sized, and we never look
at the "modified integer" afterwards, so there are no consequences
warranting allocation of a CVE ID.
Signed-off-by: rootvector2 <dxbnaveed.k@gmail.com> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org> Acked-by: Antonio Quartulli <antonio@mandelbit.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1789 Reported-By: 章鱼哥 (www.aipyaipy.com) Reported-By: Yu Zhang Wong <wongyuzhang45@gmail.com>
Change-Id: I8219c6295acf28ff10ddb2fcc285f813c42fa8fe
Message-Id: <20260715202210.9010-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37652.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Wed, 8 Jul 2026 15:31:07 +0000 (17:31 +0200)]
Replace strtok with strtok_r
This does not change anything in our source code but makes compiling
with newer Android NDKs (version 30 pre release) -Werror safe again
as it has started throwing warning on this.
The compat version is taken from current FreeBSD (commit dc36d6f9bb1)
src/lib/libc/string/strtok.c and reformatted to our clang standard.
Change-Id: I70560efd113308b7377424127eb2c1da4266371a Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1679
Message-Id: <20260708153107.60809-1-frank@lichtenheld.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37538.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
- Exclude tests that use verify_script on Windows.
We currently do not have openvpn_execve available
for Windows tests. It would also need more work
to replace the hardcoded paths.
- Use platform_gen_path instead of hard-coding /
Do to the previous change that is not strictly
necessary, but it also doesn't hurt and it fixes
at least one issue if anyone ever decides to port
this to Windows).
Change-Id: I45ddc8e350d3948b3197ae725df102d8ce73fa77 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Lev Stipakov <lstipakov@gmail.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1781
Message-Id: <20260714121238.13936-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37593.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
t_client.sh.in: Do not run resolvectl if systemd is not running
In some cases we will have resolvectl installed but no
running systemd. E.g. on old Ubuntu distros resolvectl
is part of the main systemd package which we have installed
as a build-dependency.
Supress the warnings from resolvectl in this case.
Change-Id: I677d3206c24aad997889ed76fb8eca2e6f4b1259 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1778
Message-Id: <20260713151816.22005-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37566.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Lev Stipakov [Thu, 9 Jul 2026 14:42:40 +0000 (16:42 +0200)]
CMake: detect cmocka_version.h via include path, not by linking
check_include_files() was invoked with cmocka in CMAKE_REQUIRED_LIBRARIES,
which makes the probe link the (shared, imported) cmocka library. On some
platforms that link step fails inside the minimal probe, so the header check
reports failure and HAVE_CMOCKA_VERSION_H is left undefined even though
cmocka_version.h is present.
test_common.h then selects its cmocka 1.x compatibility shims and redefines
macros (check_expected_uint, expect_uint_value, ...) that cmocka 2.x already
provides, which breaks the -Werror build of every unit test driver.
Detecting a header only needs the include search path, so pass cmocka's
INTERFACE_INCLUDE_DIRECTORIES via CMAKE_REQUIRED_INCLUDES and drop the library
link requirement from the probe.
Change-Id: Icc14b286f2409738c73873aa7550dcc005ee8cbb Signed-off-by: Lev Stipakov <lev@openvpn.net> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1739
Message-Id: <20260709144240.61362-1-frank@lichtenheld.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37552.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
ssl_pkt: Fix doxygen warning about read_control_auth
Commit 01ee1693f960a696a613e7b83f9960002264a379
("Ensure tls-crypt keys are not setup twice") removed
the argument but did not delete it from the doxygen
documentation, leading to warnings.
Change-Id: I20cc89a546b69aceadcd1630828de407d530d7c7 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1765
Message-Id: <20260702100704.24692-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37459.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Thu, 18 Jun 2026 14:33:43 +0000 (16:33 +0200)]
Ensure tls-crypt keys are not setup twice
Commit 82ee2fe4b42d already did this when the session id stayed the same
but forgot the other code path that could also lead to tls-crypt keys to be
setup.
This approach was a bit too fragile as it missed some other code path
that might trigger the same behaviour. This commit changes the logic
to directly infer if the key is already initialised instead of taking
a proxy (like key state as the previous commit did).
The fix in commit 7a6ab5773 (#121, #127) made sure that we do not try
to extract the tls-crypt-v2 key multiple times and made the unit test
basically not work as the extraction was skipped and then could also
not fail anymore. I could work around it in the unit test but improving
tls_wrap_free felt preferable.
CVE: 2026-13698 Reported-By: Max Fillinger <maximilian.fillinger@sentyron.com>
Github: OpenVPN/openvpn-private-issues#137
Github: OpenVPN/openvpn-private-issues#138
Change-Id: I3b5e4e84762aa253d46e69103f7b1e84ebefca1d Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-By: Max Fillinger <maximilian.fillinger@sentyron.com>
Lev Stipakov [Fri, 22 May 2026 09:05:43 +0000 (12:05 +0300)]
openvpnserv: fix DNS SearchList state pollution on (dis)connect
RemoveDnsSearchDomains used wcsstr on the comma-separated SearchList,
so removing a VPN-pushed domain like "vpn.corp.local" could match
inside an unrelated pre-existing entry like "test.vpn.corp.local"
and corrupt it. The wmemmove length was also too short, truncating
the tail of the list when the removed segment was shorter than what
followed. The wcsncmp against InitialSearchList was prefix-only too,
so a shortened list that happened to be a prefix of the initial one
triggered a spurious reset.
Replace the manual cut with two pure helpers that are unit-tested in
test_openvpnserv.c:
* AppendSearchList just appends the requested string, with a separator
comma if the list is non-empty. No deduplication: pushed domains are
always appended verbatim.
* RemoveSearchListTokens uses multiset semantics. For each comma-
separated token in the undo string it finds the last remaining
token in the list that fully matches (no substring) and splices it
out in place. If a domain appears K times in the list and L times in
the undo set, min(K, L) instances are removed.
Together these properties give the right behavior under overlap:
user has "corp.local"; VPN pushes "corp.local"
-> SearchList = "corp.local,corp.local"
-> on disconnect one occurrence is removed, user's entry preserved.
session A pushes "openvpn.com"; session B pushes "openvpn.com"
-> SearchList = "openvpn.com,openvpn.com"
-> A disconnects: one removed, B still sees its domain.
-> B disconnects: list returns to original.
AddDnsSearchDomains and RemoveDnsSearchDomains are now thin wrappers
around the helpers: read SearchList, call the helper, write back,
plus the StoreInitialDnsSearchList / ResetDnsSearchDomains dance.
Max Fillinger [Fri, 22 May 2026 14:55:13 +0000 (16:55 +0200)]
Fix ack_write_buf use after free
If the active TLS session has a pending dedicated ACK packet,
tls_multi_process sets to_link to ks->ack_write_buf. If in the same
execution of tls_multi_process, the initializing session reaches the
authenticated stage, the active session will be freed which leaves
to_link.data pointing to freed memory.
This commit extends check_session_buf_not_used so that it also checks
ks->ack_write_buf for all key states.
Max Fillinger [Fri, 22 May 2026 12:34:57 +0000 (14:34 +0200)]
Fix tls_wrap_reneg use after free
When dynamic tls-crypt is active, it is possible for tls_multi_process
to set to_link to session->tls_wrap_reneg.work and later free that
session, leaving to_link.data pointing to freed memory.
This is not caught by the function check_session_buf_not_used because it
checks only tls_wrap, not tls_wrap_reneg. This commit adds that check.
Arne Schwabe [Mon, 15 Jun 2026 18:35:07 +0000 (20:35 +0200)]
Clean up metadata handling in tls_crypt_v2_extract_client_key
This makes the metadata a local variable instead of a member of the
wrap_context struct. Also always ensure that this buffer is freed to
avoid any leak of the metadata buffer.
This touches the check methods. Ensure that they still work as
intended by adding unit tests for both script and age checks.
dco.c: fix argument order in dco_install_key() log string
The debug log in dco_install_key() has the epoch and dco_keys_installed
arguments swapped. So a line like epoch=1, currently 0 keys installed
actually means dco_keys_installed == 1 and epoch == false.
Use the correct argument ordering in the log string.
Lev Stipakov [Mon, 29 Jun 2026 12:48:34 +0000 (14:48 +0200)]
win32: fix plugin trusted-dir check prefix bypass
plugin_in_trusted_dir() validated the plugin path against the trusted
plugin/install directory (and the system directory fallback) using a raw
string prefix match via wcsnicmp(). When the trusted directory path does
not end in a separator (e.g. the plugin_dir registry value is set to
"C:\openvpn_plugins"), a sibling directory sharing the same prefix
("C:\openvpn_plugins_evil") also passes the check, allowing a plugin to
be loaded from outside the allow-listed directory.
Introduce win_path_in_dir() in win32-util.c which performs the prefix
match but additionally requires the match to end on a path-component
boundary, and use it for both the plugin/install directory and the
system directory checks. Add unit tests in test_misc.c.
Heiko Hund [Sun, 28 Jun 2026 13:02:50 +0000 (15:02 +0200)]
openvpnserv: rework ConvertItfDnsDomains and tests
Since there were issues with in-place modification of the buffer
repeatedly, re-implement ConvertItfDnsDomains() to use a internal
temporary buffer to prevent use of memmove and the length calculations
that come with it. Code should be easier to grasp since we're dealing
with one set of lengths (WCHARs) instead of two (WCHARs + octets) now.
The unit tests did not actually test the MULTI_SZs correctly, fixed
that and also added some more tests to cover more scenarios.
This was initially reported as a security vulnerability, as the previous
code could be tricked into overreading a buffer and accessing undefined
memory - but we decided against assigning a CVE ID because the data read
is subsequently never leaked anywhere, and it was not possible to trigger
a crash, so "just a bug, no security implications".
Arne Schwabe [Fri, 26 Jun 2026 15:29:46 +0000 (17:29 +0200)]
Make get_random return int64 instead of long
This avoids having get_ranomd being different on 32bit/Windows vs
64 bit Unix platform. Also adjust platform_create_temp_file to
create the same files on all platforms.
Change-Id: Ifefb3ad204c0c16cb4952dd6e8661fdc9136b125 Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1732
Message-Id: <20260626152951.29207-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37322.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
options: fix use-after-free of DNS options on client connect
struct dns_options embeds its own gc_arena. When inherit_context_child()
/inherit_context_top() copy struct options by value, the child shares the
parent's DNS arena. options_detach() detached o->gc but not
o->dns_options.gc, so pre_connect_restore()'s gc_free() (and context
teardown) freed allocations the parent still referenced.
With one or more non-pushed --dhcp-option directives that yield a DNS
entry, a connecting client triggers this and the server crashes
(use-after-free in setenv_dns_options(), reported as a double free).
Detach o->dns_options.gc as well, mirroring the existing o->gc handling.
Change-Id: I49b37b5a90554fa2d4a83c8fc5608dad2a36b835
GitHub: closes openvpn/OpenVPN#1060 Signed-off-by: Antonio Quartulli <antonio@mandelbit.com> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1715
Message-Id: <20260622120856.21586-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37230.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
saddamr3e [Thu, 18 Jun 2026 06:18:28 +0000 (08:18 +0200)]
dns: Fix memory leak in dns_server_addr_parse
When the DNS server's address count is already full (exceeds the
limit of 8), the function returned early without freeing the
successfully resolved addrinfo struct. Fix this by checking the
limit before executing the DNS lookup.
udp_flags does not guarantee correct association with the socket being
processed. Use the rwflags delivered by the event engine along with the
event to ensure proper per-socket I/O handling.
Remove udp_flags entirely.
Replace the previous global-style flag computation with a per-socket
decision model in p2mp_iow_flags(), which derives I/O flags
directly from the current multi_context state and the specific socket
being processed. This ensures that read/write decisions are correctly
bound to the active socket rather than shared or implicit global state.
This change is based on an investigation triggered by a report from
Joshua Rogers using ZeroPath.
Change-Id: I6b303805a3688b6f6363140c76853a58badecd8f Signed-off-by: Gianmarco De Gregori <gianmarco@mandelbit.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1635
Message-Id: <20260616162129.28519-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37198.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Tue, 9 Jun 2026 15:52:06 +0000 (17:52 +0200)]
AWS-LC: Use openssl_stack_size_t for declaring stack size
OpenSSL and AWS-LC disagree on the type that they use for
stack size. Instead of doing a lot of various casts, use
a typedef to avoid these casts and use the right type for
each library.
Change-Id: Ifd29485524674c64d56fc5f7ef8bdd1e00215fc9 Signed-off-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1627
Message-Id: <20260609155211.30747-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37144.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Since Github will switch to windows-2025 image to use
VS 2026 at some point in the near future (according to
https://github.blog/changelog/2026-02-05-github-actions-early-february-2026-updates/#windows-server-2025-with-visual-studio-2026-image-now-available-for-github-hosted-runners)
enforce that switch to avoid any build failures. Since
we hardcode the VS version in CMakePresets.json (and I
do not see an easy way to avoid this with CMake), we
need to override the generator value. We can switch the
default once our release infrastructure has been switched
to VS 2026.
Change-Id: I8a17d452e9e5690a5507d17129286142df6c88f1 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Arne Schwabe <arne-openvpn@rfc2549.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1711
Message-Id: <20260609152123.27460-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37139.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Max Fillinger [Tue, 9 Jun 2026 10:24:01 +0000 (12:24 +0200)]
Null-terminate tls-crypt client keys when testing
After generating a tls-crypt-v2 client key, OpenVPN will try to load the
generated key to verify that it was generated correctly. If the client
key is not written to disk but printed out on the command line, the PEM
encoded key is stored in memory and read_pem_key_file is called with
key_file_inline = true. However, this key is not a null-terminated
string, so we end up calling strlen on a buffer that isn't
null-terminated.
This commit adds a null-byte at the end of the key.
Change-Id: I2ca8bf90a796f2b757c2fde0ae24468ef3abc3b5 Signed-off-by: Max Fillinger <maximilian.fillinger@sentyron.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1701
Message-Id: <20260609102407.32590-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37116.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Building a HARD_RESET reply was queueing the result into three
multi_context fields and deferring the send to the next event-loop
iteration, where multi_process_outgoing_link() flushed it:
1. hmac_reply_dest = &m->top.c2.from stored a pointer alias into
shared mutable state. Any subsequent read into m->top.c2.from
silently retargeted the pending reply to a different peer.
2. m->hmac_reply_ls = sock; at the top of multi_get_create_instance_udp()
was executed unconditionally for every UDP packet, including packets
that did not queue a reply. A stale queued reply could thus be sent
on the wrong listening socket.
3. hmac_reply.data pointed into m->top.c2.buffers->aux_buf (the only
slot). A second send_hmac_reset_packet() before the first flush
would overwrite the first reply's bytes.
These were latent on master because m->multi_io->udp_flags was consumed
and zeroed by the first event in each multi_io_process_io() loop, so at
most one UDP read ran per outer iteration.
Send the reply synchronously from within send_hmac_reset_packet() using
the sock that the read fired on (threaded through do_pre_decrypt_check).
The reply is small, stateless, and rate-limited by the existing
reflect_filter_rate_limit_check(); dropping on EAGAIN is acceptable
because the client retransmits its HARD_RESET. The three multi_context
fields and the deferred-flush block in multi_process_outgoing_link() are
gone; p2mp_iow_flags() no longer needs an IOW_TO_LINK branch for hmac
state.
Change-Id: I2df0fec786184b9fcf9b7c56c74816325cdb6942 Signed-off-by: Antonio Quartulli <antonio@mandelbit.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1702
Message-Id: <20260609075413.17380-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37117.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
When port-share is used, enforce the presence
of a TCP listener by checking the local_list
entries insted of rely on the global
connection_entry proto field.
Github: fixes OpenVPN/openvpn#1027
Change-Id: Id4e21efebbe64b963cf7847ad77bc41339af7a37 Signed-off-by: Gianmarco De Gregori <gianmarco@mandelbit.com> Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1680
Message-Id: <20260520101152.17453-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg36986.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Massively improve how we call cppcheck to cover
more code and identify more issues.
When specifying any -D argument all other defines
are ignored unless --force or --max-configs is
specified as well. I mistakenly assumed that this
was covered by --check-level=exhaustive. We need
to try finding a value for --max-configs so that
cppcheck doesn't spend hours scanning options.c
Add a library cfg for our code which for now
- identifies some printf-style functions
- adds some common macro defines
Use existing libraries.
Add a second call to cppcheck to separate the
Windows and Unixy code scans. This avoids some
very non-sensical define combinations.
Change-Id: I05720ccc3bcf706bbe62254afb74562580f5de56 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1665
Message-Id: <20260607170713.4980-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg37078.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
Arne Schwabe [Fri, 5 Jun 2026 18:09:25 +0000 (20:09 +0200)]
Ensure pushed tun-mtu is no lower than TUN_MTU_MIN
The normal path ensure that the minimum tun mtu is set to at least
TUN_MTU_MIN. However, the pushed options path does not have this
restriction.
Check that the tun-mtu is within the limits of min/max mtu
in options.c. This ensure that the check is also correctly done
on the pushed variant.
Also add an extra check to keep the allowed payload for icmp6 packets
to be at least 64 bytes in the the block-ipv6 code path
(ipv6_send_icmp_unreachable) as extra layer of defence.
Pushing a low mtu like 1 and also block-ipv6 could trigger an
assertion in the ipv6_send_icmp_unreachable code path.
Lev Stipakov [Fri, 5 Jun 2026 14:18:02 +0000 (16:18 +0200)]
socket: assert buffer length before reading prepended sockaddr family
read_sockaddr_from_packet() inspected sa->sa_family before any check
on buf->len, so a short delivery from the dco-win driver would have
produced a garbage peer address from uninitialized buffer memory.
The driver always prepends a full sockaddr and validates the family
before writing, so reaching any of the size/family checks would mean
something is severely wrong on the driver side - assert the three
preconditions instead of M_FATAL'ing on them.
- Fix some uninitalised fields due to BUF_INIT_TRACKING
(found by cppcheck and the original reason for this
change).
- Fix "unused functions" if only BUF_INIT_TRACKING is
defined.
- Fix conversion error
Change-Id: I3ecb76d9022dcd7dae92eb5e9d62e5f018744883 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1666
Message-Id: <20260513092251.28857-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg36901.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
dco_freebsd: Add check_malloc_return after realloc
cppcheck complained about a potential memleak
due to realloc failure. But trying to handle that
is probably not useful. Just abort like we do
for other malloc failures.
Change-Id: Icd8ea093dfe9f1888570f3d7b786b951b5262e47 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1669
Message-Id: <20260507075321.25123-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg36842.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
t_client.sh: Do not use CA_CERT variable as indicator for good .rc file
t_client.sh doesn't actually care about this variable, and our
.rc files do not use it anymore. If you really want to dynamically
skip running t_client.sh just set TEST_RUN_LIST to empty in the .rc
file.
Change-Id: I7cf7146c3c4f1a01b0bcb57e03d09b32f8b59780 Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1664
Message-Id: <20260506145933.22301-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg36827.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
dns-scripts: Fix dnssec values in comments and Copyright statement format
- Fix the example value of dnssec to an actual valid one
- Fix the formatting of the Copyright statements to be
consistent with all other files in the project
Change-Id: Id6832e3f56420debc8b19d0144d53ca41abb678b Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com> Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1645
Message-Id: <20260430130354.25337-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg36800.html Signed-off-by: Gert Doering <gert@greenie.muc.de>