From 46de5eee61127499d7401c8981dd5697307f4f12 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Thu, 2 Aug 2018 12:10:45 -0700 Subject: [PATCH] Reduce unnecessary connection-rebuilding for Juniper The current oNCP (Juniper) protocol support sets "Connection: close" in all HTTP requests. This is not ideal because it requires many TLS handshakes and round-trips, making the connection very slow to start when the latency of the connection to the gateway is high, especially if the number of authentication forms and redirects is large. Simply removing the "Connection: close" header causes the oNCP connection to fail; the server doesn't interpret the first packet sent over the oNCP tunnel correctly (the vestigial authentication packet). However, it appears that the "Connection: close" header *only* needs to be specified for this final HTTP request, and not for any of the prior ones. The presence of this header seems to signal to the gateway that it should stop treating this as an HTTP connection, and start treating it as an oNCP tunnel. Tested on two different Juniper gateways, one which returns "NCP-Version: 2" and one which returns "NCP-Version: 3" in response to the oNCP negotiation requests. --- auth-juniper.c | 1 - oncp.c | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/auth-juniper.c b/auth-juniper.c index acd9c77e..30ceb3ae 100644 --- a/auth-juniper.c +++ b/auth-juniper.c @@ -47,7 +47,6 @@ void oncp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b { http_common_headers(vpninfo, buf); - buf_append(buf, "Connection: close\r\n"); // buf_append(buf, "Content-Length: 256\r\n"); buf_append(buf, "NCP-Version: 3\r\n"); // buf_append(buf, "Accept-Encoding: gzip\r\n"); diff --git a/oncp.c b/oncp.c index 59d2fd98..5690edd9 100644 --- a/oncp.c +++ b/oncp.c @@ -561,6 +561,11 @@ int oncp_connect(struct openconnect_info *vpninfo) reqbuf = buf_alloc(); buf_append(reqbuf, "POST /dana/js?prot=1&svc=1 HTTP/1.1\r\n"); + /* Seems unnecessary because we always ignore the response body, + and close the connection anyway, but retained in case any + server depends on it. (See comments on second negotiation + request below. */ + buf_append(reqbuf, "Connection: close\r\n"); oncp_common_headers(vpninfo, reqbuf); buf_append(reqbuf, "Content-Length: 256\r\n"); buf_append(reqbuf, "\r\n"); @@ -572,6 +577,7 @@ int oncp_connect(struct openconnect_info *vpninfo) goto out; } + vpn_progress(vpninfo, PRG_TRACE, _("Sending oNCP negotiation request #1\n")); ret = vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos); if (ret < 0) goto out; @@ -606,6 +612,13 @@ int oncp_connect(struct openconnect_info *vpninfo) buf_truncate(reqbuf); buf_append(reqbuf, "POST /dana/js?prot=1&svc=4 HTTP/1.1\r\n"); + /* The TLS socket actually remains open for use by the oNCP + tunnel, but the "Connection: close" header is nevertheless + required here. It appears to signal to the server to stop + treating this as an HTTP connection and to start treating + it as an oNCP connection. + */ + buf_append(reqbuf, "Connection: close\r\n"); oncp_common_headers(vpninfo, reqbuf); buf_append(reqbuf, "Content-Length: 256\r\n"); buf_append(reqbuf, "\r\n"); @@ -616,6 +629,7 @@ int oncp_connect(struct openconnect_info *vpninfo) ret = buf_error(reqbuf); goto out; } + vpn_progress(vpninfo, PRG_TRACE, _("Sending oNCP negotiation request #2\n")); ret = vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos); if (ret < 0) goto out;