Squid Web Cache master
Loading...
Searching...
No Matches
ipcache.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 14 IP Cache */
10
11#include "squid.h"
12#include "base/IoManip.h"
13#include "CacheManager.h"
14#include "cbdata.h"
15#include "debug/Messages.h"
16#include "dlink.h"
17#include "dns/LookupDetails.h"
18#include "dns/rfc3596.h"
19#include "event.h"
20#include "ip/Address.h"
21#include "ip/tools.h"
22#include "ipcache.h"
23#include "mgr/Registration.h"
24#include "snmp_agent.h"
25#include "SquidConfig.h"
26#include "StatCounters.h"
27#include "Store.h"
28#include "util.h"
29#include "wordlist.h"
30
31#if SQUID_SNMP
32#include "snmp_core.h"
33#endif
34
72template <class Content>
74{
75public:
76 typedef Content DataType;
77 const char *kind;
79};
80
83{
84public:
87 IpCacheLookupForwarder(IPH *fun, void *data);
88
90 void finalCallback(const Dns::CachedIps *addrs, const Dns::LookupDetails &details);
91
94 bool forwardIp(const Ip::Address &ip);
95
97 void forwardHits(const Dns::CachedIps &ips);
98
101
103 void forwardLookup(const char *error);
104
107
108protected:
111
112private:
113 /* receiverObj and receiverFun are mutually exclusive */
115 IPH *receiverFun = nullptr;
117
118 struct timeval firstLookupStart {0,0};
119 struct timeval lastLookupEnd {0,0};
120};
121
131{
133
134public:
135 ipcache_entry(const char *);
137
138 hash_link hash; /* must be first */
139 time_t lastref;
140 time_t expires;
144
146 unsigned short locks;
147 struct Flags {
148 Flags() : negcached(false), fromhosts(false) {}
149
153
154 bool sawCname = false;
155
156 const char *name() const { return static_cast<const char*>(hash.key); }
157
159 int totalResponseTime() const;
162
164 template <class Specs>
165 void addGood(const rfc1035_rr &rr, Specs &specs);
166
168 void latestError(const char *text);
169
170protected:
171 void updateTtl(const unsigned int rrTtl);
172};
173
188
191
192// forward-decls
193static void stat_ipcache_get(StoreEntry *);
194
198static ipcache_entry *ipcache_get(const char *);
199static void ipcacheLockEntry(ipcache_entry *);
201static void ipcacheUnlockEntry(ipcache_entry *);
202static void ipcacheRelease(ipcache_entry *, bool dofree = true);
203static const Dns::CachedIps *ipcacheCheckNumeric(const char *name);
204static void ipcache_nbgethostbyname_(const char *name, IpCacheLookupForwarder handler);
205
207static hash_table *ip_table = nullptr;
208
210static long ipcache_low = 180;
212static long ipcache_high = 200;
213
214#if LIBRESOLV_DNS_TTL_HACK
215extern int _dns_ttl_;
216#endif
217
219
221 receiverObj(receiver)
222{
223}
224
226 receiverFun(fun), receiverData(data)
227{
228}
229
230void
231IpCacheLookupForwarder::finalCallback(const Dns::CachedIps * const possiblyEmptyAddrs, const Dns::LookupDetails &details)
232{
233 // TODO: Consider removing nil-supplying IpcacheStats.invalid code and refactoring accordingly.
234 // may be nil but is never empty
235 const auto addrs = (possiblyEmptyAddrs && possiblyEmptyAddrs->empty()) ? nullptr : possiblyEmptyAddrs;
236
237 debugs(14, 7, addrs << " " << details);
238 if (receiverObj.set()) {
239 if (auto receiver = receiverObj.valid())
240 receiver->noteIps(addrs, details);
242 } else if (receiverFun) {
243 if (receiverData.valid())
244 receiverFun(addrs, details, receiverData.validDone());
245 receiverFun = nullptr;
246 }
247}
248
251bool
253{
254 debugs(14, 7, ip);
255 if (receiverObj.set()) {
256 if (auto receiver = receiverObj.valid()) {
257 receiver->noteIp(ip);
258 return true;
259 }
260 return false;
261 }
262 // else do nothing: ReceiverFun does not do incremental notifications
263 return false;
264}
265
267void
269{
270 if (receiverObj.set()) {
271 for (const auto &ip: ips.good()) {
272 if (!forwardIp(ip))
273 break; // receiver gone
274 }
275 }
276 // else do nothing: ReceiverFun does not do incremental notifications
277}
278
279void
281{
282 // Lookups run concurrently, but HttpRequest::recordLookup() thinks they
283 // are sequential. Give it just the new, yet-unaccounted-for delay.
284 if (receiverObj.set()) {
285 if (auto receiver = receiverObj.valid()) {
286 receiver->noteLookup(Dns::LookupDetails(SBuf(error), additionalLookupDelay()));
288 }
289 }
290 // else do nothing: ReceiverFun gets no individual lookup notifications
291}
292
294inline int ipcacheCount() { return ip_table ? ip_table->count : 0; }
295
301static void
303{
304 if (!i) {
305 debugs(14, DBG_CRITICAL, "ipcacheRelease: Releasing entry with i=<NULL>");
306 return;
307 }
308
309 if (!i || !i->hash.key) {
310 debugs(14, DBG_CRITICAL, "ipcacheRelease: Releasing entry without hash link!");
311 return;
312 }
313
314 debugs(14, 3, "ipcacheRelease: Releasing entry for '" << (const char *) i->hash.key << "'");
315
317 dlinkDelete(&i->lru, &lru_list);
318 if (dofree)
320}
321
323static ipcache_entry *
324ipcache_get(const char *name)
325{
326 if (ip_table != nullptr)
327 return (ipcache_entry *) hash_lookup(ip_table, name);
328 else
329 return nullptr;
330}
331
333static int
335{
336 /* all static entries are locked, so this takes care of them too */
337
338 if (i->locks != 0)
339 return 0;
340
341 if (i->addrs.empty())
342 if (0 == i->flags.negcached)
343 return 1;
344
345 if (i->expires > squid_curtime)
346 return 0;
347
348 return 1;
349}
350
352void
354{
355 dlink_node *m;
356 dlink_node *prev = nullptr;
357 ipcache_entry *i;
358 int removed = 0;
359 eventAdd("ipcache_purgelru", ipcache_purgelru, nullptr, 10.0, 1);
360
361 for (m = lru_list.tail; m; m = prev) {
363 break;
364
365 prev = m->prev;
366
367 i = (ipcache_entry *)m->data;
368
369 if (i->locks != 0)
370 continue;
371
373
374 ++removed;
375 }
376
377 debugs(14, 9, "ipcache_purgelru: removed " << removed << " entries");
378}
379
385static void
387{
389 ipcache_entry *i = nullptr, *t;
390
391 while (m) {
392 if (i != nullptr) { /* need to delay deletion */
393 ipcacheRelease(i); /* we just override locks */
394 i = nullptr;
395 }
396
397 t = (ipcache_entry*)m->data;
398
399 if (t->flags.fromhosts)
400 i = t;
401
402 m = m->next;
403 }
404
405 if (i != nullptr)
407}
408
410 lastref(0),
411 expires(0),
412 error_message(nullptr),
413 locks(0) // XXX: use Lock type ?
414{
415 hash.key = xstrdup(aName);
416 Tolower(static_cast<char*>(hash.key));
418}
419
421static void
423{
425
426 if (nullptr != e) {
427 /* avoid collision */
428 ipcache_entry *q = (ipcache_entry *) e;
430 }
431
432 hash_join(ip_table, &i->hash);
433 dlinkAdd(i, &i->lru, &lru_list);
435}
436
442static void
443ipcacheCallback(ipcache_entry *i, const bool hit, const int wait)
444{
446
448
449 if (hit)
451 const Dns::LookupDetails details(SBuf(i->error_message), wait);
452 i->handler.finalCallback(&i->addrs, details);
453
455}
456
457void
459{
460 debugs(14, 3, "ERROR: DNS failure while resolving " << name() << ": " << text);
463}
464
465static void
466ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *error_message)
467{
468 int k;
469
470 // XXX: Callers use zero ancount instead of -1 on errors!
471 if (nr < 0) {
472 i->latestError(error_message);
473 return;
474 }
475
476 if (nr == 0) {
477 i->latestError("No DNS records");
478 return;
479 }
480
481 debugs(14, 3, nr << " answers for " << i->name());
482 assert(answers);
483
484 for (k = 0; k < nr; ++k) {
485
486 if (Ip::EnableIpv6 && answers[k].type == RFC1035_TYPE_AAAA) {
487 static const RrSpecs<struct in6_addr> QuadA = { "IPv6", IpcacheStats.rr_aaaa };
488 i->addGood(answers[k], QuadA);
489 continue;
490 }
491
492 if (answers[k].type == RFC1035_TYPE_A) {
493 static const RrSpecs<struct in_addr> SingleA = { "IPv4", IpcacheStats.rr_a };
494 i->addGood(answers[k], SingleA);
495 continue;
496 }
497
498 /* With A and AAAA, the CNAME does not necessarily come with additional records to use. */
499 if (answers[k].type == RFC1035_TYPE_CNAME) {
500 i->sawCname = true;
502 continue;
503 }
504
505 // otherwise its an unknown RR. debug at level 9 since we usually want to ignore these and they are common.
506 debugs(14, 9, "Unknown RR type received: type=" << answers[k].type << " starting at " << &(answers[k]) );
507 }
508}
509
510template <class Specs>
511void
512ipcache_entry::addGood(const rfc1035_rr &rr, Specs &specs)
513{
514 typename Specs::DataType address;
515 if (rr.rdlength != sizeof(address)) {
516 debugs(14, DBG_IMPORTANT, "ERROR: Ignoring invalid " << specs.kind << " address record while resolving " << name());
517 return;
518 }
519
520 ++specs.recordCounter;
521
522 // Do not store more than 255 addresses (TODO: Why?)
523 if (addrs.raw().size() >= 255)
524 return;
525
526 memcpy(&address, rr.rdata, sizeof(address));
527 const Ip::Address ip = address;
528 if (addrs.have(ip)) {
529 debugs(14, 3, "refusing to add duplicate " << ip);
530 return;
531 }
532 addrs.pushUnique(address);
533
534 updateTtl(rr.ttl);
535
536 debugs(14, 3, name() << " #" << addrs.size() << " " << ip);
537 handler.forwardIp(ip); // we are only called with good IPs
538}
539
540void
541ipcache_entry::updateTtl(const unsigned int rrTtl)
542{
543 const time_t ttl = std::min(std::max(
544 Config.negativeDnsTtl, // smallest value allowed
545 static_cast<time_t>(rrTtl)),
546 Config.positiveDnsTtl); // largest value allowed
547
548 const time_t rrExpires = squid_curtime + ttl;
549 if (addrs.size() <= 1) {
550 debugs(14, 5, "use first " << ttl << " from RR TTL " << rrTtl);
551 expires = rrExpires;
552 } else if (rrExpires < expires) {
553 debugs(14, 5, "use smaller " << ttl << " from RR TTL " << rrTtl << "; was: " << (expires - squid_curtime));
554 expires = rrExpires;
555 } else {
556 debugs(14, 7, "ignore " << ttl << " from RR TTL " << rrTtl << "; keep: " << (expires - squid_curtime));
557 }
558}
559
561static void
562ipcacheHandleReply(void *data, const rfc1035_rr * answers, int na, const char *error_message, const bool lastAnswer)
563{
564 ipcache_entry *i = static_cast<ipcache_entry*>(data);
565
566 i->handler.forwardLookup(error_message);
567 ipcacheParse(i, answers, na, error_message);
568
569 if (!lastAnswer)
570 return;
571
573 const auto age = i->handler.totalResponseTime();
575
576 if (i->addrs.empty()) {
577 i->flags.negcached = true;
579
580 if (!i->error_message) {
581 i->latestError("No valid address records");
582 if (i->sawCname)
584 }
585 }
586
587 debugs(14, 3, "done with " << i->name() << ": " << i->addrs);
589 ipcacheCallback(i, false, age);
590}
591
608void
609ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
610{
611 debugs(14, 4, name);
612 ipcache_nbgethostbyname_(name, IpCacheLookupForwarder(handler, handlerData));
613}
614
615void
616Dns::nbgethostbyname(const char *name, const CbcPointer<IpReceiver> &receiver)
617{
618 debugs(14, 4, name);
620}
621
623static void
625{
626 ipcache_entry *i = nullptr;
627 const ipcache_addrs *addrs = nullptr;
629
630 if (name == nullptr || name[0] == '\0') {
631 debugs(14, 4, "ipcache_nbgethostbyname: Invalid name!");
633 static const Dns::LookupDetails details(SBuf("Invalid hostname"), -1); // error, no lookup
634 handler.finalCallback(nullptr, details);
635 return;
636 }
637
638 if ((addrs = ipcacheCheckNumeric(name))) {
639 debugs(14, 4, "ipcache_nbgethostbyname: BYPASS for '" << name << "' (already numeric)");
640 handler.forwardHits(*addrs);
642 const Dns::LookupDetails details; // no error, no lookup
643 handler.finalCallback(addrs, details);
644 return;
645 }
646
647 i = ipcache_get(name);
648
649 if (nullptr == i) {
650 /* miss */
651 (void) 0;
652 } else if (ipcacheExpiredEntry(i)) {
653 /* hit, but expired -- bummer */
655 i = nullptr;
656 } else {
657 /* hit */
658 debugs(14, 4, "ipcache_nbgethostbyname: HIT for '" << name << "'");
659
660 if (i->flags.negcached)
662 else
664
665 i->handler = std::move(handler);
666 ipcacheCallback(i, true, -1); // no lookup
667
668 return;
669 }
670
671 debugs(14, 5, "ipcache_nbgethostbyname: MISS for '" << name << "'");
673 i = new ipcache_entry(name);
674 i->handler = std::move(handler);
677}
678
680static void
682{
683 Mgr::RegisterAction("ipcache",
684 "IP Cache Stats and Contents",
685 stat_ipcache_get, 0, 1);
686}
687
695void
697{
698 int n;
699 debugs(14, Important(24), "Initializing IP Cache...");
700 memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
702
703 ipcache_high = (long) (((float) Config.ipcache.size *
704 (float) Config.ipcache.high) / (float) 100);
705 ipcache_low = (long) (((float) Config.ipcache.size *
706 (float) Config.ipcache.low) / (float) 100);
707 n = hashPrime(ipcache_high / 4);
708 ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
709
711}
712
728const ipcache_addrs *
729ipcache_gethostbyname(const char *name, int flags)
730{
731 ipcache_entry *i = nullptr;
732 assert(name);
733 debugs(14, 3, "'" << name << "', flags=" << asHex(flags));
735 i = ipcache_get(name);
736
737 if (nullptr == i) {
738 (void) 0;
739 } else if (ipcacheExpiredEntry(i)) {
741 i = nullptr;
742 } else if (i->flags.negcached) {
744 // ignore i->error_message: the caller just checks IP cache presence
745 return nullptr;
746 } else {
749 // ignore i->error_message: the caller just checks IP cache presence
750 return &i->addrs;
751 }
752
753 /* no entry [any more] */
754
755 if (const auto addrs = ipcacheCheckNumeric(name)) {
757 return addrs;
758 }
759
761
762 if (flags & IP_LOOKUP_IF_MISS)
763 ipcache_nbgethostbyname(name, nullptr, nullptr);
764
765 return nullptr;
766}
767
769static void
771{
772 char buf[MAX_IPSTRLEN];
773
774 if (!sentry) {
775 debugs(14, DBG_CRITICAL, "ERROR: sentry is NULL!");
776 return;
777 }
778
779 if (!i) {
780 debugs(14, DBG_CRITICAL, "ERROR: ipcache_entry is NULL!");
781 storeAppendPrintf(sentry, "CRITICAL ERROR\n");
782 return;
783 }
784
785 storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)",
786 hashKeyStr(&i->hash),
787 i->flags.fromhosts ? 'H' : ' ',
788 i->flags.negcached ? 'N' : ' ',
789 (int) (squid_curtime - i->lastref),
790 (int) ((i->flags.fromhosts ? -1 : i->expires - squid_curtime)),
791 static_cast<int>(i->addrs.size()),
792 static_cast<int>(i->addrs.badCount()));
793
796 if (i->flags.negcached) {
797 storeAppendPrintf(sentry, "\n");
798 return;
799 }
800
803 bool firstLine = true;
804 for (const auto &addr: i->addrs.raw()) {
805 /* Display tidy-up: IPv6 are so big make the list vertical */
806 const char *indent = firstLine ? "" : " ";
807 storeAppendPrintf(sentry, "%s %45.45s-%3s\n",
808 indent,
809 addr.ip.toStr(buf, MAX_IPSTRLEN),
810 addr.bad() ? "BAD" : "OK ");
811 firstLine = false;
812 }
813}
814
820void
822{
823 dlink_node *m;
824 assert(ip_table != nullptr);
825 storeAppendPrintf(sentry, "IP Cache Statistics:\n");
826 storeAppendPrintf(sentry, "IPcache Entries Cached: %d\n",
827 ipcacheCount());
828 storeAppendPrintf(sentry, "IPcache Requests: %d\n",
830 storeAppendPrintf(sentry, "IPcache Hits: %d\n",
832 storeAppendPrintf(sentry, "IPcache Negative Hits: %d\n",
834 storeAppendPrintf(sentry, "IPcache Numeric Hits: %d\n",
836 storeAppendPrintf(sentry, "IPcache Misses: %d\n",
838 storeAppendPrintf(sentry, "IPcache Retrieved A: %d\n",
840 storeAppendPrintf(sentry, "IPcache Retrieved AAAA: %d\n",
842 storeAppendPrintf(sentry, "IPcache Retrieved CNAME: %d\n",
844 storeAppendPrintf(sentry, "IPcache CNAME-Only Response: %d\n",
846 storeAppendPrintf(sentry, "IPcache Invalid Request: %d\n",
848 storeAppendPrintf(sentry, "\n\n");
849 storeAppendPrintf(sentry, "IP Cache Contents:\n\n");
850 storeAppendPrintf(sentry, " %-31.31s %3s %6s %6s %4s\n",
851 "Hostname",
852 "Flg",
853 "lstref",
854 "TTL",
855 "N(b)");
856
857 for (m = lru_list.head; m; m = m->next) {
858 assert( m->next != m );
859 ipcacheStatPrint((ipcache_entry *)m->data, sentry);
860 }
861}
862
864void
865ipcacheInvalidate(const char *name)
866{
867 ipcache_entry *i;
868
869 if ((i = ipcache_get(name)) == nullptr)
870 return;
871
873
874 /*
875 * NOTE, don't call ipcacheRelease here because we might be here due
876 * to a thread started from a callback.
877 */
878}
879
881void
883{
884 ipcache_entry *i;
885
886 if ((i = ipcache_get(name)) == nullptr)
887 return;
888
889 if (i->flags.negcached)
891
892 /*
893 * NOTE, don't call ipcacheRelease here because we might be here due
894 * to a thread started from a callback.
895 */
896}
897
899static const Dns::CachedIps *
900ipcacheCheckNumeric(const char *name)
901{
902 Ip::Address ip;
903 if (!ip.fromHost(name))
904 return nullptr;
905
906 debugs(14, 4, "HIT_BYPASS for " << name << "=" << ip);
907 static Dns::CachedIps static_addrs;
908 static_addrs.reset(ip);
909 return &static_addrs;
910}
911
913static void
915{
916 if (i->locks++ == 0) {
917 dlinkDelete(&i->lru, &lru_list);
918 dlinkAdd(i, &i->lru, &lru_list);
919 }
920}
921
923static void
925{
926 if (i->locks < 1) {
927 debugs(14, DBG_IMPORTANT, "WARNING: ipcacheEntry unlocked with no lock! locks=" << i->locks);
928 return;
929 }
930
931 -- i->locks;
932
933 if (ipcacheExpiredEntry(i))
935}
936
939bool
941{
942 // linear search!
943 for (size_t seen = 0; seen < ips.size(); ++seen) {
944 if (++goodPosition >= ips.size())
945 goodPosition = 0;
946 if (!ips[goodPosition].bad()) {
947 debugs(14, 3, "succeeded for " << name << ": " << *this);
948 return true;
949 }
950 }
951 goodPosition = ips.size();
952 debugs(14, 3, "failed for " << name << ": " << *this);
953 return false;
954}
955
956void
958{
959 ips.clear();
960 ips.emplace_back(ip);
961 goodPosition = 0;
962 // Assume that the given IP is good because CachedIps are designed to never
963 // run out of good IPs.
964 badCount_ = 0;
965}
966
968void
970{
971 if (badCount() >= size()) {
972 // There are no good IPs left. Clear all bad marks. This must help
973 // because we are called only after a good address was tested as bad.
974 for (auto &cachedIp: ips)
975 cachedIp.forgetMarking();
976 badCount_ = 0;
977 debugs(14, 3, "cleared all " << size() << " bad IPs for " << name);
978 // fall through to reset goodPosition and report the current state
979 }
980 Must(seekNewGood(name));
981}
982
983bool
984Dns::CachedIps::have(const Ip::Address &ip, size_t *positionOrNil) const
985{
986 // linear search!
987 size_t pos = 0;
988 for (const auto &cachedIp: ips) {
989 if (cachedIp.ip == ip) {
990 if (auto position = positionOrNil)
991 *position = pos;
992 debugs(14, 7, ip << " at " << pos << " in " << *this);
993 return true;
994 }
995 ++pos; // TODO: Replace with std::views::enumerate() after upgrading to C++23
996 }
997 // no such address; leave *position as is
998 debugs(14, 7, " no " << ip << " in " << *this);
999 return false;
1000}
1001
1002void
1004{
1005 assert(!have(ip));
1006 [[maybe_unused]] auto &cachedIp = ips.emplace_back(ip);
1007 assert(!cachedIp.bad());
1008}
1009
1010void
1011Dns::CachedIps::reportCurrent(std::ostream &os) const
1012{
1013 if (empty())
1014 os << "[no cached IPs]";
1015 else if (goodPosition == size())
1016 os << "[" << size() << " bad cached IPs]"; // could only be temporary
1017 else
1018 os << current() << " #" << (goodPosition+1) << "/" << ips.size() << "-" << badCount();
1019}
1020
1021void
1022Dns::CachedIps::markAsBad(const char *name, const Ip::Address &ip)
1023{
1024 size_t badPosition = 0;
1025 if (!have(ip, &badPosition))
1026 return; // no such address
1027
1028 auto &cachedIp = ips[badPosition];
1029 if (cachedIp.bad())
1030 return; // already marked correctly
1031
1032 cachedIp.markAsBad();
1033 ++badCount_;
1034 debugs(14, 2, ip << " of " << name);
1035
1036 if (goodPosition == badPosition)
1037 restoreGoodness(name);
1038 // else nothing to do: goodPositon still points to a good IP
1039}
1040
1041void
1042Dns::CachedIps::forgetMarking(const char *name, const Ip::Address &ip)
1043{
1044 if (!badCount_)
1045 return; // all IPs are already "good"
1046
1047 size_t badPosition = 0;
1048 if (!have(ip, &badPosition))
1049 return; // no such address
1050
1051 auto &cachedIp = ips[badPosition];
1052 if (!cachedIp.bad())
1053 return; // already marked correctly
1054
1055 cachedIp.forgetMarking();
1056 assert(!cachedIp.bad());
1057 --badCount_;
1058 debugs(14, 2, ip << " of " << name);
1059}
1060
1068void
1069ipcacheMarkBadAddr(const char *name, const Ip::Address &addr)
1070{
1071 if (auto cached = ipcache_get(name))
1072 cached->addrs.markAsBad(name, addr);
1073}
1074
1076void
1077ipcacheMarkGoodAddr(const char *name, const Ip::Address &addr)
1078{
1079 if (auto cached = ipcache_get(name))
1080 cached->addrs.forgetMarking(name, addr);
1081}
1082
1084static void
1086{
1087 ipcache_entry *i = (ipcache_entry *)data;
1088 delete i;
1089}
1090
1092{
1093 xfree(error_message);
1094 xfree(hash.key);
1095}
1096
1104void
1106{
1107 ipcache_high = (long) (((float) Config.ipcache.size *
1108 (float) Config.ipcache.high) / (float) 100);
1109 ipcache_low = (long) (((float) Config.ipcache.size *
1110 (float) Config.ipcache.low) / (float) 100);
1112}
1113
1125int
1126ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
1127{
1128 ipcache_entry *i;
1129
1130 Ip::Address ip;
1131
1132 if (!(ip = ipaddr)) {
1133 if (strchr(ipaddr, ':') && strspn(ipaddr, "0123456789abcdefABCDEF:") == strlen(ipaddr)) {
1134 debugs(14, 3, "ipcacheAddEntryFromHosts: Skipping IPv6 address '" << ipaddr << "'");
1135 } else {
1136 debugs(14, DBG_IMPORTANT, "ERROR: ipcacheAddEntryFromHosts: Bad IP address '" << ipaddr << "'");
1137 }
1138
1139 return 1;
1140 }
1141
1142 if (!Ip::EnableIpv6 && ip.isIPv6()) {
1143 debugs(14, 2, "skips IPv6 address in /etc/hosts because IPv6 support was disabled: " << ip);
1144 return 1;
1145 }
1146
1147 if ((i = ipcache_get(name))) {
1148 if (1 == i->flags.fromhosts) {
1150 } else if (i->locks > 0) {
1151 debugs(14, DBG_IMPORTANT, "ERROR: ipcacheAddEntryFromHosts: cannot add static entry for locked name '" << name << "'");
1152 return 1;
1153 } else {
1154 ipcacheRelease(i);
1155 }
1156 }
1157
1158 i = new ipcache_entry(name);
1159 i->addrs.pushUnique(ip);
1160 i->flags.fromhosts = true;
1161 ipcacheAddEntry(i);
1163 return 0;
1164}
1165
1166#if SQUID_SNMP
1174{
1175 variable_list *Answer = nullptr;
1176 MemBuf tmp;
1177 debugs(49, 5, "snmp_netIpFn: Processing request:" << snmpDebugOid(Var->name, Var->name_length, tmp));
1178 *ErrP = SNMP_ERR_NOERROR;
1179
1180 switch (Var->name[LEN_SQ_NET + 1]) {
1181
1182 case IP_ENT:
1183 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1184 ipcacheCount(),
1185 SMI_GAUGE32);
1186 break;
1187
1188 case IP_REQ:
1189 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1192 break;
1193
1194 case IP_HITS:
1195 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1198 break;
1199
1200 case IP_PENDHIT:
1201 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1202 0,
1203 SMI_GAUGE32);
1204 break;
1205
1206 case IP_NEGHIT:
1207 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1210 break;
1211
1212 case IP_MISS:
1213 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1216 break;
1217
1218 case IP_GHBN:
1219 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1220 0, /* deprecated */
1222 break;
1223
1224 case IP_LOC:
1225 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1226 0, /* deprecated */
1228 break;
1229
1230 default:
1231 *ErrP = SNMP_ERR_NOSUCHNAME;
1232 assert(!Answer);
1233 }
1234
1235 return Answer;
1236}
1237
1238#endif /*SQUID_SNMP */
1239
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
Definition IoManip.h:169
int size
Definition ModDevPoll.cc:70
time_t squid_curtime
class SquidConfig Config
StatCounters statCounter
#define Must(condition)
void error(char *format,...)
#define assert(EX)
Definition assert.h:17
#define LEN_SQ_NET
Definition cache_snmp.h:49
@ IP_HITS
Definition cache_snmp.h:191
@ IP_REQ
Definition cache_snmp.h:190
@ IP_ENT
Definition cache_snmp.h:189
@ IP_MISS
Definition cache_snmp.h:194
@ IP_NEGHIT
Definition cache_snmp.h:193
@ IP_GHBN
Definition cache_snmp.h:195
@ IP_LOC
Definition cache_snmp.h:196
@ IP_PENDHIT
Definition cache_snmp.h:192
int64_t snint
Definition cache_snmp.h:14
#define CBDATA_CLASS_INIT(type)
Definition cbdata.h:325
#define CBDATA_CLASS(type)
Definition cbdata.h:289
an old-style void* callback parameter
Definition cbdata.h:384
void * validDone()
Definition cbdata.h:396
bool valid() const
Definition cbdata.h:395
Cbc * valid() const
was set and is valid
Definition CbcPointer.h:41
void clear()
make pointer not set; does not invalidate cbdata
Definition CbcPointer.h:144
bool set() const
was set but may be invalid
Definition CbcPointer.h:40
void markAsBad(const char *name, const Ip::Address &ip)
Definition ipcache.cc:1022
size_t goodPosition
position of the IP returned by current()
Definition ipcache.h:100
void reset(const Ip::Address &ip)
replace all info with the given (presumed good) IP address
Definition ipcache.cc:957
void pushUnique(const Ip::Address &ip)
Definition ipcache.cc:1003
bool have(const Ip::Address &ip, size_t *position=nullptr) const
Definition ipcache.cc:984
const Storage & raw() const
all cached entries
Definition ipcache.h:69
size_t size() const noexcept
all cached IPs
Definition ipcache.h:62
void forgetMarking(const char *name, const Ip::Address &ip)
undo successful markAsBad()
Definition ipcache.cc:1042
bool seekNewGood(const char *name)
Definition ipcache.cc:940
IpsSelector< GoodIpsIterator > good() const
good IPs
Definition ipcache.h:243
Storage ips
good and bad IPs
Definition ipcache.h:97
void restoreGoodness(const char *name)
makes current() calls possible after a successful markAsBad()
Definition ipcache.cc:969
void reportCurrent(std::ostream &os) const
prints current IP and other debugging information
Definition ipcache.cc:1011
size_t badCount() const noexcept
bad IPs
Definition ipcache.h:63
bool empty() const noexcept
whether we cached no IPs at all
Definition ipcache.h:61
encapsulates DNS lookup results
forwards non-blocking IP cache lookup results to either IPH or IpReciever
Definition ipcache.cc:83
void forwardHits(const Dns::CachedIps &ips)
convenience wrapper to safely forwardIp() for each IP in the container
Definition ipcache.cc:268
IPH * receiverFun
gets final results
Definition ipcache.cc:115
void forwardLookup(const char *error)
inform recipient of a finished lookup
Definition ipcache.cc:280
bool forwardIp(const Ip::Address &ip)
Definition ipcache.cc:252
void finalCallback(const Dns::CachedIps *addrs, const Dns::LookupDetails &details)
forwards notification about the end of the lookup; last method to be called
Definition ipcache.cc:231
CbcPointer< Dns::IpReceiver > receiverObj
gets incremental and final results
Definition ipcache.cc:114
void lookupsStarting()
initialize lookup timestamps for Dns::LookupDetails delay calculation
Definition ipcache.cc:100
int totalResponseTime() const
Definition ipcache.cc:106
CallbackData receiverData
caller-specific data for the handler (optional)
Definition ipcache.cc:116
int additionalLookupDelay() const
Definition ipcache.cc:110
bool fromHost(const char *hostWithoutPort)
Definition Address.cc:910
bool isIPv6() const
Definition Address.cc:184
metadata for parsing DNS A and AAAA records
Definition ipcache.cc:74
const char * kind
human-friendly record type description
Definition ipcache.cc:77
int & recordCounter
where this kind of records are counted (for stats)
Definition ipcache.cc:78
Content DataType
actual RR DATA type
Definition ipcache.cc:76
Definition SBuf.h:94
time_t negativeDnsTtl
struct SquidConfig::@86 ipcache
time_t positiveDnsTtl
StatHist svcTime
struct StatCounters::@109 dns
void count(double val)
Definition StatHist.cc:55
int count
Definition hash.h:31
Definition ipcache.cc:131
void addGood(const rfc1035_rr &rr, Specs &specs)
adds the contents of a "good" DNS A or AAAA record to stored IPs
Definition ipcache.cc:512
time_t lastref
Definition ipcache.cc:139
IpCacheLookupForwarder handler
Definition ipcache.cc:142
struct ipcache_entry::Flags flags
char * error_message
Definition ipcache.cc:143
time_t expires
Definition ipcache.cc:140
unsigned short locks
Definition ipcache.cc:146
hash_link hash
Definition ipcache.cc:138
ipcache_entry(const char *)
Definition ipcache.cc:409
bool sawCname
Definition ipcache.cc:154
int additionalLookupDelay() const
milliseconds since the last lookup start or -1 if there were no lookups
int totalResponseTime() const
milliseconds since the first lookup start or -1 if there were no lookups
const char * name() const
Definition ipcache.cc:156
ipcache_addrs addrs
Definition ipcache.cc:141
void latestError(const char *text)
remembers the last error seen, overwriting any previous errors
Definition ipcache.cc:458
~ipcache_entry()
Definition ipcache.cc:1091
void updateTtl(const unsigned int rrTtl)
Definition ipcache.cc:541
dlink_node lru
Definition ipcache.cc:145
char * rdata
Definition rfc1035.h:44
unsigned short rdlength
Definition rfc1035.h:43
unsigned int ttl
Definition rfc1035.h:42
#define Important(id)
Definition Messages.h:93
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define DBG_CRITICAL
Definition Stream.h:37
#define IP_LOOKUP_IF_MISS
Definition defines.h:37
void IDNSCB(void *cbdata, const rfc1035_rr *answer, const int recordsInAnswer, const char *error, bool lastAnswer)
Definition forward.h:17
void idnsALookup(const char *, IDNSCB *, void *)
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition event.cc:107
static void purge_entries_fromhosts(void)
Definition fqdncache.cc:229
void ipcacheInvalidateNegative(const char *name)
Definition ipcache.cc:882
void ipcache_restart(void)
Definition ipcache.cc:1105
const ipcache_addrs * ipcache_gethostbyname(const char *name, int flags)
Definition ipcache.cc:729
void ipcache_init(void)
Definition ipcache.cc:696
void ipcacheInvalidate(const char *name)
Definition ipcache.cc:865
variable_list * snmp_netIpFn(variable_list *Var, snint *ErrP)
Definition ipcache.cc:1173
void ipcache_purgelru(void *)
Definition ipcache.cc:353
void ipcacheMarkGoodAddr(const char *name, const Ip::Address &addr)
Definition ipcache.cc:1077
int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
Definition ipcache.cc:1126
void ipcache_nbgethostbyname(const char *name, IPH *handler, void *handlerData)
Definition ipcache.cc:609
static const Dns::CachedIps * ipcacheCheckNumeric(const char *name)
Definition ipcache.cc:900
static void ipcacheUnlockEntry(ipcache_entry *)
Definition ipcache.cc:924
static ipcache_entry * ipcache_get(const char *)
Definition ipcache.cc:324
static hash_table * ip_table
Definition ipcache.cc:207
static void ipcacheStatPrint(ipcache_entry *, StoreEntry *)
Definition ipcache.cc:770
static void ipcacheLockEntry(ipcache_entry *)
Definition ipcache.cc:914
static void purge_entries_fromhosts(void)
Definition ipcache.cc:386
int ipcacheCount()
Definition ipcache.cc:294
static struct _ipcache_stats IpcacheStats
static void ipcacheCallback(ipcache_entry *i, const bool hit, const int wait)
Definition ipcache.cc:443
static void stat_ipcache_get(StoreEntry *)
Definition ipcache.cc:821
static long ipcache_high
Definition ipcache.cc:212
static dlink_list lru_list
Definition ipcache.cc:190
static void ipcacheRelease(ipcache_entry *, bool dofree=true)
Definition ipcache.cc:302
static long ipcache_low
Definition ipcache.cc:210
static void ipcacheRegisterWithCacheManager(void)
Definition ipcache.cc:681
static void ipcacheAddEntry(ipcache_entry *i)
Definition ipcache.cc:422
static int ipcacheExpiredEntry(ipcache_entry *)
Definition ipcache.cc:334
hash_link * hash_lookup(hash_table *, const void *)
Definition hash.cc:146
hash_table * hash_create(HASHCMP *, int, HASHHASH *)
Definition hash.cc:108
int HASHCMP(const void *, const void *)
Definition hash.h:13
void hash_join(hash_table *, hash_link *)
Definition hash.cc:131
HASHHASH hash4
Definition hash.h:46
void hash_remove_link(hash_table *, hash_link *)
Definition hash.cc:220
int hashPrime(int n)
Definition hash.cc:293
const char * hashKeyStr(const hash_link *)
Definition hash.cc:313
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition forward.h:25
void ipcacheMarkBadAddr(const char *name, const Ip::Address &addr)
Definition ipcache.cc:1069
static FREE ipcacheFreeEntry
Definition ipcache.cc:195
static void ipcache_nbgethostbyname_(const char *name, IpCacheLookupForwarder handler)
implements ipcache_nbgethostbyname() and Dns::nbgethostbyname() APIs
Definition ipcache.cc:624
static IDNSCB ipcacheHandleReply
Definition ipcache.cc:196
static void ipcacheParse(ipcache_entry *i, const rfc1035_rr *answers, int nr, const char *error_message)
Definition ipcache.cc:466
void IPH(const ipcache_addrs *, const Dns::LookupDetails &details, void *)
Definition ipcache.h:227
void FREE(void *)
Definition forward.h:37
void nbgethostbyname(const char *name, const CbcPointer< IpReceiver > &receiver)
initiate an (often) asynchronous DNS lookup; the receiver gets the results
Definition ipcache.cc:616
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
#define xfree
#define xstrdup
#define RFC1035_TYPE_A
Definition rfc1035.h:93
#define RFC1035_TYPE_CNAME
Definition rfc1035.h:94
#define RFC1035_TYPE_AAAA
Definition rfc3596.h:48
const char * snmpDebugOid(oid *Name, snint Len, MemBuf &outbuf)
#define SNMP_ERR_NOERROR
Definition snmp_error.h:42
#define SNMP_ERR_NOSUCHNAME
Definition snmp_error.h:44
#define SMI_GAUGE32
Definition snmp_vars.h:77
#define SMI_COUNTER32
Definition snmp_vars.h:76
struct variable_list * snmp_var_new_integer(oid *, int, int, unsigned char)
Definition snmp_vars.c:151
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition store.cc:855
time of the idnsALookup() call
Definition ipcache.cc:118
time of the last noteLookup() call
Definition ipcache.cc:119
Definition ipcache.cc:147
Flags()
Definition ipcache.cc:148
bool fromhosts
Definition ipcache.cc:151
bool negcached
Definition ipcache.cc:150
int unsigned int
Definition stub_fd.cc:19
SBuf text("GET http://resource.com/path HTTP/1.1\r\n" "Host: resource.com\r\n" "Cookie: laijkpk3422r j1noin \r\n" "\r\n")
static hash_table * hash
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition gadgets.cc:18
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition gadgets.cc:51
void Tolower(char *)
Definition util.cc:28
#define safe_free(x)
Definition xalloc.h:73