Attention is currently required from: stipa.
Hello plaisthos,
I'd like you to reexamine a change. Please visit
http://gerrit.openvpn.net/c/openvpn/+/1771?usp=email
to look at the new patch set (#18).
Change subject: oob: fall back quickly when a probe-started handshake is ignored
......................................................................
oob: fall back quickly when a probe-started handshake is ignored
If the server does not accept the third packet of a handshake started
from a probe reply, the client previously stalled for the full
handshake_window (~60s) before recovering.
In a normal handshake, no answer could mean the server is down, so
waiting is right. Here we know it is up, since it answered a probe a
moment ago -- so no answer means it did not accept the reply as a reset,
and waiting 60s is pointless. That happens when a load balancer sends
the probe and the handshake to different instances, when NAT changes the
source port the cookie is bound to, or when the server restarted and
rotated its session-id HMAC key.
Give such a session a short first-response deadline
(min(handshake_window, 5s)); once the server answers, tls_pre_decrypt()
restores the full window so a slow-but-working handshake is not cut off.
If no response arrives the session times out quickly and the client
restarts the attempt rather than retrying in place: the restart moves on
to the next resolved address or connection entry, so the server that
answered the probe is not tried again this cycle. A rejected reply
therefore costs a few seconds instead of ~60, at the price of giving up
on that server.
Change-Id: Icec4696ff263ab39ebab06e8d478395a5ddfaab9
Signed-off-by: Lev Stipakov <[email protected]>
---
M src/openvpn/ssl.c
M src/openvpn/ssl_common.h
2 files changed, 41 insertions(+), 1 deletion(-)
git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/71/1771/18
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index ec6c212..22f8f62 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -2587,6 +2587,11 @@
return session_move_pre_start(session, ks, true);
}
+/* Seconds to wait for the server's first response to a probe-started handshake
+ * before giving up and falling back to a normal handshake. A couple of
+ * control-channel retransmits; capped at handshake_window by the caller. */
+#define OOB_PROBE_START_FALLBACK_SECS 5
+
bool
session_skip_to_pre_start_client(struct tls_session *session, const struct
session_id *client_sid,
const struct session_id *server_sid,
@@ -2639,6 +2644,10 @@
return false;
}
ks->state = S_PRE_START;
+
+ /* Fail fast if the server ignores it: wait seconds, not handshake_window.
+ * tls_pre_decrypt() restores the full window once the server answers. */
+ ks->oob_probe_start = true;
return true;
}
@@ -2884,12 +2893,31 @@
continue_tls_process = session_move_pre_start(session, ks, false);
}
+ /* Start the probe-started fallback clock only once our first control
packet
+ * is queued: opening the tun, plugin init and chroot all happen before
that
+ * and must not be counted against a deadline meant for the server's
reply. */
+ if (ks->oob_probe_start && !reliable_empty(ks->send_reliable))
+ {
+ const time_t deadline =
+ now + min_int(session->opt->handshake_window,
OOB_PROBE_START_FALLBACK_SECS);
+ if (ks->must_negotiate > deadline)
+ {
+ ks->must_negotiate = deadline;
+ }
+ }
+
/* Are we timed out on receive? */
if (now >= ks->must_negotiate && ks->state >= S_UNDEF && ks->state <
S_ACTIVE)
{
+ /* Report the window that actually applied: an unanswered probe-started
+ * handshake times out on the short fallback deadline, not
+ * handshake_window. */
+ int window = ks->oob_probe_start
+ ? min_int(session->opt->handshake_window,
OOB_PROBE_START_FALLBACK_SECS)
+ : session->opt->handshake_window;
msg(D_TLS_ERRORS,
"TLS Error: TLS key negotiation failed to occur within %d seconds
(check your network connectivity)",
- session->opt->handshake_window);
+ window);
goto error;
}
@@ -3999,6 +4027,16 @@
goto error;
}
+ /* First valid response to a probe-started handshake: the server accepted
it,
+ * so restore the normal negotiation window (it was shortened to fail fast
if
+ * the probe reply had been ignored). Only after the source address
matched,
+ * or any forged packet could re-arm the long window. */
+ if (ks->oob_probe_start)
+ {
+ ks->oob_probe_start = false;
+ ks->must_negotiate = now + session->opt->handshake_window;
+ }
+
/*
* Should we do a retransmit of all unacknowledged packets in
* the send buffer? This improves the start-up efficiency of the
diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h
index f6392f9..905006c 100644
--- a/src/openvpn/ssl_common.h
+++ b/src/openvpn/ssl_common.h
@@ -227,6 +227,8 @@
time_t initial; /* when we created this session */
time_t established; /* when our state went S_ACTIVE */
time_t must_negotiate; /* key negotiation times out if not
finished before this time */
+ bool oob_probe_start; /* probe-started handshake:
must_negotiate is a short
+ * first-response deadline, not the
full window */
time_t must_die; /* this object is destroyed at this
time */
time_t peer_last_packet; /* Last time we received a packet
in this control session */
--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1771?usp=email
To unsubscribe, or for help writing mail filters, visit
http://gerrit.openvpn.net/settings?usp=email
Gerrit-MessageType: newpatchset
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: Icec4696ff263ab39ebab06e8d478395a5ddfaab9
Gerrit-Change-Number: 1771
Gerrit-PatchSet: 18
Gerrit-Owner: stipa <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: stipa <[email protected]>
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel