This is an automated email from the ASF dual-hosted git repository. markt-asf pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat-native.git
commit 71f5fd2ab6fe6c9a231f0baed8d57b93660d2d89 Author: Mark Thomas <[email protected]> AuthorDate: Sun Nov 8 12:18:41 2026 +0000 Fail fast on refused loopback connections to OCSP responders on Windows By default Windows retries a refused connection attempt by re-sending the SYN so a refused connection takes ~2s to fail. Disable SYN retransmission for loopback connections to the OCSP responder, as the JDK does, so that a refused connection fails immediately. Co-Authored-By: Claude Opus 5.5 <[email protected]> --- native/src/sslutils.c | 34 ++++++++++++++++++++++++++++++++++ xdocs/miscellaneous/changelog.xml | 5 +++++ 2 files changed, 39 insertions(+) diff --git a/native/src/sslutils.c b/native/src/sslutils.c index a81b82702..a337dec17 100644 --- a/native/src/sslutils.c +++ b/native/src/sslutils.c @@ -29,6 +29,10 @@ extern int WIN32_SSL_password_prompt(tcn_pass_cb_t *data); #ifdef HAVE_OCSP #include <openssl/bio.h> #include <openssl/ocsp.h> +#ifdef WIN32 +/* For SIO_TCP_INITIAL_RTO. Requires winsock2.h which is included via apr.h. */ +#include <mstcpip.h> +#endif /* defines with the values as seen by the asn1parse -dump openssl command */ #define ASN1_SEQUENCE 0x30 #define ASN1_OID 0x06 @@ -727,6 +731,32 @@ static int add_ocsp_cert(OCSP_REQUEST *req, X509 *cert, X509 *issuer) } +#if defined(WIN32) && defined(SIO_TCP_INITIAL_RTO) +/* By default, Windows retries a connection attempt that is refused by + re-sending the SYN, so a refused connection takes ~2s to fail. For + loopback connections, where packet loss is not a concern, disable SYN + retransmission so that a refused connection fails immediately. The JDK + does the same. This is best effort - if it fails, the connection attempt + proceeds with the default behaviour. +*/ +static void disable_loopback_syn_retransmission(apr_socket_t *sock, apr_sockaddr_t *sa) +{ + apr_os_sock_t os_sock; + TCP_INITIAL_RTO_PARAMETERS rto; + DWORD bytes; + + if (sa->family != APR_INET || (ntohl(sa->sa.sin.sin_addr.s_addr) >> 24) != 127) { + return; + } + if (apr_os_sock_get(&os_sock, sock) != APR_SUCCESS) { + return; + } + rto.Rtt = TCP_INITIAL_RTO_UNSPECIFIED_RTT; + rto.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; + WSAIoctl(os_sock, SIO_TCP_INITIAL_RTO, &rto, sizeof(rto), NULL, 0, &bytes, NULL, NULL); +} +#endif + /* Creates the APR socket and connect to the hostname. Returns the socket or NULL if there is an error. The timeout (in microseconds) applies to the connection attempt as well as subsequent I/O. @@ -742,6 +772,10 @@ static apr_socket_t *make_socket(char *hostname, int port, int timeout, apr_pool if (status == APR_SUCCESS) status = apr_socket_create(&sock, sa_in->family, SOCK_STREAM, APR_PROTO_TCP, mp); +#if defined(WIN32) && defined(SIO_TCP_INITIAL_RTO) + if (status == APR_SUCCESS) + disable_loopback_syn_retransmission(sock, sa_in); +#endif /* Set the timeout before connecting so it also limits the connection attempt */ if (status == APR_SUCCESS) status = apr_socket_timeout_set(sock, timeout); diff --git a/xdocs/miscellaneous/changelog.xml b/xdocs/miscellaneous/changelog.xml index ed4cc123d..30fc77b64 100644 --- a/xdocs/miscellaneous/changelog.xml +++ b/xdocs/miscellaneous/changelog.xml @@ -38,6 +38,11 @@ the OCSP responder. Previously, the timeout was only applied once the connection had been established. (markt) </fix> + <fix> + On Windows, ensure that a refused connection to an OCSP responder on a + loopback address fails immediately rather than after approximately two + seconds of connection retries. (markt) + </fix> </changelog> </section> <section name="2.0.17" rtext="2026-10-29"> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
