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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors