[Openvpn-devel] [S] Change in openvpn[master]: oob: advertise a connect_lifetime in the probe reply
"stipa \(Code Review\) via Openvpn-devel" <[email protected]> Wed, 29 Jul 2026 12:22:54 +0000
| Newsgroups | net.sourceforge.lists.openvpn-devel |
|---|---|
| Message-ID | <8361c43f4ca4d4516ae921cde6f7d869bdf41a14-EmailReplacePatchSet-HTML@gerrit.openvpn.net> |
--===============2256299606525791415==
Content-Transfer-Encoding: 8bit
Content-Disposition: inline
Content-Type: multipart/alternative; boundary="nkxeMzl1q+A="; charset=UTF-8
--nkxeMzl1q+A=
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Attention is currently required from: stipa=2E
Hello plaisthos,
I'd like=
you to reexamine a change=2E Please visit
http://gerrit=2Eopenvpn=2En=
et/c/openvpn/+/1768?usp=3Demail
to look at the new patch set (#10)=2E
Ch=
ange subject: oob: advertise a connect_lifetime in the probe reply
=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
oob: advertise a co=
nnect_lifetime in the probe reply
A server answering an out-of-band SERVER=
_PROBE now also advertises a
connect_lifetime in the PROBE_REPLY: how long,=
in seconds, a probing client may
use the reply as the server's HARD_RESET =
when it starts a handshake=2E
The value is inferred, not configurable: the=
reply is only usable as that reset
while its stateless SYN-cookie is valid=
, i=2Ee=2E the guaranteed cookie window of
~handshake_window (2 quantised b=
uckets; see check_session_hmac_and_pkt_id), so
the server advertises exactl=
y that=2E A probe that arrived as
P_CONTROL_OOB_WKC_V1 also gets OOB_PROBE_=
REPLY_FLAG_RESEND_WKC, telling the
client to resend the WKc when completing=
the handshake, since the server keeps
no state=2E
Only the wire advertise=
ment is added here -- the server fills both values into
the probe_reply it =
hands to oob_build_probe_reply()=2E The client side that acts
on them follo=
ws=2E
Change-Id: Ib2b6c2246f9d9c0a505292ee8d879f714901ffae
Signed-off-by: =
Lev Stipakov <lev@openvpn=2Enet>
---
M src/openvpn/mudp=2Ec
M src/openvpn/o=
ob=2Eh
M tests/unit_tests/openvpn/test_oob=2Ec
3 files changed, 26 insertio=
ns(+), 2 deletions(-)
git pull ssh://gerrit=2Eopenvpn=2Enet:29418/openv=
pn refs/changes/68/1768/10
diff --git a/src/openvpn/mudp=2Ec b/src/openvpn=
/mudp=2Ec
index 2f48fff=2E=2E9a3acb5 100644
--- a/src/openvpn/mudp=2Ec
+++ =
b/src/openvpn/mudp=2Ec
@@ -243,11 +243,27 @@
/* Out-of-band server=
probe=2E state->newbuf points at the TLV payload
* (read_control=
_auth has stripped the opcode, session id and any
* tls-auth/tls-=
crypt wrapping)=2E Answer it without creating a session=2E */
+
+ /*=
A tls-crypt-v2 client must resend the WKc if it later uses this reply
+ =
* to start a handshake, since we keep no state=2E */
+ uint32_=
t reply_flags =3D
+ (verdict =3D=3D VERDICT_VALID_OOB_WKC_V1) ? =
OOB_PROBE_REPLY_FLAG_RESEND_WKC : 0;
+
+ /* The client's third packe=
t validates only while its SYN-cookie does, so
+ * the advertised c=
onnect_lifetime is inferred (not configurable): the
+ * guaranteed =
cookie window of ~handshake_window (2 quantised buckets; see
+ * ch=
eck_session_hmac_and_pkt_id)=2E Advertising more would make the client
+ =
* trust an already-expired cookie=2E (RFC: connect_lifetime is how lo=
ng the
+ * server considers the reply valid=2E) */
+ int con=
nect_lifetime =3D 2 * ((handwindow + 1) / 2);
+
/* what we adverti=
se; oob_build_probe_reply() adds the peer's session id */
struct o=
ob_probe_reply reply =3D {
=2Epriority =3D (uint16_t)m->top=2E=
options=2Eserver_probe_reply_priority,
=2Eweight =3D (uint16_t=
)m->top=2Eoptions=2Eserver_probe_reply_weight,
=2Emax_latency_=
diff =3D (uint16_t)m->top=2Eoptions=2Eserver_probe_reply_max_latency_diff,
=
+ =2Econnect_lifetime =3D (uint16_t)connect_lifetime,
+ =
=2Eflags =3D reply_flags,
};
if (!oob_build_probe_repl=
y(&state->newbuf, (uint64_t)now, (uint64_t)handwindow,
=
&state->peer_session_id, &reply))
diff --git a/src/openvpn/=
oob=2Eh b/src/openvpn/oob=2Eh
index 4eec498=2E=2E3ff7b53 100644
--- a/src/o=
penvpn/oob=2Eh
+++ b/src/openvpn/oob=2Eh
@@ -157,6 +157,12 @@
*/
bool oo=
b_timestamp_in_window(uint64_t probe_ts, uint64_t now, uint64_t window_secs=
);
+/* probe_reply flags (the reply TLV's 32-bit flags field) */
+/* bit =
0: the client must resend the wrapped client key (via P_CONTROL_WKC_V1)
+ *=
when it completes the handshake started from this reply=2E Set
+ * by a tl=
s-crypt-v2 server, which is stateless and discarded the WKc=2E */
+#define =
OOB_PROBE_REPLY_FLAG_RESEND_WKC 0x1
+
/**
* Process the TLV payload of a=
received SERVER_PROBE and decide whether to
* answer it=2E Combines oob_=
server_probe_read() and oob_timestamp_in_window():
diff --git a/tests/unit_=
tests/openvpn/test_oob=2Ec b/tests/unit_tests/openvpn/test_oob=2Ec
index f6=
e25b4=2E=2Ee6eb6db 100644
--- a/tests/unit_tests/openvpn/test_oob=2Ec
+++ b=
/tests/unit_tests/openvpn/test_oob=2Ec
@@ -390,13 +390,15 @@
=2Epr=
iority =3D 5,
=2Eweight =3D 50,
=2Emax_latency_diff =3D 2=
5,
+ =2Econnect_lifetime =3D 120,
+ =2Eflags =3D OOB_PROBE_RE=
PLY_FLAG_RESEND_WKC,
};
assert_true(oob_build_probe_reply(&buf, n=
ow, 30, &peer, &reply));
assert_memory_equal(reply=2Epeer_session_id=
=2Eid, peer=2Eid, SID_SIZE);
assert_int_equal(reply=2Epriority, 5);
=
assert_int_equal(reply=2Eweight, 50);
- assert_int_equal(reply=2Econn=
ect_lifetime, 0);
- assert_int_equal(reply=2Eflags, 0);
+ assert_int_=
equal(reply=2Econnect_lifetime, 120);
+ assert_int_equal(reply=2Eflags, =
OOB_PROBE_REPLY_FLAG_RESEND_WKC);
assert_int_equal(reply=2Emax_latency=
_diff, 25);
gc_free(&gc);
--
To view, visit http://gerrit=2Eopenvp=
n=2Enet/c/openvpn/+/1768?usp=3Demail
To unsubscribe, or for help writing ma=
il filters, visit http://gerrit=2Eopenvpn=2Enet/settings?usp=3Demail
Gerri=
t-MessageType: newpatchset
Gerrit-Project: openvpn
Gerrit-Branch: master
Ge=
rrit-Change-Id: Ib2b6c2246f9d9c0a505292ee8d879f714901ffae
Gerrit-Change-Num=
ber: 1768
Gerrit-PatchSet: 10
Gerrit-Owner: stipa <lstipakov@gmail=2Ecom>
G=
errit-Reviewer: plaisthos <arne-openvpn@rfc2549=2Eorg>
Gerrit-CC: openvpn-d=
evel <openvpn-devel@lists=2Esourceforge=2Enet>
Gerrit-Attention: stipa <lst=
ipakov@gmail=2Ecom>
--nkxeMzl1q+A=
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<!DOCTYPE html><html><head><style></style></head><body><p> Attention is cur=
rently required from: stipa=2E </p>
<p>stipa <strong>uploaded patch set #10=
</strong> to this change=2E</p><p><a href=3D"http://gerrit=2Eopenvpn=2Enet/=
c/openvpn/+/1768?usp=3Demail">View Change</a></p><pre class=3D"blocks" styl=
e=3D"font-family: monospace,monospace; white-space: pre-wrap;">oob: adverti=
se a connect_lifetime in the probe reply<br><br>A server answering an out-o=
f-band SERVER_PROBE now also advertises a<br>connect_lifetime in the PROBE_=
REPLY: how long, in seconds, a probing client may<br>use the reply as the s=
erver's HARD_RESET when it starts a handshake=2E<br><br>The value is in=
ferred, not configurable: the reply is only usable as that reset<br>while i=
ts stateless SYN-cookie is valid, i=2Ee=2E the guaranteed cookie window of<=
br>~handshake_window (2 quantised buckets; see check_session_hmac_and_pkt_i=
d), so<br>the server advertises exactly that=2E A probe that arrived as<br>=
P_CONTROL_OOB_WKC_V1 also gets OOB_PROBE_REPLY_FLAG_RESEND_WKC, telling the=
<br>client to resend the WKc when completing the handshake, since the serve=
r keeps<br>no state=2E<br><br>Only the wire advertisement is added here -- =
the server fills both values into<br>the probe_reply it hands to oob_build_=
probe_reply()=2E The client side that acts<br>on them follows=2E<br><br>Cha=
nge-Id: Ib2b6c2246f9d9c0a505292ee8d879f714901ffae<br>Signed-off-by: Lev Sti=
pakov <lev@openvpn=2Enet><br>---<br>M src/openvpn/mudp=2Ec<br>M src/o=
penvpn/oob=2Eh<br>M tests/unit_tests/openvpn/test_oob=2Ec<br>3 files change=
d, 26 insertions(+), 2 deletions(-)<br><br></pre><pre class=3D"blocks" styl=
e=3D"font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh=
://gerrit=2Eopenvpn=2Enet:29418/openvpn refs/changes/68/1768/10</pre><pre s=
tyle=3D"font-family: monospace,monospace; white-space: pre-wrap;"><span>dif=
f --git a/src/openvpn/mudp=2Ec b/src/openvpn/mudp=2Ec</span><br><span>index=
2f48fff=2E=2E9a3acb5 100644</span><br><span>--- a/src/openvpn/mudp=2Ec</sp=
an><br><span>+++ b/src/openvpn/mudp=2Ec</span><br><span>@@ -243,11 +243,27 =
@@</span><br><span> /* Out-of-band server probe=2E state->newbuf=
points at the TLV payload</span><br><span> * (read_control_auth h=
as stripped the opcode, session id and any</span><br><span> * tls-=
auth/tls-crypt wrapping)=2E Answer it without creating a session=2E */</spa=
n><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ /* A tls-crypt-v2 client must res=
end the WKc if it later uses this reply</span><br><span style=3D"color: hsl=
(120, 100%, 40%);">+ * to start a handshake, since we keep no state=
=2E */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ uint3=
2_t reply_flags =3D</span><br><span style=3D"color: hsl(120, 100%, 40%);">+=
(verdict =3D=3D VERDICT_VALID_OOB_WKC_V1) ? OOB_PROBE_REPLY_FLA=
G_RESEND_WKC : 0;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</=
span><br><span style=3D"color: hsl(120, 100%, 40%);">+ /* The client=
's third packet validates only while its SYN-cookie does, so</span><br>=
<span style=3D"color: hsl(120, 100%, 40%);">+ * the advertised conn=
ect_lifetime is inferred (not configurable): the</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+ * guaranteed cookie window of ~handsh=
ake_window (2 quantised buckets; see</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+ * check_session_hmac_and_pkt_id)=2E Advertising m=
ore would make the client</span><br><span style=3D"color: hsl(120, 100%, 40=
%);">+ * trust an already-expired cookie=2E (RFC: connect_lifetime =
is how long the</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
* server considers the reply valid=2E) */</span><br><span style=3D"col=
or: hsl(120, 100%, 40%);">+ int connect_lifetime =3D 2 * ((handwindo=
w + 1) / 2);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span>=
<br><span> /* what we advertise; oob_build_probe_reply() adds the p=
eer's session id */</span><br><span> struct oob_probe_reply rep=
ly =3D {</span><br><span> =2Epriority =3D (uint16_t)m->top=
=2Eoptions=2Eserver_probe_reply_priority,</span><br><span> =2Ew=
eight =3D (uint16_t)m->top=2Eoptions=2Eserver_probe_reply_weight,</span>=
<br><span> =2Emax_latency_diff =3D (uint16_t)m->top=2Eoption=
s=2Eserver_probe_reply_max_latency_diff,</span><br><span style=3D"color: hs=
l(120, 100%, 40%);">+ =2Econnect_lifetime =3D (uint16_t)connect_=
lifetime,</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
=2Eflags =3D reply_flags,</span><br><span> };</span><br><span> =
if (!oob_build_probe_reply(&state->newbuf, (uint64_t)now, (uin=
t64_t)handwindow,</span><br><span> &=
state->peer_session_id, &reply))</span><br><span>diff --git a/src/op=
envpn/oob=2Eh b/src/openvpn/oob=2Eh</span><br><span>index 4eec498=2E=2E3ff7=
b53 100644</span><br><span>--- a/src/openvpn/oob=2Eh</span><br><span>+++ b/=
src/openvpn/oob=2Eh</span><br><span>@@ -157,6 +157,12 @@</span><br><span> =
*/</span><br><span> bool oob_timestamp_in_window(uint64_t probe_ts, uint64_=
t now, uint64_t window_secs);</span><br><span> </span><br><span style=3D"co=
lor: hsl(120, 100%, 40%);">+/* probe_reply flags (the reply TLV's 32-bi=
t flags field) */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+/*=
bit 0: the client must resend the wrapped client key (via P_CONTROL_WKC_V1=
)</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * when it complet=
es the handshake started from this reply=2E Set</span><br><span style=3D"co=
lor: hsl(120, 100%, 40%);">+ * by a tls-crypt-v2 server, which is stateless=
and discarded the WKc=2E */</span><br><span style=3D"color: hsl(120, 100%,=
40%);">+#define OOB_PROBE_REPLY_FLAG_RESEND_WKC 0x1</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+</span><br><span> /**</span><br><span> *=
Process the TLV payload of a received SERVER_PROBE and decide whether to</=
span><br><span> * answer it=2E Combines oob_server_probe_read() and oob_ti=
mestamp_in_window():</span><br><span>diff --git a/tests/unit_tests/openvpn/=
test_oob=2Ec b/tests/unit_tests/openvpn/test_oob=2Ec</span><br><span>index =
f6e25b4=2E=2Ee6eb6db 100644</span><br><span>--- a/tests/unit_tests/openvpn/=
test_oob=2Ec</span><br><span>+++ b/tests/unit_tests/openvpn/test_oob=2Ec</s=
pan><br><span>@@ -390,13 +390,15 @@</span><br><span> =2Epriority =
=3D 5,</span><br><span> =2Eweight =3D 50,</span><br><span> =
=2Emax_latency_diff =3D 25,</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+ =2Econnect_lifetime =3D 120,</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ =2Eflags =3D OOB_PROBE_REPLY_FLAG_RESEND_W=
KC,</span><br><span> };</span><br><span> assert_true(oob_build_prob=
e_reply(&buf, now, 30, &peer, &reply));</span><br><span> as=
sert_memory_equal(reply=2Epeer_session_id=2Eid, peer=2Eid, SID_SIZE);</span=
><br><span> assert_int_equal(reply=2Epriority, 5);</span><br><span> =
assert_int_equal(reply=2Eweight, 50);</span><br><span style=3D"color: hsl(=
0, 100%, 40%);">- assert_int_equal(reply=2Econnect_lifetime, 0);</span><=
br><span style=3D"color: hsl(0, 100%, 40%);">- assert_int_equal(reply=2E=
flags, 0);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ asser=
t_int_equal(reply=2Econnect_lifetime, 120);</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+ assert_int_equal(reply=2Eflags, OOB_PROBE_REPLY=
_FLAG_RESEND_WKC);</span><br><span> assert_int_equal(reply=2Emax_latenc=
y_diff, 25);</span><br><span> </span><br><span> gc_free(&gc);</span=
><br><span></span><br></pre><p>To view, visit <a href=3D"http://gerrit=2Eop=
envpn=2Enet/c/openvpn/+/1768?usp=3Demail">change 1768</a>=2E To unsubscribe=
, or for help writing mail filters, visit <a href=3D"http://gerrit=2Eopenvp=
n=2Enet/settings?usp=3Demail">settings</a>=2E</p><div itemscope itemtype=3D=
"http://schema=2Eorg/EmailMessage"><div itemscope itemprop=3D"action" itemt=
ype=3D"http://schema=2Eorg/ViewAction"><link itemprop=3D"url" href=3D"http:=
//gerrit=2Eopenvpn=2Enet/c/openvpn/+/1768?usp=3Demail"/><meta itemprop=3D"n=
ame" content=3D"View Change"/></div></div>
<div style=3D"display:none"> Ge=
rrit-MessageType: newpatchset </div>
<div style=3D"display:none"> Gerrit-Pr=
oject: openvpn </div>
<div style=3D"display:none"> Gerrit-Branch: master </=
div>
<div style=3D"display:none"> Gerrit-Change-Id: Ib2b6c2246f9d9c0a505292=
ee8d879f714901ffae </div>
<div style=3D"display:none"> Gerrit-Change-Number=
: 1768 </div>
<div style=3D"display:none"> Gerrit-PatchSet: 10 </div>
<div =
style=3D"display:none"> Gerrit-Owner: stipa <lstipakov@gmail=2Ecom> <=
/div>
<div style=3D"display:none"> Gerrit-Reviewer: plaisthos <arne-open=
vpn@rfc2549=2Eorg> </div>
<div style=3D"display:none"> Gerrit-CC: openvp=
n-devel <openvpn-devel@lists=2Esourceforge=2Enet> </div>
<div style=
=3D"display:none"> Gerrit-Attention: stipa <lstipakov@gmail=2Ecom> </=
div>
</body></html>
--nkxeMzl1q+A=--
--===============2256299606525791415==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
--===============2256299606525791415==
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
--===============2256299606525791415==--