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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors