]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 4528: ICAP transactions quit on async DNS lookups (#795) 4.15-20210525-snapshot 5.0.6-20210525-snapshot 6.0.0-20210525-master-snapshot
authorAlex Rousskov <rousskov@measurement-factory.com>
Fri, 21 May 2021 18:47:36 +0000 (18:47 +0000)
committerSquid Anubis <squid-anubis@squid-cache.org>
Fri, 21 May 2021 22:41:24 +0000 (22:41 +0000)
The bug directly affected some ICAP OPTIONS transactions and indirectly
affected some ICAP REQMOD/RESPMOD transactions:

* OPTIONS: When a transaction needed to look up an IP address of the
  ICAP service, and that address was not cached by Squid, it ended
  prematurely because Adaptation::Icap::Xaction::doneAll() was unaware
  of ipcache_nbgethostbyname()'s async nature. This bug is fixed now.

* REQMOD/RESPMOD: Adaptation::Icap::ModXact masked the _direct_ effects
  of the bug: ModXact::startWriting() sets state.writing before calling
  openConnection() which schedules the DNS lookup. That "I am still
  writing" state makes ModXact::doneAll() false while a REQMOD or
  RESPMOD transaction waits for the DNS lookup.

  However, REQMOD and RESPMOD transactions that require an OPTIONS
  transaction (because the service options have never been fetched
  before or have expired) could still fail because the OPTIONS
  transaction they trigger could fail as described in the first bullet.
  For example, the first few REQMOD and RESPMOD transactions for a given
  service -- all those started before the DNS lookup completes and Squid
  caches its result -- could fail this way. With the OPTIONS now fixed,
  these REQMOD and RESPMOD transactions should work correctly.

Broken since inception (commit fb505fa).

src/adaptation/icap/Xaction.cc
src/adaptation/icap/Xaction.h

index 9bbc75dba7cc5ae609e0bbd431b077717d7b131a..09b28358363e8fc910240f7a38881b7d69a911fa 100644 (file)
@@ -86,6 +86,7 @@ Adaptation::Icap::Xaction::Xaction(const char *aTypeName, Adaptation::Icap::Serv
     isRetriable(true),
     isRepeatable(true),
     ignoreLastWrite(false),
+    waitingForDns(false),
     stopReason(NULL),
     connector(NULL),
     reader(NULL),
@@ -187,12 +188,17 @@ Adaptation::Icap::Xaction::openConnection()
     debugs(93,3, typeName << " opens connection to " << s.cfg().host.termedBuf() << ":" << s.cfg().port);
 
     // Locate the Service IP(s) to open
+    assert(!waitingForDns);
+    waitingForDns = true; // before the possibly-synchronous ipcache_nbgethostbyname()
     ipcache_nbgethostbyname(s.cfg().host.termedBuf(), icapLookupDnsResults, this);
 }
 
 void
 Adaptation::Icap::Xaction::dnsLookupDone(const ipcache_addrs *ia)
 {
+    assert(waitingForDns);
+    waitingForDns = false;
+
     Adaptation::Icap::ServiceRep &s = service();
 
     if (ia == NULL) {
@@ -418,7 +424,8 @@ void Adaptation::Icap::Xaction::callEnd()
 
 bool Adaptation::Icap::Xaction::doneAll() const
 {
-    return !connector && !securer && !reader && !writer && Adaptation::Initiate::doneAll();
+    return !waitingForDns && !connector && !securer && !reader && !writer &&
+           Adaptation::Initiate::doneAll();
 }
 
 void Adaptation::Icap::Xaction::updateTimeout()
@@ -690,6 +697,9 @@ void Adaptation::Icap::Xaction::fillPendingStatus(MemBuf &buf) const
 
         buf.append(";", 1);
     }
+
+    if (waitingForDns)
+        buf.append("D", 1);
 }
 
 void Adaptation::Icap::Xaction::fillDoneStatus(MemBuf &buf) const
index d20933d35ec8dcb25bc8fac750ce32400131a2aa..8fcceaa0ac05a7f2e3d738635b6bc1274ce78d68 100644 (file)
@@ -137,6 +137,7 @@ protected:
     bool isRetriable;  ///< can retry on persistent connection failures
     bool isRepeatable; ///< can repeat if no or unsatisfactory response
     bool ignoreLastWrite;
+    bool waitingForDns; ///< expecting a ipcache_nbgethostbyname() callback
 
     const char *stopReason;