ipcache.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 
71 template <class Content>
73 class RrSpecs
74 {
75 public:
76  typedef Content DataType;
77  const char *kind;
79 };
80 
83 {
84 public:
86  explicit IpCacheLookupForwarder(const CbcPointer<Dns::IpReceiver> &receiver);
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 
108 protected:
111 
112 private:
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 
134 public:
135  ipcache_entry(const char *);
136  ~ipcache_entry();
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 
150  bool negcached;
151  bool fromhosts;
152  } flags;
153 
154  bool sawCname = false;
155 
156  const char *name() const { return static_cast<const char*>(hash.key); }
157 
159  int totalResponseTime() const;
161  int additionalLookupDelay() const;
162 
164  template <class Specs>
165  void addGood(const rfc1035_rr &rr, Specs &specs);
166 
168  void latestError(const char *text);
169 
170 protected:
171  void updateTtl(const unsigned int rrTtl);
172 };
173 
175 static struct _ipcache_stats {
176  int requests;
177  int replies;
178  int hits;
179  int misses;
182  int rr_a;
183  int rr_aaaa;
184  int rr_cname;
186  int invalid;
187 } IpcacheStats;
188 
191 
192 // forward-decls
193 static void stat_ipcache_get(StoreEntry *);
194 
197 static int ipcacheExpiredEntry(ipcache_entry *);
198 static ipcache_entry *ipcache_get(const char *);
199 static void ipcacheLockEntry(ipcache_entry *);
200 static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
201 static void ipcacheUnlockEntry(ipcache_entry *);
202 static void ipcacheRelease(ipcache_entry *, bool dofree = true);
203 static const Dns::CachedIps *ipcacheCheckNumeric(const char *name);
204 static void ipcache_nbgethostbyname_(const char *name, IpCacheLookupForwarder handler);
205 
207 static hash_table *ip_table = nullptr;
208 
210 static long ipcache_low = 180;
212 static long ipcache_high = 200;
213 
214 #if LIBRESOLV_DNS_TTL_HACK
215 extern int _dns_ttl_;
216 #endif
217 
219 
221  receiverObj(receiver)
222 {
223 }
224 
226  receiverFun(fun), receiverData(data)
227 {
228 }
229 
230 void
231 IpCacheLookupForwarder::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);
241  receiverObj.clear();
242  } else if (receiverFun) {
243  if (receiverData.valid())
244  receiverFun(addrs, details, receiverData.validDone());
245  receiverFun = nullptr;
246  }
247 }
248 
251 bool
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 
267 void
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 
279 void
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 
294 inline int ipcacheCount() { return ip_table ? ip_table->count : 0; }
295 
301 static void
302 ipcacheRelease(ipcache_entry * i, bool dofree)
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)
319  ipcacheFreeEntry(i);
320 }
321 
323 static ipcache_entry *
324 ipcache_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 
333 static 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 
352 void
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) {
362  if (ipcacheCount() < ipcache_low)
363  break;
364 
365  prev = m->prev;
366 
367  i = (ipcache_entry *)m->data;
368 
369  if (i->locks != 0)
370  continue;
371 
372  ipcacheRelease(i);
373 
374  ++removed;
375  }
376 
377  debugs(14, 9, "ipcache_purgelru: removed " << removed << " entries");
378 }
379 
385 static void
387 {
388  dlink_node *m = lru_list.head;
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)
406  ipcacheRelease(i);
407 }
408 
409 ipcache_entry::ipcache_entry(const char *aName):
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 
421 static void
423 {
425 
426  if (nullptr != e) {
427  /* avoid collision */
428  ipcache_entry *q = (ipcache_entry *) e;
429  ipcacheRelease(q);
430  }
431 
432  hash_join(ip_table, &i->hash);
433  dlinkAdd(i, &i->lru, &lru_list);
434  i->lastref = squid_curtime;
435 }
436 
442 static void
443 ipcacheCallback(ipcache_entry *i, const bool hit, const int wait)
444 {
445  i->lastref = squid_curtime;
446 
447  ipcacheLockEntry(i);
448 
449  if (hit)
450  i->handler.forwardHits(i->addrs);
451  const Dns::LookupDetails details(SBuf(i->error_message), wait);
452  i->handler.finalCallback(&i->addrs, details);
453 
455 }
456 
457 void
459 {
460  debugs(14, 3, "ERROR: DNS failure while resolving " << name() << ": " << text);
463 }
464 
465 static void
466 ipcacheParse(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 
510 template <class Specs>
511 void
512 ipcache_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 
540 void
541 ipcache_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 
561 static void
562 ipcacheHandleReply(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);
588  ipcacheAddEntry(i);
589  ipcacheCallback(i, false, age);
590 }
591 
608 void
609 ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
610 {
611  debugs(14, 4, name);
612  ipcache_nbgethostbyname_(name, IpCacheLookupForwarder(handler, handlerData));
613 }
614 
615 void
616 Dns::nbgethostbyname(const char *name, const CbcPointer<IpReceiver> &receiver)
617 {
618  debugs(14, 4, name);
620 }
621 
623 static 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 */
654  ipcacheRelease(i);
655  i = nullptr;
656  } else {
657  /* hit */
658  debugs(14, 4, "ipcache_nbgethostbyname: HIT for '" << name << "'");
659 
660  if (i->flags.negcached)
662  else
663  ++IpcacheStats.hits;
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 
680 static void
682 {
683  Mgr::RegisterAction("ipcache",
684  "IP Cache Stats and Contents",
685  stat_ipcache_get, 0, 1);
686 }
687 
695 void
697 {
698  int n;
699  debugs(14, Important(24), "Initializing IP Cache...");
700  memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
701  lru_list = dlink_list();
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 
728 const ipcache_addrs *
729 ipcache_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)) {
740  ipcacheRelease(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 {
747  ++IpcacheStats.hits;
748  i->lastref = squid_curtime;
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 
769 static 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 
820 void
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 
864 void
865 ipcacheInvalidate(const char *name)
866 {
867  ipcache_entry *i;
868 
869  if ((i = ipcache_get(name)) == nullptr)
870  return;
871 
872  i->expires = squid_curtime;
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 
881 void
882 ipcacheInvalidateNegative(const char *name)
883 {
884  ipcache_entry *i;
885 
886  if ((i = ipcache_get(name)) == nullptr)
887  return;
888 
889  if (i->flags.negcached)
890  i->expires = squid_curtime;
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 
899 static const Dns::CachedIps *
900 ipcacheCheckNumeric(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 
913 static void
915 {
916  if (i->locks++ == 0) {
917  dlinkDelete(&i->lru, &lru_list);
918  dlinkAdd(i, &i->lru, &lru_list);
919  }
920 }
921 
923 static 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))
934  ipcacheRelease(i);
935 }
936 
939 bool
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 
956 void
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 
968 void
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 
983 bool
984 Dns::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 
1002 void
1004 {
1005  assert(!have(ip));
1006  [[maybe_unused]] auto &cachedIp = ips.emplace_back(ip);
1007  assert(!cachedIp.bad());
1008 }
1009 
1010 void
1011 Dns::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 
1021 void
1022 Dns::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 
1041 void
1042 Dns::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 
1068 void
1069 ipcacheMarkBadAddr(const char *name, const Ip::Address &addr)
1070 {
1071  if (auto cached = ipcache_get(name))
1072  cached->addrs.markAsBad(name, addr);
1073 }
1074 
1076 void
1077 ipcacheMarkGoodAddr(const char *name, const Ip::Address &addr)
1078 {
1079  if (auto cached = ipcache_get(name))
1080  cached->addrs.forgetMarking(name, addr);
1081 }
1082 
1084 static void
1085 ipcacheFreeEntry(void *data)
1086 {
1087  ipcache_entry *i = (ipcache_entry *)data;
1088  delete i;
1089 }
1090 
1092 {
1093  xfree(error_message);
1094  xfree(hash.key);
1095 }
1096 
1104 void
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 
1125 int
1126 ipcacheAddEntryFromHosts(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) {
1149  ipcacheUnlockEntry(i);
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);
1162  ipcacheLockEntry(i);
1163  return 0;
1164 }
1165 
1166 #if SQUID_SNMP
1167 
1172 variable_list *
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,
1191  SMI_COUNTER32);
1192  break;
1193 
1194  case IP_HITS:
1195  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1197  SMI_COUNTER32);
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,
1209  SMI_COUNTER32);
1210  break;
1211 
1212  case IP_MISS:
1213  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1215  SMI_COUNTER32);
1216  break;
1217 
1218  case IP_GHBN:
1219  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1220  0, /* deprecated */
1221  SMI_COUNTER32);
1222  break;
1223 
1224  case IP_LOC:
1225  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1226  0, /* deprecated */
1227  SMI_COUNTER32);
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 
an old-style void* callback parameter
Definition: cbdata.h:383
time_t lastref
Definition: ipcache.cc:139
bool fromhosts
Definition: ipcache.cc:151
CbcPointer< Dns::IpReceiver > receiverObj
gets incremental and final results
Definition: ipcache.cc:114
#define IP_LOOKUP_IF_MISS
Definition: defines.h:37
void markAsBad(const char *name, const Ip::Address &ip)
Definition: ipcache.cc:1022
#define RFC1035_TYPE_CNAME
Definition: rfc1035.h:94
void latestError(const char *text)
remembers the last error seen, overwriting any previous errors
Definition: ipcache.cc:458
const char * snmpDebugOid(oid *Name, snint Len, MemBuf &outbuf)
Definition: snmp_core.cc:1056
static void ipcache_nbgethostbyname_(const char *name, IpCacheLookupForwarder handler)
implements ipcache_nbgethostbyname() and Dns::nbgethostbyname() APIs
Definition: ipcache.cc:624
#define DBG_CRITICAL
Definition: Stream.h:37
size_t goodPosition
position of the IP returned by current()
Definition: ipcache.h:100
static long ipcache_low
Definition: ipcache.cc:210
int ipcacheCount()
Definition: ipcache.cc:294
bool negcached
Definition: ipcache.cc:150
void FREE(void *)
Definition: forward.h:37
void ipcacheInvalidate(const char *name)
Definition: ipcache.cc:865
unsigned short rdlength
Definition: rfc1035.h:43
variable_list * snmp_netIpFn(variable_list *Var, snint *ErrP)
Definition: ipcache.cc:1173
@ IP_MISS
Definition: cache_snmp.h:194
time_t expires
Definition: ipcache.cc:140
static void purge_entries_fromhosts(void)
Definition: ipcache.cc:386
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:855
void hash_remove_link(hash_table *, hash_link *)
Definition: hash.cc:220
void error(char *format,...)
void ipcacheInvalidateNegative(const char *name)
Definition: ipcache.cc:882
static int ipcacheExpiredEntry(ipcache_entry *)
Definition: ipcache.cc:334
bool sawCname
Definition: ipcache.cc:154
static void ipcacheUnlockEntry(ipcache_entry *)
Definition: ipcache.cc:924
#define CBDATA_CLASS(type)
Definition: cbdata.h:289
IpCacheLookupForwarder handler
Definition: ipcache.cc:142
Definition: SBuf.h:93
@ IP_LOC
Definition: cache_snmp.h:196
#define xstrdup
const ipcache_addrs * ipcache_gethostbyname(const char *name, int flags)
Definition: ipcache.cc:729
bool fromHost(const char *hostWithoutPort)
Definition: Address.cc:918
bool valid() const
Definition: cbdata.h:395
bool have(const Ip::Address &ip, size_t *position=nullptr) const
Definition: ipcache.cc:984
const A & max(A const &lhs, A const &rhs)
CallbackData receiverData
caller-specific data for the handler (optional)
Definition: ipcache.cc:116
~ipcache_entry()
Definition: ipcache.cc:1091
void updateTtl(const unsigned int rrTtl)
Definition: ipcache.cc:541
dlink_node lru
Definition: ipcache.cc:145
int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
Definition: ipcache.cc:1126
hash_link * hash_lookup(hash_table *, const void *)
Definition: hash.cc:146
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
int HASHCMP(const void *, const void *)
Definition: hash.h:13
struct StatCounters::@116 dns
void ipcache_restart(void)
Definition: ipcache.cc:1105
int count
Definition: hash.h:31
int totalResponseTime() const
milliseconds since the first lookup start or -1 if there were no lookups
int additionalLookupDelay() const
Definition: ipcache.cc:110
HASHHASH hash4
Definition: hash.h:46
ipcache_addrs addrs
Definition: ipcache.cc:141
int hashPrime(int n)
Definition: hash.cc:293
static void ipcacheAddEntry(ipcache_entry *i)
Definition: ipcache.cc:422
static const Dns::CachedIps * ipcacheCheckNumeric(const char *name)
Definition: ipcache.cc:900
int additionalLookupDelay() const
milliseconds since the last lookup start or -1 if there were no lookups
hash_link hash
Definition: ipcache.cc:138
const char * hashKeyStr(const hash_link *)
Definition: hash.cc:313
IPH * receiverFun
gets final results
Definition: ipcache.cc:115
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:51
@ IP_HITS
Definition: cache_snmp.h:191
@ IP_PENDHIT
Definition: cache_snmp.h:192
int name_length
Definition: snmp_vars.h:71
#define RFC1035_TYPE_A
Definition: rfc1035.h:93
Flags()
Definition: ipcache.cc:148
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:25
oid * name
Definition: snmp_vars.h:70
static void ipcacheLockEntry(ipcache_entry *)
Definition: ipcache.cc:914
forwards non-blocking IP cache lookup results to either IPH or IpReciever
Definition: ipcache.cc:82
int64_t snint
Definition: cache_snmp.h:14
int negative_hits
Definition: ipcache.cc:180
void Tolower(char *)
Definition: util.cc:28
int size
Definition: ModDevPoll.cc:69
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:18
StatHist svcTime
Definition: StatCounters.h:99
char * rdata
Definition: rfc1035.h:44
void nbgethostbyname(const char *name, const CbcPointer< IpReceiver > &receiver)
initiate an (often) asynchronous DNS lookup; the receiver gets the results
Definition: ipcache.cc:616
static struct _ipcache_stats IpcacheStats
bool isIPv6() const
Definition: Address.cc:184
static IDNSCB ipcacheHandleReply
Definition: ipcache.cc:196
Definition: MemBuf.h:23
SBuf text("GET http://resource.com/path HTTP/1.1\r\n" "Host: resource.com\r\n" "Cookie: laijkpk3422r j1noin \r\n" "\r\n")
void ipcache_nbgethostbyname(const char *name, IPH *handler, void *handlerData)
Definition: ipcache.cc:609
Definition: ipcache.cc:130
#define SMI_GAUGE32
Definition: snmp_vars.h:77
struct variable_list * snmp_var_new_integer(oid *, int, int, unsigned char)
Definition: snmp_vars.c:151
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
Definition: IoManip.h:169
time_t positiveDnsTtl
Definition: SquidConfig.h:106
#define safe_free(x)
Definition: xalloc.h:73
@ IP_NEGHIT
Definition: cache_snmp.h:193
void count(double val)
Definition: StatHist.cc:55
#define assert(EX)
Definition: assert.h:17
@ IP_GHBN
Definition: cache_snmp.h:195
static void ipcacheRelease(ipcache_entry *, bool dofree=true)
Definition: ipcache.cc:302
time_t negativeDnsTtl
Definition: SquidConfig.h:105
void pushUnique(const Ip::Address &ip)
Definition: ipcache.cc:1003
int & recordCounter
where this kind of records are counted (for stats)
Definition: ipcache.cc:78
unsigned short locks
Definition: ipcache.cc:146
void clear()
make pointer not set; does not invalidate cbdata
Definition: CbcPointer.h:144
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
encapsulates DNS lookup results
Definition: LookupDetails.h:22
@ IP_REQ
Definition: cache_snmp.h:190
static hash_table * hash
Definition: text_backend.cc:41
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:325
#define RFC1035_TYPE_AAAA
Definition: rfc3596.h:48
time_t squid_curtime
Definition: stub_libtime.cc:20
void ipcacheMarkGoodAddr(const char *name, const Ip::Address &addr)
Definition: ipcache.cc:1077
Storage ips
good and bad IPs
Definition: ipcache.h:97
static ipcache_entry * ipcache_get(const char *)
Definition: ipcache.cc:324
#define xfree
unsigned int ttl
Definition: rfc1035.h:42
const char * kind
human-friendly record type description
Definition: ipcache.cc:77
const char * name() const
Definition: ipcache.cc:156
Definition: ipcache.cc:147
void reportCurrent(std::ostream &os) const
prints current IP and other debugging information
Definition: ipcache.cc:1011
void ipcache_init(void)
Definition: ipcache.cc:696
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 FREE ipcacheFreeEntry
Definition: ipcache.cc:195
Content DataType
actual RR DATA type
Definition: ipcache.cc:76
static hash_table * ip_table
Definition: ipcache.cc:207
static void ipcacheRegisterWithCacheManager(void)
Definition: ipcache.cc:681
int totalResponseTime() const
Definition: ipcache.cc:106
#define LEN_SQ_NET
Definition: cache_snmp.h:49
void ipcacheMarkBadAddr(const char *name, const Ip::Address &addr)
Definition: ipcache.cc:1069
static dlink_list lru_list
Definition: ipcache.cc:190
void IDNSCB(void *cbdata, const rfc1035_rr *answer, const int recordsInAnswer, const char *error, bool lastAnswer)
Definition: forward.h:17
void restoreGoodness(const char *name)
makes current() calls possible after a successful markAsBad()
Definition: ipcache.cc:969
hash_table * hash_create(HASHCMP *, int, HASHHASH *)
Definition: hash.cc:108
void forgetMarking(const char *name, const Ip::Address &ip)
undo successful markAsBad()
Definition: ipcache.cc:1042
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
Definition: Registration.cc:54
#define Must(condition)
Definition: TextException.h:75
bool forwardIp(const Ip::Address &ip)
Definition: ipcache.cc:252
#define Important(id)
Definition: Messages.h:93
static void ipcacheParse(ipcache_entry *i, const rfc1035_rr *answers, int nr, const char *error_message)
Definition: ipcache.cc:466
#define DBG_IMPORTANT
Definition: Stream.h:38
static long ipcache_high
Definition: ipcache.cc:212
ipcache_entry(const char *)
Definition: ipcache.cc:409
bool seekNewGood(const char *name)
Definition: ipcache.cc:940
static void ipcacheStatPrint(ipcache_entry *, StoreEntry *)
Definition: ipcache.cc:770
void reset(const Ip::Address &ip)
replace all info with the given (presumed good) IP address
Definition: ipcache.cc:957
void idnsALookup(const char *, IDNSCB *, void *)
@ IP_ENT
Definition: cache_snmp.h:189
char * error_message
Definition: ipcache.cc:143
#define SNMP_ERR_NOSUCHNAME
Definition: snmp_error.h:44
metadata for parsing DNS A and AAAA records
Definition: ipcache.cc:73
void * validDone()
Definition: cbdata.h:396
struct ipcache_entry::Flags flags
void ipcache_purgelru(void *)
Definition: ipcache.cc:353
void forwardLookup(const char *error)
inform recipient of a finished lookup
Definition: ipcache.cc:280
int EnableIpv6
Whether IPv6 is supported and type of support.
Definition: tools.h:25
void lookupsStarting()
initialize lookup timestamps for Dns::LookupDetails delay calculation
Definition: ipcache.cc:100
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void forwardHits(const Dns::CachedIps &ips)
convenience wrapper to safely forwardIp() for each IP in the container
Definition: ipcache.cc:268
const A & min(A const &lhs, A const &rhs)
struct SquidConfig::@93 ipcache
void hash_join(hash_table *, hash_link *)
Definition: hash.cc:131
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:107
#define SNMP_ERR_NOERROR
Definition: snmp_error.h:42
void IPH(const ipcache_addrs *, const Dns::LookupDetails &details, void *)
Definition: ipcache.h:227
class SquidConfig Config
Definition: SquidConfig.cc:12
IpsSelector< GoodIpsIterator > good() const
good IPs
Definition: ipcache.h:243
#define SMI_COUNTER32
Definition: snmp_vars.h:76
StatCounters statCounter
Definition: StatCounters.cc:12
int numeric_hits
Definition: ipcache.cc:181

 

Introduction

Documentation

Support

Miscellaneous