]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
revocation: Block only one thread per URL after a previous CRL fetch failed revocation-fetcher 2918/head
authorMartin Willi <martin@strongswan.org>
Wed, 29 Oct 2025 09:35:10 +0000 (10:35 +0100)
committerMartin Willi <martin@strongswan.org>
Mon, 3 Nov 2025 09:38:18 +0000 (10:38 +0100)
If a CRL server is unresponsive, all threads trying to fetch this CRL will
block execution. If a recent previous attempt to fetch the CRL failed, it
is likely that it will fail again. While it makes sense to retry fetching
the CRL on demand with one thread, it hardly does to block additional
threads while the first one is blocked during the fetch.

So remember the timestamp of the last CRL fetch failure per URL, and do
not block more than one thread in the CRL fetch for some time. This time
is a multiple of the configured fetch timeout, so that it works well for
any configured value. With the default configuration, a failing CRL fetch
will impact concurrent CRL fetches for the same URL for 30s.

src/libstrongswan/plugins/revocation/revocation_fetcher.c

index 8d0cd602bc1eb586bcf2a9c55505ea72d0ef9827..36c74921ea7d090f5dad27700ff3119c7177bd69 100644 (file)
@@ -26,6 +26,9 @@
 #include <credentials/certificates/ocsp_request.h>
 #include <credentials/certificates/ocsp_response.h>
 
+/* number of fetch timeouts to degrade a CRL fetch after a failure */
+#define CRL_DEGRADATION_TIMES 3
+
 typedef struct private_revocation_fetcher_t private_revocation_fetcher_t;
 
 /**
@@ -71,6 +74,11 @@ struct crl_fetch_t {
         */
        u_int fetchers;
 
+       /**
+        * Has the previous fetch failed, until when is this URL degraded?
+        */
+       time_t failing;
+
        /**
         * CRL received in the currently active fetch.
         */
@@ -119,6 +127,14 @@ static certificate_t *start_crl_fetch(private_revocation_fetcher_t *this,
        crl = do_crl_fetch(this, fetch->url, timeout);
        this->mutex->lock(this->mutex);
        fetch->crl = crl;
+       if (crl)
+       {
+               fetch->failing = 0;
+       }
+       else
+       {
+               fetch->failing = time_monotonic(NULL) + timeout * CRL_DEGRADATION_TIMES;
+       }
        while (fetch->fetchers > 1)
        {
                fetch->condvar->signal(fetch->condvar);
@@ -137,6 +153,12 @@ static certificate_t *wait_for_crl(private_revocation_fetcher_t *this,
 {
        certificate_t *crl = NULL;
 
+       if (fetch->failing && fetch->failing > time_monotonic(NULL))
+       {
+               DBG1(DBG_CFG, "  crl fetch from '%s' recently failed, skipping",
+                        fetch->url);
+               return NULL;
+       }
        DBG1(DBG_CFG, "  waiting for crl fetch from '%s' ...", fetch->url);
        if (fetch->crl)
        {