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]

Reply via email to