]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipcache.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ipcache.cc
CommitLineData
30a4f2a8 1/*
30a4f2a8 2 * DEBUG: section 14 IP Cache
3 * AUTHOR: Harvest Derived
4 *
2b6662ba 5 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 6 * ----------------------------------------------------------
30a4f2a8 7 *
2b6662ba 8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
30a4f2a8 16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
26ac0430 21 *
30a4f2a8 22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26ac0430 26 *
30a4f2a8 27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
cbdec147 29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 30 *
019dd986 31 */
44a47c6e 32
582c2af2 33#include "squid.h"
62ee09ca 34#include "CacheManager.h"
602d9612 35#include "cbdata.h"
17852883 36#include "dlink.h"
cfd66529
AJ
37#include "DnsLookupDetails.h"
38#include "event.h"
39#include "ip/Address.h"
055421ee 40#include "ip/tools.h"
714e68b7 41#include "ipcache.h"
8a89c28f 42#include "Mem.h"
8822ebee 43#include "mgr/Registration.h"
582c2af2 44#include "rfc3596.h"
4d5904f7 45#include "SquidConfig.h"
f64091a7 46#include "SquidDns.h"
985c86bc 47#include "SquidTime.h"
e4f1fdae 48#include "StatCounters.h"
e6ccf245 49#include "Store.h"
d295d770 50#include "wordlist.h"
44a47c6e 51
9c0a2256
FC
52#if SQUID_SNMP
53#include "snmp_core.h"
54#endif
55
63be0a78 56/**
57 \defgroup IPCacheAPI IP Cache API
58 \ingroup Components
59 \section Introduction Introduction
60 \par
61 * The IP cache is a built-in component of squid providing
62 * Hostname to IP-Number translation functionality and managing
63 * the involved data-structures. Efficiency concerns require
64 * mechanisms that allow non-blocking access to these mappings.
65 * The IP cache usually doesn't block on a request except for
66 * special cases where this is desired (see below).
67 *
68 \todo IP Cache should have its own API *.h header file.
69 */
70
71/**
72 \defgroup IPCacheInternal IP Cache Internals
73 \ingroup IPCacheAPI
74 \todo when IP cache is provided as a class. These sub-groups will be obsolete
75 * for now they are used to seperate the public and private functions.
76 * with the private ones all being in IPCachInternal and public in IPCacheAPI
77 *
78 \section InternalOperation Internal Operation
79 *
80 * Internally, the execution flow is as follows: On a miss,
81 * ipcache_getnbhostbyname checks whether a request for
82 * this name is already pending, and if positive, it creates
83 * a new entry using ipcacheAddNew with the IP_PENDING
84 * flag set . Then it calls ipcacheAddPending to add a
85 * request to the queue together with data and handler. Else,
86 * ipcache_dnsDispatch() is called to directly create a
87 * DNS query or to ipcacheEnqueue() if all no DNS port
88 * is free. ipcache_call_pending() is called regularly
89 * to walk down the pending list and call handlers. LRU clean-up
90 * is performed through ipcache_purgelru() according to
91 * the ipcache_high threshold.
92 */
93
63be0a78 94/**
95 \ingroup IPCacheAPI
96 *
97 * The data structure used for storing name-address mappings
98 * is a small hashtable (static hash_table *ip_table),
99 * where structures of type ipcache_entry whose most
100 * interesting members are:
101 */
e1381638
AJ
102class ipcache_entry
103{
3ff65596 104public:
186477c1 105 hash_link hash; /* must be first */
ecc3091b 106 time_t lastref;
107 time_t expires;
108 ipcache_addrs addrs;
109 IPH *handler;
110 void *handlerData;
111 char *error_message;
62e76326 112
ecc3091b 113 struct timeval request_time;
114 dlink_node lru;
ac06f720 115 unsigned short locks;
26ac0430 116 struct {
be4d35dc
FC
117 bool negcached;
118 bool fromhosts;
2fadd50d 119 } flags;
3ff65596
AR
120
121 int age() const; ///< time passed since request_time or -1 if unknown
ecc3091b 122};
123
63be0a78 124/// \ingroup IPCacheInternal
26ac0430 125static struct _ipcache_stats {
30a4f2a8 126 int requests;
f88bb09c 127 int replies;
30a4f2a8 128 int hits;
129 int misses;
30a4f2a8 130 int negative_hits;
22b245f8 131 int numeric_hits;
bae9832d 132 int rr_a;
133 int rr_aaaa;
134 int rr_cname;
135 int cname_only;
22b245f8 136 int invalid;
2fadd50d 137} IpcacheStats;
090089c4 138
63be0a78 139/// \ingroup IPCacheInternal
ce75f381 140static dlink_list lru_list;
7b04dad5 141
59a09b98
FC
142// forward-decls
143static void stat_ipcache_get(StoreEntry *);
144
74addf6c 145static FREE ipcacheFreeEntry;
7b724b86 146static IDNSCB ipcacheHandleReply;
74addf6c 147static int ipcacheExpiredEntry(ipcache_entry *);
33ab4aaf 148static int ipcacheParse(ipcache_entry *, const rfc1035_rr *, int, const char *error);
f5b8bbc4 149static ipcache_entry *ipcache_get(const char *);
74addf6c 150static void ipcacheLockEntry(ipcache_entry *);
f5b8bbc4 151static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
152static void ipcacheUnlockEntry(ipcache_entry *);
cc192b50 153static void ipcacheRelease(ipcache_entry *, bool dofree = true);
30a4f2a8 154
63be0a78 155/// \ingroup IPCacheInternal
e5f6c5c2 156static ipcache_addrs static_addrs;
63be0a78 157/// \ingroup IPCacheInternal
365e5b34 158static hash_table *ip_table = NULL;
090089c4 159
63be0a78 160/// \ingroup IPCacheInternal
24382924 161static long ipcache_low = 180;
63be0a78 162/// \ingroup IPCacheInternal
24382924 163static long ipcache_high = 200;
f88bb09c 164
c021888f 165#if LIBRESOLV_DNS_TTL_HACK
166extern int _dns_ttl_;
167#endif
168
ac49890a
CT
169/// \ingroup IPCacheInternal
170inline int ipcacheCount() { return ip_table ? ip_table->count : 0; }
171
3ff65596
AR
172int
173ipcache_entry::age() const
174{
175 return request_time.tv_sec ? tvSubMsec(request_time, current_time) : -1;
176}
177
63be0a78 178/**
179 \ingroup IPCacheInternal
180 *
181 * removes the given ipcache entry
182 */
b8d8561b 183static void
cc192b50 184ipcacheRelease(ipcache_entry * i, bool dofree)
090089c4 185{
26ac0430 186 if (!i) {
fa84c01d 187 debugs(14, DBG_CRITICAL, "ipcacheRelease: Releasing entry with i=<NULL>");
cc192b50 188 return;
189 }
190
26ac0430 191 if (!i || !i->hash.key) {
fa84c01d 192 debugs(14, DBG_CRITICAL, "ipcacheRelease: Releasing entry without hash link!");
cc192b50 193 return;
194 }
195
bf8fe701 196 debugs(14, 3, "ipcacheRelease: Releasing entry for '" << (const char *) i->hash.key << "'");
197
ecc3091b 198 hash_remove_link(ip_table, (hash_link *) i);
7b04dad5 199 dlinkDelete(&i->lru, &lru_list);
26ac0430 200 if (dofree)
cc192b50 201 ipcacheFreeEntry(i);
090089c4 202}
203
63be0a78 204/// \ingroup IPCacheInternal
b8d8561b 205static ipcache_entry *
0ee4272b 206ipcache_get(const char *name)
090089c4 207{
ecc3091b 208 if (ip_table != NULL)
62e76326 209 return (ipcache_entry *) hash_lookup(ip_table, name);
ecc3091b 210 else
62e76326 211 return NULL;
090089c4 212}
213
63be0a78 214/// \ingroup IPCacheInternal
b8d8561b 215static int
216ipcacheExpiredEntry(ipcache_entry * i)
30a4f2a8 217{
0e70aa1e 218 /* all static entries are locked, so this takes care of them too */
62e76326 219
620da955 220 if (i->locks != 0)
62e76326 221 return 0;
222
7c63efed 223 if (i->addrs.count == 0)
62e76326 224 if (0 == i->flags.negcached)
225 return 1;
226
af00901c 227 if (i->expires > squid_curtime)
62e76326 228 return 0;
229
30a4f2a8 230 return 1;
231}
090089c4 232
63be0a78 233/// \ingroup IPCacheAPI
7b04dad5 234void
235ipcache_purgelru(void *voidnotused)
236{
237 dlink_node *m;
238 dlink_node *prev = NULL;
239 ipcache_entry *i;
240 int removed = 0;
52040193 241 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
62e76326 242
7b04dad5 243 for (m = lru_list.tail; m; m = prev) {
ac49890a 244 if (ipcacheCount() < ipcache_low)
62e76326 245 break;
246
247 prev = m->prev;
248
249 i = (ipcache_entry *)m->data;
250
251 if (i->locks != 0)
252 continue;
253
254 ipcacheRelease(i);
255
95dc7ff4 256 ++removed;
7b04dad5 257 }
62e76326 258
bf8fe701 259 debugs(14, 9, "ipcache_purgelru: removed " << removed << " entries");
7b04dad5 260}
261
63be0a78 262/**
263 \ingroup IPCacheInternal
264 *
265 * purges entries added from /etc/hosts (or whatever).
266 */
0e70aa1e 267static void
268purge_entries_fromhosts(void)
269{
270 dlink_node *m = lru_list.head;
271 ipcache_entry *i = NULL, *t;
62e76326 272
0e70aa1e 273 while (m) {
62e76326 274 if (i != NULL) { /* need to delay deletion */
275 ipcacheRelease(i); /* we just override locks */
276 i = NULL;
277 }
278
279 t = (ipcache_entry*)m->data;
280
281 if (t->flags.fromhosts)
282 i = t;
283
284 m = m->next;
0e70aa1e 285 }
62e76326 286
0e70aa1e 287 if (i != NULL)
62e76326 288 ipcacheRelease(i);
0e70aa1e 289}
290
63be0a78 291/**
292 \ingroup IPCacheInternal
293 *
294 * create blank ipcache_entry
295 */
b8d8561b 296static ipcache_entry *
ecc3091b 297ipcacheCreateEntry(const char *name)
090089c4 298{
7b04dad5 299 static ipcache_entry *i;
e6ccf245 300 i = (ipcache_entry *)memAllocate(MEM_IPCACHE_ENTRY);
186477c1 301 i->hash.key = xstrdup(name);
7176768b 302 Tolower(static_cast<char*>(i->hash.key));
7b04dad5 303 i->expires = squid_curtime + Config.negativeDnsTtl;
7b04dad5 304 return i;
090089c4 305}
306
63be0a78 307/// \ingroup IPCacheInternal
b8d8561b 308static void
ecc3091b 309ipcacheAddEntry(ipcache_entry * i)
dd7ad0a4 310{
e6ccf245 311 hash_link *e = (hash_link *)hash_lookup(ip_table, i->hash.key);
62e76326 312
ecc3091b 313 if (NULL != e) {
62e76326 314 /* avoid colission */
315 ipcache_entry *q = (ipcache_entry *) e;
2b72648d 316 ipcacheRelease(q);
ecc3091b 317 }
62e76326 318
186477c1 319 hash_join(ip_table, &i->hash);
ecc3091b 320 dlinkAdd(i, &i->lru, &lru_list);
dd7ad0a4 321 i->lastref = squid_curtime;
090089c4 322}
323
63be0a78 324/**
325 \ingroup IPCacheInternal
326 *
327 * walks down the pending list, calling handlers
328 */
b8d8561b 329static void
3ff65596 330ipcacheCallback(ipcache_entry *i, int wait)
090089c4 331{
fa80a8ef 332 IPH *callback = i->handler;
cc192b50 333 void *cbdata = NULL;
30a4f2a8 334 i->lastref = squid_curtime;
62e76326 335
fa80a8ef 336 if (!i->handler)
62e76326 337 return;
338
fa80a8ef 339 ipcacheLockEntry(i);
62e76326 340
fa80a8ef 341 callback = i->handler;
62e76326 342
ecc3091b 343 i->handler = NULL;
62e76326 344
fa80a8ef 345 if (cbdataReferenceValidDone(i->handlerData, &cbdata)) {
3ff65596
AR
346 const DnsLookupDetails details(i->error_message, wait);
347 callback((i->addrs.count ? &i->addrs : NULL), details, cbdata);
090089c4 348 }
62e76326 349
620da955 350 ipcacheUnlockEntry(i);
090089c4 351}
352
63be0a78 353/// \ingroup IPCacheAPI
7ba8d0b8 354static int
33ab4aaf 355ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *error_message)
7b724b86 356{
7cfc1c9a 357 int k;
cc192b50 358 int j = 0;
7cfc1c9a 359 int na = 0;
7ba8d0b8 360 int ttl = 0;
361 const char *name = (const char *)i->hash.key;
bae9832d 362 int cname_found = 0;
363
7ba8d0b8 364 i->expires = squid_curtime + Config.negativeDnsTtl;
be4d35dc 365 i->flags.negcached = true;
7ba8d0b8 366 safe_free(i->addrs.in_addrs);
cc192b50 367 assert(i->addrs.in_addrs == NULL);
7ba8d0b8 368 safe_free(i->addrs.bad_mask);
cc192b50 369 assert(i->addrs.bad_mask == NULL);
7ba8d0b8 370 safe_free(i->error_message);
cc192b50 371 assert(i->error_message == NULL);
7ba8d0b8 372 i->addrs.count = 0;
62e76326 373
7cfc1c9a 374 if (nr < 0) {
bf8fe701 375 debugs(14, 3, "ipcacheParse: Lookup failed '" << error_message << "' for '" << (const char *)i->hash.key << "'");
7ba8d0b8 376 i->error_message = xstrdup(error_message);
377 return -1;
7cfc1c9a 378 }
62e76326 379
7cfc1c9a 380 if (nr == 0) {
bf8fe701 381 debugs(14, 3, "ipcacheParse: No DNS records in response to '" << name << "'");
7ba8d0b8 382 i->error_message = xstrdup("No DNS records");
cc192b50 383 return -1;
7cfc1c9a 384 }
62e76326 385
48e7baac 386 debugs(14, 3, "ipcacheParse: " << nr << " answers for '" << name << "'");
7cfc1c9a 387 assert(answers);
62e76326 388
95dc7ff4 389 for (k = 0; k < nr; ++k) {
62e76326 390
055421ee 391 if (Ip::EnableIpv6 && answers[k].type == RFC1035_TYPE_AAAA) {
26ac0430 392 if (answers[k].rdlength != sizeof(struct in6_addr)) {
e0236918 393 debugs(14, DBG_IMPORTANT, "ipcacheParse: Invalid IPv6 address in response to '" << name << "'");
26ac0430
AJ
394 continue;
395 }
95dc7ff4
FC
396 ++na;
397 ++IpcacheStats.rr_aaaa;
26ac0430
AJ
398 continue;
399 }
62e76326 400
cc192b50 401 if (answers[k].type == RFC1035_TYPE_A) {
26ac0430 402 if (answers[k].rdlength != sizeof(struct in_addr)) {
e0236918 403 debugs(14, DBG_IMPORTANT, "ipcacheParse: Invalid IPv4 address in response to '" << name << "'");
26ac0430
AJ
404 continue;
405 }
95dc7ff4
FC
406 ++na;
407 ++IpcacheStats.rr_a;
26ac0430
AJ
408 continue;
409 }
cc192b50 410
26ac0430 411 /* With A and AAAA, the CNAME does not necessarily come with additional records to use. */
cc192b50 412 if (answers[k].type == RFC1035_TYPE_CNAME) {
bae9832d 413 cname_found=1;
95dc7ff4 414 ++IpcacheStats.rr_cname;
470cd749 415 continue;
416 }
bae9832d 417
418 // otherwise its an unknown RR. debug at level 9 since we usually want to ignore these and they are common.
419 debugs(14, 9, HERE << "Unknown RR type received: type=" << answers[k].type << " starting at " << &(answers[k]) );
cc192b50 420 }
7cfc1c9a 421 if (na == 0) {
e0236918 422 debugs(14, DBG_IMPORTANT, "ipcacheParse: No Address records in response to '" << name << "'");
7ba8d0b8 423 i->error_message = xstrdup("No Address records");
26ac0430 424 if (cname_found)
95dc7ff4 425 ++IpcacheStats.cname_only;
7ba8d0b8 426 return 0;
7cfc1c9a 427 }
62e76326 428
b7ac5457 429 i->addrs.in_addrs = static_cast<Ip::Address *>(xcalloc(na, sizeof(Ip::Address)));
95dc7ff4 430 for (int l = 0; l < na; ++l)
4dd643d5 431 i->addrs.in_addrs[l].setEmpty(); // perform same init actions as constructor would.
7ba8d0b8 432 i->addrs.bad_mask = (unsigned char *)xcalloc(na, sizeof(unsigned char));
62e76326 433
95dc7ff4 434 for (j = 0, k = 0; k < nr; ++k) {
62e76326 435
2d320a3a 436 if (answers[k].type == RFC1035_TYPE_A) {
cc192b50 437 if (answers[k].rdlength != sizeof(struct in_addr))
2d320a3a 438 continue;
439
cc192b50 440 struct in_addr temp;
41d00cd3 441 memcpy(&temp, answers[k].rdata, sizeof(struct in_addr));
cc192b50 442 i->addrs.in_addrs[j] = temp;
2d320a3a 443
cc192b50 444 debugs(14, 3, "ipcacheParse: " << name << " #" << j << " " << i->addrs.in_addrs[j]);
95dc7ff4 445 ++j;
bf8fe701 446
055421ee 447 } else if (Ip::EnableIpv6 && answers[k].type == RFC1035_TYPE_AAAA) {
cc192b50 448 if (answers[k].rdlength != sizeof(struct in6_addr))
449 continue;
450
451 struct in6_addr temp;
41d00cd3 452 memcpy(&temp, answers[k].rdata, sizeof(struct in6_addr));
cc192b50 453 i->addrs.in_addrs[j] = temp;
454
455 debugs(14, 3, "ipcacheParse: " << name << " #" << j << " " << i->addrs.in_addrs[j] );
95dc7ff4 456 ++j;
bae9832d 457 }
7ba8d0b8 458 if (ttl == 0 || (int) answers[k].ttl < ttl)
459 ttl = answers[k].ttl;
7b724b86 460 }
62e76326 461
7cfc1c9a 462 assert(j == na);
7ba8d0b8 463
be6e7af9 464 if (na < 256)
465 i->addrs.count = (unsigned char) na;
466 else
467 i->addrs.count = 255;
7ba8d0b8 468
3e8c4107 469 if (ttl > Config.positiveDnsTtl)
7ba8d0b8 470 ttl = Config.positiveDnsTtl;
471
472 if (ttl < Config.negativeDnsTtl)
473 ttl = Config.negativeDnsTtl;
474
475 i->expires = squid_curtime + ttl;
476
be4d35dc 477 i->flags.negcached = false;
7ba8d0b8 478
7c16f24c 479 return i->addrs.count;
7b724b86 480}
62e76326 481
63be0a78 482/// \ingroup IPCacheInternal
a7e59001 483static void
33ab4aaf 484ipcacheHandleReply(void *data, const rfc1035_rr * answers, int na, const char *error_message)
090089c4 485{
aa839030 486 ipcache_entry *i;
487 static_cast<generic_cbdata *>(data)->unwrap(&i);
95dc7ff4 488 ++IpcacheStats.replies;
3ff65596 489 const int age = i->age();
e8baef82 490 statCounter.dns.svcTime.count(age);
e1381638 491
12f3560e 492 int done = ipcacheParse(i, answers, na, error_message);
cc192b50 493
494 /* If we have not produced either IPs or Error immediately, wait for recursion to finish. */
17852883 495 if (done != 0 || error_message != NULL) {
cc192b50 496 ipcacheAddEntry(i);
3ff65596 497 ipcacheCallback(i, age);
cc192b50 498 }
30a4f2a8 499}
500
63be0a78 501/**
502 \ingroup IPCacheAPI
503 *
504 \param name Host to resolve.
505 \param handler Pointer to the function to be called when the reply
506 * from the IP cache (or the DNS if the IP cache misses)
507 \param handlerData Information that is passed to the handler and does not affect the IP cache.
79300bcb
AR
508 *
509 * XXX: on hits and some errors, the handler is called immediately instead
510 * of scheduling an async call. This reentrant behavior means that the
511 * user job must be extra careful after calling ipcache_nbgethostbyname,
26ac0430 512 * especially if the handler destroys the job. Moreover, the job has
55cbb02b
AJ
513 * no way of knowing whether the reentrant call happened.
514 * Comm::Connection setup usually protects the job by scheduling an async call,
515 * but some user code calls ipcache_nbgethostbyname directly.
63be0a78 516 */
b8d8561b 517void
8407afee 518ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
090089c4 519{
30a4f2a8 520 ipcache_entry *i = NULL;
429fdbec 521 const ipcache_addrs *addrs = NULL;
74addf6c 522 generic_cbdata *c;
bf8fe701 523 debugs(14, 4, "ipcache_nbgethostbyname: Name '" << name << "'.");
95dc7ff4 524 ++IpcacheStats.requests;
62e76326 525
090089c4 526 if (name == NULL || name[0] == '\0') {
bf8fe701 527 debugs(14, 4, "ipcache_nbgethostbyname: Invalid name!");
95dc7ff4 528 ++IpcacheStats.invalid;
3ff65596 529 const DnsLookupDetails details("Invalid hostname", -1); // error, no lookup
7fd65651
A
530 if (handler)
531 handler(NULL, details, handlerData);
62e76326 532 return;
af00901c 533 }
62e76326 534
e5f6c5c2 535 if ((addrs = ipcacheCheckNumeric(name))) {
cc192b50 536 debugs(14, 4, "ipcache_nbgethostbyname: BYPASS for '" << name << "' (already numeric)");
95dc7ff4 537 ++IpcacheStats.numeric_hits;
3ff65596 538 const DnsLookupDetails details(NULL, -1); // no error, no lookup
7fd65651
A
539 if (handler)
540 handler(addrs, details, handlerData);
62e76326 541 return;
090089c4 542 }
62e76326 543
ecc3091b 544 i = ipcache_get(name);
62e76326 545
ecc3091b 546 if (NULL == i) {
62e76326 547 /* miss */
548 (void) 0;
ecc3091b 549 } else if (ipcacheExpiredEntry(i)) {
62e76326 550 /* hit, but expired -- bummer */
551 ipcacheRelease(i);
552 i = NULL;
ecc3091b 553 } else {
62e76326 554 /* hit */
bf8fe701 555 debugs(14, 4, "ipcache_nbgethostbyname: HIT for '" << name << "'");
62e76326 556
557 if (i->flags.negcached)
95dc7ff4 558 ++IpcacheStats.negative_hits;
62e76326 559 else
95dc7ff4 560 ++IpcacheStats.hits;
62e76326 561
562 i->handler = handler;
563
564 i->handlerData = cbdataReference(handlerData);
565
3ff65596 566 ipcacheCallback(i, -1); // no lookup
62e76326 567
568 return;
090089c4 569 }
62e76326 570
bf8fe701 571 debugs(14, 5, "ipcache_nbgethostbyname: MISS for '" << name << "'");
95dc7ff4 572 ++IpcacheStats.misses;
ecc3091b 573 i = ipcacheCreateEntry(name);
574 i->handler = handler;
fa80a8ef 575 i->handlerData = cbdataReference(handlerData);
ecc3091b 576 i->request_time = current_time;
aa839030 577 c = new generic_cbdata(i);
186477c1 578 idnsALookup(hashKeyStr(&i->hash), ipcacheHandleReply, c);
090089c4 579}
580
5f5e883f
FC
581/// \ingroup IPCacheInternal
582static void
583ipcacheRegisterWithCacheManager(void)
584{
8822ebee 585 Mgr::RegisterAction("ipcache",
d9fc6862
A
586 "IP Cache Stats and Contents",
587 stat_ipcache_get, 0, 1);
5f5e883f
FC
588}
589
63be0a78 590/**
591 \ingroup IPCacheAPI
592 *
593 * Initialize the ipcache.
594 * Is called from mainInitialize() after disk initialization
595 * and prior to the reverse FQDNCache initialization
596 */
b8d8561b 597void
0673c0ba 598ipcache_init(void)
0ffd22bc 599{
aa9e2cab 600 int n;
8eb28163 601 debugs(14, DBG_IMPORTANT, "Initializing IP Cache...");
30a4f2a8 602 memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
3eb55834 603 memset(&lru_list, '\0', sizeof(lru_list));
e5f6c5c2 604 memset(&static_addrs, '\0', sizeof(ipcache_addrs));
62e76326 605
b7ac5457 606 static_addrs.in_addrs = static_cast<Ip::Address *>(xcalloc(1, sizeof(Ip::Address)));
4dd643d5 607 static_addrs.in_addrs->setEmpty(); // properly setup the Ip::Address!
e6ccf245 608 static_addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
b15e6857 609 ipcache_high = (long) (((float) Config.ipcache.size *
62e76326 610 (float) Config.ipcache.high) / (float) 100);
b15e6857 611 ipcache_low = (long) (((float) Config.ipcache.size *
62e76326 612 (float) Config.ipcache.low) / (float) 100);
aa9e2cab 613 n = hashPrime(ipcache_high / 4);
30abd221 614 ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
ecc3091b 615 memDataInit(MEM_IPCACHE_ENTRY, "ipcache_entry", sizeof(ipcache_entry), 0);
d120ed12
FC
616
617 ipcacheRegisterWithCacheManager();
090089c4 618}
619
63be0a78 620/**
621 \ingroup IPCacheAPI
622 *
623 * Is different from ipcache_nbgethostbyname in that it only checks
624 * if an entry exists in the cache and does not by default contact the DNS,
625 * unless this is requested, by setting the flags.
626 *
627 \param name Host name to resolve.
628 \param flags Default is NULL, set to IP_LOOKUP_IF_MISS
629 * to explicitly perform DNS lookups.
630 *
631 \retval NULL An error occured during lookup
632 \retval NULL No results available in cache and no lookup specified
633 \retval * Pointer to the ipcahce_addrs structure containing the lookup results
634 */
0ee4272b 635const ipcache_addrs *
636ipcache_gethostbyname(const char *name, int flags)
090089c4 637{
30a4f2a8 638 ipcache_entry *i = NULL;
e5f6c5c2 639 ipcache_addrs *addrs;
ecc3091b 640 assert(name);
bf8fe701 641 debugs(14, 3, "ipcache_gethostbyname: '" << name << "', flags=" << std::hex << flags);
95dc7ff4 642 ++IpcacheStats.requests;
ecc3091b 643 i = ipcache_get(name);
62e76326 644
ecc3091b 645 if (NULL == i) {
62e76326 646 (void) 0;
ecc3091b 647 } else if (ipcacheExpiredEntry(i)) {
62e76326 648 ipcacheRelease(i);
649 i = NULL;
ecc3091b 650 } else if (i->flags.negcached) {
95dc7ff4 651 ++IpcacheStats.negative_hits;
3ff65596 652 // ignore i->error_message: the caller just checks IP cache presence
62e76326 653 return NULL;
ecc3091b 654 } else {
95dc7ff4 655 ++IpcacheStats.hits;
62e76326 656 i->lastref = squid_curtime;
3ff65596 657 // ignore i->error_message: the caller just checks IP cache presence
62e76326 658 return &i->addrs;
30a4f2a8 659 }
62e76326 660
3ff65596 661 /* no entry [any more] */
2ffff82e 662
22b245f8 663 if ((addrs = ipcacheCheckNumeric(name))) {
95dc7ff4 664 ++IpcacheStats.numeric_hits;
62e76326 665 return addrs;
22b245f8 666 }
62e76326 667
95dc7ff4 668 ++IpcacheStats.misses;
62e76326 669
30a4f2a8 670 if (flags & IP_LOOKUP_IF_MISS)
7c16f24c 671 ipcache_nbgethostbyname(name, NULL, NULL);
62e76326 672
30a4f2a8 673 return NULL;
090089c4 674}
675
63be0a78 676/// \ingroup IPCacheInternal
b8d8561b 677static void
678ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
af00901c 679{
680 int k;
cc192b50 681 char buf[MAX_IPSTRLEN];
682
26ac0430 683 if (!sentry) {
fa84c01d 684 debugs(14, DBG_CRITICAL, HERE << "CRITICAL: sentry is NULL!");
71aab4cc 685 return;
cc192b50 686 }
687
26ac0430 688 if (!i) {
fa84c01d 689 debugs(14, DBG_CRITICAL, HERE << "CRITICAL: ipcache_entry is NULL!");
cc192b50 690 storeAppendPrintf(sentry, "CRITICAL ERROR\n");
691 return;
692 }
693
71aab4cc
AJ
694 int count = i->addrs.count;
695
181b1adc 696 storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)",
62e76326 697 hashKeyStr(&i->hash),
698 i->flags.fromhosts ? 'H' : ' ',
699 i->flags.negcached ? 'N' : ' ',
700 (int) (squid_curtime - i->lastref),
701 (int) ((i->flags.fromhosts ? -1 : i->expires - squid_curtime)),
702 (int) i->addrs.count,
703 (int) i->addrs.badcount);
704
cc192b50 705 /** \par
706 * Negative-cached entries have no IPs listed. */
26ac0430 707 if (i->flags.negcached) {
cc192b50 708 storeAppendPrintf(sentry, "\n");
709 return;
52926044 710 }
62e76326 711
cc192b50 712 /** \par
d85b8894 713 * Cached entries have IPs listed with a BNF of: ip-address '-' ('OK'|'BAD') */
95dc7ff4 714 for (k = 0; k < count; ++k) {
cc192b50 715 /* Display tidy-up: IPv6 are so big make the list vertical */
26ac0430 716 if (k == 0)
cc192b50 717 storeAppendPrintf(sentry, " %45.45s-%3s\n",
4dd643d5 718 i->addrs.in_addrs[k].toStr(buf,MAX_IPSTRLEN),
cc192b50 719 i->addrs.bad_mask[k] ? "BAD" : "OK ");
720 else
721 storeAppendPrintf(sentry, "%s %45.45s-%3s\n",
722 " ", /* blank-space indenting IP list */
4dd643d5 723 i->addrs.in_addrs[k].toStr(buf,MAX_IPSTRLEN),
cc192b50 724 i->addrs.bad_mask[k] ? "BAD" : "OK ");
725 }
af00901c 726}
090089c4 727
63be0a78 728/**
729 \ingroup IPCacheInternal
730 *
731 * process objects list
732 */
b8d8561b 733void
734stat_ipcache_get(StoreEntry * sentry)
090089c4 735{
7b04dad5 736 dlink_node *m;
737 assert(ip_table != NULL);
15576b6a 738 storeAppendPrintf(sentry, "IP Cache Statistics:\n");
ac49890a 739 storeAppendPrintf(sentry, "IPcache Entries In Use: %d\n",
62e76326 740 memInUse(MEM_IPCACHE_ENTRY));
ac49890a
CT
741 storeAppendPrintf(sentry, "IPcache Entries Cached: %d\n",
742 ipcacheCount());
15576b6a 743 storeAppendPrintf(sentry, "IPcache Requests: %d\n",
62e76326 744 IpcacheStats.requests);
22b245f8 745 storeAppendPrintf(sentry, "IPcache Hits: %d\n",
62e76326 746 IpcacheStats.hits);
22b245f8 747 storeAppendPrintf(sentry, "IPcache Negative Hits: %d\n",
62e76326 748 IpcacheStats.negative_hits);
22b245f8 749 storeAppendPrintf(sentry, "IPcache Numeric Hits: %d\n",
750 IpcacheStats.numeric_hits);
751 storeAppendPrintf(sentry, "IPcache Misses: %d\n",
62e76326 752 IpcacheStats.misses);
f2d71697 753 storeAppendPrintf(sentry, "IPcache Retrieved A: %d\n",
bae9832d 754 IpcacheStats.rr_a);
f2d71697 755 storeAppendPrintf(sentry, "IPcache Retrieved AAAA: %d\n",
bae9832d 756 IpcacheStats.rr_aaaa);
757 storeAppendPrintf(sentry, "IPcache Retrieved CNAME: %d\n",
758 IpcacheStats.rr_cname);
759 storeAppendPrintf(sentry, "IPcache CNAME-Only Response: %d\n",
760 IpcacheStats.cname_only);
22b245f8 761 storeAppendPrintf(sentry, "IPcache Invalid Request: %d\n",
762 IpcacheStats.invalid);
15576b6a 763 storeAppendPrintf(sentry, "\n\n");
764 storeAppendPrintf(sentry, "IP Cache Contents:\n\n");
cc192b50 765 storeAppendPrintf(sentry, " %-31.31s %3s %6s %6s %4s\n",
62e76326 766 "Hostname",
767 "Flg",
768 "lstref",
769 "TTL",
cc192b50 770 "N(b)");
62e76326 771
cc192b50 772 for (m = lru_list.head; m; m = m->next) {
773 assert( m->next != m );
62e76326 774 ipcacheStatPrint((ipcache_entry *)m->data, sentry);
cc192b50 775 }
776}
777
63be0a78 778/// \ingroup IPCacheAPI
b8d8561b 779void
0ee4272b 780ipcacheInvalidate(const char *name)
f900607e 781{
782 ipcache_entry *i;
62e76326 783
f900607e 784 if ((i = ipcache_get(name)) == NULL)
62e76326 785 return;
786
6c11e193 787 i->expires = squid_curtime;
62e76326 788
ecc3091b 789 /*
63be0a78 790 * NOTE, don't call ipcacheRelease here because we might be here due
ecc3091b 791 * to a thread started from a callback.
792 */
f900607e 793}
af00901c 794
63be0a78 795/// \ingroup IPCacheAPI
a12a049a 796void
797ipcacheInvalidateNegative(const char *name)
798{
799 ipcache_entry *i;
800
801 if ((i = ipcache_get(name)) == NULL)
802 return;
803
804 if (i->flags.negcached)
805 i->expires = squid_curtime;
806
807 /*
63be0a78 808 * NOTE, don't call ipcacheRelease here because we might be here due
a12a049a 809 * to a thread started from a callback.
810 */
811}
812
63be0a78 813/// \ingroup IPCacheAPI
4d650936 814ipcache_addrs *
0ee4272b 815ipcacheCheckNumeric(const char *name)
af00901c 816{
b7ac5457 817 Ip::Address ip;
af00901c 818 /* check if it's already a IP address in text form. */
62e76326 819
cc192b50 820 /* it may be IPv6-wrapped */
26ac0430 821 if (name[0] == '[') {
cc192b50 822 char *tmp = xstrdup(&name[1]);
823 tmp[strlen(tmp)-1] = '\0';
824 if (!(ip = tmp)) {
825 delete tmp;
826 return NULL;
827 }
828 delete tmp;
26ac0430 829 } else if (!(ip = name))
62e76326 830 return NULL;
831
cc192b50 832 debugs(14, 4, "ipcacheCheckNumeric: HIT_BYPASS for '" << name << "' == " << ip );
833
e5f6c5c2 834 static_addrs.count = 1;
62e76326 835
e5f6c5c2 836 static_addrs.cur = 0;
62e76326 837
cc192b50 838 static_addrs.in_addrs[0] = ip;
62e76326 839
22c653cd 840 static_addrs.bad_mask[0] = FALSE;
62e76326 841
22c653cd 842 static_addrs.badcount = 0;
62e76326 843
e5f6c5c2 844 return &static_addrs;
af00901c 845}
8905d949 846
63be0a78 847/// \ingroup IPCacheInternal
b8d8561b 848static void
849ipcacheLockEntry(ipcache_entry * i)
620da955 850{
7b04dad5 851 if (i->locks++ == 0) {
62e76326 852 dlinkDelete(&i->lru, &lru_list);
853 dlinkAdd(i, &i->lru, &lru_list);
7b04dad5 854 }
620da955 855}
856
63be0a78 857/// \ingroup IPCacheInternal
b8d8561b 858static void
859ipcacheUnlockEntry(ipcache_entry * i)
620da955 860{
26ac0430 861 if (i->locks < 1) {
e0236918 862 debugs(14, DBG_IMPORTANT, "WARNING: ipcacheEntry unlocked with no lock! locks=" << i->locks);
cc192b50 863 return;
864 }
865
5e263176 866 -- i->locks;
62e76326 867
620da955 868 if (ipcacheExpiredEntry(i))
62e76326 869 ipcacheRelease(i);
620da955 870}
e5f6c5c2 871
63be0a78 872/// \ingroup IPCacheAPI
52926044 873void
4b4cd312 874ipcacheCycleAddr(const char *name, ipcache_addrs * ia)
52926044 875{
876 ipcache_entry *i;
877 unsigned char k;
878 assert(name || ia);
62e76326 879
52926044 880 if (NULL == ia) {
62e76326 881 if ((i = ipcache_get(name)) == NULL)
882 return;
883
884 if (i->flags.negcached)
885 return;
886
887 ia = &i->addrs;
52926044 888 }
62e76326 889
95dc7ff4 890 for (k = 0; k < ia->count; ++k) {
62e76326 891 if (++ia->cur == ia->count)
892 ia->cur = 0;
893
894 if (!ia->bad_mask[ia->cur])
895 break;
52926044 896 }
62e76326 897
52926044 898 if (k == ia->count) {
62e76326 899 /* All bad, reset to All good */
bf8fe701 900 debugs(14, 3, "ipcacheCycleAddr: Changing ALL " << name << " addrs from BAD to OK");
62e76326 901
95dc7ff4 902 for (k = 0; k < ia->count; ++k)
62e76326 903 ia->bad_mask[k] = 0;
904
905 ia->badcount = 0;
906
907 ia->cur = 0;
52926044 908 }
62e76326 909
149b31df
AJ
910 /* NP: zero-based so we increase the human-readable number of our position */
911 debugs(14, 3, "ipcacheCycleAddr: " << name << " now at " << ia->in_addrs[ia->cur] << " (" << (ia->cur+1) << " of " << ia->count << ")");
52926044 912}
e5f6c5c2 913
63be0a78 914/**
915 \ingroup IPCacheAPI
916 *
917 \param name domain name to have an IP marked bad
918 \param addr specific addres to be marked bad
22c653cd 919 */
e5f6c5c2 920void
b7ac5457 921ipcacheMarkBadAddr(const char *name, const Ip::Address &addr)
e5f6c5c2 922{
923 ipcache_entry *i;
924 ipcache_addrs *ia;
925 int k;
62e76326 926
63be0a78 927 /** Does nothing if the domain name does not exist. */
e5f6c5c2 928 if ((i = ipcache_get(name)) == NULL)
62e76326 929 return;
930
e5f6c5c2 931 ia = &i->addrs;
62e76326 932
95dc7ff4 933 for (k = 0; k < (int) ia->count; ++k) {
cc192b50 934 if (addr == ia->in_addrs[k] )
62e76326 935 break;
e5f6c5c2 936 }
62e76326 937
63be0a78 938 /** Does nothing if the IP does not exist for the doamin. */
939 if (k == (int) ia->count)
62e76326 940 return;
941
63be0a78 942 /** Marks the given address as BAD */
26ac0430 943 if (!ia->bad_mask[k]) {
62e76326 944 ia->bad_mask[k] = TRUE;
95dc7ff4 945 ++ia->badcount;
d85c3078 946 i->expires = min(squid_curtime + max((time_t)60, Config.negativeDnsTtl), i->expires);
cc192b50 947 debugs(14, 2, "ipcacheMarkBadAddr: " << name << " " << addr );
22c653cd 948 }
62e76326 949
63be0a78 950 /** then calls ipcacheCycleAddr() to advance the current pointer to the next OK address. */
52926044 951 ipcacheCycleAddr(name, ia);
e5f6c5c2 952}
56e15c50 953
ec505200
HN
954/// \ingroup IPCacheAPI
955void
956ipcacheMarkAllGood(const char *name)
957{
958 ipcache_entry *i;
959 ipcache_addrs *ia;
960 int k;
961
962 if ((i = ipcache_get(name)) == NULL)
963 return;
964
965 ia = &i->addrs;
966
967 /* All bad, reset to All good */
968 debugs(14, 3, "ipcacheMarkAllGood: Changing ALL " << name << " addrs to OK (" << ia->badcount << "/" << ia->count << " bad)");
969
95dc7ff4 970 for (k = 0; k < ia->count; ++k)
ec505200
HN
971 ia->bad_mask[k] = 0;
972
973 ia->badcount = 0;
974}
975
63be0a78 976/// \ingroup IPCacheAPI
22c653cd 977void
b7ac5457 978ipcacheMarkGoodAddr(const char *name, const Ip::Address &addr)
22c653cd 979{
980 ipcache_entry *i;
981 ipcache_addrs *ia;
982 int k;
62e76326 983
22c653cd 984 if ((i = ipcache_get(name)) == NULL)
62e76326 985 return;
986
22c653cd 987 ia = &i->addrs;
62e76326 988
95dc7ff4 989 for (k = 0; k < (int) ia->count; ++k) {
cc192b50 990 if (addr == ia->in_addrs[k])
62e76326 991 break;
22c653cd 992 }
62e76326 993
52926044 994 if (k == (int) ia->count) /* not found */
62e76326 995 return;
996
52926044 997 if (!ia->bad_mask[k]) /* already OK */
62e76326 998 return;
999
52926044 1000 ia->bad_mask[k] = FALSE;
62e76326 1001
5e263176 1002 -- ia->badcount;
62e76326 1003
cc192b50 1004 debugs(14, 2, "ipcacheMarkGoodAddr: " << name << " " << addr );
22c653cd 1005}
1006
63be0a78 1007/// \ingroup IPCacheInternal
ec878047 1008static void
1009ipcacheFreeEntry(void *data)
1010{
e6ccf245 1011 ipcache_entry *i = (ipcache_entry *)data;
ec878047 1012 safe_free(i->addrs.in_addrs);
1013 safe_free(i->addrs.bad_mask);
186477c1 1014 safe_free(i->hash.key);
ec878047 1015 safe_free(i->error_message);
db1cd23c 1016 memFree(i, MEM_IPCACHE_ENTRY);
ec878047 1017}
1018
63be0a78 1019/// \ingroup IPCacheAPI
56e15c50 1020void
1021ipcacheFreeMemory(void)
1022{
ec878047 1023 hashFreeItems(ip_table, ipcacheFreeEntry);
56e15c50 1024 hashFreeMemory(ip_table);
afe95a7e 1025 ip_table = NULL;
56e15c50 1026}
3fb036e8 1027
63be0a78 1028/**
1029 \ingroup IPCacheAPI
1030 *
1031 * Recalculate IP cache size upon reconfigure.
1032 * Is called to clear the IPCache's data structures,
1033 * cancel all pending requests.
1034 */
429fdbec 1035void
1036ipcache_restart(void)
1037{
429fdbec 1038 ipcache_high = (long) (((float) Config.ipcache.size *
62e76326 1039 (float) Config.ipcache.high) / (float) 100);
429fdbec 1040 ipcache_low = (long) (((float) Config.ipcache.size *
62e76326 1041 (float) Config.ipcache.low) / (float) 100);
0e70aa1e 1042 purge_entries_fromhosts();
1043}
1044
63be0a78 1045/**
1046 \ingroup IPCacheAPI
1047 *
1048 * Adds a "static" entry from /etc/hosts
1049 *
1050 \param name Hostname to be linked with IP
1051 \param ipaddr IP Address to be cached.
1052 *
1053 \retval 0 Success.
1054 \retval 1 IP address is invalid or other error.
0e70aa1e 1055 */
1056int
1057ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
1058{
1059 ipcache_entry *i;
62e76326 1060
b7ac5457 1061 Ip::Address ip;
62e76326 1062
cc192b50 1063 if (!(ip = ipaddr)) {
62e76326 1064 if (strchr(ipaddr, ':') && strspn(ipaddr, "0123456789abcdefABCDEF:") == strlen(ipaddr)) {
bf8fe701 1065 debugs(14, 3, "ipcacheAddEntryFromHosts: Skipping IPv6 address '" << ipaddr << "'");
62e76326 1066 } else {
e0236918 1067 debugs(14, DBG_IMPORTANT, "ipcacheAddEntryFromHosts: Bad IP address '" << ipaddr << "'");
62e76326 1068 }
1069
1070 return 1;
0e70aa1e 1071 }
62e76326 1072
0e70aa1e 1073 if ((i = ipcache_get(name))) {
62e76326 1074 if (1 == i->flags.fromhosts) {
1075 ipcacheUnlockEntry(i);
1076 } else if (i->locks > 0) {
e0236918 1077 debugs(14, DBG_IMPORTANT, "ipcacheAddEntryFromHosts: can't add static entry for locked name '" << name << "'");
62e76326 1078 return 1;
1079 } else {
1080 ipcacheRelease(i);
1081 }
0e70aa1e 1082 }
62e76326 1083
0e70aa1e 1084 i = ipcacheCreateEntry(name);
1085 i->addrs.count = 1;
1086 i->addrs.cur = 0;
1087 i->addrs.badcount = 0;
62e76326 1088
b7ac5457 1089 i->addrs.in_addrs = static_cast<Ip::Address *>(xcalloc(1, sizeof(Ip::Address)));
e6ccf245 1090 i->addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
cc192b50 1091 i->addrs.in_addrs[0] = ip;
0e70aa1e 1092 i->addrs.bad_mask[0] = FALSE;
be4d35dc 1093 i->flags.fromhosts = true;
0e70aa1e 1094 ipcacheAddEntry(i);
1095 ipcacheLockEntry(i);
1096 return 0;
429fdbec 1097}
ce75f381 1098
59ad6d31 1099#if SQUID_SNMP
63be0a78 1100/**
1101 \ingroup IPCacheAPI
1102 *
135171fe 1103 * The function to return the ip cache statistics to via SNMP
1104 */
86115da5 1105variable_list *
1f5b542b 1106snmp_netIpFn(variable_list * Var, snint * ErrP)
d60c11be 1107{
736eb6ad 1108 variable_list *Answer = NULL;
6a644e75
AJ
1109 MemBuf tmp;
1110 debugs(49, 5, "snmp_netIpFn: Processing request:" << snmpDebugOid(Var->name, Var->name_length, tmp));
86115da5 1111 *ErrP = SNMP_ERR_NOERROR;
62e76326 1112
135171fe 1113 switch (Var->name[LEN_SQ_NET + 1]) {
62e76326 1114
1f5b542b 1115 case IP_ENT:
62e76326 1116 Answer = snmp_var_new_integer(Var->name, Var->name_length,
ac49890a 1117 ipcacheCount(),
62e76326 1118 SMI_GAUGE32);
1119 break;
1120
1f5b542b 1121 case IP_REQ:
62e76326 1122 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1123 IpcacheStats.requests,
1124 SMI_COUNTER32);
1125 break;
1126
1f5b542b 1127 case IP_HITS:
62e76326 1128 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1129 IpcacheStats.hits,
1130 SMI_COUNTER32);
1131 break;
1132
1f5b542b 1133 case IP_PENDHIT:
62e76326 1134 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1135 0,
1136 SMI_GAUGE32);
1137 break;
1138
1f5b542b 1139 case IP_NEGHIT:
62e76326 1140 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1141 IpcacheStats.negative_hits,
1142 SMI_COUNTER32);
1143 break;
1144
1f5b542b 1145 case IP_MISS:
62e76326 1146 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1147 IpcacheStats.misses,
1148 SMI_COUNTER32);
1149 break;
1150
1f5b542b 1151 case IP_GHBN:
62e76326 1152 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1153 0, /* deprecated */
1154 SMI_COUNTER32);
1155 break;
1156
1f5b542b 1157 case IP_LOC:
62e76326 1158 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1159 0, /* deprecated */
1160 SMI_COUNTER32);
1161 break;
1162
ce75f381 1163 default:
62e76326 1164 *ErrP = SNMP_ERR_NOSUCHNAME;
1165 snmp_var_free(Answer);
1166 return (NULL);
86115da5 1167 }
62e76326 1168
86115da5 1169 return Answer;
ce75f381 1170}
1f5b542b 1171
135171fe 1172#endif /*SQUID_SNMP */