]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/ipcache.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ipcache.cc
index 57e5f4fd632fef095d8122ee87baa16db3090b6b..989616c91d130841b4faf07ff669034a72eca591 100644 (file)
@@ -1,50 +1,29 @@
 /*
- * DEBUG: section 14    IP Cache
- * AUTHOR: Harvest Derived
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  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.
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
  *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
+/* DEBUG: section 14    IP Cache */
+
 #include "squid.h"
-#include "cbdata.h"
 #include "CacheManager.h"
-#include "DnsLookupDetails.h"
+#include "cbdata.h"
+#include "dlink.h"
+#include "dns/LookupDetails.h"
+#include "dns/rfc3596.h"
 #include "event.h"
 #include "ip/Address.h"
 #include "ip/tools.h"
 #include "ipcache.h"
-#include "Mem.h"
 #include "mgr/Registration.h"
-#include "rfc3596.h"
-#include "SquidDns.h"
+#include "SquidConfig.h"
 #include "SquidTime.h"
 #include "StatCounters.h"
 #include "Store.h"
+#include "util.h"
 #include "wordlist.h"
 
 #if SQUID_SNMP
@@ -70,8 +49,8 @@
  \defgroup IPCacheInternal IP Cache Internals
  \ingroup IPCacheAPI
  \todo  when IP cache is provided as a class. These sub-groups will be obsolete
- *     for now they are used to seperate the public and private functions.
- *     with the private ones all being in IPCachInternal and public in IPCacheAPI
+ *  for now they are used to seperate the public and private functions.
+ *  with the private ones all being in IPCachInternal and public in IPCacheAPI
  *
  \section InternalOperation Internal Operation
  *
  */
 class ipcache_entry
 {
+    MEMPROXY_CLASS(ipcache_entry);
+
 public:
-    hash_link hash;            /* must be first */
+    ipcache_entry(const char *);
+    ~ipcache_entry();
+
+    hash_link hash;     /* must be first */
     time_t lastref;
     time_t expires;
     ipcache_addrs addrs;
@@ -111,9 +95,11 @@ public:
     struct timeval request_time;
     dlink_node lru;
     unsigned short locks;
-    struct {
-        unsigned int negcached:1;
-        unsigned int fromhosts:1;
+    struct Flags {
+        Flags() : negcached(false), fromhosts(false) {}
+
+        bool negcached;
+        bool fromhosts;
     } flags;
 
     int age() const; ///< time passed since request_time or -1 if unknown
@@ -141,17 +127,8 @@ static dlink_list lru_list;
 static void stat_ipcache_get(StoreEntry *);
 
 static FREE ipcacheFreeEntry;
-#if USE_DNSHELPER
-static HLPCB ipcacheHandleReply;
-#else
 static IDNSCB ipcacheHandleReply;
-#endif
 static int ipcacheExpiredEntry(ipcache_entry *);
-#if USE_DNSHELPER
-static int ipcacheParse(ipcache_entry *, const char *buf);
-#else
-static int ipcacheParse(ipcache_entry *, const rfc1035_rr *, int, const char *error);
-#endif
 static ipcache_entry *ipcache_get(const char *);
 static void ipcacheLockEntry(ipcache_entry *);
 static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
@@ -238,7 +215,7 @@ ipcacheExpiredEntry(ipcache_entry * i)
 
 /// \ingroup IPCacheAPI
 void
-ipcache_purgelru(void *voidnotused)
+ipcache_purgelru(void *)
 {
     dlink_node *m;
     dlink_node *prev = NULL;
@@ -277,8 +254,8 @@ purge_entries_fromhosts(void)
     ipcache_entry *i = NULL, *t;
 
     while (m) {
-        if (i != NULL) {       /* need to delay deletion */
-            ipcacheRelease(i); /* we just override locks */
+        if (i != NULL) {    /* need to delay deletion */
+            ipcacheRelease(i);  /* we just override locks */
             i = NULL;
         }
 
@@ -294,20 +271,19 @@ purge_entries_fromhosts(void)
         ipcacheRelease(i);
 }
 
-/**
- \ingroup IPCacheInternal
- *
- * create blank ipcache_entry
- */
-static ipcache_entry *
-ipcacheCreateEntry(const char *name)
+ipcache_entry::ipcache_entry(const char *name) :
+    lastref(0),
+    expires(0),
+    handler(nullptr),
+    handlerData(nullptr),
+    error_message(nullptr),
+    locks(0) // XXX: use Lock type ?
 {
-    static ipcache_entry *i;
-    i = (ipcache_entry *)memAllocate(MEM_IPCACHE_ENTRY);
-    i->hash.key = xstrdup(name);
-    Tolower(static_cast<char*>(i->hash.key));
-    i->expires = squid_curtime + Config.negativeDnsTtl;
-    return i;
+    hash.key = xstrdup(name);
+    Tolower(static_cast<char*>(hash.key));
+    expires = squid_curtime + Config.negativeDnsTtl;
+
+    memset(&request_time, 0, sizeof(request_time));
 }
 
 /// \ingroup IPCacheInternal
@@ -349,119 +325,14 @@ ipcacheCallback(ipcache_entry *i, int wait)
     i->handler = NULL;
 
     if (cbdataReferenceValidDone(i->handlerData, &cbdata)) {
-        const DnsLookupDetails details(i->error_message, wait);
+        const Dns::LookupDetails details(i->error_message, wait);
         callback((i->addrs.count ? &i->addrs : NULL), details, cbdata);
     }
 
     ipcacheUnlockEntry(i);
 }
 
-/// \ingroup IPCacheAPI
-#if USE_DNSHELPER
-static int
-ipcacheParse(ipcache_entry *i, const char *inbuf)
-{
-    LOCAL_ARRAY(char, buf, DNS_INBUF_SZ);
-    char *token;
-    int ipcount = 0;
-    int ttl;
-    char *A[32];
-    const char *name = (const char *)i->hash.key;
-    i->expires = squid_curtime + Config.negativeDnsTtl;
-    i->flags.negcached = 1;
-    safe_free(i->addrs.in_addrs);
-    safe_free(i->addrs.bad_mask);
-    safe_free(i->error_message);
-    i->addrs.count = 0;
-
-    if (inbuf == NULL) {
-        debugs(14, DBG_IMPORTANT, "ipcacheParse: Got <NULL> reply");
-        i->error_message = xstrdup("Internal Error");
-        return -1;
-    }
-
-    xstrncpy(buf, inbuf, DNS_INBUF_SZ);
-    debugs(14, 5, "ipcacheParse: parsing: {" << buf << "}");
-    token = strtok(buf, w_space);
-
-    if (NULL == token) {
-        debugs(14, DBG_IMPORTANT, "ipcacheParse: expecting result, got '" << inbuf << "'");
-
-        i->error_message = xstrdup("Internal Error");
-        return -1;
-    }
-
-    if (0 == strcmp(token, "$fail")) {
-        token = strtok(NULL, "\n");
-        assert(NULL != token);
-        i->error_message = xstrdup(token);
-        return 0;
-    }
-
-    if (0 != strcmp(token, "$addr")) {
-        debugs(14, DBG_IMPORTANT, "ipcacheParse: expecting '$addr', got '" << inbuf << "' in response to '" << name << "'");
-
-        i->error_message = xstrdup("Internal Error");
-        return -1;
-    }
-
-    token = strtok(NULL, w_space);
-
-    if (NULL == token) {
-        debugs(14, DBG_IMPORTANT, "ipcacheParse: expecting TTL, got '" << inbuf << "' in response to '" << name << "'");
-
-        i->error_message = xstrdup("Internal Error");
-        return -1;
-    }
-
-    ttl = atoi(token);
-
-    while (NULL != (token = strtok(NULL, w_space))) {
-        A[ipcount] = token;
-
-        if (++ipcount == 32)
-            break;
-    }
-
-    if (ipcount > 0) {
-        int j, k;
-
-        i->addrs.in_addrs = static_cast<Ip::Address *>(xcalloc(ipcount, sizeof(Ip::Address)));
-        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);
-
-        for (j = 0, k = 0; k < ipcount; ++k) {
-            if ( i->addrs.in_addrs[j] = A[k] )
-                ++j;
-            else
-                debugs(14, DBG_IMPORTANT, "ipcacheParse: Invalid IP address '" << A[k] << "' in response to '" << name << "'");
-        }
-
-        i->addrs.count = (unsigned char) j;
-    }
-
-    if (i->addrs.count <= 0) {
-        debugs(14, DBG_IMPORTANT, "ipcacheParse: No addresses in response to '" << name << "'");
-        return -1;
-    }
-
-    if (ttl == 0 || ttl > Config.positiveDnsTtl)
-        ttl = Config.positiveDnsTtl;
-
-    if (ttl < Config.negativeDnsTtl)
-        ttl = Config.negativeDnsTtl;
-
-    i->expires = squid_curtime + ttl;
-
-    i->flags.negcached = 0;
-
-    return i->addrs.count;
-}
-
-#else
-static int
+static void
 ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *error_message)
 {
     int k;
@@ -472,7 +343,7 @@ ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *e
     int cname_found = 0;
 
     i->expires = squid_curtime + Config.negativeDnsTtl;
-    i->flags.negcached = 1;
+    i->flags.negcached = true;
     safe_free(i->addrs.in_addrs);
     assert(i->addrs.in_addrs == NULL);
     safe_free(i->addrs.bad_mask);
@@ -482,25 +353,25 @@ ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *e
     i->addrs.count = 0;
 
     if (nr < 0) {
-        debugs(14, 3, "ipcacheParse: Lookup failed '" << error_message << "' for '" << (const char *)i->hash.key << "'");
+        debugs(14, 3, "Lookup failed '" << error_message << "' for '" << (const char *)i->hash.key << "'");
         i->error_message = xstrdup(error_message);
-        return -1;
+        return;
     }
 
     if (nr == 0) {
-        debugs(14, 3, "ipcacheParse: No DNS records in response to '" << name << "'");
+        debugs(14, 3, "No DNS records in response to '" << name << "'");
         i->error_message = xstrdup("No DNS records");
-        return -1;
+        return;
     }
 
-    debugs(14, 3, "ipcacheParse: " << nr << " answers for '" << name << "'");
+    debugs(14, 3, nr << " answers for '" << name << "'");
     assert(answers);
 
     for (k = 0; k < nr; ++k) {
 
         if (Ip::EnableIpv6 && answers[k].type == RFC1035_TYPE_AAAA) {
             if (answers[k].rdlength != sizeof(struct in6_addr)) {
-                debugs(14, DBG_IMPORTANT, "ipcacheParse: Invalid IPv6 address in response to '" << name << "'");
+                debugs(14, DBG_IMPORTANT, MYNAME << "Invalid IPv6 address in response to '" << name << "'");
                 continue;
             }
             ++na;
@@ -510,7 +381,7 @@ ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *e
 
         if (answers[k].type == RFC1035_TYPE_A) {
             if (answers[k].rdlength != sizeof(struct in_addr)) {
-                debugs(14, DBG_IMPORTANT, "ipcacheParse: Invalid IPv4 address in response to '" << name << "'");
+                debugs(14, DBG_IMPORTANT, MYNAME << "Invalid IPv4 address in response to '" << name << "'");
                 continue;
             }
             ++na;
@@ -526,19 +397,19 @@ ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *e
         }
 
         // otherwise its an unknown RR. debug at level 9 since we usually want to ignore these and they are common.
-        debugs(14, 9, HERE << "Unknown RR type received: type=" << answers[k].type << " starting at " << &(answers[k]) );
+        debugs(14, 9, "Unknown RR type received: type=" << answers[k].type << " starting at " << &(answers[k]) );
     }
     if (na == 0) {
-        debugs(14, DBG_IMPORTANT, "ipcacheParse: No Address records in response to '" << name << "'");
+        debugs(14, DBG_IMPORTANT, MYNAME << "No Address records in response to '" << name << "'");
         i->error_message = xstrdup("No Address records");
         if (cname_found)
             ++IpcacheStats.cname_only;
-        return 0;
+        return;
     }
 
     i->addrs.in_addrs = static_cast<Ip::Address *>(xcalloc(na, sizeof(Ip::Address)));
     for (int l = 0; l < na; ++l)
-        i->addrs.in_addrs[l].SetEmpty(); // perform same init actions as constructor would.
+        i->addrs.in_addrs[l].setEmpty(); // perform same init actions as constructor would.
     i->addrs.bad_mask = (unsigned char *)xcalloc(na, sizeof(unsigned char));
 
     for (j = 0, k = 0; k < nr; ++k) {
@@ -551,7 +422,7 @@ ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *e
             memcpy(&temp, answers[k].rdata, sizeof(struct in_addr));
             i->addrs.in_addrs[j] = temp;
 
-            debugs(14, 3, "ipcacheParse: " << name << " #" << j << " " << i->addrs.in_addrs[j]);
+            debugs(14, 3, name << " #" << j << " " << i->addrs.in_addrs[j]);
             ++j;
 
         } else if (Ip::EnableIpv6 && answers[k].type == RFC1035_TYPE_AAAA) {
@@ -562,7 +433,7 @@ ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *e
             memcpy(&temp, answers[k].rdata, sizeof(struct in6_addr));
             i->addrs.in_addrs[j] = temp;
 
-            debugs(14, 3, "ipcacheParse: " << name << " #" << j << " " << i->addrs.in_addrs[j] );
+            debugs(14, 3, name << " #" << j << " " << i->addrs.in_addrs[j] );
             ++j;
         }
         if (ttl == 0 || (int) answers[k].ttl < ttl)
@@ -584,20 +455,12 @@ ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *e
 
     i->expires = squid_curtime + ttl;
 
-    i->flags.negcached = 0;
-
-    return i->addrs.count;
+    i->flags.negcached = false;
 }
 
-#endif
-
 /// \ingroup IPCacheInternal
 static void
-#if USE_DNSHELPER
-ipcacheHandleReply(void *data, char *reply)
-#else
 ipcacheHandleReply(void *data, const rfc1035_rr * answers, int na, const char *error_message)
-#endif
 {
     ipcache_entry *i;
     static_cast<generic_cbdata *>(data)->unwrap(&i);
@@ -605,29 +468,18 @@ ipcacheHandleReply(void *data, const rfc1035_rr * answers, int na, const char *e
     const int age = i->age();
     statCounter.dns.svcTime.count(age);
 
-#if USE_DNSHELPER
-    ipcacheParse(i, reply);
-#else
-
-    int 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)
-#endif
-
-    {
-        ipcacheAddEntry(i);
-        ipcacheCallback(i, age);
-    }
+    ipcacheParse(i, answers, na, error_message);
+    ipcacheAddEntry(i);
+    ipcacheCallback(i, age);
 }
 
 /**
  \ingroup IPCacheAPI
  *
- \param name           Host to resolve.
- \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.
+ \param name        Host to resolve.
+ \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
@@ -649,7 +501,7 @@ ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
     if (name == NULL || name[0] == '\0') {
         debugs(14, 4, "ipcache_nbgethostbyname: Invalid name!");
         ++IpcacheStats.invalid;
-        const DnsLookupDetails details("Invalid hostname", -1); // error, no lookup
+        const Dns::LookupDetails details("Invalid hostname", -1); // error, no lookup
         if (handler)
             handler(NULL, details, handlerData);
         return;
@@ -658,7 +510,7 @@ ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
     if ((addrs = ipcacheCheckNumeric(name))) {
         debugs(14, 4, "ipcache_nbgethostbyname: BYPASS for '" << name << "' (already numeric)");
         ++IpcacheStats.numeric_hits;
-        const DnsLookupDetails details(NULL, -1); // no error, no lookup
+        const Dns::LookupDetails details; // no error, no lookup
         if (handler)
             handler(addrs, details, handlerData);
         return;
@@ -693,16 +545,12 @@ ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
 
     debugs(14, 5, "ipcache_nbgethostbyname: MISS for '" << name << "'");
     ++IpcacheStats.misses;
-    i = ipcacheCreateEntry(name);
+    i = new ipcache_entry(name);
     i->handler = handler;
     i->handlerData = cbdataReference(handlerData);
     i->request_time = current_time;
     c = new generic_cbdata(i);
-#if USE_DNSHELPER
-    dnsSubmit(hashKeyStr(&i->hash), ipcacheHandleReply, c);
-#else
     idnsALookup(hashKeyStr(&i->hash), ipcacheHandleReply, c);
-#endif
 }
 
 /// \ingroup IPCacheInternal
@@ -731,7 +579,7 @@ ipcache_init(void)
     memset(&static_addrs, '\0', sizeof(ipcache_addrs));
 
     static_addrs.in_addrs = static_cast<Ip::Address *>(xcalloc(1, sizeof(Ip::Address)));
-    static_addrs.in_addrs->SetEmpty(); // properly setup the Ip::Address!
+    static_addrs.in_addrs->setEmpty(); // properly setup the Ip::Address!
     static_addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
     ipcache_high = (long) (((float) Config.ipcache.size *
                             (float) Config.ipcache.high) / (float) 100);
@@ -739,7 +587,6 @@ ipcache_init(void)
                            (float) Config.ipcache.low) / (float) 100);
     n = hashPrime(ipcache_high / 4);
     ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
-    memDataInit(MEM_IPCACHE_ENTRY, "ipcache_entry", sizeof(ipcache_entry), 0);
 
     ipcacheRegisterWithCacheManager();
 }
@@ -751,13 +598,13 @@ ipcache_init(void)
  * if an entry exists in the cache and does not by default contact the DNS,
  * unless this is requested, by setting the flags.
  *
- \param name           Host name to resolve.
- \param flags          Default is NULL, set to IP_LOOKUP_IF_MISS
- *                     to explicitly perform DNS lookups.
+ \param name        Host name to resolve.
+ \param flags       Default is NULL, set to IP_LOOKUP_IF_MISS
+ *          to explicitly perform DNS lookups.
  *
- \retval NULL  An error occured during lookup
- \retval NULL  No results available in cache and no lookup specified
- \retval *     Pointer to the ipcahce_addrs structure containing the lookup results
+ \retval NULL   An error occured during lookup
+ \retval NULL   No results available in cache and no lookup specified
+ \retval *  Pointer to the ipcahce_addrs structure containing the lookup results
  */
 const ipcache_addrs *
 ipcache_gethostbyname(const char *name, int flags)
@@ -842,12 +689,12 @@ ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
         /* Display tidy-up: IPv6 are so big make the list vertical */
         if (k == 0)
             storeAppendPrintf(sentry, " %45.45s-%3s\n",
-                              i->addrs.in_addrs[k].NtoA(buf,MAX_IPSTRLEN),
+                              i->addrs.in_addrs[k].toStr(buf,MAX_IPSTRLEN),
                               i->addrs.bad_mask[k] ? "BAD" : "OK ");
         else
             storeAppendPrintf(sentry, "%s %45.45s-%3s\n",
                               "                                                         ", /* blank-space indenting IP list */
-                              i->addrs.in_addrs[k].NtoA(buf,MAX_IPSTRLEN),
+                              i->addrs.in_addrs[k].toStr(buf,MAX_IPSTRLEN),
                               i->addrs.bad_mask[k] ? "BAD" : "OK ");
     }
 }
@@ -864,7 +711,7 @@ stat_ipcache_get(StoreEntry * sentry)
     assert(ip_table != NULL);
     storeAppendPrintf(sentry, "IP Cache Statistics:\n");
     storeAppendPrintf(sentry, "IPcache Entries In Use:  %d\n",
-                      memInUse(MEM_IPCACHE_ENTRY));
+                      ipcache_entry::UseCount());
     storeAppendPrintf(sentry, "IPcache Entries Cached:  %d\n",
                       ipcacheCount());
     storeAppendPrintf(sentry, "IPcache Requests: %d\n",
@@ -1041,8 +888,8 @@ ipcacheCycleAddr(const char *name, ipcache_addrs * ia)
 /**
  \ingroup IPCacheAPI
  *
- \param name   domain name to have an IP marked bad
- \param addr   specific addres to be marked bad
+ \param name    domain name to have an IP marked bad
+ \param addr    specific addres to be marked bad
  */
 void
 ipcacheMarkBadAddr(const char *name, const Ip::Address &addr)
@@ -1070,7 +917,6 @@ ipcacheMarkBadAddr(const char *name, const Ip::Address &addr)
     if (!ia->bad_mask[k]) {
         ia->bad_mask[k] = TRUE;
         ++ia->badcount;
-        i->expires = min(squid_curtime + max((time_t)60, Config.negativeDnsTtl), i->expires);
         debugs(14, 2, "ipcacheMarkBadAddr: " << name << " " << addr );
     }
 
@@ -1118,10 +964,10 @@ ipcacheMarkGoodAddr(const char *name, const Ip::Address &addr)
             break;
     }
 
-    if (k == (int) ia->count)  /* not found */
+    if (k == (int) ia->count)   /* not found */
         return;
 
-    if (!ia->bad_mask[k])      /* already OK */
+    if (!ia->bad_mask[k])   /* already OK */
         return;
 
     ia->bad_mask[k] = FALSE;
@@ -1136,11 +982,15 @@ static void
 ipcacheFreeEntry(void *data)
 {
     ipcache_entry *i = (ipcache_entry *)data;
-    safe_free(i->addrs.in_addrs);
-    safe_free(i->addrs.bad_mask);
-    safe_free(i->hash.key);
-    safe_free(i->error_message);
-    memFree(i, MEM_IPCACHE_ENTRY);
+    delete i;
+}
+
+ipcache_entry::~ipcache_entry()
+{
+    xfree(addrs.in_addrs);
+    xfree(addrs.bad_mask);
+    xfree(error_message);
+    xfree(hash.key);
 }
 
 /// \ingroup IPCacheAPI
@@ -1174,11 +1024,11 @@ ipcache_restart(void)
  *
  * Adds a "static" entry from /etc/hosts
  *
- \param name   Hostname to be linked with IP
- \param ipaddr IP Address to be cached.
+ \param name    Hostname to be linked with IP
+ \param ipaddr  IP Address to be cached.
  *
- \retval 0     Success.
- \retval 1     IP address is invalid or other error.
+ \retval 0  Success.
+ \retval 1  IP address is invalid or other error.
  */
 int
 ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
@@ -1208,7 +1058,7 @@ ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
         }
     }
 
-    i = ipcacheCreateEntry(name);
+    i = new ipcache_entry(name);
     i->addrs.count = 1;
     i->addrs.cur = 0;
     i->addrs.badcount = 0;
@@ -1217,7 +1067,7 @@ ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
     i->addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
     i->addrs.in_addrs[0] = ip;
     i->addrs.bad_mask[0] = FALSE;
-    i->flags.fromhosts = 1;
+    i->flags.fromhosts = true;
     ipcacheAddEntry(i);
     ipcacheLockEntry(i);
     return 0;
@@ -1297,3 +1147,4 @@ snmp_netIpFn(variable_list * Var, snint * ErrP)
 }
 
 #endif /*SQUID_SNMP */
+