]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/ipcache.cc
SourceFormat: enforcement
[thirdparty/squid.git] / src / ipcache.cc
index d8498631343dceb8a03a259f44ec0c90f671f768..5d1a336eb74fa8419ddaaab87d266b655750a942 100644 (file)
@@ -1,7 +1,4 @@
-
 /*
- * $Id: ipcache.cc,v 1.269 2008/02/26 21:49:35 amosjeffries Exp $
- *
  * DEBUG: section 14    IP Cache
  * AUTHOR: Harvest Derived
  *
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
- *  
+ *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *  
+ *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
@@ -40,7 +37,7 @@
 #include "SquidTime.h"
 #include "Store.h"
 #include "wordlist.h"
-#include "IPAddress.h"
+#include "ip/IpAddress.h"
 
 /**
  \defgroup IPCacheAPI IP Cache API
@@ -80,9 +77,6 @@
  * the ipcache_high threshold.
  */
 
-/// \ingroup IPCacheAPI
-typedef struct _ipcache_entry ipcache_entry;
-
 /**
  \ingroup IPCacheAPI
  *
@@ -91,8 +85,9 @@ typedef struct _ipcache_entry ipcache_entry;
  * where structures of type ipcache_entry whose most
  * interesting members are:
  */
-struct _ipcache_entry
+class ipcache_entry
 {
+public:
     hash_link hash;            /* must be first */
     time_t lastref;
     time_t expires;
@@ -108,16 +103,16 @@ struct _ipcache_entry
     unsigned short cname_wait;
 #endif
 
-    struct
-    {
+    struct {
         unsigned int negcached:1;
         unsigned int fromhosts:1;
     } flags;
+
+    int age() const; ///< time passed since request_time or -1 if unknown
 };
 
 /// \ingroup IPCacheInternal
-static struct _ipcache_stats
-{
+static struct _ipcache_stats {
     int requests;
     int replies;
     int hits;
@@ -142,7 +137,6 @@ static IDNSCB ipcacheHandleReply;
 #endif
 static IPH ipcacheHandleCnameRecurse;
 static int ipcacheExpiredEntry(ipcache_entry *);
-static int ipcache_testname(void);
 #if USE_DNSSERVERS
 static int ipcacheParse(ipcache_entry *, const char *buf);
 #else
@@ -168,23 +162,13 @@ static long ipcache_high = 200;
 extern int _dns_ttl_;
 #endif
 
-/// \ingroup IPCacheInternal
-static int
-ipcache_testname(void)
+int
+ipcache_entry::age() const
 {
-    wordlist *w = NULL;
-    debugs(14, 1, "Performing DNS Tests...");
-
-    if ((w = Config.dns_testname_list) == NULL)
-        return 1;
+    return request_time.tv_sec ? tvSubMsec(request_time, current_time) : -1;
+}
 
-    for (; w; w = w->next) {
-        if (gethostbyname(w->key) != NULL)
-            return 1;
-    }
 
-    return 0;
-}
 
 /**
  \ingroup IPCacheInternal
@@ -194,12 +178,12 @@ ipcache_testname(void)
 static void
 ipcacheRelease(ipcache_entry * i, bool dofree)
 {
-    if(!i) {
+    if (!i) {
         debugs(14, 0, "ipcacheRelease: Releasing entry with i=<NULL>");
         return;
     }
 
-    if(!i || !i->hash.key) {
+    if (!i || !i->hash.key) {
         debugs(14, 0, "ipcacheRelease: Releasing entry without hash link!");
         return;
     }
@@ -208,7 +192,7 @@ ipcacheRelease(ipcache_entry * i, bool dofree)
 
     hash_remove_link(ip_table, (hash_link *) i);
     dlinkDelete(&i->lru, &lru_list);
-    if(dofree)
+    if (dofree)
         ipcacheFreeEntry(i);
 }
 
@@ -329,12 +313,11 @@ ipcacheAddEntry(ipcache_entry * i)
         /* avoid colission */
         ipcache_entry *q = (ipcache_entry *) e;
 #if DNS_CNAME
-        if(q == i)  {
+        if (q == i)  {
             /* can occur with Multiple-depth CNAME Recursion if parent returned early with additional */
             /* just need to drop from the hash without releasing actual memory */
             ipcacheRelease(q, false);
-        }
-        else
+        } else
 #endif
             ipcacheRelease(q);
     }
@@ -350,7 +333,7 @@ ipcacheAddEntry(ipcache_entry * i)
  * walks down the pending list, calling handlers
  */
 static void
-ipcacheCallback(ipcache_entry * i)
+ipcacheCallback(ipcache_entry *i, int wait)
 {
     IPH *callback = i->handler;
     void *cbdata = NULL;
@@ -366,8 +349,8 @@ ipcacheCallback(ipcache_entry * i)
     i->handler = NULL;
 
     if (cbdataReferenceValidDone(i->handlerData, &cbdata)) {
-        dns_error_message = i->error_message;
-        callback(i->addrs.count ? &i->addrs : NULL, cbdata);
+        const DnsLookupDetails details(i->error_message, wait);
+        callback((i->addrs.count ? &i->addrs : NULL), details, cbdata);
     }
 
     ipcacheUnlockEntry(i);
@@ -443,8 +426,8 @@ ipcacheParse(ipcache_entry *i, const char *inbuf)
     if (ipcount > 0) {
         int j, k;
 
-        i->addrs.in_addrs = (IPAddress *)xcalloc(ipcount, sizeof(IPAddress));
-        for(int l = 0; l < ipcount; l++)
+        i->addrs.in_addrs = (IpAddress *)xcalloc(ipcount, sizeof(IpAddress));
+        for (int l = 0; l < ipcount; l++)
             i->addrs.in_addrs[l].SetEmpty(); // perform same init actions as constructor would.
         i->addrs.bad_mask = (unsigned char *)xcalloc(ipcount, sizeof(unsigned char));
         memset(i->addrs.bad_mask, 0, sizeof(unsigned char) * ipcount);
@@ -516,27 +499,27 @@ ipcacheParse(ipcache_entry *i, rfc1035_rr * answers, int nr, const char *error_m
 
 #if USE_IPV6
         if (answers[k].type == RFC1035_TYPE_AAAA) {
-           if (answers[k].rdlength != sizeof(struct in6_addr)) {
-               debugs(14, 1, "ipcacheParse: Invalid IPv6 address in response to '" << name << "'");
-               continue;
-           }
-           na++;
+            if (answers[k].rdlength != sizeof(struct in6_addr)) {
+                debugs(14, 1, "ipcacheParse: Invalid IPv6 address in response to '" << name << "'");
+                continue;
+            }
+            na++;
             IpcacheStats.rr_aaaa++;
-           continue;
-       }
+            continue;
+        }
 #endif
 
         if (answers[k].type == RFC1035_TYPE_A) {
-           if (answers[k].rdlength != sizeof(struct in_addr)) {
-               debugs(14, 1, "ipcacheParse: Invalid IPv4 address in response to '" << name << "'");
-               continue;
-           }
-           na++;
+            if (answers[k].rdlength != sizeof(struct in_addr)) {
+                debugs(14, 1, "ipcacheParse: Invalid IPv4 address in response to '" << name << "'");
+                continue;
+            }
+            na++;
             IpcacheStats.rr_a++;
-           continue;
-       }
+            continue;
+        }
 
-            /* With A and AAAA, the CNAME does not necessarily come with additional records to use. */
+        /* With A and AAAA, the CNAME does not necessarily come with additional records to use. */
         if (answers[k].type == RFC1035_TYPE_CNAME) {
             cname_found=1;
             IpcacheStats.rr_cname++;
@@ -544,11 +527,10 @@ ipcacheParse(ipcache_entry *i, rfc1035_rr * answers, int nr, const char *error_m
 #if DNS_CNAME
             debugs(14, 5, "ipcacheParse: " << name << " CNAME " << answers[k].rdata << " (checking destination: " << i << ").");
             const ipcache_addrs *res = ipcache_gethostbyname(answers[k].rdata, 0);
-            if(res) {
+            if (res) {
                 na += res->count;
                 debugs(14, 5, "ipcacheParse: CNAME " << answers[k].rdata << " already has " << res->count << " IPs cached.");
-            }
-            else {
+            } else {
                 /* keep going on this, but flag the fact that we need to wait for a CNAME lookup to finish */
                 debugs(14, 5, "ipcacheParse: CNAME " << answers[k].rdata << " has no IPs! Recursing.");
                 ipcache_nbgethostbyname(answers[k].rdata, ipcacheHandleCnameRecurse, new generic_cbdata(i) );
@@ -564,7 +546,7 @@ ipcacheParse(ipcache_entry *i, rfc1035_rr * answers, int nr, const char *error_m
     }
 
 #if DNS_CNAME
-    if(na == 0 && i->cname_wait >0 ) {
+    if (na == 0 && i->cname_wait >0 ) {
         /* don't set any error message (yet). Allow recursion to do its work first. */
         IpcacheStats.cname_only++;
         return 0;
@@ -574,13 +556,13 @@ ipcacheParse(ipcache_entry *i, rfc1035_rr * answers, int nr, const char *error_m
     if (na == 0) {
         debugs(14, 1, "ipcacheParse: No Address records in response to '" << name << "'");
         i->error_message = xstrdup("No Address records");
-        if(cname_found)
+        if (cname_found)
             IpcacheStats.cname_only++;
         return 0;
     }
 
-    i->addrs.in_addrs = (IPAddress *)xcalloc(na, sizeof(IPAddress));
-    for(int l = 0; l < na; l++)
+    i->addrs.in_addrs = (IpAddress *)xcalloc(na, sizeof(IpAddress));
+    for (int l = 0; l < na; l++)
         i->addrs.in_addrs[l].SetEmpty(); // perform same init actions as constructor would.
     i->addrs.bad_mask = (unsigned char *)xcalloc(na, sizeof(unsigned char));
 
@@ -614,15 +596,14 @@ ipcacheParse(ipcache_entry *i, rfc1035_rr * answers, int nr, const char *error_m
         else if (answers[k].type == RFC1035_TYPE_CNAME) {
             debugs(14, 3, "ipcacheParse: " << name << " #x CNAME " << answers[k].rdata);
             const ipcache_addrs *res = ipcache_gethostbyname(answers[k].rdata, 0);
-            if(res) {
+            if (res) {
                 /* NP: the results of *that* query need to be integrated in place of the CNAME */
                 /* Ideally we should also integrate the min TTL of the above IPA's into ttl.   */
-                for(int l = 0; l < res->count; l++, j++) {
+                for (int l = 0; l < res->count; l++, j++) {
                     i->addrs.in_addrs[j] = res->in_addrs[l];
                     debugs(14, 3, "ipcacheParse: " << name << " #" << j << " " << i->addrs.in_addrs[j] );
                 }
-            }
-            else {
+            } else {
                 debugs(14, 9, "ipcacheParse: " << answers[k].rdata << " (CNAME) waiting on A/AAAA records.");
             }
         }
@@ -653,7 +634,7 @@ ipcacheParse(ipcache_entry *i, rfc1035_rr * answers, int nr, const char *error_m
     /* SPECIAL CASE: may get here IFF CNAME received with Additional records */
     /*               reurn  0/'wait for further details' value.              */
     /*               NP: 'No DNS Results' is a return -1 +msg                */
-    if(i->cname_wait)
+    if (i->cname_wait)
         return 0;
     else
 #endif /* DNS_CNAME */
@@ -674,8 +655,9 @@ ipcacheHandleReply(void *data, rfc1035_rr * answers, int na, const char *error_m
     ipcache_entry *i;
     static_cast<generic_cbdata *>(data)->unwrap(&i);
     IpcacheStats.replies++;
-    statHistCount(&statCounter.dns.svc_time,
-                  tvSubMsec(i->request_time, current_time));
+    const int age = i->age();
+    statHistCount(&statCounter.dns.svc_time, age);
+
 #if USE_DNSSERVERS
 
     done = ipcacheParse(i, reply);
@@ -684,12 +666,12 @@ ipcacheHandleReply(void *data, rfc1035_rr * answers, int na, const char *error_m
     done = ipcacheParse(i, answers, na, error_message);
 
     /* If we have not produced either IPs or Error immediately, wait for recursion to finish. */
-    if(done != 0 || error_message != NULL)
+    if (done != 0 || error_message != NULL)
 #endif
 
     {
         ipcacheAddEntry(i);
-        ipcacheCallback(i);
+        ipcacheCallback(i, age);
     }
 }
 
@@ -700,6 +682,14 @@ ipcacheHandleReply(void *data, rfc1035_rr * answers, int na, const char *error_m
  \param handler                Pointer to the function to be called when the reply
  *                     from the IP cache (or the DNS if the IP cache misses)
  \param handlerData    Information that is passed to the handler and does not affect the IP cache.
+ *
+ * XXX: on hits and some errors, the handler is called immediately instead
+ * of scheduling an async call. This reentrant behavior means that the
+ * user job must be extra careful after calling ipcache_nbgethostbyname,
+ * especially if the handler destroys the job. Moreover, the job has
+ * no way of knowing whether the reentrant call happened. commConnectStart
+ * protects the job by scheduling an async call, but some user code calls
+ * ipcache_nbgethostbyname directly.
  */
 void
 ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
@@ -714,16 +704,16 @@ ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
     if (name == NULL || name[0] == '\0') {
         debugs(14, 4, "ipcache_nbgethostbyname: Invalid name!");
         IpcacheStats.invalid++;
-        dns_error_message = "Invalid hostname";
-        handler(NULL, handlerData);
+        const DnsLookupDetails details("Invalid hostname", -1); // error, no lookup
+        handler(NULL, details, handlerData);
         return;
     }
 
     if ((addrs = ipcacheCheckNumeric(name))) {
         debugs(14, 4, "ipcache_nbgethostbyname: BYPASS for '" << name << "' (already numeric)");
-        dns_error_message = NULL;
         IpcacheStats.numeric_hits++;
-        handler(addrs, handlerData);
+        const DnsLookupDetails details(NULL, -1); // no error, no lookup
+        handler(addrs, details, handlerData);
         return;
     }
 
@@ -749,7 +739,7 @@ ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
 
         i->handlerData = cbdataReference(handlerData);
 
-        ipcacheCallback(i);
+        ipcacheCallback(i, -1); // no lookup
 
         return;
     }
@@ -770,6 +760,17 @@ ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
 #endif
 }
 
+/// \ingroup IPCacheInternal
+static void
+ipcacheRegisterWithCacheManager(void)
+{
+    CacheManager::GetInstance()->
+    registerAction("ipcache",
+                   "IP Cache Stats and Contents",
+                   stat_ipcache_get, 0, 1);
+}
+
+
 /**
  \ingroup IPCacheAPI
  *
@@ -781,23 +782,13 @@ void
 ipcache_init(void)
 {
     int n;
-    debugs(14, 3, "Initializing IP Cache...");
+    debugs(14, DBG_IMPORTANT, "Initializing IP Cache...");
     memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
     memset(&lru_list, '\0', sizeof(lru_list));
-    /* test naming lookup */
-
-    if (!opt_dns_tests) {
-        debugs(14, 4, "ipcache_init: Skipping DNS name lookup tests.");
-    } else if (!ipcache_testname()) {
-        fatal("ipcache_init: DNS name lookup tests failed.");
-    } else {
-        debugs(14, 1, "Successful DNS name lookup tests...");
-    }
-
     memset(&static_addrs, '\0', sizeof(ipcache_addrs));
 
-    static_addrs.in_addrs = (IPAddress *)xcalloc(1, sizeof(IPAddress));
-    static_addrs.in_addrs->SetEmpty(); // properly setup the IPAddress!
+    static_addrs.in_addrs = (IpAddress *)xcalloc(1, sizeof(IpAddress));
+    static_addrs.in_addrs->SetEmpty(); // properly setup the IpAddress!
     static_addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
     ipcache_high = (long) (((float) Config.ipcache.size *
                             (float) Config.ipcache.high) / (float) 100);
@@ -806,15 +797,8 @@ ipcache_init(void)
     n = hashPrime(ipcache_high / 4);
     ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
     memDataInit(MEM_IPCACHE_ENTRY, "ipcache_entry", sizeof(ipcache_entry), 0);
-}
 
-/// \ingroup IPCacheAPI
-void
-ipcacheRegisterWithCacheManager(CacheManager & manager)
-{
-    manager.registerAction("ipcache",
-                           "IP Cache Stats and Contents",
-                           stat_ipcache_get, 0, 1);
+    ipcacheRegisterWithCacheManager();
 }
 
 /**
@@ -849,16 +833,16 @@ ipcache_gethostbyname(const char *name, int flags)
         i = NULL;
     } else if (i->flags.negcached) {
         IpcacheStats.negative_hits++;
-        dns_error_message = i->error_message;
+        // ignore i->error_message: the caller just checks IP cache presence
         return NULL;
     } else {
         IpcacheStats.hits++;
         i->lastref = squid_curtime;
-        dns_error_message = i->error_message;
+        // ignore i->error_message: the caller just checks IP cache presence
         return &i->addrs;
     }
 
-    dns_error_message = NULL;
+    /* no entry [any more] */
 
     if ((addrs = ipcacheCheckNumeric(name))) {
         IpcacheStats.numeric_hits++;
@@ -878,19 +862,21 @@ static void
 ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
 {
     int k;
-    int count = i->addrs.count;
     char buf[MAX_IPSTRLEN];
 
-    if(!sentry) {
+    if (!sentry) {
         debugs(14, 0, HERE << "CRITICAL: sentry is NULL!");
+        return;
     }
 
-    if(!i) {
+    if (!i) {
         debugs(14, 0, HERE << "CRITICAL: ipcache_entry is NULL!");
         storeAppendPrintf(sentry, "CRITICAL ERROR\n");
         return;
     }
 
+    int count = i->addrs.count;
+
     storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)",
                       hashKeyStr(&i->hash),
                       i->flags.fromhosts ? 'H' : ' ',
@@ -902,16 +888,16 @@ ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
 
     /** \par
      * Negative-cached entries have no IPs listed. */
-    if(i->flags.negcached) {
+    if (i->flags.negcached) {
         storeAppendPrintf(sentry, "\n");
         return;
     }
 
     /** \par
-     * Cached entries have IPs listed with a BNF of:   <IP> '-' ('OK'|'BAD') */
+     * Cached entries have IPs listed with a BNF of:   ip-address '-' ('OK'|'BAD') */
     for (k = 0; k < count; k++) {
         /* Display tidy-up: IPv6 are so big make the list vertical */
-        if(k == 0)
+        if (k == 0)
             storeAppendPrintf(sentry, " %45.45s-%3s\n",
                               i->addrs.in_addrs[k].NtoA(buf,MAX_IPSTRLEN),
                               i->addrs.bad_mask[k] ? "BAD" : "OK ");
@@ -973,7 +959,7 @@ stat_ipcache_get(StoreEntry * sentry)
 
 #if DNS_CNAME
 /**
- * Takes two IPAddress arrays and merges them into a single array
+ * Takes two IpAddress arrays and merges them into a single array
  * which is allocated dynamically to fit the number of unique addresses
  *
  \param aaddrs One list to merge
@@ -984,44 +970,44 @@ stat_ipcache_get(StoreEntry * sentry)
  \param outlen Size of list out
  */
 void
-ipcacheMergeIPLists(const IPAddress *aaddrs, const int alen,
-                    const IPAddress *baddrs, const int blen,
-                    IPAddress **out, int &outlen )
+ipcacheMergeIPLists(const IpAddress *aaddrs, const int alen,
+                    const IpAddress *baddrs, const int blen,
+                    IpAddress **out, int &outlen )
 {
     int fc=0, t=0, c=0;
 
-    IPAddress const *ip4ptrs[255];
+    IpAddress const *ip4ptrs[255];
 #if USE_IPV6
-    IPAddress const *ip6ptrs[255];
+    IpAddress const *ip6ptrs[255];
 #endif
     int num_ip4 = 0;
     int num_ip6 = 0;
 
-    memset(ip4ptrs, 0, sizeof(IPAddress*)*255);
+    memset(ip4ptrs, 0, sizeof(IpAddress*)*255);
 #if USE_IPV6
-    memset(ip6ptrs, 0, sizeof(IPAddress*)*255);
+    memset(ip6ptrs, 0, sizeof(IpAddress*)*255);
 #endif
 
     // for each unique address in list A - grab ptr
-    for(t = 0; t < alen; t++) {
-        if(aaddrs[t].IsIPv4()) {
+    for (t = 0; t < alen; t++) {
+        if (aaddrs[t].IsIPv4()) {
             // check against IPv4 pruned list
-            for(c = 0; c <= num_ip4; c++) {
-                if(ip4ptrs[c] && aaddrs[t] == *(ip4ptrs[c]) ) break; // duplicate.
+            for (c = 0; c <= num_ip4; c++) {
+                if (ip4ptrs[c] && aaddrs[t] == *(ip4ptrs[c]) ) break; // duplicate.
             }
-            if(c > num_ip4) {
+            if (c > num_ip4) {
                 ip4ptrs[num_ip4] = &aaddrs[t];
                 num_ip4++;
             }
         }
 #if USE_IPV6
-        else if(aaddrs[t].IsIPv6()) {
-debugs(14,8, HERE << "A[" << t << "]=IPv6 " << aaddrs[t]);
+        else if (aaddrs[t].IsIPv6()) {
+            debugs(14,8, HERE << "A[" << t << "]=IPv6 " << aaddrs[t]);
             // check against IPv6 pruned list
-            for(c = 0; c <= num_ip6; c++) {
-                if(ip6ptrs[c] && aaddrs[t] == *ip6ptrs[c]) break; // duplicate.
+            for (c = 0; c <= num_ip6; c++) {
+                if (ip6ptrs[c] && aaddrs[t] == *ip6ptrs[c]) break; // duplicate.
             }
-            if(c > num_ip6) {
+            if (c > num_ip6) {
                 ip6ptrs[num_ip6] = &aaddrs[t];
                 num_ip6++;
             }
@@ -1030,24 +1016,24 @@ debugs(14,8, HERE << "A[" << t << "]=IPv6 " << aaddrs[t]);
     }
 
     // for each unique address in list B - grab ptr
-    for(t = 0; t < blen; t++) {
-        if(baddrs[t].IsIPv4()) {
+    for (t = 0; t < blen; t++) {
+        if (baddrs[t].IsIPv4()) {
             // check against IPv4 pruned list
-            for(c = 0; c <= num_ip4; c++) {
-                if(ip4ptrs[c] && baddrs[t] == *ip4ptrs[c]) break; // duplicate.
+            for (c = 0; c <= num_ip4; c++) {
+                if (ip4ptrs[c] && baddrs[t] == *ip4ptrs[c]) break; // duplicate.
             }
-            if(c > num_ip4) {
+            if (c > num_ip4) {
                 ip4ptrs[num_ip4] = &baddrs[t];
                 num_ip4++;
             }
         }
 #if USE_IPV6
-        else if(baddrs[t].IsIPv6()) {
+        else if (baddrs[t].IsIPv6()) {
             // check against IPv6 pruned list
-            for(c = 0; c <= num_ip6; c++) {
-                if(ip6ptrs[c] && baddrs[t] == *ip6ptrs[c]) break; // duplicate.
+            for (c = 0; c <= num_ip6; c++) {
+                if (ip6ptrs[c] && baddrs[t] == *ip6ptrs[c]) break; // duplicate.
             }
-            if(c > num_ip6) {
+            if (c > num_ip6) {
                 ip6ptrs[num_ip6] = &baddrs[t];
                 num_ip6++;
             }
@@ -1062,7 +1048,7 @@ debugs(14,8, HERE << "A[" << t << "]=IPv6 " << aaddrs[t]);
     debugs(14, 5, "ipcacheMergeIPLists: Merge " << alen << "+" << blen << " into " << fc << " unique IPs.");
 
     // copy the old IPs into the new list buffer.
-    (*out) = (IPAddress*)xcalloc(fc, sizeof(IPAddress));
+    (*out) = (IpAddress*)xcalloc(fc, sizeof(IpAddress));
     outlen=0;
 
     assert(out != NULL);
@@ -1070,13 +1056,13 @@ debugs(14,8, HERE << "A[" << t << "]=IPv6 " << aaddrs[t]);
 #if USE_IPV6
     /* IPv6 are preferred (tried first) over IPv4 */
 
-    for(int l = 0; outlen < num_ip6; l++, outlen++) {
+    for (int l = 0; outlen < num_ip6; l++, outlen++) {
         (*out)[outlen] = *ip6ptrs[l];
         debugs(14, 5, "ipcacheMergeIPLists:  #" << outlen << " " << (*out)[outlen] );
     }
 #endif /* USE_IPV6 */
 
-    for(int l = 0; outlen < num_ip4; l++, outlen++) {
+    for (int l = 0; outlen < num_ip4; l++, outlen++) {
         (*out)[outlen] = *ip4ptrs[l];
         debugs(14, 5, "ipcacheMergeIPLists:  #" << outlen << " " << (*out)[outlen] );
     }
@@ -1088,12 +1074,12 @@ debugs(14,8, HERE << "A[" << t << "]=IPv6 " << aaddrs[t]);
 /// \ingroup IPCacheInternal
 /// Callback.
 static void
-ipcacheHandleCnameRecurse(const ipcache_addrs *addrs, void *cbdata)
+ipcacheHandleCnameRecurse(const ipcache_addrs *addrs, const DnsLookupDetails &, void *cbdata)
 {
 #if DNS_CNAME
     ipcache_entry *i = NULL;
     char *pname = NULL;
-    IPAddress *tmpbuf = NULL;
+    IpAddress *tmpbuf = NULL;
     int fc = 0;
     int ttl = 0;
     generic_cbdata* gcb = (generic_cbdata*)cbdata;
@@ -1103,7 +1089,7 @@ ipcacheHandleCnameRecurse(const ipcache_addrs *addrs, void *cbdata)
     debugs(14, 5, "ipcacheHandleCnameRecurse: Handling basic A/AAAA response.");
 
     /* IFF no CNAME recursion being processed. do nothing. */
-    if(cbdata == NULL)
+    if (cbdata == NULL)
         return;
 
     gcb->unwrap(&i);
@@ -1119,13 +1105,13 @@ ipcacheHandleCnameRecurse(const ipcache_addrs *addrs, void *cbdata)
 
     debugs(14, 5, "ipcacheHandleCnameRecurse: Handling CNAME recursion. CBDATA('" << gcb->data << "')='" << pname << "' -> " << std::hex << i);
 
-    if(i == NULL) {
+    if (i == NULL) {
         return; // Parent has expired. Don't merge, just leave for future Ref:
     }
 
     /* IFF addrs is NULL (Usually an Error or Timeout occured on lookup.) */
     /* Ignore it and HOPE that we got some Additional records to use.     */
-    if(addrs == NULL)
+    if (addrs == NULL)
         return;
 
     ccount = (0+ addrs->count);
@@ -1133,11 +1119,11 @@ ipcacheHandleCnameRecurse(const ipcache_addrs *addrs, void *cbdata)
     ttl = i->expires;
 
     /* IFF no CNAME results. do none of the processing BUT finish anyway. */
-    if(addrs) {
+    if (addrs) {
 
         debugs(14, 5, "ipcacheHandleCnameRecurse: Merge IP Lists for " << pname << " (" << pcount << "+" << ccount << ")");
 
-            /* add new IP records to entry */
+        /* add new IP records to entry */
         tmpbuf = i->addrs.in_addrs;
         i->addrs.in_addrs = NULL;
         ipcacheMergeIPLists(tmpbuf, pcount, addrs->in_addrs, ccount, &(i->addrs.in_addrs), fc);
@@ -1145,13 +1131,13 @@ ipcacheHandleCnameRecurse(const ipcache_addrs *addrs, void *cbdata)
         assert( (pcount>0 ? tmpbuf!=NULL : tmpbuf==NULL) );
         safe_free(tmpbuf);
 
-        if( pcount > 0) {
+        if ( pcount > 0) {
             /* IFF the parent initial lookup was given Additional records with A */
             // clear the 'bad IP mask'
             safe_free(i->addrs.bad_mask);
         }
         // create a new bad IP mask to fit the new size needed.
-        if(fc > 0) {
+        if (fc > 0) {
             i->addrs.bad_mask = (unsigned char*)xcalloc(fc, sizeof(unsigned char));
             memset(i->addrs.bad_mask, 0, sizeof(unsigned char)*fc);
         }
@@ -1176,14 +1162,14 @@ ipcacheHandleCnameRecurse(const ipcache_addrs *addrs, void *cbdata)
         i->addrs.badcount = 0;
     }
 
-    if(fc == 0) {
+    if (fc == 0) {
         i->error_message = xstrdup("No DNS Records");
     }
 
     /* finish the lookup we were doing on parent when we got side-tracked for CNAME loop */
-    if(i->cname_wait == 0) {
+    if (i->cname_wait == 0) {
         ipcacheAddEntry(i);
-        ipcacheCallback(i);
+        ipcacheCallback(i, i->age()); // age since i creation, includes CNAMEs
     }
     // else still more CNAME to be found.
 #endif /* DNS_CNAME */
@@ -1229,11 +1215,11 @@ ipcache_addrs *
 ipcacheCheckNumeric(const char *name)
 {
 
-    IPAddress ip;
+    IpAddress ip;
     /* check if it's already a IP address in text form. */
 
     /* it may be IPv6-wrapped */
-    if(name[0] == '[') {
+    if (name[0] == '[') {
         char *tmp = xstrdup(&name[1]);
         tmp[strlen(tmp)-1] = '\0';
         if (!(ip = tmp)) {
@@ -1241,8 +1227,7 @@ ipcacheCheckNumeric(const char *name)
             return NULL;
         }
         delete tmp;
-    }
-    else if (!(ip = name))
+    } else if (!(ip = name))
         return NULL;
 
     debugs(14, 4, "ipcacheCheckNumeric: HIT_BYPASS for '" << name << "' == " << ip );
@@ -1274,7 +1259,7 @@ ipcacheLockEntry(ipcache_entry * i)
 static void
 ipcacheUnlockEntry(ipcache_entry * i)
 {
-    if(i->locks < 1) {
+    if (i->locks < 1) {
         debugs(14, 1, "WARNING: ipcacheEntry unlocked with no lock! locks=" << i->locks);
         return;
     }
@@ -1333,7 +1318,7 @@ ipcacheCycleAddr(const char *name, ipcache_addrs * ia)
  \param addr   specific addres to be marked bad
  */
 void
-ipcacheMarkBadAddr(const char *name, IPAddress &addr)
+ipcacheMarkBadAddr(const char *name, IpAddress &addr)
 {
     ipcache_entry *i;
     ipcache_addrs *ia;
@@ -1345,8 +1330,7 @@ ipcacheMarkBadAddr(const char *name, IPAddress &addr)
 
     ia = &i->addrs;
 
-    for (k = 0; k < (int) ia->count; k++)
-    {
+    for (k = 0; k < (int) ia->count; k++) {
         if (addr == ia->in_addrs[k] )
             break;
     }
@@ -1356,11 +1340,10 @@ ipcacheMarkBadAddr(const char *name, IPAddress &addr)
         return;
 
     /** Marks the given address as BAD */
-    if (!ia->bad_mask[k])
-    {
+    if (!ia->bad_mask[k]) {
         ia->bad_mask[k] = TRUE;
         ia->badcount++;
-        i->expires = XMIN(squid_curtime + XMAX((time_t)60, Config.negativeDnsTtl), i->expires);
+        i->expires = min(squid_curtime + max((time_t)60, Config.negativeDnsTtl), i->expires);
         debugs(14, 2, "ipcacheMarkBadAddr: " << name << " " << addr );
     }
 
@@ -1370,7 +1353,7 @@ ipcacheMarkBadAddr(const char *name, IPAddress &addr)
 
 /// \ingroup IPCacheAPI
 void
-ipcacheMarkGoodAddr(const char *name, IPAddress &addr)
+ipcacheMarkGoodAddr(const char *name, IpAddress &addr)
 {
     ipcache_entry *i;
     ipcache_addrs *ia;
@@ -1381,8 +1364,7 @@ ipcacheMarkGoodAddr(const char *name, IPAddress &addr)
 
     ia = &i->addrs;
 
-    for (k = 0; k < (int) ia->count; k++)
-    {
+    for (k = 0; k < (int) ia->count; k++) {
         if (addr == ia->in_addrs[k])
             break;
     }
@@ -1454,7 +1436,7 @@ ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
 {
     ipcache_entry *i;
 
-    IPAddress ip;
+    IpAddress ip;
 
     if (!(ip = ipaddr)) {
 #if USE_IPV6
@@ -1464,7 +1446,7 @@ ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
             debugs(14, 1, "ipcacheAddEntryFromHosts: Bad IP address '" << ipaddr << "'");
         }
 #else
-       debugs(14, 1, "ipcacheAddEntryFromHosts: Bad IP address '" << ipaddr << "'");
+        debugs(14, 1, "ipcacheAddEntryFromHosts: Bad IP address '" << ipaddr << "'");
 #endif
 
         return 1;
@@ -1486,7 +1468,7 @@ ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
     i->addrs.cur = 0;
     i->addrs.badcount = 0;
 
-    i->addrs.in_addrs = (IPAddress *)xcalloc(1, sizeof(IPAddress));
+    i->addrs.in_addrs = (IpAddress *)xcalloc(1, sizeof(IpAddress));
     i->addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
     i->addrs.in_addrs[0] = ip;
     i->addrs.bad_mask[0] = FALSE;