diff --git a/gnutls.c b/gnutls.c index 3abe7b55..eb1cd45a 100644 --- a/gnutls.c +++ b/gnutls.c @@ -1795,6 +1795,7 @@ static int verify_peer(gnutls_session_t session) return err; } + /* The F5 firewall is confused when the TLS client hello is between * 256 and 512 bytes. By disabling several TLS options we force the * client hello to be < 256 bytes. We don't do that in gnutls versions @@ -1923,6 +1924,13 @@ int openconnect_open_https(struct openconnect_info *vpninfo) if (vpninfo->my_pkey == OPENCONNECT_TPM_PKEY) gnutls_sign_callback_set(vpninfo->https_sess, gtls2_tpm_sign_cb, vpninfo); #endif + /* We depend on 3.2.9 because that has the workaround for the + obnoxious F5 firewall that drops packets of certain sizes */ + if (gnutls_check_version("3.2.9") && + string_is_hostname(vpninfo->hostname)) + gnutls_server_name_set(vpninfo->https_sess, GNUTLS_NAME_DNS, + vpninfo->hostname, + strlen(vpninfo->hostname)); if (vpninfo->pfs) { prio = DEFAULT_PRIO":-RSA"; diff --git a/openconnect-internal.h b/openconnect-internal.h index d40a3cd9..44bc075f 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -472,6 +472,7 @@ int cstp_reconnect(struct openconnect_info *vpninfo); void cstp_free_splits(struct openconnect_info *vpninfo); /* ssl.c */ +unsigned string_is_hostname(const char* str); int connect_https_socket(struct openconnect_info *vpninfo); int request_passphrase(struct openconnect_info *vpninfo, const char *label, char **response, const char *fmt, ...); diff --git a/openssl.c b/openssl.c index 13b8c0d9..f6171ce7 100644 --- a/openssl.c +++ b/openssl.c @@ -1361,6 +1361,14 @@ int openconnect_open_https(struct openconnect_info *vpninfo) BIO_set_nbio(https_bio, 1); SSL_set_bio(https_ssl, https_bio, https_bio); +#if 0 + /* Should be enabled on openssl versions that support + SSL_set_tlsext_host_name() after the F5 firewall workaround + is enabled */ + if (string_is_hostname(vpninfo->hostname)) + SSL_set_tlsext_host_name(https_ssl, vpninfo->hostname); +#endif + vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"), vpninfo->hostname); diff --git a/ssl.c b/ssl.c index 0099084d..d9a8cd3c 100644 --- a/ssl.c +++ b/ssl.c @@ -89,6 +89,21 @@ static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd, return getpeername(sockfd, (void *)&peer, &peerlen); } +/* checks whether the provided string is an IP or a hostname. + */ +unsigned string_is_hostname(const char *str) +{ + struct in_addr buf; + + /* We don't use inet_pton() because an IPv6 literal is likely to + be encased in []. So just check for a colon, which shouldn't + occur in hostnames anyway. */ + if (!str || inet_aton(str, &buf) || strchr(str, ':')) + return 0; + + return 1; +} + int connect_https_socket(struct openconnect_info *vpninfo) { int ssl_sock = -1; diff --git a/www/changelog.xml b/www/changelog.xml index f7c69a80..d587ff6c 100644 --- a/www/changelog.xml +++ b/www/changelog.xml @@ -32,6 +32,8 @@