/*
- * 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 "protos.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
\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;
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
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 *);
/// \ingroup IPCacheAPI
void
-ipcache_purgelru(void *voidnotused)
+ipcache_purgelru(void *)
{
dlink_node *m;
dlink_node *prev = NULL;
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;
}
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
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;
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);
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;
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;
}
// 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) {
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) {
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)
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);
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
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;
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;
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
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);
(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();
}
* 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)
/* 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 ");
}
}
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",
/**
\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)
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 );
}
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;
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
*
* 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)
}
}
- i = ipcacheCreateEntry(name);
+ i = new ipcache_entry(name);
i->addrs.count = 1;
i->addrs.cur = 0;
i->addrs.badcount = 0;
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;
}
#endif /*SQUID_SNMP */
+