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