[L] Change in openvpn[master]: Add lookup of multi session by session id
"plaisthos \(Code Review\) via Openvpn-devel" <[email protected]> Mon, 3 Aug 2026 13:25:30 +0000
| Newsgroups | gmane.network.openvpn.devel |
|---|---|
| Message-ID | <4894f5a259baa58153249f13d24a065715754812-EmailReplacePatchSet-HTML@gerrit.openvpn.net> |
--===============0367511233571082502==
Content-Transfer-Encoding: 8bit
Content-Disposition: inline
Content-Type: multipart/alternative; boundary="TnPoNrKfDZg="; charset=UTF-8
--TnPoNrKfDZg=
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hello flichtenheld,
I'd like you to reexamine a change=2E Please visit
=
http://gerrit=2Eopenvpn=2Enet/c/openvpn/+/1727?usp=3Demail
to look at t=
he new patch set (#25)=2E
Change subject: Add lookup of multi session by =
session id
=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=
=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=
=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E
A=
dd lookup of multi session by session id
This refactors the way that we lo=
okup control channel packets for UDP
packets from other peers=2E Instead of=
looking them up by their source
IP address, we lookup the session ids inst=
ead=2E
It also has the consequence that we can have multiple ongoing
sessi=
ons from the same source IP address and the new session will
go through all=
the connect steps like an initial session=2E
The check if the new session=
can take over the old session's IP
is now also the same as for floating=2E=
This eliminates a whole class of bugs that we currently have that
break c=
onnection if the reconnecting client has different
capabilities as the setu=
p and negotiation is inherited from the
previous client currently=2E Curren=
tly there is at least one bug
regarding the dynamic tls-crypt in this situa=
tion=2E
This also changes the user visible behaviour for clients
reconnect=
ing from the same IP and port=2E They are now almost
behaving like clients =
that reconnect from a different IP
address=2E These now do the whole renego=
tiation and run
connect scripts/plugins and all the things are normally
ski=
pped when reconnecting from the same IP and port=2E
The only difference is=
that duplicate-cn does not
allow both connection=2E
This will also eventu=
ally allow us to get rid of TM_INITIAL
slot as we now do no longer need to =
keep an ongoing and a
new session anymore=2E Currently the p2p mode still n=
eeds
the extra session slot for the new session so we cannot
remove it just=
yet=2E
This now allows a multiple pending session from the
same source IP=
and port=2E Previously a client would need
to use a different ports to cre=
ate multiple pending
session=2E This change does not make it really easier =
to
exhaust all pending session than before=2E
Change-Id: Idb59ecd119331b19=
8792ad1379bec8600211651b
Signed-off-by: Arne Schwabe <arne@rfc2549=2Eorg>
-=
--
M CMakeLists=2Etxt
M doc/man-sections/advanced-options=2Erst
M src/openv=
pn/Makefile=2Eam
M src/openvpn/mtcp=2Ec
M src/openvpn/mudp=2Ec
M src/openvp=
n/multi=2Ec
M src/openvpn/multi=2Eh
M src/openvpn/options=2Ec
M src/openvpn=
/options=2Eh
A src/openvpn/sid_hash=2Eh
M tests/unit_tests/openvpn/Makefile=
=2Eam
M tests/unit_tests/openvpn/test_misc=2Ec
12 files changed, 270 insert=
ions(+), 59 deletions(-)
git pull ssh://gerrit=2Eopenvpn=2Enet:29418/op=
envpn refs/changes/27/1727/25
diff --git a/CMakeLists=2Etxt b/CMakeLists=
=2Etxt
index 9b31b1a=2E=2E40fea99 100644
--- a/CMakeLists=2Etxt
+++ b/CMake=
Lists=2Etxt
@@ -839,6 +839,7 @@
src/openvpn/siphash=2Eh
s=
rc/openvpn/siphash=2Ec
src/openvpn/siphash_reference=2Ec
+ =
src/openvpn/session_id=2Ec
)
target_sources(test_ncp PRIVATE
di=
ff --git a/doc/man-sections/advanced-options=2Erst b/doc/man-sections/advan=
ced-options=2Erst
index 3eff3085=2E=2Eb20c3f7 100644
--- a/doc/man-sections=
/advanced-options=2Erst
+++ b/doc/man-sections/advanced-options=2Erst
@@ -2=
9,16 +29,18 @@
--hash-size args
Set the size of the real address hash=
table to ``r`` and the virtual
- address table to ``v``=2E
+ address tab=
le to ``v``=2E If specified set the size of session id hash table
+ to ``s=
``=2E Otherwise ``s`` will be set to the same value as ``r``=2E
Valid =
syntax:
::
- hash-size r v
+ hash-size r v [s]
- By default=
, both tables are sized at 4 times ``--max-clients`` buckets=2E
+ By defau=
lt, all three tables are sized at 4 times ``--max-clients`` buckets=2E
W=
ith the default of 1024 of ``--max-clients`` this gives 4096 buckets=2E
+=
--bcast-buffers n
Allocate ``n`` buffers for broadcast datagrams (defa=
ult :code:`256`)=2E
diff --git a/src/openvpn/Makefile=2Eam b/src/openvpn/=
Makefile=2Eam
index f5a7621=2E=2Eeb3533c 100644
--- a/src/openvpn/Makefile=
=2Eam
+++ b/src/openvpn/Makefile=2Eam
@@ -127,6 +127,7 @@
schedule=2Ec sc=
hedule=2Eh \
session_id=2Ec session_id=2Eh \
shaper=2Ec shaper=2Eh \
+ =
sid_hash=2Eh \
sig=2Ec sig=2Eh \
siphash_reference=2Ec \
siphash=2Ec =
siphash=2Eh \
diff --git a/src/openvpn/mtcp=2Ec b/src/openvpn/mtcp=2Ec
inde=
x f000283=2E=2Eeb4e944 100644
--- a/src/openvpn/mtcp=2Ec
+++ b/src/openvpn/=
mtcp=2Ec
@@ -42,36 +42,12 @@
{
struct gc_arena gc =3D gc_new();
=
struct multi_instance *mi =3D NULL;
- struct hash *hash =3D m->hash;
=
mi =3D multi_create_instance(m, NULL, sock);
if (mi)
{
=
mi->real=2Eproto =3D sock->info=2Eproto;
- struct hash_element *h=
e;
- const uint64_t hv =3D hash_value(hash, &mi->real);
- str=
uct hash_bucket *bucket =3D hash_bucket(hash, hv);
-
multi_assign_=
peer_id(m, mi);
-
- he =3D hash_lookup_fast(hash, bucket, &mi->real,=
hv);
-
- if (he)
- {
- struct multi_instance *old=
mi =3D (struct multi_instance *)he->value;
- msg(D_MULTI_LOW,
- =
"MULTI TCP: new incoming client address matches existing cli=
ent address -- new client takes precedence");
- oldmi->did_real_=
hash =3D false;
- multi_close_instance(m, oldmi, false);
- =
he->key =3D &mi->real;
- he->value =3D mi;
- }
- =
else
- {
- hash_add_fast(hash, bucket, &mi->real, hv=
, mi);
- }
-
- mi->did_real_hash =3D true;
}
#ifdef E=
NABLE_DEBUG
diff --git a/src/openvpn/mudp=2Ec b/src/openvpn/mudp=2Ec
index =
08c634e=2E=2E5924d9b 100644
--- a/src/openvpn/mudp=2Ec
+++ b/src/openvpn/mu=
dp=2Ec
@@ -32,6 +32,7 @@
#include "memdbg=2Eh"
#include "ssl_pkt=2Eh"
+=
#include "sid_hash=2Eh"
#ifdef HAVE_SYS_INOTIFY_H
#include <sys/inotify=
=2Eh>
@@ -186,7 +187,7 @@
}
else
{
- =
msg(D_MULTI_DEBUG,
+ msg(D_MULTI_MEDIUM,
"Valid=
packet (%s) with HMAC challenge from peer (%s), "
"accept=
ing new connection=2E",
packet_opcode_name(op), peer);
@@ =
-212,7 +213,6 @@
struct link_socket *sock,
=
struct mroute_addr *real)
{
- struct hash *hash =
=3D m->hash;
struct tls_pre_decrypt_state state =3D { 0 };
struct=
multi_instance *mi =3D NULL;
struct gc_arena gc =3D gc_new();
@@ -243=
,11 +243,6 @@
mi =3D multi_create_instance(m, real, sock);
=
if (mi)
{
- const uint64_t hv =3D has=
h_value(hash, real);
- struct hash_bucket *bucket =3D hash_b=
ucket(hash, hv);
- hash_add_fast(hash, bucket, &mi->real, hv=
, mi);
-
- mi->did_real_hash =3D true;
mult=
i_assign_peer_id(m, mi);
/* If we have a session id alre=
ady, ensure that the
@@ -262,6 +257,7 @@
{
=
session_skip_to_pre_start(session, &state, &m->top=2Ec2=2Efro=
m);
}
+ multi_hash_sid_add(m, &stat=
e=2Epeer_session_id, mi);
}
}
}
@@ -=
298,15 +294,26 @@
return NULL;
}
-struct multi_instance *
-multi_ge=
t_instance_udp_control(struct multi_context *m, struct link_socket *sock)
-=
{
- struct mroute_addr real =3D { 0 };
- real=2Eproto =3D sock->info=
=2Eproto;
- if (mroute_extract_openvpn_sockaddr(&real, &m->top=2Ec2=2E=
from=2Edest, true) && m->top=2Ec2=2Ebuf=2Elen > 0)
+static struct multi_ins=
tance *
+multi_get_instance_udp_control(struct multi_context *m)
+{
+ /*=
Copy buffer, to a tmp buffer, so that reading the sesison does not
+ *=
modify the internal pointers */
+ struct buffer tmp =3D m->top=2Ec2=2Eb=
uf;
+
+ /* op code */
+ uint8_t op =3D (uint8_t)buf_read_u8(&tmp) >> =
P_OPCODE_SHIFT;
+ (void)op;
+
+ struct session_id sid =3D { 0 };
+ =
session_id_read(&sid, &tmp);
+
+ struct hash_element *he_sid =3D multi_=
hash_sid_lookup(m, &sid);
+
+ if (he_sid)
{
- return multi_g=
et_instance_udp_real(m, &real);
+ return he_sid->value;
}
=
return NULL;
@@ -392,7 +399,14 @@
}
else
{
- mi =3D=
multi_get_instance_udp_control(m, sock);
+ if (m->top=2Ec2=2Ebuf=2E=
len < (int)SID_SIZE + 1)
+ {
+ /* control packets must be=
at least the opcode byte + session id
+ * (8 byte) long, other=
wise they are not valid packets */
+ return NULL;
+ }
+
+=
mi =3D multi_get_instance_udp_control(m);
/* we have no =
existing multi instance for this connection, control
* packets ca=
n create a session=2E Data packets cannot */
diff --git a/src/openvpn/multi=
=2Ec b/src/openvpn/multi=2Ec
index 20b4f14=2E=2E60e89fb 100644
--- a/src/op=
envpn/multi=2Ec
+++ b/src/openvpn/multi=2Ec
@@ -42,6 +42,7 @@
#include "vl=
an=2Eh"
#include "auth_token=2Eh"
#include "route=2Eh"
+#include "sid_has=
h=2Eh"
#include <inttypes=2Eh>
#include <string=2Eh>
@@ -271,8 +272,8 @=
@
struct multi_context *m =3D t->multi;
int dev =3D DEV_TYPE_UNDE=
F;
- msg(D_MULTI_LOW, "MULTI: multi_init called, r=3D%d v=3D%d", t->op=
tions=2Ereal_hash_size,
- t->options=2Evirtual_hash_size);
+ msg(=
D_MULTI_LOW, "MULTI: multi_init called, r=3D%d v=3D%d s=3D%d", t->options=
=2Ereal_hash_size,
+ t->options=2Evirtual_hash_size, t->options=2Esi=
d_hash_size);
/*
* Get tun/tap/null device type
@@ -300,6 +301=
,12 @@
m->vhash =3D hash_init(t->options=2Evirtual_hash_size,
=
mroute_addr_hash_function, mroute_addr_compare_function);=
+ /*
+ * Peer session id hash table=2E Used to lookup a session b=
y the session
+ * id of one of its active sessions */
+ m->sid_hash =
=3D hash_init(t->options=2Esid_hash_size,
+ sess=
ion_id_hash_function, session_id_hash_equal);
+
#ifdef ENABLE_MANAGEMENT
=
m->cid_hash =3D hash_init(t->options=2Ereal_hash_size, cid_hash_functio=
n, cid_compare_function);
#endif
@@ -427,8 +434,7 @@
buf_prin=
tf(&out, "%s/", cn);
}
buf_printf(&out, "%s", mroute_addr=
_print(&mi->real, gc));
- if (mi->context=2Ec2=2Etls_multi && check_=
debug_level(D_DCO_DEBUG)
- && dco_enabled(&mi->context=2Eoptions=
))
+ if (mi->context=2Ec2=2Etls_multi)
{
buf_p=
rintf(&out, " rx-peer-id=3D%d", mi->context=2Ec2=2Etls_multi->rx_peer_id);
=
}
@@ -598,6 +604,12 @@
}
#endif
+
+ if (session=
_id_defined(&mi->sid_hashed_value))
+ {
+ multi_hash_sid_=
remove(m, &mi->sid_hashed_value);
+ }
+
if (mi->context=2Ec=
2=2Etls_multi->rx_peer_id !=3D MAX_PEER_ID)
{
m->inst=
ances[mi->context=2Ec2=2Etls_multi->rx_peer_id] =3D NULL;
@@ -672,6 +684,7 =
@@
hash_free(m->hash);
hash_free(m->vhash);
+ ha=
sh_free(m->sid_hash);
#ifdef ENABLE_MANAGEMENT
hash_free(m->cid_h=
ash);
#endif
@@ -2456,6 +2469,34 @@
multi_client_connect_setenv(mi);
=
}
+static bool
+multi_check_dest_addr_allowed(struct multi_context *m, s=
truct multi_instance *mi, struct mroute_addr *real);
+
+/**
+ * This sets u=
p the client real address (outer tunnel addr) in the
+ * hash map for data =
channel packet=2E If the address is already taken
+ * this steps fails
+ */=
+static enum client_connect_return
+multi_client_connect_real_addr(struct =
multi_context *m, struct multi_instance *mi,
+ =
bool deferred, uint64_t *option_types_found)
+{
+ /* If the address is=
already taken up by another client we fail the new
+ * connection */
+=
if (!multi_check_dest_addr_allowed(m, mi, &mi->real))
+ {
+ m=
sg(D_MULTI_ERRORS,
+ "MULTI: client IP address and port already =
assigned to another "
+ "client, terminating connection");
+ =
return CC_RET_FAILED;
+ }
+
+ ASSERT(!mi->did_real_hash);
+ AS=
SERT(hash_add(m->hash, &mi->real, mi, false));
+ mi->did_real_hash =3D t=
rue;
+ return CC_RET_SUCCEEDED;
+}
+
/**
* Do the necessary modifica=
tion for doing the compress migrate=2E This is
* implemented as a connec=
t handler as it fits the modify config for a client
@@ -2550,6 +2591,7 @@
=
uint64_t *option_types_found);
static const multi_client_connect_han=
dler client_connect_handlers[] =3D {
+ multi_client_connect_real_addr,
=
multi_client_connect_compress_migrate,
multi_client_connect_source=
_ccd,
multi_client_connect_call_plugin_v1,
@@ -2618,6 +2660,7 @@
=
}
return true;
}
+
/*
* Called as soon as the SSL/TLS connection i=
s authenticated=2E
*
@@ -3104,7 +3147,7 @@
/* do not allow if target=
address is taken by client with another cert */
if (!cert_hash_compar=
e(m1->locked_cert_hash_set, m2->locked_cert_hash_set))
{
- msg(=
D_MULTI_LOW, "Disallow float to an address taken by another client %s",
+ =
msg(D_MULTI_LOW, "Disallow float/connect to an address taken by anoth=
er client %s",
multi_instance_string(ex_mi, false, &gc));
=
mi->context=2Ec2=2Ebuf=2Elen =3D 0;
@@ -3117,7 +3160,7 @@
i=
f (!m1->locked_username || !m2->locked_username
|| strcmp(m1->=
locked_username, m2->locked_username) !=3D 0)
{
- msg(D=
_MULTI_LOW, "Disallow float to an address taken by another client %s",
+ =
msg(D_MULTI_LOW, "Disallow float/connect to an address taken by an=
other client %s",
multi_instance_string(ex_mi, false, &gc)=
);
goto done;
}
diff --git a/src/openvpn/multi=2Eh b/=
src/openvpn/multi=2Eh
index 8b837fa=2E=2E98547b0 100644
--- a/src/openvpn/m=
ulti=2Eh
+++ b/src/openvpn/multi=2Eh
@@ -131,7 +131,15 @@
in_addr_t re=
porting_addr; /* IP address shown in status listing */
stru=
ct in6_addr reporting_addr_ipv6; /* IPv6 address in status listing */
+ =
/** Indicates that the real address/port of the client is hashed in
+ =
* the multi_context m->hash table=2E */
bool did_real_hash;
+
+ /*=
* If this is multi_instance is hashed in the sid lookup table the session
+=
* id here is a non-null session id and the hash map's key pointer poin=
ts
+ * to this field (the value pointer points to the whole struct) */
=
+ struct session_id sid_hashed_value;
+
#ifdef ENABLE_MANAGEMENT
b=
ool did_cid_hash;
struct buffer_list *cc_config;
@@ -170,6 +178,12 @@
=
* address of the remote peer=2E =
*/
struct hash *vhash; /**< VPN tunnel instances indexe=
d by
* virtual address of remote=
hosts=2E */
+ struct hash *sid_hash; /**< TLS sessions inde=
xed by the peer's
+ session id=
=2E We do not care about
+ colli=
sions here as clients should
+ h=
ave unique ids and supporting
+ =
clients with identical SIDs
+ is=
not needed */
struct schedule *schedule;
struct mbuf_set *mbuf; =
/**< Set of buffers for passing data
=
* channel packets between VPN tunnel
diff --git a/src/open=
vpn/options=2Ec b/src/openvpn/options=2Ec
index d0f447c=2E=2E629652e 100644=
--- a/src/openvpn/options=2Ec
+++ b/src/openvpn/options=2Ec
@@ -3764,6 +37=
64,10 @@
{
o->virtual_hash_size =3D 4 * o->max_clients;
=
}
+ if (!o->sid_hash_size)
+ {
+ o->sid_hash_size =3D o->real_=
hash_size;
+ }
}
static void
@@ -7367,7 +7371,7 @@
options-=
>ifconfig_ipv6_pool_base =3D network;
options->ifconfig_ipv6_pool_=
netbits =3D netbits;
}
- else if (streq(p[0], "hash-size") && p[1] =
&& p[2] && !p[3])
+ else if (streq(p[0], "hash-size") && p[1] && p[2] &&=
!p[4])
{
int real, virtual;
@@ -7379,6 +7383,16 @@
=
}
options->real_hash_size =3D (uint32_t)real;
options->=
virtual_hash_size =3D (uint32_t)virtual;
+
+ if (p[3])
+ {
+ =
int sid;
+ if (!atoi_constrained(p[3], &sid, "hash-si=
ze sid", 1, INT_MAX, msglevel))
+ {
+ goto err;
+=
}
+ options->sid_hash_size =3D (uint32_t)sid;
+ =
}
}
else if (streq(p[0], "connect-freq") && p[1] && p[2] && !p=
[3])
{
diff --git a/src/openvpn/options=2Eh b/src/openvpn/options=2Eh
=
index 30a146f=2E=2Ec7825c7 100644
--- a/src/openvpn/options=2Eh
+++ b/src/o=
penvpn/options=2Eh
@@ -498,6 +498,7 @@
uint32_t real_hash_size;
=
uint32_t virtual_hash_size;
+ uint32_t sid_hash_size;
const char *=
client_connect_script;
const char *client_disconnect_script;
cons=
t char *learn_address_script;
diff --git a/src/openvpn/sid_hash=2Eh b/src/o=
penvpn/sid_hash=2Eh
new file mode 100644
index 0000000=2E=2E4667fb1
--- /de=
v/null
+++ b/src/openvpn/sid_hash=2Eh
@@ -0,0 +1,90 @@
+/*
+ * OpenVPN -- =
An application to securely tunnel IP networks
+ * over a single=
TCP/UDP port, with support for SSL/TLS-based
+ * session authe=
ntication and key exchange,
+ * packet encryption, packet authe=
ntication, and
+ * packet compression=2E
+ *
+ * Copyright (C)=
2026 OpenVPN Inc <sales@openvpn=2Enet>
+ * Copyright (C) 2026 Arne Schwab=
e <arne@rfc2549=2Eorg>
+ *
+ *
+ * This program is free software; you can =
redistribute it and/or modify
+ * it under the terms of the GNU General Pu=
blic License version 2
+ * as published by the Free Software Foundation=2E=
+ *
+ * This program is distributed in the hope that it will be useful,
+=
* but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MER=
CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE=2E See the
+ * GNU Gener=
al Public License for more details=2E
+ *
+ * You should have received a c=
opy of the GNU General Public License along
+ * with this program; if not,=
write to the Free Software Foundation, Inc=2E,
+ * 51 Franklin Street, Fi=
fth Floor, Boston, MA 02110-1301 USA=2E
+ */
+
+#include "session_id=2Eh"
+=
#include "multi=2Eh"
+#include "list=2Eh"
+#include "siphash=2Eh"
+
+inline=
static void
+multi_hash_sid_add(struct multi_context *m, struct session_id=
*sid,
+ struct multi_instance *mi)
+{
+ /* This must =
only be called if the multi instance is not already present
+ * in the =
hash table */
+ ASSERT(!session_id_defined(&mi->sid_hashed_value));
+
+ =
mi->sid_hashed_value =3D *sid;
+
+ const uint64_t hv =3D hash_value(m=
->sid_hash, &mi->sid_hashed_value);
+ struct hash_bucket *bucket =3D has=
h_bucket(m->sid_hash, hv);
+ hash_add_fast(m->sid_hash, bucket, &mi->sid=
_hashed_value, hv, mi);
+ multi_instance_inc_refcount(mi);
+}
+
+static =
inline struct hash_element *
+multi_hash_sid_lookup(struct multi_context *m=
, const struct session_id *sid)
+{
+ const uint64_t sid_hv =3D hash_valu=
e(m->sid_hash, sid);
+ struct hash_bucket *sid_bucket =3D hash_bucket(m-=
>sid_hash, sid_hv);
+ struct hash_element *he_sid =3D hash_lookup_fast(m=
->sid_hash, sid_bucket, sid, sid_hv);
+ return he_sid;
+}
+
+inline stat=
ic bool
+multi_hash_sid_remove(struct multi_context *m, const struct sessio=
n_id *sid)
+{
+ const uint64_t sid_hv =3D hash_value(m->sid_hash, sid);
=
+ struct hash_bucket *sid_bucket =3D hash_bucket(m->sid_hash, sid_hv);
+=
struct hash_element *he_sid =3D hash_lookup_fast(m->sid_hash, sid_bucke=
t, sid, sid_hv);
+ if (he_sid)
+ {
+ struct multi_instance *mi=
=3D he_sid->value;
+ ASSERT(hash_remove_fast(m->sid_hash, sid_bucke=
t, sid, sid_hv));
+ CLEAR(mi->sid_hashed_value);
+ multi_inst=
ance_dec_refcount(mi);
+ return true;
+ }
+ else
+ {
+ =
return false;
+ }
+}
+
+/* hashing the session=2E As the struct is ju=
st an 8 byte array
+ * hashing is straight forward */
+static inline uint64=
_t
+session_id_hash_function(const void *key, const uint8_t hash_key[HASH_K=
EY_LEN])
+{
+ return siphash_hash_func(key, sizeof(struct session_id), h=
ash_key);
+}
+
+/* wrapper for session_id_equal to have the void* arguments=
that the
+ * hash map requires */
+static inline bool
+session_id_hash_equ=
al(const void *sid1, const void *sid2)
+{
+ return session_id_equal((str=
uct session_id *)sid1, (struct session_id *)sid2);
+}
diff --git a/tests/un=
it_tests/openvpn/Makefile=2Eam b/tests/unit_tests/openvpn/Makefile=2Eam
ind=
ex 6af25b1=2E=2Eb4611dd 100644
--- a/tests/unit_tests/openvpn/Makefile=2Eam=
+++ b/tests/unit_tests/openvpn/Makefile=2Eam
@@ -383,7 +383,8 @@
$(top_s=
rcdir)/src/openvpn/platform=2Ec \
$(top_srcdir)/src/openvpn/list=2Ec \
=
$(top_srcdir)/src/openvpn/siphash=2Ec \
- $(top_srcdir)/src/openvpn/siphash=
_reference=2Ec
+ $(top_srcdir)/src/openvpn/siphash_reference=2Ec \
+ $(top_=
srcdir)/src/openvpn/session_id=2Ec
push_update_msg_testdriver_CFLAGS =3D=
-I$(top_srcdir)/src/openvpn \
-I$(top_srcdir)/src/compat \
diff --git a/=
tests/unit_tests/openvpn/test_misc=2Ec b/tests/unit_tests/openvpn/test_misc=
=2Ec
index ab21d5e=2E=2Eb094344 100644
--- a/tests/unit_tests/openvpn/test_=
misc=2Ec
+++ b/tests/unit_tests/openvpn/test_misc=2Ec
@@ -42,6 +42,7 @@
#i=
fdef _WIN32
#include "win32-util=2Eh"
#endif
+#include "sid_hash=2Eh"
=
static void
test_compat_lzo_string(void **state)
@@ -142,13 +143,6 @@
=
return strcmp((const char *)key1, (const char *)key2) =3D=3D 0;
}
-stat=
ic uint32_t
-get_random(void)
-{
- /* rand() is not very random, but it'=
s C99 and this is just for testing */
- return (uint32_t)rand();
-}
-
s=
tatic struct hash_element *
hash_lookup_by_value(struct hash *hash, void *=
value)
{
@@ -264,7 +258,7 @@
{
struct hash_iterator =
hi;
struct hash_element *he;
- inc =3D (get_random(=
) % 3) + 1;
+ inc =3D ((int)get_random() % 3) + 1;
=
hash_iterator_init_range(hash, &hi, base, base + inc);
while=
((he =3D hash_iterator_next(&hi)))
@@ -479,6 +473,65 @@
}
#endif /* _WIN=
32 */
+
+static void
+test_sid_hash_list(void **state)
+{
+ struct gc_=
arena gc =3D gc_new();
+ /* very simple tests to ensure the basic hash f=
unctions work */
+
+ struct multi_context m =3D { 0 };
+ m=2Esid_hash=
=3D hash_init(2048, session_id_hash_function, session_id_hash_equal);
+
+ =
struct session_id sid1;
+ struct session_id sid2;
+ struct session=
_id sid3;
+
+ struct multi_instance *m1, *m3;
+
+ /* multi_hash_sid_r=
emove will call gc_free on the gc of a mi and
+ * free on the mi itself=
*/
+ ALLOC_OBJ_CLEAR(m1, struct multi_instance);
+ ALLOC_OBJ_CLEAR(m=
3, struct multi_instance);
+
+ m1->gc =3D gc_new();
+ m3->gc =3D gc_n=
ew();
+
+ session_id_random(&sid1);
+ session_id_random(&sid2);
+ =
session_id_random(&sid3);
+
+ multi_hash_sid_add(&m, &sid1, m1);
+ mu=
lti_hash_sid_add(&m, &sid3, m3);
+
+
+ /* sid2 is not added and should n=
ot be returned */
+ struct hash_element *he_sid =3D multi_hash_sid_looku=
p(&m, &sid2);
+ assert_null(he_sid);
+
+ he_sid =3D multi_hash_sid_lo=
okup(&m, &sid1);
+ assert_non_null(he_sid);
+ assert_ptr_equal(he_sid=
->value, m1);
+
+ /* Try removing elements, only that are in the map sho=
uld return true */
+ assert_true(multi_hash_sid_remove(&m, &sid1));
+ =
assert_false(multi_hash_sid_remove(&m, &sid2));
+ assert_false(multi_ha=
sh_sid_remove(&m, &sid1));
+
+ /* should no longer find the element */
+=
he_sid =3D multi_hash_sid_lookup(&m, &sid1);
+ assert_null(he_sid);
=
+
+ /* this element should still be in the hash table */
+ he_sid =3D=
multi_hash_sid_lookup(&m, &sid3);
+ assert_ptr_equal(he_sid->value, m3)=
;
+
+ assert_true(multi_hash_sid_remove(&m, &sid3));
+
+ hash_free(m=
=2Esid_hash);
+ gc_free(&gc);
+}
+
const struct CMUnitTest misc_tests[]=
=3D {
#ifdef _WIN32
cmocka_unit_test(test_win_path_in_dir),
@@ -488,=
7 +541,8 @@
cmocka_unit_test(test_auth_fail_temp_flags),
cmocka_u=
nit_test(test_auth_fail_temp_flags_msg),
cmocka_unit_test(test_list),
=
- cmocka_unit_test(test_atoi_variants)
+ cmocka_unit_test(test_atoi_v=
ariants),
+ cmocka_unit_test(test_sid_hash_list)
};
int
--
To view=
, visit http://gerrit=2Eopenvpn=2Enet/c/openvpn/+/1727?usp=3Demail
To unsub=
scribe, or for help writing mail filters, visit http://gerrit=2Eopenvpn=2En=
et/settings?usp=3Demail
Gerrit-MessageType: newpatchset
Gerrit-Project: op=
envpn
Gerrit-Branch: master
Gerrit-Change-Id: Idb59ecd119331b198792ad1379be=
c8600211651b
Gerrit-Change-Number: 1727
Gerrit-PatchSet: 25
Gerrit-Owner: p=
laisthos <arne-openvpn@rfc2549=2Eorg>
Gerrit-Reviewer: flichtenheld <frank@=
lichtenheld=2Ecom>
Gerrit-CC: openvpn-devel <openvpn-devel@lists=2Esourcefo=
rge=2Enet>
--TnPoNrKfDZg=
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<!DOCTYPE html><html><head><style></style></head><body><p>plaisthos <strong=
>uploaded patch set #25</strong> to this change=2E</p><p><a href=3D"http://=
gerrit=2Eopenvpn=2Enet/c/openvpn/+/1727?usp=3Demail">View Change</a></p><pr=
e class=3D"blocks" style=3D"font-family: monospace,monospace; white-space: =
pre-wrap;">Add lookup of multi session by session id<br><br>This refactors =
the way that we lookup control channel packets for UDP<br>packets from othe=
r peers=2E Instead of looking them up by their source<br>IP address, we loo=
kup the session ids instead=2E<br><br>It also has the consequence that we c=
an have multiple ongoing<br>sessions from the same source IP address and th=
e new session will<br>go through all the connect steps like an initial sess=
ion=2E<br><br>The check if the new session can take over the old session=
9;s IP<br>is now also the same as for floating=2E<br><br>This eliminates a =
whole class of bugs that we currently have that<br>break connection if the =
reconnecting client has different<br>capabilities as the setup and negotiat=
ion is inherited from the<br>previous client currently=2E Currently there i=
s at least one bug<br>regarding the dynamic tls-crypt in this situation=2E<=
br><br>This also changes the user visible behaviour for clients<br>reconnec=
ting from the same IP and port=2E They are now almost<br>behaving like clie=
nts that reconnect from a different IP<br>address=2E These now do the whole=
renegotiation and run<br>connect scripts/plugins and all the things are no=
rmally<br>skipped when reconnecting from the same IP and port=2E<br><br>The=
only difference is that duplicate-cn does not<br>allow both connection=2E<=
br><br>This will also eventually allow us to get rid of TM_INITIAL<br>slot =
as we now do no longer need to keep an ongoing and a<br>new session anymore=
=2E Currently the p2p mode still needs<br>the extra session slot for the ne=
w session so we cannot<br>remove it just yet=2E<br><br>This now allows a mu=
ltiple pending session from the<br>same source IP and port=2E Previously a =
client would need<br>to use a different ports to create multiple pending<br=
>session=2E This change does not make it really easier to<br>exhaust all pe=
nding session than before=2E<br><br>Change-Id: Idb59ecd119331b198792ad1379b=
ec8600211651b<br>Signed-off-by: Arne Schwabe <arne@rfc2549=2Eorg><br>=
---<br>M CMakeLists=2Etxt<br>M doc/man-sections/advanced-options=2Erst<br>M=
src/openvpn/Makefile=2Eam<br>M src/openvpn/mtcp=2Ec<br>M src/openvpn/mudp=
=2Ec<br>M src/openvpn/multi=2Ec<br>M src/openvpn/multi=2Eh<br>M src/openvpn=
/options=2Ec<br>M src/openvpn/options=2Eh<br>A src/openvpn/sid_hash=2Eh<br>=
M tests/unit_tests/openvpn/Makefile=2Eam<br>M tests/unit_tests/openvpn/test=
_misc=2Ec<br>12 files changed, 270 insertions(+), 59 deletions(-)<br><br></=
pre><pre class=3D"blocks" style=3D"font-family: monospace,monospace; white-=
space: pre-wrap;">git pull ssh://gerrit=2Eopenvpn=2Enet:29418/openvpn refs/=
changes/27/1727/25</pre><pre style=3D"font-family: monospace,monospace; whi=
te-space: pre-wrap;"><span>diff --git a/CMakeLists=2Etxt b/CMakeLists=2Etxt=
</span><br><span>index 9b31b1a=2E=2E40fea99 100644</span><br><span>--- a/CM=
akeLists=2Etxt</span><br><span>+++ b/CMakeLists=2Etxt</span><br><span>@@ -8=
39,6 +839,7 @@</span><br><span> src/openvpn/siphash=2Eh</span><br><=
span> src/openvpn/siphash=2Ec</span><br><span> src/openvpn/=
siphash_reference=2Ec</span><br><span style=3D"color: hsl(120, 100%, 40%);"=
>+ src/openvpn/session_id=2Ec</span><br><span> )</span><br><span=
> </span><br><span> target_sources(test_ncp PRIVATE</span><br><span>dif=
f --git a/doc/man-sections/advanced-options=2Erst b/doc/man-sections/advanc=
ed-options=2Erst</span><br><span>index 3eff3085=2E=2Eb20c3f7 100644</span><=
br><span>--- a/doc/man-sections/advanced-options=2Erst</span><br><span>+++ =
b/doc/man-sections/advanced-options=2Erst</span><br><span>@@ -29,16 +29,18 =
@@</span><br><span> </span><br><span> --hash-size args</span><br><span> S=
et the size of the real address hash table to ``r`` and the virtual</span><=
br><span style=3D"color: hsl(0, 100%, 40%);">- address table to ``v``=2E</=
span><br><span style=3D"color: hsl(120, 100%, 40%);">+ address table to ``=
v``=2E If specified set the size of session id hash table</span><br><span s=
tyle=3D"color: hsl(120, 100%, 40%);">+ to ``s``=2E Otherwise ``s`` will be=
set to the same value as ``r``=2E</span><br><span> </span><br><span> Val=
id syntax:</span><br><span> ::</span><br><span> </span><br><span style=3D=
"color: hsl(0, 100%, 40%);">- hash-size r v</span><br><span style=3D"co=
lor: hsl(120, 100%, 40%);">+ hash-size r v [s]</span><br><span> </span>=
<br><span style=3D"color: hsl(0, 100%, 40%);">- By default, both tables ar=
e sized at 4 times ``--max-clients`` buckets=2E</span><br><span style=3D"co=
lor: hsl(120, 100%, 40%);">+ By default, all three tables are sized at 4 t=
imes ``--max-clients`` buckets=2E</span><br><span> With the default of 10=
24 of ``--max-clients`` this gives 4096 buckets=2E</span><br><span> </span>=
<br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span> --bcast-=
buffers n</span><br><span> Allocate ``n`` buffers for broadcast datagrams=
(default :code:`256`)=2E</span><br><span> </span><br><span>diff --git a/sr=
c/openvpn/Makefile=2Eam b/src/openvpn/Makefile=2Eam</span><br><span>index f=
5a7621=2E=2Eeb3533c 100644</span><br><span>--- a/src/openvpn/Makefile=2Eam<=
/span><br><span>+++ b/src/openvpn/Makefile=2Eam</span><br><span>@@ -127,6 +=
127,7 @@</span><br><span> schedule=2Ec schedule=2Eh \</span><br><span> se=
ssion_id=2Ec session_id=2Eh \</span><br><span> shaper=2Ec shaper=2Eh \</sp=
an><br><span style=3D"color: hsl(120, 100%, 40%);">+ sid_hash=2Eh \</span><=
br><span> sig=2Ec sig=2Eh \</span><br><span> siphash_reference=2Ec \</spa=
n><br><span> siphash=2Ec siphash=2Eh \</span><br><span>diff --git a/src/op=
envpn/mtcp=2Ec b/src/openvpn/mtcp=2Ec</span><br><span>index f000283=2E=2Eeb=
4e944 100644</span><br><span>--- a/src/openvpn/mtcp=2Ec</span><br><span>+++=
b/src/openvpn/mtcp=2Ec</span><br><span>@@ -42,36 +42,12 @@</span><br><span=
> {</span><br><span> struct gc_arena gc =3D gc_new();</span><br><span> =
struct multi_instance *mi =3D NULL;</span><br><span style=3D"color: hsl=
(0, 100%, 40%);">- struct hash *hash =3D m->hash;</span><br><span> </=
span><br><span> mi =3D multi_create_instance(m, NULL, sock);</span><br>=
<span> if (mi)</span><br><span> {</span><br><span> mi->r=
eal=2Eproto =3D sock->info=2Eproto;</span><br><span style=3D"color: hsl(=
0, 100%, 40%);">- struct hash_element *he;</span><br><span style=3D"=
color: hsl(0, 100%, 40%);">- const uint64_t hv =3D hash_value(hash, =
&mi->real);</span><br><span style=3D"color: hsl(0, 100%, 40%);">- =
struct hash_bucket *bucket =3D hash_bucket(hash, hv);</span><br><span =
style=3D"color: hsl(0, 100%, 40%);">-</span><br><span> multi_assign=
_peer_id(m, mi);</span><br><span style=3D"color: hsl(0, 100%, 40%);">-</spa=
n><br><span style=3D"color: hsl(0, 100%, 40%);">- he =3D hash_lookup=
_fast(hash, bucket, &mi->real, hv);</span><br><span style=3D"color: =
hsl(0, 100%, 40%);">-</span><br><span style=3D"color: hsl(0, 100%, 40%);">-=
if (he)</span><br><span style=3D"color: hsl(0, 100%, 40%);">- =
{</span><br><span style=3D"color: hsl(0, 100%, 40%);">- struct=
multi_instance *oldmi =3D (struct multi_instance *)he->value;</span><br=
><span style=3D"color: hsl(0, 100%, 40%);">- msg(D_MULTI_LOW,</s=
pan><br><span style=3D"color: hsl(0, 100%, 40%);">- "MU=
LTI TCP: new incoming client address matches existing client address -- new=
client takes precedence");</span><br><span style=3D"color: hsl(0, 100=
%, 40%);">- oldmi->did_real_hash =3D false;</span><br><span s=
tyle=3D"color: hsl(0, 100%, 40%);">- multi_close_instance(m, old=
mi, false);</span><br><span style=3D"color: hsl(0, 100%, 40%);">- =
he->key =3D &mi->real;</span><br><span style=3D"color: hsl(0, 1=
00%, 40%);">- he->value =3D mi;</span><br><span style=3D"colo=
r: hsl(0, 100%, 40%);">- }</span><br><span style=3D"color: hsl(0, 10=
0%, 40%);">- else</span><br><span style=3D"color: hsl(0, 100%, 40%);=
">- {</span><br><span style=3D"color: hsl(0, 100%, 40%);">- =
hash_add_fast(hash, bucket, &mi->real, hv, mi);</span><br><span s=
tyle=3D"color: hsl(0, 100%, 40%);">- }</span><br><span style=3D"colo=
r: hsl(0, 100%, 40%);">-</span><br><span style=3D"color: hsl(0, 100%, 40%);=
">- mi->did_real_hash =3D true;</span><br><span> }</span><br>=
<span> </span><br><span> #ifdef ENABLE_DEBUG</span><br><span>diff --git a/s=
rc/openvpn/mudp=2Ec b/src/openvpn/mudp=2Ec</span><br><span>index 08c634e=2E=
=2E5924d9b 100644</span><br><span>--- a/src/openvpn/mudp=2Ec</span><br><spa=
n>+++ b/src/openvpn/mudp=2Ec</span><br><span>@@ -32,6 +32,7 @@</span><br><s=
pan> </span><br><span> #include "memdbg=2Eh"</span><br><span> #in=
clude "ssl_pkt=2Eh"</span><br><span style=3D"color: hsl(120, 100%=
, 40%);">+#include "sid_hash=2Eh"</span><br><span> </span><br><sp=
an> #ifdef HAVE_SYS_INOTIFY_H</span><br><span> #include <sys/inotify=2Eh=
></span><br><span>@@ -186,7 +187,7 @@</span><br><span> }</span><=
br><span> else</span><br><span> {</span><br><span style=3D"=
color: hsl(0, 100%, 40%);">- msg(D_MULTI_DEBUG,</span><br><span =
style=3D"color: hsl(120, 100%, 40%);">+ msg(D_MULTI_MEDIUM,</spa=
n><br><span> "Valid packet (%s) with HMAC challenge fr=
om peer (%s), "</span><br><span> "accepting new c=
onnection=2E",</span><br><span> packet_opcode_name(op)=
, peer);</span><br><span>@@ -212,7 +213,6 @@</span><br><span> =
struct link_socket *sock,</span><br><span> =
struct mroute_addr *real)</span><br><span> {</span><br><span style=
=3D"color: hsl(0, 100%, 40%);">- struct hash *hash =3D m->hash;</span=
><br><span> struct tls_pre_decrypt_state state =3D { 0 };</span><br><sp=
an> struct multi_instance *mi =3D NULL;</span><br><span> struct gc_=
arena gc =3D gc_new();</span><br><span>@@ -243,11 +243,6 @@</span><br><span=
> mi =3D multi_create_instance(m, real, sock);</span><br><span>=
if (mi)</span><br><span> {</span><br><span style=
=3D"color: hsl(0, 100%, 40%);">- const uint64_t hv =3D hash_=
value(hash, real);</span><br><span style=3D"color: hsl(0, 100%, 40%);">- =
struct hash_bucket *bucket =3D hash_bucket(hash, hv);</span><b=
r><span style=3D"color: hsl(0, 100%, 40%);">- hash_add_fast(=
hash, bucket, &mi->real, hv, mi);</span><br><span style=3D"color: hs=
l(0, 100%, 40%);">-</span><br><span style=3D"color: hsl(0, 100%, 40%);">- =
mi->did_real_hash =3D true;</span><br><span> =
multi_assign_peer_id(m, mi);</span><br><span> </span><br><span> =
/* If we have a session id already, ensure that the</span><br><span=
>@@ -262,6 +257,7 @@</span><br><span> {</span><br><span=
> session_skip_to_pre_start(session, &state, &a=
mp;m->top=2Ec2=2Efrom);</span><br><span> }</span><br=
><span style=3D"color: hsl(120, 100%, 40%);">+ multi_has=
h_sid_add(m, &state=2Epeer_session_id, mi);</span><br><span> =
}</span><br><span> }</span><br><span> }</span><br=
><span>@@ -298,15 +294,26 @@</span><br><span> return NULL;</span><br><s=
pan> }</span><br><span> </span><br><span style=3D"color: hsl(0, 100%, 40%);=
">-struct multi_instance *</span><br><span style=3D"color: hsl(0, 100%, 40%=
);">-multi_get_instance_udp_control(struct multi_context *m, struct link_so=
cket *sock)</span><br><span style=3D"color: hsl(0, 100%, 40%);">-{</span><b=
r><span style=3D"color: hsl(0, 100%, 40%);">- struct mroute_addr real =
=3D { 0 };</span><br><span style=3D"color: hsl(0, 100%, 40%);">- real=2E=
proto =3D sock->info=2Eproto;</span><br><span> </span><br><span style=3D=
"color: hsl(0, 100%, 40%);">- if (mroute_extract_openvpn_sockaddr(&r=
eal, &m->top=2Ec2=2Efrom=2Edest, true) && m->top=2Ec2=2Eb=
uf=2Elen > 0)</span><br><span style=3D"color: hsl(120, 100%, 40%);">+sta=
tic struct multi_instance *</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+multi_get_instance_udp_control(struct multi_context *m)</span><br><=
span style=3D"color: hsl(120, 100%, 40%);">+{</span><br><span style=3D"colo=
r: hsl(120, 100%, 40%);">+ /* Copy buffer, to a tmp buffer, so that read=
ing the sesison does not</span><br><span style=3D"color: hsl(120, 100%, 40%=
);">+ * modify the internal pointers */</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+ struct buffer tmp =3D m->top=2Ec2=2Ebuf;</sp=
an><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ /* op code */</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ uint8_t op =3D (uint8_t)buf_read_u8(&=
amp;tmp) >> P_OPCODE_SHIFT;</span><br><span style=3D"color: hsl(120, =
100%, 40%);">+ (void)op;</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ struct =
session_id sid =3D { 0 };</span><br><span style=3D"color: hsl(120, 100%, 40=
%);">+ session_id_read(&sid, &tmp);</span><br><span style=3D"col=
or: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+ struct hash_element *he_sid =3D multi_hash_sid_lookup(m, &s=
id);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><spa=
n style=3D"color: hsl(120, 100%, 40%);">+ if (he_sid)</span><br><span> =
{</span><br><span style=3D"color: hsl(0, 100%, 40%);">- return mu=
lti_get_instance_udp_real(m, &real);</span><br><span style=3D"color: hs=
l(120, 100%, 40%);">+ return he_sid->value;</span><br><span> =
}</span><br><span> </span><br><span> return NULL;</span><br><span>@@ -3=
92,7 +399,14 @@</span><br><span> }</span><br><span> else</span><br>=
<span> {</span><br><span style=3D"color: hsl(0, 100%, 40%);">- m=
i =3D multi_get_instance_udp_control(m, sock);</span><br><span style=3D"col=
or: hsl(120, 100%, 40%);">+ if (m->top=2Ec2=2Ebuf=2Elen < (int=
)SID_SIZE + 1)</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
{</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ /* =
control packets must be at least the opcode byte + session id</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+ * (8 byte) long, oth=
erwise they are not valid packets */</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+ return NULL;</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+ }</span><br><span style=3D"color: hsl(120, 10=
0%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
mi =3D multi_get_instance_udp_control(m);</span><br><span> </span><br><spa=
n> /* we have no existing multi instance for this connection, contr=
ol</span><br><span> * packets can create a session=2E Data packets=
cannot */</span><br><span>diff --git a/src/openvpn/multi=2Ec b/src/openvpn=
/multi=2Ec</span><br><span>index 20b4f14=2E=2E60e89fb 100644</span><br><spa=
n>--- a/src/openvpn/multi=2Ec</span><br><span>+++ b/src/openvpn/multi=2Ec</=
span><br><span>@@ -42,6 +42,7 @@</span><br><span> #include "vlan=2Eh&q=
uot;</span><br><span> #include "auth_token=2Eh"</span><br><span> =
#include "route=2Eh"</span><br><span style=3D"color: hsl(120, 100=
%, 40%);">+#include "sid_hash=2Eh"</span><br><span> #include <=
inttypes=2Eh></span><br><span> #include <string=2Eh></span><br><sp=
an> </span><br><span>@@ -271,8 +272,8 @@</span><br><span> struct multi_=
context *m =3D t->multi;</span><br><span> int dev =3D DEV_TYPE_UNDEF=
;</span><br><span> </span><br><span style=3D"color: hsl(0, 100%, 40%);">- =
msg(D_MULTI_LOW, "MULTI: multi_init called, r=3D%d v=3D%d", t-&=
gt;options=2Ereal_hash_size,</span><br><span style=3D"color: hsl(0, 100%, 4=
0%);">- t->options=2Evirtual_hash_size);</span><br><span style=3D=
"color: hsl(120, 100%, 40%);">+ msg(D_MULTI_LOW, "MULTI: multi_init=
called, r=3D%d v=3D%d s=3D%d", t->options=2Ereal_hash_size,</span>=
<br><span style=3D"color: hsl(120, 100%, 40%);">+ t->options=2Evi=
rtual_hash_size, t->options=2Esid_hash_size);</span><br><span> </span><b=
r><span> /*</span><br><span> * Get tun/tap/null device type</span>=
<br><span>@@ -300,6 +301,12 @@</span><br><span> m->vhash =3D hash_in=
it(t->options=2Evirtual_hash_size,</span><br><span> =
mroute_addr_hash_function, mroute_addr_compare_function);</span><br><s=
pan> </span><br><span style=3D"color: hsl(120, 100%, 40%);">+ /*</span><=
br><span style=3D"color: hsl(120, 100%, 40%);">+ * Peer session id hash=
table=2E Used to lookup a session by the session</span><br><span style=3D"=
color: hsl(120, 100%, 40%);">+ * id of one of its active sessions */</s=
pan><br><span style=3D"color: hsl(120, 100%, 40%);">+ m->sid_hash =3D=
hash_init(t->options=2Esid_hash_size,</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+ session_id_hash_function,=
session_id_hash_equal);</span><br><span style=3D"color: hsl(120, 100%, 40%=
);">+</span><br><span> #ifdef ENABLE_MANAGEMENT</span><br><span> m->=
cid_hash =3D hash_init(t->options=2Ereal_hash_size, cid_hash_function, c=
id_compare_function);</span><br><span> #endif</span><br><span>@@ -427,8 +43=
4,7 @@</span><br><span> buf_printf(&out, "%s/", c=
n);</span><br><span> }</span><br><span> buf_printf(&out=
, "%s", mroute_addr_print(&mi->real, gc));</span><br><span=
style=3D"color: hsl(0, 100%, 40%);">- if (mi->context=2Ec2=2Etls=
_multi && check_debug_level(D_DCO_DEBUG)</span><br><span style=3D"c=
olor: hsl(0, 100%, 40%);">- && dco_enabled(&mi->c=
ontext=2Eoptions))</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
if (mi->context=2Ec2=2Etls_multi)</span><br><span> {</spa=
n><br><span> buf_printf(&out, " rx-peer-id=3D%d",=
mi->context=2Ec2=2Etls_multi->rx_peer_id);</span><br><span> =
}</span><br><span>@@ -598,6 +604,12 @@</span><br><span> }</span><br=
><span> #endif</span><br><span> </span><br><span style=3D"color: hsl(120, 1=
00%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
if (session_id_defined(&mi->sid_hashed_value))</span><br><span sty=
le=3D"color: hsl(120, 100%, 40%);">+ {</span><br><span style=3D"colo=
r: hsl(120, 100%, 40%);">+ multi_hash_sid_remove(m, &mi->=
sid_hashed_value);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
}</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br>=
<span> if (mi->context=2Ec2=2Etls_multi->rx_peer_id !=3D MAX_=
PEER_ID)</span><br><span> {</span><br><span> m->inst=
ances[mi->context=2Ec2=2Etls_multi->rx_peer_id] =3D NULL;</span><br><=
span>@@ -672,6 +684,7 @@</span><br><span> </span><br><span> hash_fr=
ee(m->hash);</span><br><span> hash_free(m->vhash);</span><br>=
<span style=3D"color: hsl(120, 100%, 40%);">+ hash_free(m->sid_ha=
sh);</span><br><span> #ifdef ENABLE_MANAGEMENT</span><br><span> has=
h_free(m->cid_hash);</span><br><span> #endif</span><br><span>@@ -2456,6 =
+2469,34 @@</span><br><span> multi_client_connect_setenv(mi);</span><br=
><span> }</span><br><span> </span><br><span style=3D"color: hsl(120, 100%, =
40%);">+static bool</span><br><span style=3D"color: hsl(120, 100%, 40%);">+=
multi_check_dest_addr_allowed(struct multi_context *m, struct multi_instanc=
e *mi, struct mroute_addr *real);</span><br><span style=3D"color: hsl(120, =
100%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+/**</=
span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * This sets up the c=
lient real address (outer tunnel addr) in the</span><br><span style=3D"colo=
r: hsl(120, 100%, 40%);">+ * hash map for data channel packet=2E If the add=
ress is already taken</span><br><span style=3D"color: hsl(120, 100%, 40%);"=
>+ * this steps fails</span><br><span style=3D"color: hsl(120, 100%, 40%);"=
>+ */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+static enum cl=
ient_connect_return</span><br><span style=3D"color: hsl(120, 100%, 40%);">+=
multi_client_connect_real_addr(struct multi_context *m, struct multi_instan=
ce *mi,</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
bool deferred, uint64_t *option_types_found)</span><br><=
span style=3D"color: hsl(120, 100%, 40%);">+{</span><br><span style=3D"colo=
r: hsl(120, 100%, 40%);">+ /* If the address is already taken up by anot=
her client we fail the new</span><br><span style=3D"color: hsl(120, 100%, 4=
0%);">+ * connection */</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+ if (!multi_check_dest_addr_allowed(m, mi, &mi->real))</s=
pan><br><span style=3D"color: hsl(120, 100%, 40%);">+ {</span><br><span =
style=3D"color: hsl(120, 100%, 40%);">+ msg(D_MULTI_ERRORS,</span><b=
r><span style=3D"color: hsl(120, 100%, 40%);">+ "MULTI: cli=
ent IP address and port already assigned to another "</span><br><span =
style=3D"color: hsl(120, 100%, 40%);">+ "client, terminatin=
g connection");</span><br><span style=3D"color: hsl(120, 100%, 40%);">=
+ return CC_RET_FAILED;</span><br><span style=3D"color: hsl(120, 100=
%, 40%);">+ }</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</s=
pan><br><span style=3D"color: hsl(120, 100%, 40%);">+ ASSERT(!mi->did=
_real_hash);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ ASS=
ERT(hash_add(m->hash, &mi->real, mi, false));</span><br><span sty=
le=3D"color: hsl(120, 100%, 40%);">+ mi->did_real_hash =3D true;</spa=
n><br><span style=3D"color: hsl(120, 100%, 40%);">+ return CC_RET_SUCCEE=
DED;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+}</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+</span><br><span> /**</span><br><=
span> * Do the necessary modification for doing the compress migrate=2E T=
his is</span><br><span> * implemented as a connect handler as it fits the=
modify config for a client</span><br><span>@@ -2550,6 +2591,7 @@</span><br=
><span> uint64_t *option_types_found);</span><br><span> </span><br><spa=
n> static const multi_client_connect_handler client_connect_handlers[] =3D =
{</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ multi_client_c=
onnect_real_addr,</span><br><span> multi_client_connect_compress_migrat=
e,</span><br><span> multi_client_connect_source_ccd,</span><br><span> =
multi_client_connect_call_plugin_v1,</span><br><span>@@ -2618,6 +2660,7 =
@@</span><br><span> }</span><br><span> return true;</span><br><span=
> }</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span=
> /*</span><br><span> * Called as soon as the SSL/TLS connection is authen=
ticated=2E</span><br><span> *</span><br><span>@@ -3104,7 +3147,7 @@</span>=
<br><span> /* do not allow if target address is taken by client with an=
other cert */</span><br><span> if (!cert_hash_compare(m1->locked_cer=
t_hash_set, m2->locked_cert_hash_set))</span><br><span> {</span><br>=
<span style=3D"color: hsl(0, 100%, 40%);">- msg(D_MULTI_LOW, "D=
isallow float to an address taken by another client %s",</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+ msg(D_MULTI_LOW, "Di=
sallow float/connect to an address taken by another client %s",</span>=
<br><span> multi_instance_string(ex_mi, false, &gc));</span=
><br><span> </span><br><span> mi->context=2Ec2=2Ebuf=2Elen =3D 0=
;</span><br><span>@@ -3117,7 +3160,7 @@</span><br><span> if (!m1-&g=
t;locked_username || !m2->locked_username</span><br><span> |=
| strcmp(m1->locked_username, m2->locked_username) !=3D 0)</span><br>=
<span> {</span><br><span style=3D"color: hsl(0, 100%, 40%);">- =
msg(D_MULTI_LOW, "Disallow float to an address taken by another=
client %s",</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
msg(D_MULTI_LOW, "Disallow float/connect to an address taken=
by another client %s",</span><br><span> multi_instanc=
e_string(ex_mi, false, &gc));</span><br><span> goto done;</=
span><br><span> }</span><br><span>diff --git a/src/openvpn/multi=2E=
h b/src/openvpn/multi=2Eh</span><br><span>index 8b837fa=2E=2E98547b0 100644=
</span><br><span>--- a/src/openvpn/multi=2Eh</span><br><span>+++ b/src/open=
vpn/multi=2Eh</span><br><span>@@ -131,7 +131,15 @@</span><br><span> in_=
addr_t reporting_addr; /* IP address shown in status listing */<=
/span><br><span> struct in6_addr reporting_addr_ipv6; /* IPv6 address i=
n status listing */</span><br><span> </span><br><span style=3D"color: hsl(1=
20, 100%, 40%);">+ /** Indicates that the real address/port of the clien=
t is hashed in</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
* the multi_context m->hash table=2E */</span><br><span> bool did_re=
al_hash;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br>=
<span style=3D"color: hsl(120, 100%, 40%);">+ /** If this is multi_insta=
nce is hashed in the sid lookup table the session</span><br><span style=3D"=
color: hsl(120, 100%, 40%);">+ * id here is a non-null session id and t=
he hash map's key pointer points</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+ * to this field (the value pointer points to the whol=
e struct) */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ str=
uct session_id sid_hashed_value;</span><br><span style=3D"color: hsl(120, 1=
00%, 40%);">+</span><br><span> #ifdef ENABLE_MANAGEMENT</span><br><span> =
bool did_cid_hash;</span><br><span> struct buffer_list *cc_config;</s=
pan><br><span>@@ -170,6 +178,12 @@</span><br><span> =
* address of the remote peer=2E */</span><br><span> =
struct hash *vhash; /**< VPN tunnel instances indexed by<=
/span><br><span> * virtual addres=
s of remote hosts=2E */</span><br><span style=3D"color: hsl(120, 100%, 40%)=
;">+ struct hash *sid_hash; /**< TLS sessions indexed by =
the peer's</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
session id=2E We do not care about</=
span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
collisions here as clients should</span><br><span st=
yle=3D"color: hsl(120, 100%, 40%);">+ =
have unique ids and supporting</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+ clients with i=
dentical SIDs</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
is not needed */</span><br><span> =
struct schedule *schedule;</span><br><span> struct mbuf_set *mbuf; =
/**< Set of buffers for passing data</span><br><span> =
* channel packets between VPN tunnel</span=
><br><span>diff --git a/src/openvpn/options=2Ec b/src/openvpn/options=2Ec</=
span><br><span>index d0f447c=2E=2E629652e 100644</span><br><span>--- a/src/=
openvpn/options=2Ec</span><br><span>+++ b/src/openvpn/options=2Ec</span><br=
><span>@@ -3764,6 +3764,10 @@</span><br><span> {</span><br><span> =
o->virtual_hash_size =3D 4 * o->max_clients;</span><br><span> =
}</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ if (!o->sid=
_hash_size)</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ {</s=
pan><br><span style=3D"color: hsl(120, 100%, 40%);">+ o->sid_hash=
_size =3D o->real_hash_size;</span><br><span style=3D"color: hsl(120, 10=
0%, 40%);">+ }</span><br><span> }</span><br><span> </span><br><span> sta=
tic void</span><br><span>@@ -7367,7 +7371,7 @@</span><br><span> opt=
ions->ifconfig_ipv6_pool_base =3D network;</span><br><span> opti=
ons->ifconfig_ipv6_pool_netbits =3D netbits;</span><br><span> }</spa=
n><br><span style=3D"color: hsl(0, 100%, 40%);">- else if (streq(p[0], &=
quot;hash-size") && p[1] && p[2] && !p[3])</sp=
an><br><span style=3D"color: hsl(120, 100%, 40%);">+ else if (streq(p[0]=
, "hash-size") && p[1] && p[2] && !p[4])<=
/span><br><span> {</span><br><span> int real, virtual;</span><b=
r><span> </span><br><span>@@ -7379,6 +7383,16 @@</span><br><span> }=
</span><br><span> options->real_hash_size =3D (uint32_t)real;</s=
pan><br><span> options->virtual_hash_size =3D (uint32_t)virtual;=
</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span st=
yle=3D"color: hsl(120, 100%, 40%);">+ if (p[3])</span><br><span styl=
e=3D"color: hsl(120, 100%, 40%);">+ {</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ int sid;</span><br><span style=3D"colo=
r: hsl(120, 100%, 40%);">+ if (!atoi_constrained(p[3], &sid,=
"hash-size sid", 1, INT_MAX, msglevel))</span><br><span style=3D=
"color: hsl(120, 100%, 40%);">+ {</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ goto err;</span><br><span style=3D=
"color: hsl(120, 100%, 40%);">+ }</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ options->sid_hash_size =3D (uint32_=
t)sid;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ }</sp=
an><br><span> }</span><br><span> else if (streq(p[0], "connect=
-freq") && p[1] && p[2] && !p[3])</span><br><s=
pan> {</span><br><span>diff --git a/src/openvpn/options=2Eh b/src/openv=
pn/options=2Eh</span><br><span>index 30a146f=2E=2Ec7825c7 100644</span><br>=
<span>--- a/src/openvpn/options=2Eh</span><br><span>+++ b/src/openvpn/optio=
ns=2Eh</span><br><span>@@ -498,6 +498,7 @@</span><br><span> </span><br><spa=
n> uint32_t real_hash_size;</span><br><span> uint32_t virtual_hash_=
size;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ uint32_t s=
id_hash_size;</span><br><span> const char *client_connect_script;</span=
><br><span> const char *client_disconnect_script;</span><br><span> =
const char *learn_address_script;</span><br><span>diff --git a/src/openvpn/=
sid_hash=2Eh b/src/openvpn/sid_hash=2Eh</span><br><span>new file mode 10064=
4</span><br><span>index 0000000=2E=2E4667fb1</span><br><span>--- /dev/null<=
/span><br><span>+++ b/src/openvpn/sid_hash=2Eh</span><br><span>@@ -0,0 +1,9=
0 @@</span><br><span style=3D"color: hsl(120, 100%, 40%);">+/*</span><br><s=
pan style=3D"color: hsl(120, 100%, 40%);">+ * OpenVPN -- An application to=
securely tunnel IP networks</span><br><span style=3D"color: hsl(120, 100%,=
40%);">+ * over a single TCP/UDP port, with support for SSL/TL=
S-based</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * =
session authentication and key exchange,</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+ * packet encryption, packet authentica=
tion, and</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * =
packet compression=2E</span><br><span style=3D"color: hsl(120, 100%, 4=
0%);">+ *</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * Copyri=
ght (C) 2026 OpenVPN Inc <sales@openvpn=2Enet></span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ * Copyright (C) 2026 Arne Schwabe <a=
rne@rfc2549=2Eorg></span><br><span style=3D"color: hsl(120, 100%, 40%);"=
>+ *</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ *</span><br><s=
pan style=3D"color: hsl(120, 100%, 40%);">+ * This program is free softwar=
e; you can redistribute it and/or modify</span><br><span style=3D"color: hs=
l(120, 100%, 40%);">+ * it under the terms of the GNU General Public Licen=
se version 2</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * as =
published by the Free Software Foundation=2E</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ *</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+ * This program is distributed in the hope that it will be useful,=
</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY=
WARRANTY; without even the implied warranty of</span><br><span style=3D"co=
lor: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR=
PURPOSE=2E See the</span><br><span style=3D"color: hsl(120, 100%, 40%);">=
+ * GNU General Public License for more details=2E</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ *</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+ * You should have received a copy of the GNU General Pub=
lic License along</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ *=
with this program; if not, write to the Free Software Foundation, Inc=2E,=
</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * 51 Franklin Str=
eet, Fifth Floor, Boston, MA 02110-1301 USA=2E</span><br><span style=3D"col=
or: hsl(120, 100%, 40%);">+ */</span><br><span style=3D"color: hsl(120, 100=
%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+#include=
"session_id=2Eh"</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+#include "multi=2Eh"</span><br><span style=3D"color: hsl(=
120, 100%, 40%);">+#include "list=2Eh"</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+#include "siphash=2Eh"</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: =
hsl(120, 100%, 40%);">+inline static void</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+multi_hash_sid_add(struct multi_context *m, struct se=
ssion_id *sid,</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
struct multi_instance *mi)</span><br><span style=3D"color: hs=
l(120, 100%, 40%);">+{</span><br><span style=3D"color: hsl(120, 100%, 40%);=
">+ /* This must only be called if the multi instance is not already pre=
sent</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * in the h=
ash table */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ ASS=
ERT(!session_id_defined(&mi->sid_hashed_value));</span><br><span sty=
le=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+ mi->sid_hashed_value =3D *sid;</span><br><span styl=
e=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: hsl(120=
, 100%, 40%);">+ const uint64_t hv =3D hash_value(m->sid_hash, &m=
i->sid_hashed_value);</span><br><span style=3D"color: hsl(120, 100%, 40%=
);">+ struct hash_bucket *bucket =3D hash_bucket(m->sid_hash, hv);</s=
pan><br><span style=3D"color: hsl(120, 100%, 40%);">+ hash_add_fast(m-&g=
t;sid_hash, bucket, &mi->sid_hashed_value, hv, mi);</span><br><span =
style=3D"color: hsl(120, 100%, 40%);">+ multi_instance_inc_refcount(mi);=
</span><br><span style=3D"color: hsl(120, 100%, 40%);">+}</span><br><span s=
tyle=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: hsl(=
120, 100%, 40%);">+static inline struct hash_element *</span><br><span styl=
e=3D"color: hsl(120, 100%, 40%);">+multi_hash_sid_lookup(struct multi_conte=
xt *m, const struct session_id *sid)</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+{</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
const uint64_t sid_hv =3D hash_value(m->sid_hash, sid);</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+ struct hash_bucket *sid_bucke=
t =3D hash_bucket(m->sid_hash, sid_hv);</span><br><span style=3D"color: =
hsl(120, 100%, 40%);">+ struct hash_element *he_sid =3D hash_lookup_fast=
(m->sid_hash, sid_bucket, sid, sid_hv);</span><br><span style=3D"color: =
hsl(120, 100%, 40%);">+ return he_sid;</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+}</span><br><span style=3D"color: hsl(120, 100%, 40%)=
;">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+inline static b=
ool</span><br><span style=3D"color: hsl(120, 100%, 40%);">+multi_hash_sid_r=
emove(struct multi_context *m, const struct session_id *sid)</span><br><spa=
n style=3D"color: hsl(120, 100%, 40%);">+{</span><br><span style=3D"color: =
hsl(120, 100%, 40%);">+ const uint64_t sid_hv =3D hash_value(m->sid_h=
ash, sid);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ struc=
t hash_bucket *sid_bucket =3D hash_bucket(m->sid_hash, sid_hv);</span><b=
r><span style=3D"color: hsl(120, 100%, 40%);">+ struct hash_element *he_=
sid =3D hash_lookup_fast(m->sid_hash, sid_bucket, sid, sid_hv);</span><b=
r><span style=3D"color: hsl(120, 100%, 40%);">+ if (he_sid)</span><br><s=
pan style=3D"color: hsl(120, 100%, 40%);">+ {</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+ struct multi_instance *mi =3D he_sid-&=
gt;value;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ AS=
SERT(hash_remove_fast(m->sid_hash, sid_bucket, sid, sid_hv));</span><br>=
<span style=3D"color: hsl(120, 100%, 40%);">+ CLEAR(mi->sid_hashe=
d_value);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ mu=
lti_instance_dec_refcount(mi);</span><br><span style=3D"color: hsl(120, 100=
%, 40%);">+ return true;</span><br><span style=3D"color: hsl(120, 10=
0%, 40%);">+ }</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
else</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ {</span><=
br><span style=3D"color: hsl(120, 100%, 40%);">+ return false;</span=
><br><span style=3D"color: hsl(120, 100%, 40%);">+ }</span><br><span sty=
le=3D"color: hsl(120, 100%, 40%);">+}</span><br><span style=3D"color: hsl(1=
20, 100%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+/=
* hashing the session=2E As the struct is just an 8 byte array</span><br><s=
pan style=3D"color: hsl(120, 100%, 40%);">+ * hashing is straight forward *=
/</span><br><span style=3D"color: hsl(120, 100%, 40%);">+static inline uint=
64_t</span><br><span style=3D"color: hsl(120, 100%, 40%);">+session_id_hash=
_function(const void *key, const uint8_t hash_key[HASH_KEY_LEN])</span><br>=
<span style=3D"color: hsl(120, 100%, 40%);">+{</span><br><span style=3D"col=
or: hsl(120, 100%, 40%);">+ return siphash_hash_func(key, sizeof(struct =
session_id), hash_key);</span><br><span style=3D"color: hsl(120, 100%, 40%)=
;">+}</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+/* wrapper for session_id_equal t=
o have the void* arguments that the</span><br><span style=3D"color: hsl(120=
, 100%, 40%);">+ * hash map requires */</span><br><span style=3D"color: hsl=
(120, 100%, 40%);">+static inline bool</span><br><span style=3D"color: hsl(=
120, 100%, 40%);">+session_id_hash_equal(const void *sid1, const void *sid2=
)</span><br><span style=3D"color: hsl(120, 100%, 40%);">+{</span><br><span =
style=3D"color: hsl(120, 100%, 40%);">+ return session_id_equal((struct =
session_id *)sid1, (struct session_id *)sid2);</span><br><span style=3D"col=
or: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/unit_tests/=
openvpn/Makefile=2Eam b/tests/unit_tests/openvpn/Makefile=2Eam</span><br><s=
pan>index 6af25b1=2E=2Eb4611dd 100644</span><br><span>--- a/tests/unit_test=
s/openvpn/Makefile=2Eam</span><br><span>+++ b/tests/unit_tests/openvpn/Make=
file=2Eam</span><br><span>@@ -383,7 +383,8 @@</span><br><span> $(top_srcdi=
r)/src/openvpn/platform=2Ec \</span><br><span> $(top_srcdir)/src/openvpn/l=
ist=2Ec \</span><br><span> $(top_srcdir)/src/openvpn/siphash=2Ec \</span><=
br><span style=3D"color: hsl(0, 100%, 40%);">- $(top_srcdir)/src/openvpn/si=
phash_reference=2Ec</span><br><span style=3D"color: hsl(120, 100%, 40%);">+=
$(top_srcdir)/src/openvpn/siphash_reference=2Ec \</span><br><span style=3D=
"color: hsl(120, 100%, 40%);">+ $(top_srcdir)/src/openvpn/session_id=2Ec</s=
pan><br><span> </span><br><span> push_update_msg_testdriver_CFLAGS =3D -I$(=
top_srcdir)/src/openvpn \</span><br><span> -I$(top_srcdir)/src/compat \</s=
pan><br><span>diff --git a/tests/unit_tests/openvpn/test_misc=2Ec b/tests/u=
nit_tests/openvpn/test_misc=2Ec</span><br><span>index ab21d5e=2E=2Eb094344 =
100644</span><br><span>--- a/tests/unit_tests/openvpn/test_misc=2Ec</span><=
br><span>+++ b/tests/unit_tests/openvpn/test_misc=2Ec</span><br><span>@@ -4=
2,6 +42,7 @@</span><br><span> #ifdef _WIN32</span><br><span> #include "=
;win32-util=2Eh"</span><br><span> #endif</span><br><span style=3D"colo=
r: hsl(120, 100%, 40%);">+#include "sid_hash=2Eh"</span><br><span=
> </span><br><span> static void</span><br><span> test_compat_lzo_string(voi=
d **state)</span><br><span>@@ -142,13 +143,6 @@</span><br><span> return=
strcmp((const char *)key1, (const char *)key2) =3D=3D 0;</span><br><span> =
}</span><br><span> </span><br><span style=3D"color: hsl(0, 100%, 40%);">-st=
atic uint32_t</span><br><span style=3D"color: hsl(0, 100%, 40%);">-get_rand=
om(void)</span><br><span style=3D"color: hsl(0, 100%, 40%);">-{</span><br><=
span style=3D"color: hsl(0, 100%, 40%);">- /* rand() is not very random,=
but it's C99 and this is just for testing */</span><br><span style=3D"=
color: hsl(0, 100%, 40%);">- return (uint32_t)rand();</span><br><span st=
yle=3D"color: hsl(0, 100%, 40%);">-}</span><br><span style=3D"color: hsl(0,=
100%, 40%);">-</span><br><span> static struct hash_element *</span><br><sp=
an> hash_lookup_by_value(struct hash *hash, void *value)</span><br><span> {=
</span><br><span>@@ -264,7 +258,7 @@</span><br><span> {</span><br><=
span> struct hash_iterator hi;</span><br><span> str=
uct hash_element *he;</span><br><span style=3D"color: hsl(0, 100%, 40%);">-=
inc =3D (get_random() % 3) + 1;</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+ inc =3D ((int)get_random() % 3) + 1;</s=
pan><br><span> hash_iterator_init_range(hash, &hi, base, ba=
se + inc);</span><br><span> </span><br><span> while ((he =3D ha=
sh_iterator_next(&hi)))</span><br><span>@@ -479,6 +473,65 @@</span><br>=
<span> }</span><br><span> #endif /* _WIN32 */</span><br><span> </span><br><=
span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+static void</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+test_sid_hash_list(void **state)</span><br><span style=3D"=
color: hsl(120, 100%, 40%);">+{</span><br><span style=3D"color: hsl(120, 10=
0%, 40%);">+ struct gc_arena gc =3D gc_new();</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+ /* very simple tests to ensure the basic h=
ash functions work */</span><br><span style=3D"color: hsl(120, 100%, 40%);"=
>+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ struct multi_=
context m =3D { 0 };</span><br><span style=3D"color: hsl(120, 100%, 40%);">=
+ m=2Esid_hash =3D hash_init(2048, session_id_hash_function, session_id_=
hash_equal);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span>=
<br><span style=3D"color: hsl(120, 100%, 40%);">+ struct session_id sid1=
;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ struct session=
_id sid2;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ struct=
session_id sid3;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</=
span><br><span style=3D"color: hsl(120, 100%, 40%);">+ struct multi_inst=
ance *m1, *m3;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</spa=
n><br><span style=3D"color: hsl(120, 100%, 40%);">+ /* multi_hash_sid_re=
move will call gc_free on the gc of a mi and</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ * free on the mi itself */</span><br><span st=
yle=3D"color: hsl(120, 100%, 40%);">+ ALLOC_OBJ_CLEAR(m1, struct multi_i=
nstance);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ ALLOC_=
OBJ_CLEAR(m3, struct multi_instance);</span><br><span style=3D"color: hsl(1=
20, 100%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
m1->gc =3D gc_new();</span><br><span style=3D"color: hsl(120, 100%, 4=
0%);">+ m3->gc =3D gc_new();</span><br><span style=3D"color: hsl(120,=
100%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
session_id_random(&sid1);</span><br><span style=3D"color: hsl(120, 100%=
, 40%);">+ session_id_random(&sid2);</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+ session_id_random(&sid3);</span><br><span s=
tyle=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: hsl(=
120, 100%, 40%);">+ multi_hash_sid_add(&m, &sid1, m1);</span><br=
><span style=3D"color: hsl(120, 100%, 40%);">+ multi_hash_sid_add(&m=
, &sid3, m3);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</=
span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span styl=
e=3D"color: hsl(120, 100%, 40%);">+ /* sid2 is not added and should not =
be returned */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ s=
truct hash_element *he_sid =3D multi_hash_sid_lookup(&m, &sid2);</s=
pan><br><span style=3D"color: hsl(120, 100%, 40%);">+ assert_null(he_sid=
);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span =
style=3D"color: hsl(120, 100%, 40%);">+ he_sid =3D multi_hash_sid_lookup=
(&m, &sid1);</span><br><span style=3D"color: hsl(120, 100%, 40%);">=
+ assert_non_null(he_sid);</span><br><span style=3D"color: hsl(120, 100%=
, 40%);">+ assert_ptr_equal(he_sid->value, m1);</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: hsl(120,=
100%, 40%);">+ /* Try removing elements, only that are in the map shoul=
d return true */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
assert_true(multi_hash_sid_remove(&m, &sid1));</span><br><span sty=
le=3D"color: hsl(120, 100%, 40%);">+ assert_false(multi_hash_sid_remove(=
&m, &sid2));</span><br><span style=3D"color: hsl(120, 100%, 40%);">=
+ assert_false(multi_hash_sid_remove(&m, &sid1));</span><br><spa=
n style=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+ /* should no longer find the element */</span><br=
><span style=3D"color: hsl(120, 100%, 40%);">+ he_sid =3D multi_hash_sid=
_lookup(&m, &sid1);</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+ assert_null(he_sid);</span><br><span style=3D"color: hsl(120, 1=
00%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ /*=
this element should still be in the hash table */</span><br><span style=3D=
"color: hsl(120, 100%, 40%);">+ he_sid =3D multi_hash_sid_lookup(&m,=
&sid3);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ ass=
ert_ptr_equal(he_sid->value, m3);</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
assert_true(multi_hash_sid_remove(&m, &sid3));</span><br><span st=
yle=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: hsl(1=
20, 100%, 40%);">+ hash_free(m=2Esid_hash);</span><br><span style=3D"col=
or: hsl(120, 100%, 40%);">+ gc_free(&gc);</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+}</span><br><span style=3D"color: hsl(120, 100=
%, 40%);">+</span><br><span> const struct CMUnitTest misc_tests[] =3D {</sp=
an><br><span> #ifdef _WIN32</span><br><span> cmocka_unit_test(test_win_=
path_in_dir),</span><br><span>@@ -488,7 +541,8 @@</span><br><span> cmoc=
ka_unit_test(test_auth_fail_temp_flags),</span><br><span> cmocka_unit_t=
est(test_auth_fail_temp_flags_msg),</span><br><span> cmocka_unit_test(t=
est_list),</span><br><span style=3D"color: hsl(0, 100%, 40%);">- cmocka_=
unit_test(test_atoi_variants)</span><br><span style=3D"color: hsl(120, 100%=
, 40%);">+ cmocka_unit_test(test_atoi_variants),</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ cmocka_unit_test(test_sid_hash_list)<=
/span><br><span> };</span><br><span> </span><br><span> int</span><br><span>=
</span><br></pre><p>To view, visit <a href=3D"http://gerrit=2Eopenvpn=2Enet=
/c/openvpn/+/1727?usp=3Demail">change 1727</a>=2E To unsubscribe, or for he=
lp writing mail filters, visit <a href=3D"http://gerrit=2Eopenvpn=2Enet/set=
tings?usp=3Demail">settings</a>=2E</p><div itemscope itemtype=3D"http://sch=
ema=2Eorg/EmailMessage"><div itemscope itemprop=3D"action" itemtype=3D"http=
://schema=2Eorg/ViewAction"><link itemprop=3D"url" href=3D"http://gerrit=2E=
openvpn=2Enet/c/openvpn/+/1727?usp=3Demail"/><meta itemprop=3D"name" conten=
t=3D"View Change"/></div></div>
<div style=3D"display:none"> Gerrit-Messag=
eType: newpatchset </div>
<div style=3D"display:none"> Gerrit-Project: open=
vpn </div>
<div style=3D"display:none"> Gerrit-Branch: master </div>
<div s=
tyle=3D"display:none"> Gerrit-Change-Id: Idb59ecd119331b198792ad1379bec8600=
211651b </div>
<div style=3D"display:none"> Gerrit-Change-Number: 1727 </di=
v>
<div style=3D"display:none"> Gerrit-PatchSet: 25 </div>
<div style=3D"di=
splay:none"> Gerrit-Owner: plaisthos <arne-openvpn@rfc2549=2Eorg> </d=
iv>
<div style=3D"display:none"> Gerrit-Reviewer: flichtenheld <frank@li=
chtenheld=2Ecom> </div>
<div style=3D"display:none"> Gerrit-CC: openvpn-=
devel <openvpn-devel@lists=2Esourceforge=2Enet> </div>
</body></html=
>
--TnPoNrKfDZg=--
--===============0367511233571082502==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
--===============0367511233571082502==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel
--===============0367511233571082502==--