From 0eb82a1428fe709e93f92cec80082be4ca46daf7 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Sat, 27 Jul 2024 15:04:58 -0700 Subject: [PATCH] Add a fake IPSEC/ESP configuration to fake-gp-server.py This allows testing for correct interpretation of the ESP configuration, as in https://lists.infradead.org/pipermail/openconnect-devel/2024-July/005447.html Also needed to fix a mistake in the logout handler of fake-gp-server.py ("POST not GET"), and an oversight in how GP propagated errors when falling back to TLS tunnel from ESP. Signed-off-by: Daniel Lenski --- gpst.c | 9 +++++---- tests/fake-gp-server.py | 24 +++++++++++++++++++++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/gpst.c b/gpst.c index 0450107a..cb3ff89e 100644 --- a/gpst.c +++ b/gpst.c @@ -769,6 +769,7 @@ static int gpst_connect(struct openconnect_info *vpninfo) if (ret==sizeof(start_tunnel)) { ret = vpninfo->ssl_gets(vpninfo, buf+sizeof(start_tunnel), sizeof(buf)-sizeof(start_tunnel)); ret = (ret>0 ? ret : 0) + sizeof(start_tunnel); + dump_buf(vpninfo, '<', buf); } int status = check_http_status(buf, ret); /* XX: GP servers return 502 when they don't like the cookie */ @@ -1152,9 +1153,9 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable) _("Failed to connect ESP tunnel; using HTTPS instead.\n")); /* XX: gpst_connect does nothing if ESP is enabled and has secrets */ vpninfo->dtls_state = DTLS_NOSECRET; - if (gpst_connect(vpninfo)) { + if (ret = gpst_connect(vpninfo)) { vpninfo->quit_reason = "GPST connect failed"; - return 1; + return ret; } break; case DTLS_NOSECRET: @@ -1310,9 +1311,9 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable) return ret; } /* XX: no need to do_reconnect, since ESP doesn't need reconnection */ - if (gpst_connect(vpninfo)) + if (ret = gpst_connect(vpninfo)) vpninfo->quit_reason = "GPST connect failed"; - return 1; + return ret; } switch (keepalive_action(&vpninfo->ssl_times, timeout)) { diff --git a/tests/fake-gp-server.py b/tests/fake-gp-server.py index 98792e20..908f91c7 100755 --- a/tests/fake-gp-server.py +++ b/tests/fake-gp-server.py @@ -95,6 +95,7 @@ class TestConfiguration: gateway_saml: str = None saml_comments_only: int = None saml_needs_js: int = None + esp: bool = True C = TestConfiguration() OUTSTANDING_SAML_TOKENS = set() @@ -103,7 +104,7 @@ OUTSTANDING_SAML_TOKENS = set() def configure(): global C if request.method == 'POST': - gateways, portal_2fa, gw_2fa, portal_cookie, portal_saml, gateway_saml, saml_comments_only, saml_needs_js = request.form.get('gateways'), request.form.get('portal_2fa'), request.form.get('gw_2fa'), request.form.get('portal_cookie'), request.form.get('portal_saml'), request.form.get('gateway_saml'), request.form.get('saml_comments_only'), request.form.get('saml_needs_js') + gateways, portal_2fa, gw_2fa, portal_cookie, portal_saml, gateway_saml, saml_comments_only, saml_needs_js, esp = request.form.get('gateways'), request.form.get('portal_2fa'), request.form.get('gw_2fa'), request.form.get('portal_cookie'), request.form.get('portal_saml'), request.form.get('gateway_saml'), request.form.get('saml_comments_only'), request.form.get('saml_needs_js'), request.form.get('esp') C.gateways = gateways.split(',') if gateways else ('Default gateway',) C.portal_cookie = portal_cookie C.portal_2fa = portal_2fa and portal_2fa.strip().lower() @@ -112,6 +113,7 @@ def configure(): C.gateway_saml = gateway_saml C.saml_comments_only = int(saml_comments_only) if saml_comments_only else None C.saml_needs_js = int(saml_needs_js) if saml_needs_js else None + C.esp = int(esp) if esp else None return '', 201 else: return 'Current configuration of fake GP server configuration:\n{}\n'.format(C) @@ -340,9 +342,25 @@ def gateway_login(): def getconfig(): session.update(step='gateway-config') addrs = '{}'.format(session['preferred_ip']) + addrs += '127.0.0.1' + addrs += '::1' # some(?) servers send the IPv6 address even if not otherwise configured for IPv6 if session['ipv6_support'] == 'yes': addrs += '{}'.format(session['preferred_ipv6']) - return '''{}/ssl-tunnel-connect.sslvpn'''.format(addrs) + ipsec = '' + if C.esp: + ipsec = ''' + 4501 + esp-tunnel + aes-128-cbc + sha1 + 0xa5a5a5a5 + 0x5a5a5a5a + 160deadbeefdeadbeefdeadbeefdeadbeefdeadbeef + 160deadbeefdeadbeefdeadbeefdeadbeefdeadbee1 + 128deadbeefdeadbeefdeadbeefdeadbeef + 128deadbeefdeadbeefdeadbeefdeadbee1 + ''' + return '''{}{}/ssl-tunnel-connect.sslvpn'''.format(addrs, ipsec) # Respond to gateway hipreportcheck request @@ -366,7 +384,7 @@ def tunnel(): # Respond to 'GET /ssl-vpn/logout.esp' by clearing session and MRHSession -@app.route('/ssl-vpn/logout.esp') +@app.route('/ssl-vpn/logout.esp', methods=('POST',)) # XX: real server really requires all these fields; see auth-globalprotect.c @check_form_against_session('authcookie', 'portal', 'user', 'computer') def logout(): -- 2.50.1