ipcache.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 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 "CacheManager.h"
13 #include "cbdata.h"
14 #include "debug/Messages.h"
15 #include "dlink.h"
16 #include "dns/LookupDetails.h"
17 #include "dns/rfc3596.h"
18 #include "event.h"
19 #include "ip/Address.h"
20 #include "ip/tools.h"
21 #include "ipcache.h"
22 #include "mgr/Registration.h"
23 #include "snmp_agent.h"
24 #include "SquidConfig.h"
25 #include "StatCounters.h"
26 #include "Store.h"
27 #include "util.h"
28 #include "wordlist.h"
29 
30 #if SQUID_SNMP
31 #include "snmp_core.h"
32 #endif
33 
70 template <class Content>
72 class RrSpecs
73 {
74 public:
75  typedef Content DataType;
76  const char *kind;
78 };
79 
82 {
83 public:
85  explicit IpCacheLookupForwarder(const CbcPointer<Dns::IpReceiver> &receiver);
86  IpCacheLookupForwarder(IPH *fun, void *data);
87 
89  void finalCallback(const Dns::CachedIps *addrs, const Dns::LookupDetails &details);
90 
93  bool forwardIp(const Ip::Address &ip);
94 
96  void forwardHits(const Dns::CachedIps &ips);
97 
100 
102  void forwardLookup(const char *error);
103 
106 
107 protected:
110 
111 private:
112  /* receiverObj and receiverFun are mutually exclusive */
114  IPH *receiverFun = nullptr;
116 
117  struct timeval firstLookupStart {0,0};
118  struct timeval lastLookupEnd {0,0};
119 };
120 
130 {
132 
133 public:
134  ipcache_entry(const char *);
135  ~ipcache_entry();
136 
137  hash_link hash; /* must be first */
138  time_t lastref;
139  time_t expires;
143 
145  unsigned short locks;
146  struct Flags {
148 
149  bool negcached;
150  bool fromhosts;
151  } flags;
152 
153  bool sawCname = false;
154 
155  const char *name() const { return static_cast<const char*>(hash.key); }
156 
158  int totalResponseTime() const;
161 
163  template <class Specs>
164  void addGood(const rfc1035_rr &rr, Specs &specs);
165 
167  void latestError(const char *text, const int debugLevel = 3);
168 
169 protected:
170  void updateTtl(const unsigned int rrTtl);
171 };
172 
174 static struct _ipcache_stats {
175  int requests;
176  int replies;
177  int hits;
178  int misses;
181  int rr_a;
182  int rr_aaaa;
183  int rr_cname;
185  int invalid;
187 
190 
191 // forward-decls
192 static void stat_ipcache_get(StoreEntry *);
193 
196 static int ipcacheExpiredEntry(ipcache_entry *);
197 static ipcache_entry *ipcache_get(const char *);
198 static void ipcacheLockEntry(ipcache_entry *);
199 static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
200 static void ipcacheUnlockEntry(ipcache_entry *);
201 static void ipcacheRelease(ipcache_entry *, bool dofree = true);
202 static const Dns::CachedIps *ipcacheCheckNumeric(const char *name);
203 static void ipcache_nbgethostbyname_(const char *name, IpCacheLookupForwarder handler);
204 
207 
209 static long ipcache_low = 180;
211 static long ipcache_high = 200;
212 
213 #if LIBRESOLV_DNS_TTL_HACK
214 extern int _dns_ttl_;
215 #endif
216 
218 
220  receiverObj(receiver)
221 {
222 }
223 
225  receiverFun(fun), receiverData(data)
226 {
227 }
228 
229 void
231 {
232  debugs(14, 7, addrs << " " << details);
233  if (receiverObj.set()) {
234  if (auto receiver = receiverObj.valid())
235  receiver->noteIps(addrs, details);
236  receiverObj.clear();
237  } else if (receiverFun) {
238  if (receiverData.valid()) {
239  const Dns::CachedIps *emptyIsNil = (addrs && !addrs->empty()) ? addrs : nullptr;
240  receiverFun(emptyIsNil, details, receiverData.validDone());
241  }
242  receiverFun = nullptr;
243  }
244 }
245 
248 bool
250 {
251  debugs(14, 7, ip);
252  if (receiverObj.set()) {
253  if (auto receiver = receiverObj.valid()) {
254  receiver->noteIp(ip);
255  return true;
256  }
257  return false;
258  }
259  // else do nothing: ReceiverFun does not do incremental notifications
260  return false;
261 }
262 
264 void
266 {
267  if (receiverObj.set()) {
268  for (const auto &ip: ips.good()) {
269  if (!forwardIp(ip))
270  break; // receiver gone
271  }
272  }
273  // else do nothing: ReceiverFun does not do incremental notifications
274 }
275 
276 void
278 {
279  // Lookups run concurrently, but HttpRequest::recordLookup() thinks they
280  // are sequential. Give it just the new, yet-unaccounted-for delay.
281  if (receiverObj.set()) {
282  if (auto receiver = receiverObj.valid()) {
283  receiver->noteLookup(Dns::LookupDetails(error, additionalLookupDelay()));
285  }
286  }
287  // else do nothing: ReceiverFun gets no individual lookup notifications
288 }
289 
291 inline int ipcacheCount() { return ip_table ? ip_table->count : 0; }
292 
298 static void
299 ipcacheRelease(ipcache_entry * i, bool dofree)
300 {
301  if (!i) {
302  debugs(14, DBG_CRITICAL, "ipcacheRelease: Releasing entry with i=<NULL>");
303  return;
304  }
305 
306  if (!i || !i->hash.key) {
307  debugs(14, DBG_CRITICAL, "ipcacheRelease: Releasing entry without hash link!");
308  return;
309  }
310 
311  debugs(14, 3, "ipcacheRelease: Releasing entry for '" << (const char *) i->hash.key << "'");
312 
314  dlinkDelete(&i->lru, &lru_list);
315  if (dofree)
316  ipcacheFreeEntry(i);
317 }
318 
320 static ipcache_entry *
321 ipcache_get(const char *name)
322 {
323  if (ip_table != NULL)
324  return (ipcache_entry *) hash_lookup(ip_table, name);
325  else
326  return NULL;
327 }
328 
330 static int
332 {
333  /* all static entries are locked, so this takes care of them too */
334 
335  if (i->locks != 0)
336  return 0;
337 
338  if (i->addrs.empty())
339  if (0 == i->flags.negcached)
340  return 1;
341 
342  if (i->expires > squid_curtime)
343  return 0;
344 
345  return 1;
346 }
347 
349 void
351 {
352  dlink_node *m;
353  dlink_node *prev = NULL;
354  ipcache_entry *i;
355  int removed = 0;
356  eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
357 
358  for (m = lru_list.tail; m; m = prev) {
359  if (ipcacheCount() < ipcache_low)
360  break;
361 
362  prev = m->prev;
363 
364  i = (ipcache_entry *)m->data;
365 
366  if (i->locks != 0)
367  continue;
368 
369  ipcacheRelease(i);
370 
371  ++removed;
372  }
373 
374  debugs(14, 9, "ipcache_purgelru: removed " << removed << " entries");
375 }
376 
382 static void
384 {
385  dlink_node *m = lru_list.head;
386  ipcache_entry *i = NULL, *t;
387 
388  while (m) {
389  if (i != NULL) { /* need to delay deletion */
390  ipcacheRelease(i); /* we just override locks */
391  i = NULL;
392  }
393 
394  t = (ipcache_entry*)m->data;
395 
396  if (t->flags.fromhosts)
397  i = t;
398 
399  m = m->next;
400  }
401 
402  if (i != NULL)
403  ipcacheRelease(i);
404 }
405 
406 ipcache_entry::ipcache_entry(const char *aName):
407  lastref(0),
408  expires(0),
409  error_message(nullptr),
410  locks(0) // XXX: use Lock type ?
411 {
412  hash.key = xstrdup(aName);
413  Tolower(static_cast<char*>(hash.key));
415 }
416 
418 static void
420 {
422 
423  if (NULL != e) {
424  /* avoid collision */
425  ipcache_entry *q = (ipcache_entry *) e;
426  ipcacheRelease(q);
427  }
428 
429  hash_join(ip_table, &i->hash);
430  dlinkAdd(i, &i->lru, &lru_list);
431  i->lastref = squid_curtime;
432 }
433 
439 static void
440 ipcacheCallback(ipcache_entry *i, const bool hit, const int wait)
441 {
442  i->lastref = squid_curtime;
443 
444  ipcacheLockEntry(i);
445 
446  if (hit)
447  i->handler.forwardHits(i->addrs);
448  const Dns::LookupDetails details(i->error_message, wait);
449  i->handler.finalCallback(&i->addrs, details);
450 
452 }
453 
454 void
455 ipcache_entry::latestError(const char *text, const int debugLevel)
456 {
457  debugs(14, debugLevel, "ERROR: DNS failure while resolving " << name() << ": " << text);
460 }
461 
462 static void
463 ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *error_message)
464 {
465  int k;
466 
467  // XXX: Callers use zero ancount instead of -1 on errors!
468  if (nr < 0) {
469  i->latestError(error_message);
470  return;
471  }
472 
473  if (nr == 0) {
474  i->latestError("No DNS records");
475  return;
476  }
477 
478  debugs(14, 3, nr << " answers for " << i->name());
479  assert(answers);
480 
481  for (k = 0; k < nr; ++k) {
482 
483  if (Ip::EnableIpv6 && answers[k].type == RFC1035_TYPE_AAAA) {
484  static const RrSpecs<struct in6_addr> QuadA = { "IPv6", IpcacheStats.rr_aaaa };
485  i->addGood(answers[k], QuadA);
486  continue;
487  }
488 
489  if (answers[k].type == RFC1035_TYPE_A) {
490  static const RrSpecs<struct in_addr> SingleA = { "IPv4", IpcacheStats.rr_a };
491  i->addGood(answers[k], SingleA);
492  continue;
493  }
494 
495  /* With A and AAAA, the CNAME does not necessarily come with additional records to use. */
496  if (answers[k].type == RFC1035_TYPE_CNAME) {
497  i->sawCname = true;
499  continue;
500  }
501 
502  // otherwise its an unknown RR. debug at level 9 since we usually want to ignore these and they are common.
503  debugs(14, 9, "Unknown RR type received: type=" << answers[k].type << " starting at " << &(answers[k]) );
504  }
505 }
506 
507 template <class Specs>
508 void
509 ipcache_entry::addGood(const rfc1035_rr &rr, Specs &specs)
510 {
511  typename Specs::DataType address;
512  if (rr.rdlength != sizeof(address)) {
513  debugs(14, DBG_IMPORTANT, "ERROR: Ignoring invalid " << specs.kind << " address record while resolving " << name());
514  return;
515  }
516 
517  ++specs.recordCounter;
518 
519  // Do not store more than 255 addresses (TODO: Why?)
520  if (addrs.raw().size() >= 255)
521  return;
522 
523  memcpy(&address, rr.rdata, sizeof(address));
524  const Ip::Address ip = address;
525  if (addrs.have(ip)) {
526  debugs(14, 3, "refusing to add duplicate " << ip);
527  return;
528  }
529  addrs.pushUnique(address);
530 
531  updateTtl(rr.ttl);
532 
533  debugs(14, 3, name() << " #" << addrs.size() << " " << ip);
534  handler.forwardIp(ip); // we are only called with good IPs
535 }
536 
537 void
538 ipcache_entry::updateTtl(const unsigned int rrTtl)
539 {
540  const time_t ttl = std::min(std::max(
541  Config.negativeDnsTtl, // smallest value allowed
542  static_cast<time_t>(rrTtl)),
543  Config.positiveDnsTtl); // largest value allowed
544 
545  const time_t rrExpires = squid_curtime + ttl;
546  if (rrExpires < expires)
547  expires = rrExpires;
548 }
549 
551 static void
552 ipcacheHandleReply(void *data, const rfc1035_rr * answers, int na, const char *error_message, const bool lastAnswer)
553 {
554  ipcache_entry *i = static_cast<ipcache_entry*>(data);
555 
556  i->handler.forwardLookup(error_message);
557  ipcacheParse(i, answers, na, error_message);
558 
559  if (!lastAnswer)
560  return;
561 
563  const auto age = i->handler.totalResponseTime();
565 
566  if (i->addrs.empty()) {
567  i->flags.negcached = true;
569 
570  if (!i->error_message) {
571  i->latestError("No valid address records", DBG_IMPORTANT);
572  if (i->sawCname)
574  }
575  }
576 
577  debugs(14, 3, "done with " << i->name() << ": " << i->addrs);
578  ipcacheAddEntry(i);
579  ipcacheCallback(i, false, age);
580 }
581 
598 void
599 ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
600 {
601  debugs(14, 4, name);
603 }
604 
605 void
606 Dns::nbgethostbyname(const char *name, const CbcPointer<IpReceiver> &receiver)
607 {
608  debugs(14, 4, name);
610 }
611 
613 static void
615 {
616  ipcache_entry *i = NULL;
617  const ipcache_addrs *addrs = NULL;
619 
620  if (name == NULL || name[0] == '\0') {
621  debugs(14, 4, "ipcache_nbgethostbyname: Invalid name!");
623  const Dns::LookupDetails details("Invalid hostname", -1); // error, no lookup
624  handler.finalCallback(nullptr, details);
625  return;
626  }
627 
628  if ((addrs = ipcacheCheckNumeric(name))) {
629  debugs(14, 4, "ipcache_nbgethostbyname: BYPASS for '" << name << "' (already numeric)");
630  handler.forwardHits(*addrs);
632  const Dns::LookupDetails details; // no error, no lookup
633  handler.finalCallback(addrs, details);
634  return;
635  }
636 
637  i = ipcache_get(name);
638 
639  if (NULL == i) {
640  /* miss */
641  (void) 0;
642  } else if (ipcacheExpiredEntry(i)) {
643  /* hit, but expired -- bummer */
644  ipcacheRelease(i);
645  i = NULL;
646  } else {
647  /* hit */
648  debugs(14, 4, "ipcache_nbgethostbyname: HIT for '" << name << "'");
649 
650  if (i->flags.negcached)
652  else
653  ++IpcacheStats.hits;
654 
655  i->handler = std::move(handler);
656  ipcacheCallback(i, true, -1); // no lookup
657 
658  return;
659  }
660 
661  debugs(14, 5, "ipcache_nbgethostbyname: MISS for '" << name << "'");
663  i = new ipcache_entry(name);
664  i->handler = std::move(handler);
667 }
668 
670 static void
672 {
673  Mgr::RegisterAction("ipcache",
674  "IP Cache Stats and Contents",
675  stat_ipcache_get, 0, 1);
676 }
677 
685 void
687 {
688  int n;
689  debugs(14, Important(24), "Initializing IP Cache...");
690  memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
691  lru_list = dlink_list();
692 
693  ipcache_high = (long) (((float) Config.ipcache.size *
694  (float) Config.ipcache.high) / (float) 100);
695  ipcache_low = (long) (((float) Config.ipcache.size *
696  (float) Config.ipcache.low) / (float) 100);
697  n = hashPrime(ipcache_high / 4);
698  ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
699 
701 }
702 
718 const ipcache_addrs *
719 ipcache_gethostbyname(const char *name, int flags)
720 {
721  ipcache_entry *i = NULL;
722  assert(name);
723  debugs(14, 3, "ipcache_gethostbyname: '" << name << "', flags=" << std::hex << flags);
725  i = ipcache_get(name);
726 
727  if (NULL == i) {
728  (void) 0;
729  } else if (ipcacheExpiredEntry(i)) {
730  ipcacheRelease(i);
731  i = NULL;
732  } else if (i->flags.negcached) {
734  // ignore i->error_message: the caller just checks IP cache presence
735  return NULL;
736  } else {
737  ++IpcacheStats.hits;
738  i->lastref = squid_curtime;
739  // ignore i->error_message: the caller just checks IP cache presence
740  return &i->addrs;
741  }
742 
743  /* no entry [any more] */
744 
745  if (const auto addrs = ipcacheCheckNumeric(name)) {
747  return addrs;
748  }
749 
751 
752  if (flags & IP_LOOKUP_IF_MISS)
754 
755  return NULL;
756 }
757 
759 static void
761 {
762  char buf[MAX_IPSTRLEN];
763 
764  if (!sentry) {
765  debugs(14, DBG_CRITICAL, "ERROR: sentry is NULL!");
766  return;
767  }
768 
769  if (!i) {
770  debugs(14, DBG_CRITICAL, "ERROR: ipcache_entry is NULL!");
771  storeAppendPrintf(sentry, "CRITICAL ERROR\n");
772  return;
773  }
774 
775  storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)",
776  hashKeyStr(&i->hash),
777  i->flags.fromhosts ? 'H' : ' ',
778  i->flags.negcached ? 'N' : ' ',
779  (int) (squid_curtime - i->lastref),
780  (int) ((i->flags.fromhosts ? -1 : i->expires - squid_curtime)),
781  static_cast<int>(i->addrs.size()),
782  static_cast<int>(i->addrs.badCount()));
783 
786  if (i->flags.negcached) {
787  storeAppendPrintf(sentry, "\n");
788  return;
789  }
790 
793  bool firstLine = true;
794  for (const auto &addr: i->addrs.raw()) {
795  /* Display tidy-up: IPv6 are so big make the list vertical */
796  const char *indent = firstLine ? "" : " ";
797  storeAppendPrintf(sentry, "%s %45.45s-%3s\n",
798  indent,
799  addr.ip.toStr(buf, MAX_IPSTRLEN),
800  addr.bad() ? "BAD" : "OK ");
801  firstLine = false;
802  }
803 }
804 
810 void
812 {
813  dlink_node *m;
814  assert(ip_table != NULL);
815  storeAppendPrintf(sentry, "IP Cache Statistics:\n");
816  storeAppendPrintf(sentry, "IPcache Entries Cached: %d\n",
817  ipcacheCount());
818  storeAppendPrintf(sentry, "IPcache Requests: %d\n",
820  storeAppendPrintf(sentry, "IPcache Hits: %d\n",
822  storeAppendPrintf(sentry, "IPcache Negative Hits: %d\n",
824  storeAppendPrintf(sentry, "IPcache Numeric Hits: %d\n",
826  storeAppendPrintf(sentry, "IPcache Misses: %d\n",
828  storeAppendPrintf(sentry, "IPcache Retrieved A: %d\n",
830  storeAppendPrintf(sentry, "IPcache Retrieved AAAA: %d\n",
832  storeAppendPrintf(sentry, "IPcache Retrieved CNAME: %d\n",
834  storeAppendPrintf(sentry, "IPcache CNAME-Only Response: %d\n",
836  storeAppendPrintf(sentry, "IPcache Invalid Request: %d\n",
838  storeAppendPrintf(sentry, "\n\n");
839  storeAppendPrintf(sentry, "IP Cache Contents:\n\n");
840  storeAppendPrintf(sentry, " %-31.31s %3s %6s %6s %4s\n",
841  "Hostname",
842  "Flg",
843  "lstref",
844  "TTL",
845  "N(b)");
846 
847  for (m = lru_list.head; m; m = m->next) {
848  assert( m->next != m );
849  ipcacheStatPrint((ipcache_entry *)m->data, sentry);
850  }
851 }
852 
854 void
855 ipcacheInvalidate(const char *name)
856 {
857  ipcache_entry *i;
858 
859  if ((i = ipcache_get(name)) == NULL)
860  return;
861 
862  i->expires = squid_curtime;
863 
864  /*
865  * NOTE, don't call ipcacheRelease here because we might be here due
866  * to a thread started from a callback.
867  */
868 }
869 
871 void
872 ipcacheInvalidateNegative(const char *name)
873 {
874  ipcache_entry *i;
875 
876  if ((i = ipcache_get(name)) == NULL)
877  return;
878 
879  if (i->flags.negcached)
880  i->expires = squid_curtime;
881 
882  /*
883  * NOTE, don't call ipcacheRelease here because we might be here due
884  * to a thread started from a callback.
885  */
886 }
887 
889 static const Dns::CachedIps *
890 ipcacheCheckNumeric(const char *name)
891 {
892  Ip::Address ip;
893  if (!ip.fromHost(name))
894  return nullptr;
895 
896  debugs(14, 4, "HIT_BYPASS for " << name << "=" << ip);
897  static Dns::CachedIps static_addrs;
898  static_addrs.reset(ip);
899  return &static_addrs;
900 }
901 
903 static void
905 {
906  if (i->locks++ == 0) {
907  dlinkDelete(&i->lru, &lru_list);
908  dlinkAdd(i, &i->lru, &lru_list);
909  }
910 }
911 
913 static void
915 {
916  if (i->locks < 1) {
917  debugs(14, DBG_IMPORTANT, "WARNING: ipcacheEntry unlocked with no lock! locks=" << i->locks);
918  return;
919  }
920 
921  -- i->locks;
922 
923  if (ipcacheExpiredEntry(i))
924  ipcacheRelease(i);
925 }
926 
929 bool
931 {
932  // linear search!
933  for (size_t seen = 0; seen < ips.size(); ++seen) {
934  if (++goodPosition >= ips.size())
935  goodPosition = 0;
936  if (!ips[goodPosition].bad()) {
937  debugs(14, 3, "succeeded for " << name << ": " << *this);
938  return true;
939  }
940  }
941  goodPosition = ips.size();
942  debugs(14, 3, "failed for " << name << ": " << *this);
943  return false;
944 }
945 
946 void
948 {
949  ips.clear();
950  ips.emplace_back(ip);
951  goodPosition = 0;
952  // Assume that the given IP is good because CachedIps are designed to never
953  // run out of good IPs.
954  badCount_ = 0;
955 }
956 
958 void
960 {
961  if (badCount() >= size()) {
962  // There are no good IPs left. Clear all bad marks. This must help
963  // because we are called only after a good address was tested as bad.
964  for (auto &cachedIp: ips)
965  cachedIp.forgetMarking();
966  badCount_ = 0;
967  }
968  Must(seekNewGood(name));
969  debugs(14, 3, "cleared all IPs for " << name << "; now back to " << *this);
970 }
971 
972 bool
973 Dns::CachedIps::have(const Ip::Address &ip, size_t *positionOrNil) const
974 {
975  // linear search!
976  size_t pos = 0;
977  for (const auto &cachedIp: ips) {
978  if (cachedIp.ip == ip) {
979  if (auto position = positionOrNil)
980  *position = pos;
981  debugs(14, 7, ip << " at " << pos << " in " << *this);
982  return true;
983  }
984  }
985  // no such address; leave *position as is
986  debugs(14, 7, " no " << ip << " in " << *this);
987  return false;
988 }
989 
990 void
992 {
993  assert(!have(ip));
994  ips.emplace_back(ip);
995  assert(!raw().back().bad());
996 }
997 
998 void
999 Dns::CachedIps::reportCurrent(std::ostream &os) const
1000 {
1001  if (empty())
1002  os << "[no cached IPs]";
1003  else if (goodPosition == size())
1004  os << "[" << size() << " bad cached IPs]"; // could only be temporary
1005  else
1006  os << current() << " #" << (goodPosition+1) << "/" << ips.size() << "-" << badCount();
1007 }
1008 
1009 void
1010 Dns::CachedIps::markAsBad(const char *name, const Ip::Address &ip)
1011 {
1012  size_t badPosition = 0;
1013  if (!have(ip, &badPosition))
1014  return; // no such address
1015 
1016  auto &cachedIp = ips[badPosition];
1017  if (cachedIp.bad())
1018  return; // already marked correctly
1019 
1020  cachedIp.markAsBad();
1021  ++badCount_;
1022  debugs(14, 2, ip << " of " << name);
1023 
1024  if (goodPosition == badPosition)
1025  restoreGoodness(name);
1026  // else nothing to do: goodPositon still points to a good IP
1027 }
1028 
1029 void
1030 Dns::CachedIps::forgetMarking(const char *name, const Ip::Address &ip)
1031 {
1032  if (!badCount_)
1033  return; // all IPs are already "good"
1034 
1035  size_t badPosition = 0;
1036  if (!have(ip, &badPosition))
1037  return; // no such address
1038 
1039  auto &cachedIp = ips[badPosition];
1040  if (!cachedIp.bad())
1041  return; // already marked correctly
1042 
1043  cachedIp.forgetMarking();
1044  assert(!cachedIp.bad());
1045  --badCount_;
1046  debugs(14, 2, ip << " of " << name);
1047 }
1048 
1056 void
1057 ipcacheMarkBadAddr(const char *name, const Ip::Address &addr)
1058 {
1059  if (auto cached = ipcache_get(name))
1060  cached->addrs.markAsBad(name, addr);
1061 }
1062 
1064 void
1065 ipcacheMarkGoodAddr(const char *name, const Ip::Address &addr)
1066 {
1067  if (auto cached = ipcache_get(name))
1068  cached->addrs.forgetMarking(name, addr);
1069 }
1070 
1072 static void
1073 ipcacheFreeEntry(void *data)
1074 {
1075  ipcache_entry *i = (ipcache_entry *)data;
1076  delete i;
1077 }
1078 
1080 {
1081  xfree(error_message);
1082  xfree(hash.key);
1083 }
1084 
1086 void
1088 {
1091  ip_table = NULL;
1092 }
1093 
1101 void
1103 {
1104  ipcache_high = (long) (((float) Config.ipcache.size *
1105  (float) Config.ipcache.high) / (float) 100);
1106  ipcache_low = (long) (((float) Config.ipcache.size *
1107  (float) Config.ipcache.low) / (float) 100);
1109 }
1110 
1122 int
1123 ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
1124 {
1125  ipcache_entry *i;
1126 
1127  Ip::Address ip;
1128 
1129  if (!(ip = ipaddr)) {
1130  if (strchr(ipaddr, ':') && strspn(ipaddr, "0123456789abcdefABCDEF:") == strlen(ipaddr)) {
1131  debugs(14, 3, "ipcacheAddEntryFromHosts: Skipping IPv6 address '" << ipaddr << "'");
1132  } else {
1133  debugs(14, DBG_IMPORTANT, "ERROR: ipcacheAddEntryFromHosts: Bad IP address '" << ipaddr << "'");
1134  }
1135 
1136  return 1;
1137  }
1138 
1139  if (!Ip::EnableIpv6 && ip.isIPv6()) {
1140  debugs(14, 2, "skips IPv6 address in /etc/hosts because IPv6 support was disabled: " << ip);
1141  return 1;
1142  }
1143 
1144  if ((i = ipcache_get(name))) {
1145  if (1 == i->flags.fromhosts) {
1146  ipcacheUnlockEntry(i);
1147  } else if (i->locks > 0) {
1148  debugs(14, DBG_IMPORTANT, "ERROR: ipcacheAddEntryFromHosts: cannot add static entry for locked name '" << name << "'");
1149  return 1;
1150  } else {
1151  ipcacheRelease(i);
1152  }
1153  }
1154 
1155  i = new ipcache_entry(name);
1156  i->addrs.pushUnique(ip);
1157  i->flags.fromhosts = true;
1158  ipcacheAddEntry(i);
1159  ipcacheLockEntry(i);
1160  return 0;
1161 }
1162 
1163 #if SQUID_SNMP
1164 
1169 variable_list *
1171 {
1172  variable_list *Answer = NULL;
1173  MemBuf tmp;
1174  debugs(49, 5, "snmp_netIpFn: Processing request:" << snmpDebugOid(Var->name, Var->name_length, tmp));
1175  *ErrP = SNMP_ERR_NOERROR;
1176 
1177  switch (Var->name[LEN_SQ_NET + 1]) {
1178 
1179  case IP_ENT:
1180  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1181  ipcacheCount(),
1182  SMI_GAUGE32);
1183  break;
1184 
1185  case IP_REQ:
1186  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1188  SMI_COUNTER32);
1189  break;
1190 
1191  case IP_HITS:
1192  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1194  SMI_COUNTER32);
1195  break;
1196 
1197  case IP_PENDHIT:
1198  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1199  0,
1200  SMI_GAUGE32);
1201  break;
1202 
1203  case IP_NEGHIT:
1204  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1206  SMI_COUNTER32);
1207  break;
1208 
1209  case IP_MISS:
1210  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1212  SMI_COUNTER32);
1213  break;
1214 
1215  case IP_GHBN:
1216  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1217  0, /* deprecated */
1218  SMI_COUNTER32);
1219  break;
1220 
1221  case IP_LOC:
1222  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1223  0, /* deprecated */
1224  SMI_COUNTER32);
1225  break;
1226 
1227  default:
1228  *ErrP = SNMP_ERR_NOSUCHNAME;
1229  snmp_var_free(Answer);
1230  return (NULL);
1231  }
1232 
1233  return Answer;
1234 }
1235 
1236 #endif /*SQUID_SNMP */
1237 
an old-style void* callback parameter
Definition: cbdata.h:377
static ipcache_entry * ipcache_get(const char *)
Definition: ipcache.cc:321
time_t lastref
Definition: ipcache.cc:138
bool fromhosts
Definition: ipcache.cc:150
CbcPointer< Dns::IpReceiver > receiverObj
gets incremental and final results
Definition: ipcache.cc:113
#define IP_LOOKUP_IF_MISS
Definition: defines.h:39
void markAsBad(const char *name, const Ip::Address &ip)
Definition: ipcache.cc:1010
SQUIDCEXTERN HASHHASH hash4
Definition: hash.h:46
#define RFC1035_TYPE_CNAME
Definition: rfc1035.h:94
const char * snmpDebugOid(oid *Name, snint Len, MemBuf &outbuf)
Definition: snmp_core.cc:1052
static void ipcacheUnlockEntry(ipcache_entry *)
Definition: ipcache.cc:914
static void ipcache_nbgethostbyname_(const char *name, IpCacheLookupForwarder handler)
implements ipcache_nbgethostbyname() and Dns::nbgethostbyname() APIs
Definition: ipcache.cc:614
#define DBG_CRITICAL
Definition: Stream.h:40
size_t goodPosition
position of the IP returned by current()
Definition: ipcache.h:100
static long ipcache_low
Definition: ipcache.cc:209
Cbc * valid() const
was set and is valid
Definition: CbcPointer.h:41
size_t badCount() const noexcept
bad IPs
Definition: ipcache.h:63
int ipcacheCount()
Definition: ipcache.cc:291
bool negcached
Definition: ipcache.cc:149
void FREE(void *)
Definition: forward.h:36
void ipcacheInvalidate(const char *name)
Definition: ipcache.cc:855
unsigned short rdlength
Definition: rfc1035.h:43
variable_list * snmp_netIpFn(variable_list *Var, snint *ErrP)
Definition: ipcache.cc:1170
time_t expires
Definition: ipcache.cc:139
static void handler(int signo)
Definition: purge.cc:854
static void purge_entries_fromhosts(void)
Definition: ipcache.cc:383
bool set() const
was set but may be invalid
Definition: CbcPointer.h:40
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:830
void error(char *format,...)
void ipcacheInvalidateNegative(const char *name)
Definition: ipcache.cc:872
bool sawCname
Definition: ipcache.cc:153
@ IP_GHBN
Definition: cache_snmp.h:195
#define CBDATA_CLASS(type)
Definition: cbdata.h:302
SQUIDCEXTERN void hash_remove_link(hash_table *, hash_link *)
Definition: hash.cc:220
IpCacheLookupForwarder handler
Definition: ipcache.cc:141
size_t size() const noexcept
all cached IPs
Definition: ipcache.h:62
#define xstrdup
const ipcache_addrs * ipcache_gethostbyname(const char *name, int flags)
Definition: ipcache.cc:719
bool fromHost(const char *hostWithoutPort)
Definition: Address.cc:898
bool valid() const
Definition: cbdata.h:388
bool have(const Ip::Address &ip, size_t *position=nullptr) const
Definition: ipcache.cc:973
CallbackData receiverData
caller-specific data for the handler (optional)
Definition: ipcache.cc:115
~ipcache_entry()
Definition: ipcache.cc:1079
void updateTtl(const unsigned int rrTtl)
Definition: ipcache.cc:538
int type
Definition: errorpage.cc:152
SQUIDCEXTERN void hashFreeItems(hash_table *, HASHFREE *)
Definition: hash.cc:252
dlink_node lru
Definition: ipcache.cc:144
int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
Definition: ipcache.cc:1123
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:230
int HASHCMP(const void *, const void *)
Definition: hash.h:13
void ipcache_restart(void)
Definition: ipcache.cc:1102
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:109
SQUIDCEXTERN void Tolower(char *)
Definition: util.c:28
@ IP_LOC
Definition: cache_snmp.h:196
ipcache_addrs addrs
Definition: ipcache.cc:140
SQUIDCEXTERN void hash_join(hash_table *, hash_link *)
Definition: hash.cc:131
SQUIDCEXTERN void hashFreeMemory(hash_table *)
Definition: hash.cc:268
static void ipcacheAddEntry(ipcache_entry *i)
Definition: ipcache.cc:419
static const Dns::CachedIps * ipcacheCheckNumeric(const char *name)
Definition: ipcache.cc:890
int additionalLookupDelay() const
milliseconds since the last lookup start or -1 if there were no lookups
hash_link hash
Definition: ipcache.cc:137
A const & max(A const &lhs, A const &rhs)
IPH * receiverFun
gets final results
Definition: ipcache.cc:114
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:51
bool empty() const noexcept
whether we cached no IPs at all
Definition: ipcache.h:61
const Storage & raw() const
all cached entries
Definition: ipcache.h:69
int name_length
Definition: snmp_vars.h:47
#define RFC1035_TYPE_A
Definition: rfc1035.h:93
@ IP_NEGHIT
Definition: cache_snmp.h:193
Flags()
Definition: ipcache.cc:147
#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:46
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:179
time of the idnsALookup() call
Definition: ipcache.cc:117
int size
Definition: ModDevPoll.cc:75
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:17
StatHist svcTime
Definition: StatCounters.h:98
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:606
#define NULL
Definition: types.h:166
static struct _ipcache_stats IpcacheStats
const char * text
Definition: errorpage.cc:153
@ IP_PENDHIT
Definition: cache_snmp.h:192
bool isIPv6() const
Definition: Address.cc:164
static IDNSCB ipcacheHandleReply
Definition: ipcache.cc:195
Definition: MemBuf.h:24
void ipcache_nbgethostbyname(const char *name, IPH *handler, void *handlerData)
Definition: ipcache.cc:599
Definition: ipcache.cc:130
#define SMI_GAUGE32
Definition: snmp_vars.h:77
@ IP_REQ
Definition: cache_snmp.h:190
struct variable_list * snmp_var_new_integer(oid *, int, int, unsigned char)
Definition: snmp_vars.c:151
time_t positiveDnsTtl
Definition: SquidConfig.h:104
#define safe_free(x)
Definition: xalloc.h:73
void count(double val)
Definition: StatHist.cc:55
#define assert(EX)
Definition: assert.h:19
@ IP_HITS
Definition: cache_snmp.h:191
static void ipcacheRelease(ipcache_entry *, bool dofree=true)
Definition: ipcache.cc:299
SQUIDCEXTERN const char * hashKeyStr(const hash_link *)
Definition: hash.cc:313
time_t negativeDnsTtl
Definition: SquidConfig.h:103
void pushUnique(const Ip::Address &ip)
Definition: ipcache.cc:991
int & recordCounter
where this kind of records are counted (for stats)
Definition: ipcache.cc:77
unsigned short locks
Definition: ipcache.cc:145
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:509
encapsulates DNS lookup results
Definition: LookupDetails.h:21
static hash_table * hash
Definition: text_backend.cc:41
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
#define RFC1035_TYPE_AAAA
Definition: rfc3596.h:53
struct SquidConfig::@106 ipcache
time_t squid_curtime
Definition: stub_libtime.cc:20
void ipcacheMarkGoodAddr(const char *name, const Ip::Address &addr)
Definition: ipcache.cc:1065
Storage ips
good and bad IPs
Definition: ipcache.h:97
void ipcacheFreeMemory(void)
Definition: ipcache.cc:1087
#define xfree
unsigned int ttl
Definition: rfc1035.h:42
const char * kind
human-friendly record type description
Definition: ipcache.cc:76
const char * name() const
Definition: ipcache.cc:155
Definition: ipcache.cc:146
void reportCurrent(std::ostream &os) const
prints current IP and other debugging information
Definition: ipcache.cc:999
void snmp_var_free(struct variable_list *)
Definition: snmp_vars.c:227
void ipcache_init(void)
Definition: ipcache.cc:686
static void ipcacheCallback(ipcache_entry *i, const bool hit, const int wait)
Definition: ipcache.cc:440
static void stat_ipcache_get(StoreEntry *)
Definition: ipcache.cc:811
static void ipcacheStatPrint(ipcache_entry *, StoreEntry *)
Definition: ipcache.cc:760
static FREE ipcacheFreeEntry
Definition: ipcache.cc:194
Content DataType
actual RR DATA type
Definition: ipcache.cc:75
static hash_table * ip_table
Definition: ipcache.cc:206
static void ipcacheRegisterWithCacheManager(void)
Definition: ipcache.cc:671
int totalResponseTime() const
Definition: ipcache.cc:105
#define LEN_SQ_NET
Definition: cache_snmp.h:49
void ipcacheMarkBadAddr(const char *name, const Ip::Address &addr)
Definition: ipcache.cc:1057
static dlink_list lru_list
Definition: ipcache.cc:189
void IDNSCB(void *cbdata, const rfc1035_rr *answer, const int recordsInAnswer, const char *error, bool lastAnswer)
Definition: forward.h:16
void restoreGoodness(const char *name)
makes current() calls possible after a successful markAsBad()
Definition: ipcache.cc:959
void forgetMarking(const char *name, const Ip::Address &ip)
undo successful markAsBad()
Definition: ipcache.cc:1030
#define Must(condition)
Definition: TextException.h:71
bool forwardIp(const Ip::Address &ip)
Definition: ipcache.cc:249
#define Important(id)
Definition: Messages.h:91
static void ipcacheParse(ipcache_entry *i, const rfc1035_rr *answers, int nr, const char *error_message)
Definition: ipcache.cc:463
#define DBG_IMPORTANT
Definition: Stream.h:41
static long ipcache_high
Definition: ipcache.cc:211
ipcache_entry(const char *)
Definition: ipcache.cc:406
bool seekNewGood(const char *name)
Definition: ipcache.cc:930
SQUIDCEXTERN hash_table * hash_create(HASHCMP *, int, HASHHASH *)
Definition: hash.cc:108
void reset(const Ip::Address &ip)
replace all info with the given (presumed good) IP address
Definition: ipcache.cc:947
void idnsALookup(const char *, IDNSCB *, void *)
static int ipcacheExpiredEntry(ipcache_entry *)
Definition: ipcache.cc:331
void latestError(const char *text, const int debugLevel=3)
remembers the last error seen, overwriting any previous errors
Definition: ipcache.cc:455
char * error_message
Definition: ipcache.cc:142
#define SNMP_ERR_NOSUCHNAME
Definition: snmp_error.h:44
static void ipcacheLockEntry(ipcache_entry *)
Definition: ipcache.cc:904
metadata for parsing DNS A and AAAA records
Definition: ipcache.cc:73
void * validDone()
Definition: cbdata.h:389
@ IP_ENT
Definition: cache_snmp.h:189
struct ipcache_entry::Flags flags
void ipcache_purgelru(void *)
Definition: ipcache.cc:350
void RegisterAction(char const *action, char const *desc, OBJH *handler, int pw_req_flag, int atomic)
Definition: Registration.cc:16
void forwardLookup(const char *error)
inform recipient of a finished lookup
Definition: ipcache.cc:277
SQUIDCEXTERN hash_link * hash_lookup(hash_table *, const void *)
Definition: hash.cc:146
int EnableIpv6
Whether IPv6 is supported and type of support.
Definition: tools.h:25
@ IP_MISS
Definition: cache_snmp.h:194
void lookupsStarting()
initialize lookup timestamps for Dns::LookupDetails delay calculation
Definition: ipcache.cc:99
#define false
Definition: GnuRegex.c:233
A const & min(A const &lhs, A const &rhs)
SQUIDCEXTERN int hashPrime(int n)
Definition: hash.cc:293
struct StatCounters::@132 dns
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
void forwardHits(const Dns::CachedIps &ips)
convenience wrapper to safely forwardIp() for each IP in the container
Definition: ipcache.cc:265
time of the last noteLookup() call
Definition: ipcache.cc:118
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:219
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:180

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors