[M] Change in openvpn[master]: oob: start the client handshake from the server probe
"stipa \(Code Review\) via Openvpn-devel" <[email protected]> Wed, 29 Jul 2026 12:22:54 +0000
| Newsgroups | gmane.network.openvpn.devel |
|---|---|
| Message-ID | <074e118cb1a5b1fbfee0c8eaaf14e5a2ccfda3a6-EmailReplacePatchSet-HTML@gerrit.openvpn.net> |
--===============2128253188981459948==
Content-Transfer-Encoding: 8bit
Content-Disposition: inline
Content-Type: multipart/alternative; boundary="XJd/Lz9GVFc="; charset=UTF-8
--XJd/Lz9GVFc=
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Attention is currently required from: plaisthos=2E
Hello plaisthos,
I'd =
like you to reexamine a change=2E Please visit
http://gerrit=2Eopenvpn=
=2Enet/c/openvpn/+/1770?usp=3Demail
to look at the new patch set (#10)=2E
=
Change subject: oob: start the client handshake from the server probe
=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: start the c=
lient handshake from the server probe
When the best remote answered a prob=
e and advertised a connect_lifetime, its
reply also served as the server's =
HARD_RESET: its session id is a valid
stateless SYN-cookie=2E The client th=
erefore starts the handshake from that reply
instead of running its own res=
et exchange=2E
Note this does not shorten the handshake itself -- the prob=
e and its reply take
the place of the two reset packets rather than removin=
g them=2E The saving is one
RTT compared with probing and then connecting; =
a client that does not probe is
unaffected=2E
- oob_client=2Ec: when the=
winner advertised a connect_lifetime, hand its probe
socket, the captu=
red server session id (cookie), our probe session id, the
pinned respon=
der address, and the resend-wkc flag to the connection via c2;
relinqui=
sh that socket (do not close it); gate off for dco-win, which has no
us=
er-to-kernel socket handoff (probing still works, only starting from the
=
reply is skipped)=2E
- ssl=2Ec session_skip_to_pre_start_client(): seed=
our session id to the probe's
(the cookie is an HMAC over it), the rem=
ote session id to the cookie, ack
the phantom server reset (id 0) so th=
e third packet carries the cookie, set
CO_RESEND_WKC for tls-crypt-v2, =
and drop to S_PRE_START so tls_process()
promotes to S_START and sends =
the ClientHello (no HARD_RESET sent)=2E
- init=2Ec: invoke the client ski=
p after tls_multi_init_finalize when adopting,
and count the probe repl=
y as the initial packet received (n_sessions++, as
the server does befo=
re its own session_skip_to_pre_start) so
check_server_poll_timeout() do=
es not restart the connected session=2E
Change-Id: I454d5040cbad4d373ee4f9=
0b8d683200d2a4c0e4
Signed-off-by: Lev Stipakov <lev@openvpn=2Enet>
---
M Ch=
anges=2Erst
M src/openvpn/init=2Ec
M src/openvpn/oob=2Eh
M src/openvpn/oob_=
client=2Ec
M src/openvpn/openvpn=2Eh
M src/openvpn/ssl=2Ec
M src/openvpn/ss=
l=2Eh
7 files changed, 176 insertions(+), 6 deletions(-)
git pull ssh:/=
/gerrit=2Eopenvpn=2Enet:29418/openvpn refs/changes/70/1770/10
diff --git a=
/Changes=2Erst b/Changes=2Erst
index 080d928=2E=2E4d7a16c9 100644
--- a/Cha=
nges=2Erst
+++ b/Changes=2Erst
@@ -9,6 +9,13 @@
measured latency and a=
dvertised weight with DNS-SRV-like semantics=2E
Servers advertise thes=
e values with ``--server-probe-reply``=2E
+Probe exchange doubles as the =
start of the handshake
+ When a probing client picks a server that adver=
tises support for it,
+ the probe and its reply take the place of the cl=
ient's and server's
+ reset packets, so the client does not need a separ=
ate reset exchange
+ before the handshake=2E This saves one round trip c=
ompared with probing
+ and then connecting, and needs no extra configura=
tion=2E
+
Overview of changes in 2=2E7
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
diff --git a/src/openvpn/i=
nit=2Ec b/src/openvpn/init=2Ec
index 1598a23=2E=2E065cc47 100644
--- a/src/=
openvpn/init=2Ec
+++ b/src/openvpn/init=2Ec
@@ -3507,6 +3507,21 @@
=
/* Keep the max mtu also in the frame of tls multi so it can access
=
* it in push_peer_info */
c->c2=2Etls_multi->opt=2Eframe=2Etun=
_max_mtu =3D c->c2=2Eframe=2Etun_max_mtu;
+
+ /* OOB server probe: t=
he probe reply already served as the server's
+ * HARD_RESET (it ca=
rried a valid SYN-cookie), so the handshake starts
+ * from that re=
ply and we send no reset of our own=2E Count
+ * the reply as the i=
nitial packet received (as the server does before its
+ * own sessi=
on_skip_to_pre_start), so tls_initial_packet_received() is true
+ *=
and check_server_poll_timeout() does not restart a connected session=2E */=
+ if (c->c2=2Eoob_probe_adopt)
+ {
+ c->c2=2Etls_=
multi->n_sessions++;
+ session_skip_to_pre_start_client(&c->c2=
=2Etls_multi->session[TM_ACTIVE],
+ =
&c->c2=2Eoob_probe_client_sid,
+ =
&c->c2=2Eoob_probe_server_sid, &c->c2=2Eoob_probe_remote,
+ =
c->c2=2Eoob_probe_resend_wkc);
+ =
}
}
if (c->c2=2Etls_auth_standalone)
{
diff --git a/src/ope=
nvpn/oob=2Eh b/src/openvpn/oob=2Eh
index 3ff7b53=2E=2E9e758ce 100644
--- a/=
src/openvpn/oob=2Eh
+++ b/src/openvpn/oob=2Eh
@@ -197,8 +197,11 @@
{
=
int index;
bool responded;
- unsigned int rtt_ms; /* probe=
round-trip time in ms (responders only) */
- struct oob_probe_reply rep=
ly; /* the values the server advertised */
+ unsigned int rtt_ms; /* pro=
be round-trip time in ms (responders only) */
+ /* Captured from the pac=
ket and its reply TLV (responders only): */
+ struct session_id server_s=
id; /* the packet's own session id =3D server SYN-cookie */
+ struc=
t sockaddr_storage responder; /* address that answered (pin the connection =
to it) */
+ struct oob_probe_reply reply; /* the values the server =
advertised */
};
/**
diff --git a/src/openvpn/oob_client=2Ec b/src/open=
vpn/oob_client=2Ec
index d53e376=2E=2Ebfc129b 100644
--- a/src/openvpn/oob_=
client=2Ec
+++ b/src/openvpn/oob_client=2Ec
@@ -38,6 +38,7 @@
#include "ot=
ime=2Eh"
#include "fdmisc=2Eh"
#include "crypto=2Eh"
+#include "dco=2Eh"
=
#include "error=2Eh"
#include "memdbg=2Eh"
@@ -217,6 +218,13 @@
=
return;
}
+ /* The reply's own session id (the server's statele=
ss SYN-cookie) follows the
+ * opcode byte=2E Capture it before read_co=
ntrol_auth() strips it: a client may
+ * reuse it to start the handshak=
e from this reply (the connect_lifetime
+ * advertisement)=2E */
+ s=
truct session_id server_sid;
+ memcpy(server_sid=2Eid, data + 1, SID_SIZ=
E);
+
struct buffer buf;
buf_set_read(&buf, data, (size_t)len);
=
@@ -274,6 +282,8 @@
results[i]=2Eresponded =3D true;
r=
esults[i]=2Ertt_ms =3D (ms > 0) ? (unsigned int)ms : 0;
+ results[i]=
=2Eserver_sid =3D server_sid;
+ results[i]=2Eresponder =3D *from; /*=
pin the connection to the address that answered */
results[i]=2Er=
eply =3D reply;
break;
}
@@ -590,7 +600,6 @@
{
=
oob_probe_collect(&pc, &probe, &client_sid, &tas->tls_wrap, targets, result=
s, l->len);
}
- oob_probe_sockets_close(&pc);
/* Log each re=
mote's outcome while results[i] still maps to array[i]=2E */
int respo=
nded =3D 0;
@@ -609,10 +618,10 @@
: r=
esults[i]=2Ereply=2Emax_latency_diff > 0 ? "server-advertised"
=
: "defaul=
t";
msg(D_LOW,
- "server-probe: %s:%s answered =
(priority %d, weight %d, rtt %u ms;"
- " latency margin %d m=
s [%s])",
+ "server-probe: %s:%s answered (priority %d, weig=
ht %d, connect-lifetime %d s,"
+ " rtt %u ms; latency margin=
%d ms [%s])",
ce->remote, ce->remote_port, results[i]=2Er=
eply=2Epriority, results[i]=2Ereply=2Eweight,
- results[i]=
=2Ertt_ms, margin, margin_src);
+ results[i]=2Ereply=2Econne=
ct_lifetime, results[i]=2Ertt_ms, margin, margin_src);
}
=
else
{
@@ -634,6 +643,69 @@
msg(M_INFO, "server-probe: %d of =
%d remote(s) answered; connecting best-first", responded,
l->len);=
+ /* If the winner advertised a connect_lifetime, its reply also serv=
ed as the
+ * server's reset: hand its probe socket and the captured co=
okie to the
+ * connection, which then starts the handshake from that r=
eply (see
+ * session_skip_to_pre_start_client)=2E Reusing that socket =
keeps the source
+ * IP+port the cookie is bound to=2E dco-win cannot h=
and a socket to the
+ * kernel, so it only gets the probe ordering=2E *=
/
+
+ /* Single-use, so the RFC's connect_lifetime expiry check is not n=
eeded yet:
+ * we probe once (c->first_time) and arm only results[0]=2E=
*/
+ bool probe_start =3D results[0]=2Eresponded && results[0]=2Ereply=
=2Econnect_lifetime > 0;
+ bool dco_win_gate =3D false;
+#if defined(_WI=
N32)
+ if (dco_enabled(&c->options))
+ {
+ probe_start =3D fal=
se;
+ dco_win_gate =3D true;
+ }
+#endif
+ if (probe_start)
+ =
{
+ const int af_idx =3D probe_af_index(results[0]=2Eresponder=2E=
ss_family);
+ c->c2=2Eoob_probe_sd =3D pc=2Esd[af_idx];
+ pc=
=2Esd[af_idx] =3D SOCKET_UNDEFINED; /* relinquish: the connection owns it n=
ow */
+
+ CLEAR(c->c2=2Eoob_probe_remote);
+ if (results[0]=
=2Eresponder=2Ess_family =3D=3D AF_INET)
+ {
+ c->c2=2Eoo=
b_probe_remote=2Eaddr=2Ein4 =3D *(struct sockaddr_in *)(void *)&results[0]=
=2Eresponder;
+ }
+ else
+ {
+ c->c2=2Eoob_=
probe_remote=2Eaddr=2Ein6 =3D *(struct sockaddr_in6 *)(void *)&results[0]=
=2Eresponder;
+ }
+ c->c2=2Eoob_probe_client_sid =3D client_s=
id;
+ c->c2=2Eoob_probe_server_sid =3D results[0]=2Eserver_sid;
+ =
c->c2=2Eoob_probe_resend_wkc =3D
+ (results[0]=2Ereply=2Efl=
ags & OOB_PROBE_REPLY_FLAG_RESEND_WKC) !=3D 0;
+ c->c2=2Eoob_probe_a=
dopt =3D true;
+
+ msg(D_LOW, "server-probe: starting handshake from=
probe reply of %s:%s"
+ " (connect-lifetime %d s)",
+ =
l->array[0]->remote, l->array[0]->remote_port, results[0]=2Ereply=
=2Econnect_lifetime);
+ }
+ else if (results[0]=2Eresponded)
+ {
+=
/* A server answered but we won't start the handshake from it -- sa=
y why=2E */
+ if (dco_win_gate)
+ {
+ msg(D_LOW, "=
server-probe: cannot start the handshake from a probe reply"
+ =
" with dco-win;"
+ " using a full handshake=
");
+ }
+ else if (results[0]=2Ereply=2Econnect_lifetime =3D=
=3D 0)
+ {
+ msg(D_LOW, "server-probe: %s:%s did not adve=
rtise a connect-lifetime"
+ " (connect-lifetime 0); u=
sing a full handshake",
+ l->array[0]->remote, l->array[0]->=
remote_port);
+ }
+ }
+
+ /* Close any probe sockets we did no=
t hand off to the connection=2E */
+ oob_probe_sockets_close(&pc);
+
=
tls_auth_standalone_free(tas);
gc_free(&gc);
}
diff --git a/src/ope=
nvpn/openvpn=2Eh b/src/openvpn/openvpn=2Eh
index 44c598f=2E=2Ed8e02f2 10064=
4
--- a/src/openvpn/openvpn=2Eh
+++ b/src/openvpn/openvpn=2Eh
@@ -249,6 +24=
9,9 @@
bool oob_probe_adopt;
socket_descriptor_t oob_probe_sd;
=
struct openvpn_sockaddr oob_probe_remote;
+ struct session_id oob_pro=
be_client_sid; /* our probe session id (cookie was minted over it) */
+ =
struct session_id oob_probe_server_sid; /* the reply's session id =3D ser=
ver cookie to echo back */
+ bool oob_probe_resend_wkc; /*=
reply asked to complete with CONTROL_WKC_V1 (v2) */
struct link_soc=
ket_actual *to_link_addr; /* IP address of remote */
struct link_socke=
t_actual from; /* address of incoming datagram */
diff --git a/src=
/openvpn/ssl=2Ec b/src/openvpn/ssl=2Ec
index 9e1a6aa=2E=2Eee8c5bf 100644
--=
- a/src/openvpn/ssl=2Ec
+++ b/src/openvpn/ssl=2Ec
@@ -2516,6 +2516,59 @@
=
return session_move_pre_start(session, ks, true);
}
+bool
+session_sk=
ip_to_pre_start_client(struct tls_session *session, const struct session_id=
*client_sid,
+ const struct session_id *se=
rver_sid,
+ const struct openvpn_sockaddr *=
remote, bool resend_wkc)
+{
+ struct key_state *ks =3D &session->key[KS_=
PRIMARY];
+
+ /* Our session id must be the one used for the probe: the =
server's cookie
+ * (server_sid) is an HMAC over it, and the server re-=
derives and checks it
+ * when it validates our third packet=2E */
+ =
session->session_id =3D *client_sid;
+ ks->session_id_remote =3D *serve=
r_sid;
+
+ struct link_socket_actual act =3D { 0 };
+ act=2Edest =3D =
*remote;
+ ks->remote_addr =3D act;
+ session->untrusted_addr =3D act=
;
+ session->burst =3D true;
+
+ /* tls-crypt-v2: the stateless serve=
r discarded the WKc after the probe, so
+ * complete the handshake with=
P_CONTROL_WKC_V1 (drives control_packet_needs_wkc)=2E */
+ if (resend_w=
kc)
+ {
+ ks->crypto_options=2Eflags |=3D CO_RESEND_WKC;
+ }
+=
+ /* We never received the server's HARD_RESET (id 0) =E2=80=94 the pro=
be reply stood
+ * in for it=2E Acknowledge that phantom id 0 so our th=
ird packet carries an
+ * ACK together with the server session id (the =
cookie): reliable_ack_write()
+ * only emits that session id when at le=
ast one ACK is present, and the server
+ * needs it to validate the sta=
teless cookie=2E */
+ reliable_ack_acknowledge_packet_id(ks->rec_ack, 0)=
;
+
+ /* Skip one (RESET) packet in each direction, so ids start at 1 (s=
ee
+ * session_skip_to_pre_start)=2E */
+ ks->rec_reliable->packet_i=
d =3D 1;
+ session->tls_wrap=2Eopt=2Epacket_id=2Esend=2Eid =3D 1;
+
+ =
/* Do not send our own HARD_RESET=2E Unlike the server's skip, the client =
must
+ * send first: the stateless server only replies once it sees our=
third
+ * packet=2E session_move_pre_start(skip=3Dtrue) leaves us in S=
_PRE_START_SKIP,
+ * which only advances when a packet is *received*; i=
nstead drop to
+ * S_PRE_START with an empty send-reliable (the initial=
packet was generated
+ * and immediately deleted), so tls_process() pr=
omotes us to S_START and
+ * sends the ClientHello without waiting for =
a server reset=2E */
+ if (!session_move_pre_start(session, ks, true))
+=
{
+ return false;
+ }
+ ks->state =3D S_PRE_START;
+ re=
turn true;
+}
+
/**
* Parses the TLVs (type, length, value) in the early=
negotiation
*/
diff --git a/src/openvpn/ssl=2Eh b/src/openvpn/ssl=2Eh
in=
dex 7ddf965=2E=2Ea534007 100644
--- a/src/openvpn/ssl=2Eh
+++ b/src/openvpn=
/ssl=2Eh
@@ -576,4 +576,21 @@
bool session_skip_to_pre_start(struct tls_se=
ssion *session, struct tls_pre_decrypt_state *state,
=
struct link_socket_actual *from);
+/**
+ * Client counterpart o=
f session_skip_to_pre_start(): start the handshake from a
+ * server sessio=
n id (SYN-cookie) learned earlier from an OOB server probe
+ * reply, which=
already served as the server's HARD_RESET, so we send none=2E
+ *
+ * @par=
am session the (client) TLS session to fast-forward
+ * @param client_s=
id session id used for the probe (the cookie is an HMAC over it)
+ * @para=
m server_sid the server's cookie, echoed back to complete the handshake
+ =
* @param remote the probed (pinned) server address to connect to
+ * @=
param resend_wkc true to complete with P_CONTROL_WKC_V1 (tls-crypt-v2)
+ *=
@return true if the session was fast-forwarded, false on failure
+ */
+boo=
l session_skip_to_pre_start_client(struct tls_session *session,
+ =
const struct session_id *client_sid,
+ =
const struct session_id *server_sid,
+ =
const struct openvpn_sockaddr *remote, bool r=
esend_wkc);
+
#endif /* ifndef OPENVPN_SSL_H */
--
To view, visit http:/=
/gerrit=2Eopenvpn=2Enet/c/openvpn/+/1770?usp=3Demail
To unsubscribe, or for=
help writing mail filters, visit http://gerrit=2Eopenvpn=2Enet/settings?us=
p=3Demail
Gerrit-MessageType: newpatchset
Gerrit-Project: openvpn
Gerrit-B=
ranch: master
Gerrit-Change-Id: I454d5040cbad4d373ee4f90b8d683200d2a4c0e4
G=
errit-Change-Number: 1770
Gerrit-PatchSet: 10
Gerrit-Owner: stipa <lstipako=
v@gmail=2Ecom>
Gerrit-Reviewer: plaisthos <arne-openvpn@rfc2549=2Eorg>
Gerr=
it-CC: openvpn-devel <openvpn-devel@lists=2Esourceforge=2Enet>
Gerrit-Atten=
tion: plaisthos <arne-openvpn@rfc2549=2Eorg>
--XJd/Lz9GVFc=
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: plaisthos=2E </p>
<p>stipa <strong>uploaded patch set=
#10</strong> to this change=2E</p><p><a href=3D"http://gerrit=2Eopenvpn=2E=
net/c/openvpn/+/1770?usp=3Demail">View Change</a></p><pre class=3D"blocks" =
style=3D"font-family: monospace,monospace; white-space: pre-wrap;">oob: sta=
rt the client handshake from the server probe<br><br>When the best remote a=
nswered a probe and advertised a connect_lifetime, its<br>reply also served=
as the server's HARD_RESET: its session id is a valid<br>stateless SYN=
-cookie=2E The client therefore starts the handshake from that reply<br>ins=
tead of running its own reset exchange=2E<br><br>Note this does not shorten=
the handshake itself -- the probe and its reply take<br>the place of the t=
wo reset packets rather than removing them=2E The saving is one<br>RTT comp=
ared with probing and then connecting; a client that does not probe is<br>u=
naffected=2E<br><br> - oob_client=2Ec: when the winner advertised a connec=
t_lifetime, hand its probe<br> socket, the captured server session id (c=
ookie), our probe session id, the<br> pinned responder address, and the =
resend-wkc flag to the connection via c2;<br> relinquish that socket (do=
not close it); gate off for dco-win, which has no<br> user-to-kernel so=
cket handoff (probing still works, only starting from the<br> reply is s=
kipped)=2E<br> - ssl=2Ec session_skip_to_pre_start_client(): seed our sess=
ion id to the probe's<br> (the cookie is an HMAC over it), the remot=
e session id to the cookie, ack<br> the phantom server reset (id 0) so t=
he third packet carries the cookie, set<br> CO_RESEND_WKC for tls-crypt-=
v2, and drop to S_PRE_START so tls_process()<br> promotes to S_START and=
sends the ClientHello (no HARD_RESET sent)=2E<br> - init=2Ec: invoke the =
client skip after tls_multi_init_finalize when adopting,<br> and count t=
he probe reply as the initial packet received (n_sessions++, as<br> the =
server does before its own session_skip_to_pre_start) so<br> check_serve=
r_poll_timeout() does not restart the connected session=2E<br><br>Change-Id=
: I454d5040cbad4d373ee4f90b8d683200d2a4c0e4<br>Signed-off-by: Lev Stipakov =
<lev@openvpn=2Enet><br>---<br>M Changes=2Erst<br>M src/openvpn/init=
=2Ec<br>M src/openvpn/oob=2Eh<br>M src/openvpn/oob_client=2Ec<br>M src/open=
vpn/openvpn=2Eh<br>M src/openvpn/ssl=2Ec<br>M src/openvpn/ssl=2Eh<br>7 file=
s changed, 176 insertions(+), 6 deletions(-)<br><br></pre><pre class=3D"blo=
cks" style=3D"font-family: monospace,monospace; white-space: pre-wrap;">git=
pull ssh://gerrit=2Eopenvpn=2Enet:29418/openvpn refs/changes/70/1770/10</p=
re><pre style=3D"font-family: monospace,monospace; white-space: pre-wrap;">=
<span>diff --git a/Changes=2Erst b/Changes=2Erst</span><br><span>index 080d=
928=2E=2E4d7a16c9 100644</span><br><span>--- a/Changes=2Erst</span><br><spa=
n>+++ b/Changes=2Erst</span><br><span>@@ -9,6 +9,13 @@</span><br><span> =
measured latency and advertised weight with DNS-SRV-like semantics=2E</spa=
n><br><span> Servers advertise these values with ``--server-probe-reply=
``=2E</span><br><span> </span><br><span style=3D"color: hsl(120, 100%, 40%)=
;">+Probe exchange doubles as the start of the handshake</span><br><span st=
yle=3D"color: hsl(120, 100%, 40%);">+ When a probing client picks a serv=
er that advertises support for it,</span><br><span style=3D"color: hsl(120,=
100%, 40%);">+ the probe and its reply take the place of the client'=
;s and server's</span><br><span style=3D"color: hsl(120, 100%, 40%);">+=
reset packets, so the client does not need a separate reset exchange</s=
pan><br><span style=3D"color: hsl(120, 100%, 40%);">+ before the handsha=
ke=2E This saves one round trip compared with probing</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ and then connecting, and needs no ext=
ra configuration=2E</span><br><span style=3D"color: hsl(120, 100%, 40%);">+=
</span><br><span> </span><br><span> Overview of changes in 2=2E7</span><br>=
<span> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D</span><br><span>diff --git a/src/openvpn/init=2Ec b/src/openvp=
n/init=2Ec</span><br><span>index 1598a23=2E=2E065cc47 100644</span><br><spa=
n>--- a/src/openvpn/init=2Ec</span><br><span>+++ b/src/openvpn/init=2Ec</sp=
an><br><span>@@ -3507,6 +3507,21 @@</span><br><span> /* Keep the ma=
x mtu also in the frame of tls multi so it can access</span><br><span> =
* it in push_peer_info */</span><br><span> c->c2=2Etls_mult=
i->opt=2Eframe=2Etun_max_mtu =3D c->c2=2Eframe=2Etun_max_mtu;</span><=
br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+ /* OOB server probe: the probe reply a=
lready served as the server's</span><br><span style=3D"color: hsl(120, =
100%, 40%);">+ * HARD_RESET (it carried a valid SYN-cookie), so the=
handshake starts</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
* from that reply and we send no reset of our own=2E Count</span><br=
><span style=3D"color: hsl(120, 100%, 40%);">+ * the reply as the i=
nitial packet received (as the server does before its</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ * own session_skip_to_pre_start)=
, so tls_initial_packet_received() is true</span><br><span style=3D"color: =
hsl(120, 100%, 40%);">+ * and check_server_poll_timeout() does not =
restart a connected session=2E */</span><br><span style=3D"color: hsl(120, =
100%, 40%);">+ if (c->c2=2Eoob_probe_adopt)</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ {</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+ c->c2=2Etls_multi->n_sessions++;<=
/span><br><span style=3D"color: hsl(120, 100%, 40%);">+ session_=
skip_to_pre_start_client(&c->c2=2Etls_multi->session[TM_ACTIVE],<=
/span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
&c->c2=2Eoob_probe_client_sid,</span><br><s=
pan style=3D"color: hsl(120, 100%, 40%);">+ =
&c->c2=2Eoob_probe_server_sid, &c->c2=2Eoob_prob=
e_remote,</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
c->c2=2Eoob_probe_resend_wkc);</span>=
<br><span style=3D"color: hsl(120, 100%, 40%);">+ }</span><br><span>=
}</span><br><span> if (c->c2=2Etls_auth_standalone)</span><br><=
span> {</span><br><span>diff --git a/src/openvpn/oob=2Eh b/src/openvpn/=
oob=2Eh</span><br><span>index 3ff7b53=2E=2E9e758ce 100644</span><br><span>-=
-- a/src/openvpn/oob=2Eh</span><br><span>+++ b/src/openvpn/oob=2Eh</span><b=
r><span>@@ -197,8 +197,11 @@</span><br><span> {</span><br><span> int in=
dex;</span><br><span> bool responded;</span><br><span style=3D"color: h=
sl(0, 100%, 40%);">- unsigned int rtt_ms; /* probe round-trip t=
ime in ms (responders only) */</span><br><span style=3D"color: hsl(0, 100%,=
40%);">- struct oob_probe_reply reply; /* the values the server adverti=
sed */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ unsigned =
int rtt_ms; /* probe round-trip time in ms (responders only) */</span><br><=
span style=3D"color: hsl(120, 100%, 40%);">+ /* Captured from the packet=
and its reply TLV (responders only): */</span><br><span style=3D"color: hs=
l(120, 100%, 40%);">+ struct session_id server_sid; /* the packet&#=
39;s own session id =3D server SYN-cookie */</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ struct sockaddr_storage responder; /* address =
that answered (pin the connection to it) */</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+ struct oob_probe_reply reply; /* the value=
s the server advertised */</span><br><span> };</span><br><span> </span><br>=
<span> /**</span><br><span>diff --git a/src/openvpn/oob_client=2Ec b/src/op=
envpn/oob_client=2Ec</span><br><span>index d53e376=2E=2Ebfc129b 100644</spa=
n><br><span>--- a/src/openvpn/oob_client=2Ec</span><br><span>+++ b/src/open=
vpn/oob_client=2Ec</span><br><span>@@ -38,6 +38,7 @@</span><br><span> #incl=
ude "otime=2Eh"</span><br><span> #include "fdmisc=2Eh"<=
/span><br><span> #include "crypto=2Eh"</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+#include "dco=2Eh"</span><br><span> =
#include "error=2Eh"</span><br><span> </span><br><span> #include =
"memdbg=2Eh"</span><br><span>@@ -217,6 +218,13 @@</span><br><span=
> return;</span><br><span> }</span><br><span> </span><br><span =
style=3D"color: hsl(120, 100%, 40%);">+ /* The reply's own session i=
d (the server's stateless SYN-cookie) follows the</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ * opcode byte=2E Capture it before r=
ead_control_auth() strips it: a client may</span><br><span style=3D"color: =
hsl(120, 100%, 40%);">+ * reuse it to start the handshake from this rep=
ly (the connect_lifetime</span><br><span style=3D"color: hsl(120, 100%, 40%=
);">+ * advertisement)=2E */</span><br><span style=3D"color: hsl(120, 1=
00%, 40%);">+ struct session_id server_sid;</span><br><span style=3D"col=
or: hsl(120, 100%, 40%);">+ memcpy(server_sid=2Eid, data + 1, SID_SIZE);=
</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span> =
struct buffer buf;</span><br><span> buf_set_read(&buf, data, (si=
ze_t)len);</span><br><span> </span><br><span>@@ -274,6 +282,8 @@</span><br>=
<span> </span><br><span> results[i]=2Eresponded =3D true;</span><br=
><span> results[i]=2Ertt_ms =3D (ms > 0) ? (unsigned int)ms : 0;=
</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ results[i]=
=2Eserver_sid =3D server_sid;</span><br><span style=3D"color: hsl(120, 100%=
, 40%);">+ results[i]=2Eresponder =3D *from; /* pin the connection t=
o the address that answered */</span><br><span> results[i]=2Ereply =
=3D reply;</span><br><span> break;</span><br><span> }</span><br=
><span>@@ -590,7 +600,6 @@</span><br><span> {</span><br><span> =
oob_probe_collect(&pc, &probe, &client_sid, &tas->tls_wr=
ap, targets, results, l->len);</span><br><span> }</span><br><span st=
yle=3D"color: hsl(0, 100%, 40%);">- oob_probe_sockets_close(&pc);</s=
pan><br><span> </span><br><span> /* Log each remote's outcome while=
results[i] still maps to array[i]=2E */</span><br><span> int responded=
=3D 0;</span><br><span>@@ -609,10 +618,10 @@</span><br><span> =
: results[i]=2Ereply=2Emax_latency_diff > 0 ? &=
quot;server-advertised"</span><br><span> =
: "default";</spa=
n><br><span> msg(D_LOW,</span><br><span style=3D"color: hsl(0, =
100%, 40%);">- "server-probe: %s:%s answered (priority =
%d, weight %d, rtt %u ms;"</span><br><span style=3D"color: hsl(0, 100%=
, 40%);">- " latency margin %d ms [%s])",</span><b=
r><span style=3D"color: hsl(120, 100%, 40%);">+ "server=
-probe: %s:%s answered (priority %d, weight %d, connect-lifetime %d s,"=
;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ &q=
uot; rtt %u ms; latency margin %d ms [%s])",</span><br><span> =
ce->remote, ce->remote_port, results[i]=2Ereply=2Epriority, r=
esults[i]=2Ereply=2Eweight,</span><br><span style=3D"color: hsl(0, 100%, 40=
%);">- results[i]=2Ertt_ms, margin, margin_src);</span><br><=
span style=3D"color: hsl(120, 100%, 40%);">+ results[i]=2Ere=
ply=2Econnect_lifetime, results[i]=2Ertt_ms, margin, margin_src);</span><br=
><span> }</span><br><span> else</span><br><span> {<=
/span><br><span>@@ -634,6 +643,69 @@</span><br><span> msg(M_INFO, "=
;server-probe: %d of %d remote(s) answered; connecting best-first", re=
sponded,</span><br><span> l->len);</span><br><span> </span><br><=
span style=3D"color: hsl(120, 100%, 40%);">+ /* If the winner advertised=
a connect_lifetime, its reply also served as the</span><br><span style=3D"=
color: hsl(120, 100%, 40%);">+ * server's reset: hand its probe soc=
ket and the captured cookie to the</span><br><span style=3D"color: hsl(120,=
100%, 40%);">+ * connection, which then starts the handshake from that=
reply (see</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * s=
ession_skip_to_pre_start_client)=2E Reusing that socket keeps the source</s=
pan><br><span style=3D"color: hsl(120, 100%, 40%);">+ * IP+port the coo=
kie is bound to=2E dco-win cannot hand a socket to the</span><br><span styl=
e=3D"color: hsl(120, 100%, 40%);">+ * kernel, so it only gets the probe=
ordering=2E */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</sp=
an><br><span style=3D"color: hsl(120, 100%, 40%);">+ /* Single-use, so t=
he RFC's connect_lifetime expiry check is not needed yet:</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+ * we probe once (c->first=
_time) and arm only results[0]=2E */</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+ bool probe_start =3D results[0]=2Eresponded &&=
results[0]=2Ereply=2Econnect_lifetime > 0;</span><br><span style=3D"col=
or: hsl(120, 100%, 40%);">+ bool dco_win_gate =3D false;</span><br><span=
style=3D"color: hsl(120, 100%, 40%);">+#if defined(_WIN32)</span><br><span=
style=3D"color: hsl(120, 100%, 40%);">+ if (dco_enabled(&c->opti=
ons))</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ {</span><b=
r><span style=3D"color: hsl(120, 100%, 40%);">+ probe_start =3D fals=
e;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ dco_win_g=
ate =3D true;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ }<=
/span><br><span style=3D"color: hsl(120, 100%, 40%);">+#endif</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+ if (probe_start)</span><br><s=
pan style=3D"color: hsl(120, 100%, 40%);">+ {</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+ const int af_idx =3D probe_af_index(re=
sults[0]=2Eresponder=2Ess_family);</span><br><span style=3D"color: hsl(120,=
100%, 40%);">+ c->c2=2Eoob_probe_sd =3D pc=2Esd[af_idx];</span><=
br><span style=3D"color: hsl(120, 100%, 40%);">+ pc=2Esd[af_idx] =3D=
SOCKET_UNDEFINED; /* relinquish: the connection owns it now */</span><br><=
span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ CLEAR(c->c2=2Eoob_probe_remote);</span>=
<br><span style=3D"color: hsl(120, 100%, 40%);">+ if (results[0]=2Er=
esponder=2Ess_family =3D=3D AF_INET)</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+ {</span><br><span style=3D"color: hsl(120, 100%, 4=
0%);">+ c->c2=2Eoob_probe_remote=2Eaddr=2Ein4 =3D *(struct so=
ckaddr_in *)(void *)&results[0]=2Eresponder;</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+ }</span><br><span style=3D"color: hsl(=
120, 100%, 40%);">+ else</span><br><span style=3D"color: hsl(120, 10=
0%, 40%);">+ {</span><br><span style=3D"color: hsl(120, 100%, 40%);"=
>+ c->c2=2Eoob_probe_remote=2Eaddr=2Ein6 =3D *(struct sockadd=
r_in6 *)(void *)&results[0]=2Eresponder;</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ }</span><br><span style=3D"color: hsl(120,=
100%, 40%);">+ c->c2=2Eoob_probe_client_sid =3D client_sid;</spa=
n><br><span style=3D"color: hsl(120, 100%, 40%);">+ c->c2=2Eoob_p=
robe_server_sid =3D results[0]=2Eserver_sid;</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ c->c2=2Eoob_probe_resend_wkc =3D</span>=
<br><span style=3D"color: hsl(120, 100%, 40%);">+ (results[0]=2E=
reply=2Eflags & OOB_PROBE_REPLY_FLAG_RESEND_WKC) !=3D 0;</span><br><spa=
n style=3D"color: hsl(120, 100%, 40%);">+ c->c2=2Eoob_probe_adopt=
=3D true;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><b=
r><span style=3D"color: hsl(120, 100%, 40%);">+ msg(D_LOW, "ser=
ver-probe: starting handshake from probe reply of %s:%s"</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+ " (connec=
t-lifetime %d s)",</span><br><span style=3D"color: hsl(120, 100%, 40%)=
;">+ l->array[0]->remote, l->array[0]->remote_port, =
results[0]=2Ereply=2Econnect_lifetime);</span><br><span style=3D"color: hsl=
(120, 100%, 40%);">+ }</span><br><span style=3D"color: hsl(120, 100%, 40=
%);">+ else if (results[0]=2Eresponded)</span><br><span style=3D"color: =
hsl(120, 100%, 40%);">+ {</span><br><span style=3D"color: hsl(120, 100%,=
40%);">+ /* A server answered but we won't start the handshake =
from it -- say why=2E */</span><br><span style=3D"color: hsl(120, 100%, 40%=
);">+ if (dco_win_gate)</span><br><span style=3D"color: hsl(120, 100=
%, 40%);">+ {</span><br><span style=3D"color: hsl(120, 100%, 40%);">=
+ msg(D_LOW, "server-probe: cannot start the handshake from=
a probe reply"</span><br><span style=3D"color: hsl(120, 100%, 40%);">=
+ " with dco-win;"</span><br><span style=3D=
"color: hsl(120, 100%, 40%);">+ " using a full h=
andshake");</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
}</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ else =
if (results[0]=2Ereply=2Econnect_lifetime =3D=3D 0)</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+ {</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+ msg(D_LOW, "server-probe: %s:%s di=
d not advertise a connect-lifetime"</span><br><span style=3D"color: hs=
l(120, 100%, 40%);">+ " (connect-lifetime 0); us=
ing a full handshake",</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+ l->array[0]->remote, l->array[0]->remot=
e_port);</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%);">+</span><br><span style=3D"color: hs=
l(120, 100%, 40%);">+ /* Close any probe sockets we did not hand off to =
the connection=2E */</span><br><span style=3D"color: hsl(120, 100%, 40%);">=
+ oob_probe_sockets_close(&pc);</span><br><span style=3D"color: hsl(=
120, 100%, 40%);">+</span><br><span> tls_auth_standalone_free(tas);</sp=
an><br><span> gc_free(&gc);</span><br><span> }</span><br><span>diff=
--git a/src/openvpn/openvpn=2Eh b/src/openvpn/openvpn=2Eh</span><br><span>=
index 44c598f=2E=2Ed8e02f2 100644</span><br><span>--- a/src/openvpn/openvpn=
=2Eh</span><br><span>+++ b/src/openvpn/openvpn=2Eh</span><br><span>@@ -249,=
6 +249,9 @@</span><br><span> bool oob_probe_adopt;</span><br><span> =
socket_descriptor_t oob_probe_sd;</span><br><span> struct openvpn_sock=
addr oob_probe_remote;</span><br><span style=3D"color: hsl(120, 100%, 40%);=
">+ struct session_id oob_probe_client_sid; /* our probe session id (co=
okie was minted over it) */</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+ struct session_id oob_probe_server_sid; /* the reply's ses=
sion id =3D server cookie to echo back */</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+ bool oob_probe_resend_wkc; /* reply=
asked to complete with CONTROL_WKC_V1 (v2) */</span><br><span> </span><br>=
<span> struct link_socket_actual *to_link_addr; /* IP address of remote=
*/</span><br><span> struct link_socket_actual from; /* addres=
s of incoming datagram */</span><br><span>diff --git a/src/openvpn/ssl=2Ec =
b/src/openvpn/ssl=2Ec</span><br><span>index 9e1a6aa=2E=2Eee8c5bf 100644</sp=
an><br><span>--- a/src/openvpn/ssl=2Ec</span><br><span>+++ b/src/openvpn/ss=
l=2Ec</span><br><span>@@ -2516,6 +2516,59 @@</span><br><span> return se=
ssion_move_pre_start(session, ks, true);</span><br><span> }</span><br><span=
> </span><br><span style=3D"color: hsl(120, 100%, 40%);">+bool</span><br><s=
pan style=3D"color: hsl(120, 100%, 40%);">+session_skip_to_pre_start_client=
(struct tls_session *session, const struct session_id *client_sid,</span><b=
r><span style=3D"color: hsl(120, 100%, 40%);">+ =
const struct session_id *server_sid,</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+ const struct openvpn=
_sockaddr *remote, bool resend_wkc)</span><br><span style=3D"color: hsl(120=
, 100%, 40%);">+{</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
struct key_state *ks =3D &session->key[KS_PRIMARY];</span><br><spa=
n style=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+ /* Our session id must be the one used for the pr=
obe: the server's cookie</span><br><span style=3D"color: hsl(120, 100%,=
40%);">+ * (server_sid) is an HMAC over it, and the server re-derives =
and checks it</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ *=
when it validates our third packet=2E */</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+ session->session_id =3D *client_sid;</span><br=
><span style=3D"color: hsl(120, 100%, 40%);">+ ks->session_id_remote =
=3D *server_sid;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</s=
pan><br><span style=3D"color: hsl(120, 100%, 40%);">+ struct link_socket=
_actual act =3D { 0 };</span><br><span style=3D"color: hsl(120, 100%, 40%);=
">+ act=2Edest =3D *remote;</span><br><span style=3D"color: hsl(120, 100=
%, 40%);">+ ks->remote_addr =3D act;</span><br><span style=3D"color: =
hsl(120, 100%, 40%);">+ session->untrusted_addr =3D act;</span><br><s=
pan style=3D"color: hsl(120, 100%, 40%);">+ session->burst =3D true;<=
/span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><br><span sty=
le=3D"color: hsl(120, 100%, 40%);">+ /* tls-crypt-v2: the stateless serv=
er discarded the WKc after the probe, so</span><br><span style=3D"color: hs=
l(120, 100%, 40%);">+ * complete the handshake with P_CONTROL_WKC_V1 (d=
rives control_packet_needs_wkc)=2E */</span><br><span style=3D"color: hsl(1=
20, 100%, 40%);">+ if (resend_wkc)</span><br><span style=3D"color: hsl(1=
20, 100%, 40%);">+ {</span><br><span style=3D"color: hsl(120, 100%, 40%)=
;">+ ks->crypto_options=2Eflags |=3D CO_RESEND_WKC;</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+ }</span><br><span style=3D"co=
lor: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%,=
40%);">+ /* We never received the server's HARD_RESET (id 0) =E2=80=
=94 the probe reply stood</span><br><span style=3D"color: hsl(120, 100%, 40=
%);">+ * in for it=2E Acknowledge that phantom id 0 so our third packet=
carries an</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * A=
CK together with the server session id (the cookie): reliable_ack_write()</=
span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * only emits tha=
t session id when at least one ACK is present, and the server</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+ * needs it to validate the s=
tateless cookie=2E */</span><br><span style=3D"color: hsl(120, 100%, 40%);"=
>+ reliable_ack_acknowledge_packet_id(ks->rec_ack, 0);</span><br><spa=
n style=3D"color: hsl(120, 100%, 40%);">+</span><br><span style=3D"color: h=
sl(120, 100%, 40%);">+ /* Skip one (RESET) packet in each direction, so =
ids start at 1 (see</span><br><span style=3D"color: hsl(120, 100%, 40%);">+=
* session_skip_to_pre_start)=2E */</span><br><span style=3D"color: hsl=
(120, 100%, 40%);">+ ks->rec_reliable->packet_id =3D 1;</span><br>=
<span style=3D"color: hsl(120, 100%, 40%);">+ session->tls_wrap=2Eopt=
=2Epacket_id=2Esend=2Eid =3D 1;</span><br><span style=3D"color: hsl(120, 10=
0%, 40%);">+</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ /* =
Do not send our own HARD_RESET=2E Unlike the server's skip, the client =
must</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * send fir=
st: the stateless server only replies once it sees our third</span><br><spa=
n style=3D"color: hsl(120, 100%, 40%);">+ * packet=2E session_move_pre_=
start(skip=3Dtrue) leaves us in S_PRE_START_SKIP,</span><br><span style=3D"=
color: hsl(120, 100%, 40%);">+ * which only advances when a packet is *=
received*; instead drop to</span><br><span style=3D"color: hsl(120, 100%, 4=
0%);">+ * S_PRE_START with an empty send-reliable (the initial packet w=
as generated</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * =
and immediately deleted), so tls_process() promotes us to S_START and</span=
><br><span style=3D"color: hsl(120, 100%, 40%);">+ * sends the ClientHe=
llo without waiting for a server reset=2E */</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+ if (!session_move_pre_start(session, ks, true)=
)</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ {</span><br><s=
pan style=3D"color: hsl(120, 100%, 40%);">+ return false;</span><br>=
<span style=3D"color: hsl(120, 100%, 40%);">+ }</span><br><span style=3D=
"color: hsl(120, 100%, 40%);">+ ks->state =3D S_PRE_START;</span><br>=
<span style=3D"color: hsl(120, 100%, 40%);">+ return true;</span><br><sp=
an style=3D"color: hsl(120, 100%, 40%);">+}</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+</span><br><span> /**</span><br><span> * Parses th=
e TLVs (type, length, value) in the early negotiation</span><br><span> */<=
/span><br><span>diff --git a/src/openvpn/ssl=2Eh b/src/openvpn/ssl=2Eh</spa=
n><br><span>index 7ddf965=2E=2Ea534007 100644</span><br><span>--- a/src/ope=
nvpn/ssl=2Eh</span><br><span>+++ b/src/openvpn/ssl=2Eh</span><br><span>@@ -=
576,4 +576,21 @@</span><br><span> bool session_skip_to_pre_start(struct tls=
_session *session, struct tls_pre_decrypt_state *state,</span><br><span> =
struct link_socket_actual *from);</span><br><s=
pan> </span><br><span style=3D"color: hsl(120, 100%, 40%);">+/**</span><br>=
<span style=3D"color: hsl(120, 100%, 40%);">+ * Client counterpart of sessi=
on_skip_to_pre_start(): start the handshake from a</span><br><span style=3D=
"color: hsl(120, 100%, 40%);">+ * server session id (SYN-cookie) learned ea=
rlier from an OOB server probe</span><br><span style=3D"color: hsl(120, 100=
%, 40%);">+ * reply, which already served as the server's HARD_RESET, s=
o we send none=2E</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ *=
</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * @param session =
the (client) TLS session to fast-forward</span><br><span style=3D"color:=
hsl(120, 100%, 40%);">+ * @param client_sid session id used for the probe=
(the cookie is an HMAC over it)</span><br><span style=3D"color: hsl(120, 1=
00%, 40%);">+ * @param server_sid the server's cookie, echoed back to =
complete the handshake</span><br><span style=3D"color: hsl(120, 100%, 40%);=
">+ * @param remote the probed (pinned) server address to connect to</=
span><br><span style=3D"color: hsl(120, 100%, 40%);">+ * @param resend_wkc =
true to complete with P_CONTROL_WKC_V1 (tls-crypt-v2)</span><br><span styl=
e=3D"color: hsl(120, 100%, 40%);">+ * @return true if the session was fast-=
forwarded, false on failure</span><br><span style=3D"color: hsl(120, 100%, =
40%);">+ */</span><br><span style=3D"color: hsl(120, 100%, 40%);">+bool ses=
sion_skip_to_pre_start_client(struct tls_session *session,</span><br><span =
style=3D"color: hsl(120, 100%, 40%);">+ =
const struct session_id *client_sid,</span><br><span style=3D"color: hsl(=
120, 100%, 40%);">+ const struct sessi=
on_id *server_sid,</span><br><span style=3D"color: hsl(120, 100%, 40%);">+ =
const struct openvpn_sockaddr *remote,=
bool resend_wkc);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+<=
/span><br><span> #endif /* ifndef OPENVPN_SSL_H */</span><br><span></span><=
br></pre><p>To view, visit <a href=3D"http://gerrit=2Eopenvpn=2Enet/c/openv=
pn/+/1770?usp=3Demail">change 1770</a>=2E To unsubscribe, or for help writi=
ng mail filters, visit <a href=3D"http://gerrit=2Eopenvpn=2Enet/settings?us=
p=3Demail">settings</a>=2E</p><div itemscope itemtype=3D"http://schema=2Eor=
g/EmailMessage"><div itemscope itemprop=3D"action" itemtype=3D"http://schem=
a=2Eorg/ViewAction"><link itemprop=3D"url" href=3D"http://gerrit=2Eopenvpn=
=2Enet/c/openvpn/+/1770?usp=3Demail"/><meta itemprop=3D"name" content=3D"Vi=
ew Change"/></div></div>
<div style=3D"display:none"> Gerrit-MessageType: =
newpatchset </div>
<div style=3D"display:none"> Gerrit-Project: openvpn </d=
iv>
<div style=3D"display:none"> Gerrit-Branch: master </div>
<div style=3D=
"display:none"> Gerrit-Change-Id: I454d5040cbad4d373ee4f90b8d683200d2a4c0e4=
</div>
<div style=3D"display:none"> Gerrit-Change-Number: 1770 </div>
<div=
style=3D"display:none"> Gerrit-PatchSet: 10 </div>
<div style=3D"display:n=
one"> Gerrit-Owner: stipa <lstipakov@gmail=2Ecom> </div>
<div style=
=3D"display:none"> Gerrit-Reviewer: plaisthos <arne-openvpn@rfc2549=2Eor=
g> </div>
<div style=3D"display:none"> Gerrit-CC: openvpn-devel <open=
vpn-devel@lists=2Esourceforge=2Enet> </div>
<div style=3D"display:none">=
Gerrit-Attention: plaisthos <arne-openvpn@rfc2549=2Eorg> </div>
</b=
ody></html>
--XJd/Lz9GVFc=--
--===============2128253188981459948==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
--===============2128253188981459948==
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
--===============2128253188981459948==--