dns_internal.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 78 DNS lookups; interacts with dns/rfc1035.cc */
10 
11 #include "squid.h"
12 #include "base/CodeContext.h"
13 #include "base/InstanceId.h"
14 #include "base/IoManip.h"
15 #include "base/Random.h"
16 #include "base/RunnersRegistry.h"
17 #include "comm.h"
18 #include "comm/Connection.h"
19 #include "comm/ConnOpener.h"
20 #include "comm/Loops.h"
21 #include "comm/Read.h"
22 #include "comm/Write.h"
23 #include "debug/Messages.h"
24 #include "dlink.h"
25 #include "dns/forward.h"
26 #include "dns/rfc3596.h"
27 #include "event.h"
28 #include "fd.h"
29 #include "fde.h"
30 #include "ip/tools.h"
31 #include "MemBuf.h"
32 #include "mgr/Registration.h"
33 #include "snmp_agent.h"
34 #include "SquidConfig.h"
35 #include "Store.h"
36 #include "tools.h"
37 #include "util.h"
38 #include "wordlist.h"
39 
40 #if SQUID_SNMP
41 #include "snmp_core.h"
42 #endif
43 
44 #if HAVE_ARPA_NAMESER_H
45 #include <arpa/nameser.h>
46 #endif
47 #include <cerrno>
48 #if HAVE_RESOLV_H
49 #include <resolv.h>
50 #endif
51 
52 #if _SQUID_WINDOWS_
53 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
54 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
55 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
56 #endif
57 #ifndef _PATH_RESCONF
58 #define _PATH_RESCONF "/etc/resolv.conf"
59 #endif
60 #ifndef NS_DEFAULTPORT
61 #define NS_DEFAULTPORT 53
62 #endif
63 
64 #ifndef NS_MAXDNAME
65 #define NS_MAXDNAME 1025
66 #endif
67 
68 #ifndef MAXDNSRCH
69 #define MAXDNSRCH 6
70 #endif
71 
72 /* The buffer size required to store the maximum allowed search path */
73 #ifndef RESOLV_BUFSZ
74 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
75 #endif
76 
77 #define IDNS_MAX_TRIES 20
78 #define MAX_RCODE 17
79 #define MAX_ATTEMPT 3
81 // NP: see http://www.iana.org/assignments/dns-parameters
82 static const char *Rcodes[] = {
83  /* RFC 1035 */
84  "Success",
85  "Packet Format Error",
86  "DNS Server Failure",
87  "Non-Existent Domain",
88  "Not Implemented",
89  "Query Refused",
90  /* RFC 2136 */
91  "Name Exists when it should not",
92  "RR Set Exists when it should not",
93  "RR Set that should exist does not",
94  "Server Not Authoritative for zone",
95  "Name not contained in zone",
96  /* unassigned */
97  "","","","","",
98  /* RFC 2671 */
99  "Bad OPT Version or TSIG Signature Failure"
100 };
101 
102 typedef struct _sp sp;
103 
105 {
107 
108 public:
110  codeContext(CodeContext::Current())
111  {
112  callback = nullptr;
113  memset(&query, 0, sizeof(query));
114  *buf = 0;
115  *name = 0;
116  *orig = 0;
117  memset(&start_t, 0, sizeof(start_t));
118  memset(&sent_t, 0, sizeof(sent_t));
119  memset(&queue_t, 0, sizeof(queue_t));
120  }
121 
123  if (message)
125  delete queue;
126  delete slave;
127  // master is just a back-reference
129  }
130 
134  char name[NS_MAXDNAME + 1];
135  char orig[NS_MAXDNAME + 1];
136  ssize_t sz = 0;
137  unsigned short query_id = 0;
139 
140  int nsends = 0;
141  int need_vc = 0;
142  bool permit_mdns = false;
143  int pending = 0;
144 
145  struct timeval start_t;
146  struct timeval sent_t;
147  struct timeval queue_t;
149 
151  void *callback_data = nullptr;
153 
154  int attempt = 0;
155  int rcode = 0;
156  idns_query *queue = nullptr;
157  idns_query *slave = nullptr; // single linked list
158  idns_query *master = nullptr; // single pointer to a shared master
159  unsigned short domain = 0;
160  unsigned short do_searchpath = 0;
162  int ancount = 0;
163  const char *error = nullptr;
164 };
165 
167 
169 
170 class nsvc
171 {
173 
174 public:
175  explicit nsvc(size_t nsv) : ns(nsv), msg(new MemBuf()), queue(new MemBuf()) {}
176  ~nsvc();
177 
178  size_t ns = 0;
180  unsigned short msglen = 0;
181  int read_msglen = 0;
182  MemBuf *msg = nullptr;
183  MemBuf *queue = nullptr;
184  bool busy = true;
185 };
186 
188 
189 class ns
190 {
191 public:
193  int nqueries = 0;
194  int nreplies = 0;
195 #if WHEN_EDNS_RESPONSES_ARE_PARSED
196  int last_seen_edns = 0;
197 #endif
198  bool mDNSResolver = false;
199  nsvc *vc = nullptr;
200 };
201 
202 namespace Dns
203 {
204 
207 {
208 public:
209  /* RegisteredRunner API */
210  void startReconfigure() override;
211  void endingShutdown() override;
212 };
213 
214 } // namespace Dns
215 
216 DefineRunnerRegistratorIn(Dns, ConfigRr);
217 
218 struct _sp {
220  int queries;
221 };
222 
223 static std::vector<ns> nameservers;
224 static sp *searchpath = nullptr;
225 static int nns_mdns_count = 0;
226 static int npc = 0;
227 static int npc_alloc = 0;
228 static int ndots = 1;
230 static int event_queued = 0;
231 static hash_table *idns_lookup_hash = nullptr;
232 
233 /*
234  * Notes on EDNS:
235  *
236  * Squid design:
237  * Squid is optimized to generate one packet and re-send it to all NS
238  * due to this we cannot customize the EDNS size per NS.
239  *
240  * As such we take the configuration option value as fixed.
241  *
242  * FUTURE TODO:
243  * This may not be worth doing, but if/when additional-records are parsed
244  * we will be able to recover the OPT value specific to any one NS and
245  * cache it. Effectively automating the tuning of EDNS advertised to the
246  * size our active NS are capable.
247  * Default would need to start with 512 bytes RFC1035 says every NS must accept.
248  * Responses from the configured NS may cause this to be raised or turned off.
249  */
250 #if WHEN_EDNS_RESPONSES_ARE_PARSED
251 static int max_shared_edns = RFC1035_DEFAULT_PACKET_SZ;
252 #endif
253 
255 static void idnsAddNameserver(const char *buf);
256 static void idnsAddMDNSNameservers();
257 static void idnsAddPathComponent(const char *buf);
258 static void idnsFreeSearchpath(void);
259 static bool idnsParseNameservers(void);
260 static bool idnsParseResolvConf(void);
261 #if _SQUID_WINDOWS_
262 static bool idnsParseWIN32Registry(void);
263 static void idnsParseWIN32SearchList(const char *);
264 #endif
265 static void idnsStartQuery(idns_query * q, IDNSCB * callback, void *data);
266 static void idnsSendQuery(idns_query * q);
268 static void idnsDoSendQueryVC(nsvc *vc);
272 
273 static int idnsFromKnownNameserver(Ip::Address const &from);
274 static idns_query *idnsFindQuery(unsigned short id);
275 static void idnsGrokReply(const char *buf, size_t sz, int from_ns);
276 static PF idnsRead;
278 static void idnsTickleQueue(void);
279 static void idnsRcodeCount(int, int);
281 static unsigned short idnsQueryID(void);
282 static void idnsSendSlaveAAAAQuery(idns_query *q);
283 static void idnsCallbackOnEarlyError(IDNSCB *callback, void *cbdata, const char *error);
284 
285 static void
287 {
288  if (!Config.onoff.dns_mdns || q->permit_mdns)
289  return;
290 
291  size_t slen = strlen(q->name);
292  if (slen > 6 && memcmp(q->name +(slen-6),".local", 6) == 0) {
293  q->permit_mdns = true;
294  }
295 }
296 
297 static void
299 {
300  nns_mdns_count=0;
301 
302  // mDNS is disabled
303  if (!Config.onoff.dns_mdns)
304  return;
305 
306  // mDNS resolver addresses are explicit multicast group IPs
307  if (Ip::EnableIpv6) {
308  idnsAddNameserver("FF02::FB");
309  nameservers.back().S.port(5353);
310  nameservers.back().mDNSResolver = true;
311  ++nns_mdns_count;
312  }
313 
314  idnsAddNameserver("224.0.0.251");
315  nameservers.back().S.port(5353);
316  nameservers.back().mDNSResolver = true;
317 
318  ++nns_mdns_count;
319 }
320 
321 static void
322 idnsAddNameserver(const char *buf)
323 {
324  Ip::Address A;
325 
326  if (!(A = buf)) {
327  debugs(78, DBG_CRITICAL, "WARNING: rejecting '" << buf << "' as a name server, because it is not a numeric IP address");
328  return;
329  }
330 
331  if (A.isAnyAddr()) {
332  debugs(78, DBG_CRITICAL, "WARNING: Squid does not accept " << A << " in DNS server specifications.");
333  A.setLocalhost();
334  debugs(78, DBG_CRITICAL, "Will be using " << A << " instead, assuming you meant that DNS is running on the same machine");
335  }
336 
337  if (!Ip::EnableIpv6 && !A.setIPv4()) {
338  debugs(78, DBG_IMPORTANT, "WARNING: IPv6 is disabled. Discarding " << A << " in DNS server specifications.");
339  return;
340  }
341 
342  auto &nameserver = nameservers.emplace_back(ns());
343  A.port(NS_DEFAULTPORT);
344  nameserver.S = A;
345 #if WHEN_EDNS_RESPONSES_ARE_PARSED
346  nameserver.last_seen_edns = RFC1035_DEFAULT_PACKET_SZ;
347  // TODO generate a test packet to probe this NS from EDNS size and ability.
348 #endif
349  debugs(78, 3, "Added nameserver #" << nameservers.size()-1 << " (" << A << ")");
350 }
351 
352 static void
353 idnsAddPathComponent(const char *buf)
354 {
355  if (npc == npc_alloc) {
356  int oldalloc = npc_alloc;
357  sp *oldptr = searchpath;
358 
359  if (0 == npc_alloc)
360  npc_alloc = 2;
361  else
362  npc_alloc <<= 1;
363 
364  searchpath = (sp *)xcalloc(npc_alloc, sizeof(*searchpath));
365 
366  if (oldptr && oldalloc)
367  memcpy(searchpath, oldptr, oldalloc * sizeof(*searchpath));
368 
369  if (oldptr)
370  safe_free(oldptr);
371  }
372 
373  assert(npc < npc_alloc);
374  strncpy(searchpath[npc].domain, buf, sizeof(searchpath[npc].domain)-1);
375  searchpath[npc].domain[sizeof(searchpath[npc].domain)-1] = '\0';
376  Tolower(searchpath[npc].domain);
377  debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc << ": " << searchpath[npc].domain);
378  ++npc;
379 }
380 
381 static void
383 {
385  npc = npc_alloc = 0;
386 }
387 
388 static bool
390 {
391  bool result = false;
392  for (auto &i : Config.dns.nameservers) {
393  debugs(78, Important(15), "Adding nameserver " << i << " from squid.conf");
394  idnsAddNameserver(i.c_str());
395  result = true;
396  }
397  return result;
398 }
399 
400 static bool
402 {
403  bool result = false;
404 #if !_SQUID_WINDOWS_
405  FILE *fp = fopen(_PATH_RESCONF, "r");
406 
407  if (!fp) {
408  int xerrno = errno;
409  debugs(78, DBG_IMPORTANT, "" << _PATH_RESCONF << ": " << xstrerr(xerrno));
410  return false;
411  }
412 
413  char buf[RESOLV_BUFSZ];
414  const char *t = nullptr;
415  while (fgets(buf, RESOLV_BUFSZ, fp)) {
416  t = strtok(buf, w_space);
417 
418  if (nullptr == t) {
419  continue;
420  } else if (strcmp(t, "nameserver") == 0) {
421  t = strtok(nullptr, w_space);
422 
423  if (nullptr == t)
424  continue;
425 
426  debugs(78, DBG_IMPORTANT, "Adding nameserver " << t << " from " << _PATH_RESCONF);
427 
429  result = true;
430  } else if (strcmp(t, "domain") == 0) {
432  t = strtok(nullptr, w_space);
433 
434  if (nullptr == t)
435  continue;
436 
437  debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from " << _PATH_RESCONF);
438 
440  } else if (strcmp(t, "search") == 0) {
442  while (nullptr != t) {
443  t = strtok(nullptr, w_space);
444 
445  if (nullptr == t)
446  continue;
447 
448  debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from " << _PATH_RESCONF);
449 
451  }
452  } else if (strcmp(t, "options") == 0) {
453  while (nullptr != t) {
454  t = strtok(nullptr, w_space);
455 
456  if (nullptr == t)
457  continue;
458 
459  if (strncmp(t, "ndots:", 6) == 0) {
460  ndots = atoi(t + 6);
461 
462  if (ndots < 1)
463  ndots = 1;
464 
465  debugs(78, DBG_IMPORTANT, "Adding ndots " << ndots << " from " << _PATH_RESCONF);
466  }
467  }
468  }
469  }
470  if (npc == 0 && (t = getMyHostname())) {
471  t = strchr(t, '.');
472  if (t)
474  }
475 
476  fclose(fp);
477 #endif
478  return result;
479 }
480 
481 #if _SQUID_WINDOWS_
482 static void
483 idnsParseWIN32SearchList(const char * Separator)
484 {
485  char *t;
486  char *token;
487  HKEY hndKey;
488 
489  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
490  DWORD Type = 0;
491  DWORD Size = 0;
492  LONG Result;
493  Result = RegQueryValueEx(hndKey, "Domain", nullptr, &Type, nullptr, &Size);
494 
495  if (Result == ERROR_SUCCESS && Size) {
496  t = (char *) xmalloc(Size);
497  RegQueryValueEx(hndKey, "Domain", nullptr, &Type, (LPBYTE) t, &Size);
498  debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from Registry");
500  xfree(t);
501  }
502  Result = RegQueryValueEx(hndKey, "SearchList", nullptr, &Type, nullptr, &Size);
503 
504  if (Result == ERROR_SUCCESS && Size) {
505  t = (char *) xmalloc(Size);
506  RegQueryValueEx(hndKey, "SearchList", nullptr, &Type, (LPBYTE) t, &Size);
507  token = strtok(t, Separator);
508 
509  while (token) {
510  idnsAddPathComponent(token);
511  debugs(78, DBG_IMPORTANT, "Adding domain " << token << " from Registry");
512  token = strtok(nullptr, Separator);
513  }
514  xfree(t);
515  }
516 
517  RegCloseKey(hndKey);
518  }
519  if (npc == 0 && (t = (char *) getMyHostname())) {
520  t = strchr(t, '.');
521  if (t)
522  idnsAddPathComponent(t + 1);
523  }
524 }
525 
526 static bool
527 idnsParseWIN32Registry(void)
528 {
529  char *t;
530  char *token;
531  HKEY hndKey, hndKey2;
532  bool result = false;
533 
534  switch (WIN32_OS_version) {
535 
536  case _WIN_OS_WINNT:
537  /* get nameservers from the Windows NT registry */
538 
539  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
540  DWORD Type = 0;
541  DWORD Size = 0;
542  LONG Result;
543  Result = RegQueryValueEx(hndKey, "DhcpNameServer", nullptr, &Type, nullptr, &Size);
544 
545  if (Result == ERROR_SUCCESS && Size) {
546  t = (char *) xmalloc(Size);
547  RegQueryValueEx(hndKey, "DhcpNameServer", nullptr, &Type, (LPBYTE) t, &Size);
548  token = strtok(t, ", ");
549 
550  while (token) {
551  idnsAddNameserver(token);
552  result = true;
553  debugs(78, DBG_IMPORTANT, "Adding DHCP nameserver " << token << " from Registry");
554  token = strtok(nullptr, ",");
555  }
556  xfree(t);
557  }
558 
559  Result = RegQueryValueEx(hndKey, "NameServer", nullptr, &Type, nullptr, &Size);
560 
561  if (Result == ERROR_SUCCESS && Size) {
562  t = (char *) xmalloc(Size);
563  RegQueryValueEx(hndKey, "NameServer", nullptr, &Type, (LPBYTE) t, &Size);
564  token = strtok(t, ", ");
565 
566  while (token) {
567  debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
568  idnsAddNameserver(token);
569  result = true;
570  token = strtok(nullptr, ", ");
571  }
572  xfree(t);
573  }
574 
575  RegCloseKey(hndKey);
576  }
577 
578  idnsParseWIN32SearchList(" ");
579 
580  break;
581 
582  case _WIN_OS_WIN2K:
583 
584  case _WIN_OS_WINXP:
585 
586  case _WIN_OS_WINNET:
587 
588  case _WIN_OS_WINLON:
589 
590  case _WIN_OS_WIN7:
591  /* get nameservers from the Windows 2000 registry */
592  /* search all interfaces for DNS server addresses */
593 
594  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA_INTERFACES, 0, KEY_READ, &hndKey) == ERROR_SUCCESS) {
595  int i;
596  DWORD MaxSubkeyLen, InterfacesCount;
597  char *keyname;
598  FILETIME ftLastWriteTime;
599 
600  if (RegQueryInfoKey(hndKey, nullptr, nullptr, nullptr, &InterfacesCount, &MaxSubkeyLen, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS) {
601  keyname = (char *) xmalloc(++MaxSubkeyLen);
602  for (i = 0; i < (int) InterfacesCount; ++i) {
603  DWORD j;
604  j = MaxSubkeyLen;
605  if (RegEnumKeyEx(hndKey, i, keyname, &j, nullptr, nullptr, nullptr, &ftLastWriteTime) == ERROR_SUCCESS) {
606  char *newkeyname;
607  newkeyname = (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES) + j + 2);
608  strcpy(newkeyname, REG_TCPIP_PARA_INTERFACES);
609  strcat(newkeyname, "\\");
610  strcat(newkeyname, keyname);
611  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newkeyname, 0, KEY_QUERY_VALUE, &hndKey2) == ERROR_SUCCESS) {
612  DWORD Type = 0;
613  DWORD Size = 0;
614  LONG Result;
615  Result = RegQueryValueEx(hndKey2, "DhcpNameServer", nullptr, &Type, nullptr, &Size);
616  if (Result == ERROR_SUCCESS && Size) {
617  t = (char *) xmalloc(Size);
618  RegQueryValueEx(hndKey2, "DhcpNameServer", nullptr, &Type, (LPBYTE)t, &Size);
619  token = strtok(t, ", ");
620  while (token) {
621  debugs(78, DBG_IMPORTANT, "Adding DHCP nameserver " << token << " from Registry");
622  idnsAddNameserver(token);
623  result = true;
624  token = strtok(nullptr, ", ");
625  }
626  xfree(t);
627  }
628 
629  Result = RegQueryValueEx(hndKey2, "NameServer", nullptr, &Type, nullptr, &Size);
630  if (Result == ERROR_SUCCESS && Size) {
631  t = (char *) xmalloc(Size);
632  RegQueryValueEx(hndKey2, "NameServer", nullptr, &Type, (LPBYTE)t, &Size);
633  token = strtok(t, ", ");
634  while (token) {
635  debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
636  idnsAddNameserver(token);
637  result = true;
638  token = strtok(nullptr, ", ");
639  }
640 
641  xfree(t);
642  }
643 
644  RegCloseKey(hndKey2);
645  }
646 
647  xfree(newkeyname);
648  }
649  }
650 
651  xfree(keyname);
652  }
653 
654  RegCloseKey(hndKey);
655  }
656 
657  idnsParseWIN32SearchList(", ");
658 
659  break;
660 
661  case _WIN_OS_WIN95:
662 
663  case _WIN_OS_WIN98:
664 
665  case _WIN_OS_WINME:
666  /* get nameservers from the Windows 9X registry */
667 
668  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_VXD_MSTCP, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
669  DWORD Type = 0;
670  DWORD Size = 0;
671  LONG Result;
672  Result = RegQueryValueEx(hndKey, "NameServer", nullptr, &Type, nullptr, &Size);
673 
674  if (Result == ERROR_SUCCESS && Size) {
675  t = (char *) xmalloc(Size);
676  RegQueryValueEx(hndKey, "NameServer", nullptr, &Type, (LPBYTE) t, &Size);
677  token = strtok(t, ", ");
678 
679  while (token) {
680  debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
681  idnsAddNameserver(token);
682  result = true;
683  token = strtok(nullptr, ", ");
684  }
685  xfree(t);
686  }
687 
688  RegCloseKey(hndKey);
689  }
690 
691  break;
692 
693  default:
694  debugs(78, DBG_IMPORTANT, "ERROR: Failed to read nameserver from Registry: Unknown System Type.");
695  }
696 
697  return result;
698 }
699 
700 #endif
701 
702 static void
704 {
705  dlink_node *n;
706  idns_query *q;
707  int i;
708  int j;
709  char buf[MAX_IPSTRLEN];
710  storeAppendPrintf(sentry, "Internal DNS Statistics:\n");
711  storeAppendPrintf(sentry, "\nThe Queue:\n");
712  storeAppendPrintf(sentry, " DELAY SINCE\n");
713  storeAppendPrintf(sentry, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
714  storeAppendPrintf(sentry, "------ ---- ----- ---------- --------- - ----\n");
715 
716  for (n = lru_list.head; n; n = n->next) {
717  q = (idns_query *)n->data;
718  storeAppendPrintf(sentry, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
719  (int) q->query_id, (int) q->sz, q->nsends,
722  (q->permit_mdns? 'M':' '),
723  q->name);
724  }
725 
726  if (Config.dns.packet_max > 0)
727  storeAppendPrintf(sentry, "\nDNS jumbo-grams: %zd Bytes\n", Config.dns.packet_max);
728  else
729  storeAppendPrintf(sentry, "\nDNS jumbo-grams: not working\n");
730 
731  storeAppendPrintf(sentry, "\nNameservers:\n");
732  storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES Type\n");
733  storeAppendPrintf(sentry, "---------------------------------------------- --------- --------- --------\n");
734 
735  for (const auto &server : nameservers) {
736  storeAppendPrintf(sentry, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
737  server.S.toStr(buf,MAX_IPSTRLEN),
738  server.nqueries,
739  server.nreplies,
740  server.mDNSResolver?"multicast":"recurse");
741  }
742 
743  storeAppendPrintf(sentry, "\nRcode Matrix:\n");
744  storeAppendPrintf(sentry, "RCODE");
745 
746  for (i = 0; i < MAX_ATTEMPT; ++i)
747  storeAppendPrintf(sentry, " ATTEMPT%d", i + 1);
748 
749  storeAppendPrintf(sentry, " PROBLEM\n");
750 
751  for (j = 0; j < MAX_RCODE; ++j) {
752  if (j > 10 && j < 16)
753  continue; // unassigned by IANA.
754 
755  storeAppendPrintf(sentry, "%5d", j);
756 
757  for (i = 0; i < MAX_ATTEMPT; ++i)
758  storeAppendPrintf(sentry, " %8d", RcodeMatrix[j][i]);
759 
760  storeAppendPrintf(sentry, " : %s\n",Rcodes[j]);
761  }
762 
763  if (npc) {
764  storeAppendPrintf(sentry, "\nSearch list:\n");
765 
766  for (i=0; i < npc; ++i)
767  storeAppendPrintf(sentry, "%s\n", searchpath[i].domain);
768 
769  storeAppendPrintf(sentry, "\n");
770  }
771 }
772 
773 static void
775 {
776  if (event_queued)
777  return;
778 
779  if (nullptr == lru_list.tail)
780  return;
781 
782  const double when = min(Config.Timeout.idns_query, Config.Timeout.idns_retransmit)/1000.0;
783 
784  eventAdd("idnsCheckQueue", idnsCheckQueue, nullptr, when, 1);
785 
786  event_queued = 1;
787 }
788 
789 static void
790 idnsSentQueryVC(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int, void *data)
791 {
792  nsvc * vc = (nsvc *)data;
793 
794  if (flag == Comm::ERR_CLOSING)
795  return;
796 
797  // XXX: irrelevant now that we have conn pointer?
798  if (!Comm::IsConnOpen(conn) || fd_table[conn->fd].closing())
799  return;
800 
801  if (flag != Comm::OK || size <= 0) {
802  conn->close();
803  return;
804  }
805 
806  vc->busy = 0;
807  idnsDoSendQueryVC(vc);
808 }
809 
810 static void
812 {
813  if (vc->busy)
814  return;
815 
816  if (vc->queue->contentSize() == 0)
817  return;
818 
819  // if retrying after a TC UDP response, our close handler cb may be pending
820  if (fd_table[vc->conn->fd].closing())
821  return;
822 
823  MemBuf *mb = vc->queue;
824 
825  vc->queue = new MemBuf;
826 
827  vc->busy = 1;
828 
829  // Comm needs seconds but idnsCheckQueue() will check the exact timeout
830  const auto timeout = (Config.Timeout.idns_query % 1000 ?
832  AsyncCall::Pointer nil;
833 
834  commSetConnTimeout(vc->conn, timeout, nil);
835 
836  AsyncCall::Pointer call = commCbCall(78, 5, "idnsSentQueryVC",
838  Comm::Write(vc->conn, mb, call);
839 
840  delete mb;
841 }
842 
843 static void
844 idnsInitVCConnected(const Comm::ConnectionPointer &conn, Comm::Flag status, int, void *data)
845 {
846  nsvc * vc = (nsvc *)data;
847 
848  if (status != Comm::OK || !conn) {
849  char buf[MAX_IPSTRLEN] = "";
850  if (vc->ns < nameservers.size())
851  nameservers[vc->ns].S.toStr(buf,MAX_IPSTRLEN);
852  debugs(78, DBG_IMPORTANT, "ERROR: Failed to connect to nameserver " << buf << " using TCP.");
853  delete vc;
854  return;
855  }
856 
857  vc->conn = conn;
858 
860  AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
862  comm_read(conn, (char *)&vc->msglen, 2, call);
863  vc->busy = 0;
864  idnsDoSendQueryVC(vc);
865 }
866 
867 static void
869 {
870  nsvc * vc = (nsvc *)params.data;
871  if (vc->conn) {
872  vc->conn->noteClosure();
873  vc->conn = nullptr;
874  }
875  delete vc;
876 }
877 
879 {
880  delete queue;
881  delete msg;
882  // we may outlive nameservers version that was pointing to us because
883  // reconfigurations repopulate nameservers
884  if (ns < nameservers.size() && nameservers[ns].vc == this)
885  nameservers[ns].vc = nullptr;
886 }
887 
888 static void
889 idnsInitVC(size_t nsv)
890 {
891  assert(nsv < nameservers.size());
892  nsvc *vc = new nsvc(nsv);
893  assert(vc->conn == nullptr); // MUST be NULL from the construction process!
894  nameservers[nsv].vc = vc;
895 
897 
900  else
902 
903  if (conn->remote.isIPv4())
904  conn->local.setIPv4();
905 
906  AsyncCall::Pointer call = commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected, vc));
907 
908  Comm::ConnOpener *cs = new Comm::ConnOpener(conn, call, Config.Timeout.connect);
909  cs->setHost("DNS TCP Socket");
910  AsyncJob::Start(cs);
911 }
912 
913 static void
914 idnsSendQueryVC(idns_query * q, size_t nsn)
915 {
916  assert(nsn < nameservers.size());
917  if (nameservers[nsn].vc == nullptr)
918  idnsInitVC(nsn);
919 
920  nsvc *vc = nameservers[nsn].vc;
921 
922  if (!vc) {
923  char buf[MAX_IPSTRLEN];
924  debugs(78, DBG_IMPORTANT, "ERROR: idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers[nsn].S.toStr(buf,MAX_IPSTRLEN) << "!");
925 
926  return;
927  }
928 
929  if (vc->queue->isNull())
930  vc->queue->init();
931 
932  const auto serialiedQuerySize = 2 + q->sz + 1; // payload_length + payload + terminate()
933  if (vc->queue->potentialSpaceSize() < serialiedQuerySize) {
934  // header + payload + MemBuf terminator exceed maximum space size
935  debugs(78, DBG_IMPORTANT, "ERROR: Dropping DNS query due to insufficient buffer space for DNS over TCP query queue" <<
936  Debug::Extra << "query: " << q->name <<
937  Debug::Extra << "nameserver: " << nameservers[nsn].S <<
938  Debug::Extra << "used space: " << vc->queue->contentSize() <<
939  Debug::Extra << "remaining space: " << vc->queue->potentialSpaceSize() <<
940  Debug::Extra << "required space: " << serialiedQuerySize);
941  return; // the query will timeout and either fail or be retried
942  }
943 
944  short head = htons(q->sz);
945 
946  vc->queue->append((char *)&head, 2);
947 
948  vc->queue->append(q->buf, q->sz);
949 
950  idnsDoSendQueryVC(vc);
951 }
952 
953 static void
955 {
956  // XXX: DNS sockets get closed during reconfigure produces a race between
957  // any already active connections (or ones received between closing DNS
958  // sockets and server listening sockets) and the reconfigure completing
959  // (Runner syncConfig() being run). Transactions which loose this race will
960  // produce DNS timeouts (or whatever the caller set) as their queries never
961  // get queued to be re-tried after the DNS socekts are re-opened.
962 
963  if (DnsSocketA < 0 && DnsSocketB < 0) {
964  debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
965  return;
966  }
967 
968  if (nameservers.empty()) {
969  debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
970  return;
971  }
972 
973  assert(q->lru.next == nullptr);
974 
975  assert(q->lru.prev == nullptr);
976 
977  int x = -1, y = -1;
978  size_t nsn;
979  const auto nsCount = nameservers.size();
980 
981  do {
982  // only use mDNS resolvers for mDNS compatible queries
983  if (!q->permit_mdns)
984  nsn = nns_mdns_count + q->nsends % (nsCount - nns_mdns_count);
985  else
986  nsn = q->nsends % nsCount;
987 
988  if (q->need_vc) {
989  idnsSendQueryVC(q, nsn);
990  x = y = 0;
991  } else {
992  if (DnsSocketB >= 0 && nameservers[nsn].S.isIPv6())
993  y = comm_udp_sendto(DnsSocketB, nameservers[nsn].S, q->buf, q->sz);
994  else if (DnsSocketA >= 0)
995  x = comm_udp_sendto(DnsSocketA, nameservers[nsn].S, q->buf, q->sz);
996  }
997  int xerrno = errno;
998 
999  ++ q->nsends;
1000 
1001  q->sent_t = current_time;
1002 
1003  if (y < 0 && nameservers[nsn].S.isIPv6())
1004  debugs(50, DBG_IMPORTANT, MYNAME << "FD " << DnsSocketB << ": sendto: " << xstrerr(xerrno));
1005  if (x < 0 && nameservers[nsn].S.isIPv4())
1006  debugs(50, DBG_IMPORTANT, MYNAME << "FD " << DnsSocketA << ": sendto: " << xstrerr(xerrno));
1007 
1008  } while ( (x<0 && y<0) && q->nsends % nsCount != 0);
1009 
1010  if (y > 0) {
1012  }
1013  if (x > 0) {
1015  }
1016 
1017  ++ nameservers[nsn].nqueries;
1018  q->queue_t = current_time;
1019  dlinkAdd(q, &q->lru, &lru_list);
1020  q->pending = 1;
1021  idnsTickleQueue();
1022 }
1023 
1024 static int
1026 {
1027  for (int i = 0; static_cast<size_t>(i) < nameservers.size(); ++i) {
1028  if (nameservers[i].S != from)
1029  continue;
1030 
1031  if (nameservers[i].S.port() != from.port())
1032  continue;
1033 
1034  return i;
1035  }
1036 
1037  return -1;
1038 }
1039 
1040 static idns_query *
1041 idnsFindQuery(unsigned short id)
1042 {
1043  dlink_node *n;
1044  idns_query *q;
1045 
1046  for (n = lru_list.tail; n; n = n->prev) {
1047  q = (idns_query*)n->data;
1048 
1049  if (q->query_id == id)
1050  return q;
1051  }
1052 
1053  return nullptr;
1054 }
1055 
1056 static unsigned short
1058 {
1059  // NP: apparently ranlux are faster, but not quite as "proven"
1060  static std::mt19937 mt(RandomSeed32());
1061  unsigned short id = mt() & 0xFFFF;
1062  unsigned short first_id = id;
1063 
1064  // ensure temporal uniqueness by looking for an existing use
1065  while (idnsFindQuery(id)) {
1066  ++id;
1067 
1068  if (id == first_id) {
1069  debugs(78, DBG_IMPORTANT, "WARNING: idnsQueryID: too many pending DNS requests");
1070  break;
1071  }
1072  }
1073 
1074  return id;
1075 }
1076 
1078 static bool
1080 {
1081  assert(!master->master); // we were given the master transaction
1082  for (const idns_query *qi = master; qi; qi = qi->slave) {
1083  if (qi->pending)
1084  return true;
1085  }
1086  return false;
1087 }
1088 
1089 static std::ostream &
1090 operator <<(std::ostream &os, const idns_query &answered)
1091 {
1092  if (answered.error)
1093  os << "error \"" << answered.error << "\"";
1094  else
1095  os << answered.ancount << " records";
1096  return os;
1097 }
1098 
1099 static void
1100 idnsCallbackOnEarlyError(IDNSCB *callback, void *cbdata, const char *error)
1101 {
1102  // A cbdataReferenceValid() check asserts on unlocked cbdata: Early errors,
1103  // by definition, happen before we store/cbdataReference() cbdata.
1104  debugs(78, 6, "\"" << error << "\" for " << cbdata);
1105  callback(cbdata, nullptr, 0, "Internal error", true); // hide error details
1106 }
1107 
1109 static bool
1110 idnsCallbackOneWithAnswer(IDNSCB *callback, void *cbdata, const idns_query &answered, const bool lastAnswer)
1111 {
1113  return false;
1114  const rfc1035_rr *records = answered.message ? answered.message->answer : nullptr;
1115  debugs(78, 6, (lastAnswer ? "last " : "") << answered << " for " << cbdata);
1116  callback(cbdata, records, answered.ancount, answered.error, lastAnswer);
1117  return true;
1118 }
1119 
1120 static void
1121 idnsCallbackNewCallerWithOldAnswers(IDNSCB *callback, void *cbdata, const idns_query * const master)
1122 {
1123  const bool lastAnswer = false;
1124  // iterate all queries to act on answered ones
1125  for (auto query = master; query; query = query->slave) {
1126  if (query->pending)
1127  continue; // no answer yet
1128  // no CallBack(CodeContext...) -- we always run in requestor's context
1129  if (!idnsCallbackOneWithAnswer(callback, cbdata, *query, lastAnswer))
1130  break; // the caller disappeared
1131  }
1132 }
1133 
1134 static void
1135 idnsCallbackAllCallersWithNewAnswer(const idns_query * const answered, const bool lastAnswer)
1136 {
1137  debugs(78, 8, (lastAnswer ? "last " : "") << *answered);
1138  const auto master = answered->master ? answered->master : answered;
1139  // iterate all queued lookup callers
1140  for (auto looker = master; looker; looker = looker->queue) {
1141  CallBack(looker->codeContext, [&] {
1142  (void)idnsCallbackOneWithAnswer(looker->callback, looker->callback_data,
1143  *answered, lastAnswer);
1144  });
1145  }
1146 }
1147 
1148 static void
1150 {
1151  if (error)
1152  q->error = error;
1153 
1154  auto master = q->master ? q->master : q;
1155 
1156  const bool lastAnswer = !idnsStillPending(master);
1157  idnsCallbackAllCallersWithNewAnswer(q, lastAnswer);
1158 
1159  if (!lastAnswer)
1160  return; // wait for more answers
1161 
1162  if (master->hash.key) {
1164  master->hash.key = nullptr;
1165  }
1166 
1167  delete master;
1168 }
1169 
1170 static void
1171 idnsGrokReply(const char *buf, size_t sz, int /*from_ns*/)
1172 {
1173  rfc1035_message *message = nullptr;
1174 
1175  int n = rfc1035MessageUnpack(buf, sz, &message);
1176 
1177  if (message == nullptr) {
1178  debugs(78, DBG_IMPORTANT, "ERROR: idnsGrokReply: Malformed DNS response");
1179  return;
1180  }
1181 
1182  debugs(78, 3, "idnsGrokReply: QID 0x" << asHex(message->id) << ", " << n << " answers");
1183 
1184  idns_query *q = idnsFindQuery(message->id);
1185 
1186  if (q == nullptr) {
1187  debugs(78, 3, "idnsGrokReply: Late response");
1188  rfc1035MessageDestroy(&message);
1189  return;
1190  }
1191 
1192  if (rfc1035QueryCompare(&q->query, message->query) != 0) {
1193  debugs(78, 3, "idnsGrokReply: Query mismatch (" << q->query.name << " != " << message->query->name << ")");
1194  rfc1035MessageDestroy(&message);
1195  return;
1196  }
1197 
1198 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1199 // TODO: actually gr the message right here.
1200 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1201 // this is overall better than force-feeding A response with AAAA an section later anyway.
1202 // AND allows us to merge AN+AR sections from both responses (one day)
1203 
1204  if (q->edns_seen >= 0) {
1205  if (max_shared_edns == nameservers[from_ns].last_seen_edns && max_shared_edns < q->edns_seen) {
1206  nameservers[from_ns].last_seen_edns = q->edns_seen;
1207  // the altered NS was limiting the whole group.
1208  max_shared_edns = q->edns_seen;
1209  // may be limited by one of the others still
1210  for (const auto &server : nameservers)
1211  max_shared_edns = min(max_shared_edns, server.last_seen_edns);
1212  } else {
1213  nameservers[from_ns].last_seen_edns = q->edns_seen;
1214  // maybe reduce the global limit downwards to accommodate this NS
1215  max_shared_edns = min(max_shared_edns, q->edns_seen);
1216  }
1217  if (max_shared_edns < RFC1035_DEFAULT_PACKET_SZ)
1218  max_shared_edns = -1;
1219  }
1220 #endif
1221 
1222  dlinkDelete(&q->lru, &lru_list);
1223  q->pending = 0;
1224 
1225  if (message->tc) {
1226  debugs(78, 3, "Resolver requested TC (" << q->query.name << ")");
1227  rfc1035MessageDestroy(&message);
1228 
1229  if (!q->need_vc) {
1230  q->need_vc = 1;
1231  -- q->nsends;
1232  idnsSendQuery(q);
1233  } else {
1234  // Strange: A TCP DNS response with the truncation bit (TC) set.
1235  // Return an error and cleanup; no point in trying TCP again.
1236  debugs(78, 3, "TCP DNS response");
1237  idnsCallback(q, "Truncated TCP DNS response");
1238  }
1239 
1240  return;
1241  }
1242 
1243  idnsRcodeCount(n, q->attempt);
1244 
1245  if (n < 0) {
1246  q->rcode = -n;
1247  debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n) << " (" << q->rcode << ")");
1248 
1249  if (q->rcode == 2 && (++ q->attempt) < MAX_ATTEMPT) {
1250  /*
1251  * RCODE 2 is "Server failure - The name server was
1252  * unable to process this query due to a problem with
1253  * the name server."
1254  */
1255  debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1256  rfc1035MessageDestroy(&message);
1257  idnsSendQuery(q);
1258  return;
1259  }
1260 
1261  // Do searchpath processing on the master A query only to keep
1262  // things simple. NXDOMAIN is authoritative for the label, not
1263  // the record type.
1264  if (q->rcode == 3 && !q->master && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
1265  assert(nullptr == message->answer);
1266  strcpy(q->name, q->orig);
1267 
1268  debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q->name );
1269 
1270  if (q->domain < npc) {
1271  strcat(q->name, ".");
1272  strcat(q->name, searchpath[q->domain].domain);
1273  debugs(78, 3, "idnsGrokReply: searchpath used for " << q->name);
1274  ++ q->domain;
1275  } else {
1276  ++ q->attempt;
1277  }
1278 
1279  rfc1035MessageDestroy(&message);
1280 
1281  // cleanup slave AAAA query
1282  while (idns_query *slave = q->slave) {
1283  dlinkDelete(&slave->lru, &lru_list);
1284  q->slave = slave->slave;
1285  slave->slave = nullptr;
1286  delete slave;
1287  }
1288 
1289  // Build new query
1290  q->query_id = idnsQueryID();
1291  debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
1292  q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query);
1293  if (q->sz < 0) {
1294  /* problem with query data -- query not sent */
1295  idnsCallback(q, "Internal error");
1296  return;
1297  }
1298 
1299  q->nsends = 0;
1300 
1301  idnsCheckMDNS(q);
1302  idnsSendQuery(q);
1303  if (Ip::EnableIpv6)
1305  return;
1306  }
1307  }
1308 
1309  q->message = message;
1310  q->ancount = n;
1311 
1312  if (n >= 0)
1313  idnsCallback(q, nullptr);
1314  else
1316 
1317 }
1318 
1319 static void
1320 idnsRead(int fd, void *)
1321 {
1322  int *N = &incoming_sockets_accepted;
1323  int len;
1324  int max = INCOMING_DNS_MAX;
1325  static char rbuf[SQUID_UDP_SO_RCVBUF];
1326  Ip::Address from;
1327 
1328  debugs(78, 3, "idnsRead: starting with FD " << fd);
1329 
1330  // Always keep reading. This stops (or at least makes harder) several
1331  // attacks on the DNS client.
1332  Comm::SetSelect(fd, COMM_SELECT_READ, idnsRead, nullptr, 0);
1333 
1334  /* BUG (UNRESOLVED)
1335  * two code lines after returning from comm_udprecvfrom()
1336  * something overwrites the memory behind the from parameter.
1337  * NO matter where in the stack declaration list above it is placed
1338  * The cause of this is still unknown, however copying the data appears
1339  * to allow it to be passed further without this erasure.
1340  */
1341  Ip::Address bugbypass;
1342 
1343  while (max) {
1344  --max;
1345  len = comm_udp_recvfrom(fd, rbuf, SQUID_UDP_SO_RCVBUF, 0, bugbypass);
1346 
1347  from = bugbypass; // BUG BYPASS. see notes above.
1348 
1349  if (len == 0)
1350  break;
1351 
1352  if (len < 0) {
1353  int xerrno = errno;
1354  if (ignoreErrno(xerrno))
1355  break;
1356 
1357 #if _SQUID_LINUX_
1358  /* Some Linux systems seem to set the FD for reading and then
1359  * return ECONNREFUSED when sendto() fails and generates an ICMP
1360  * port unreachable message. */
1361  /* or maybe an EHOSTUNREACH "No route to host" message */
1362  if (xerrno != ECONNREFUSED && xerrno != EHOSTUNREACH)
1363 #endif
1364  debugs(50, DBG_IMPORTANT, MYNAME << "FD " << fd << " recvfrom: " << xstrerr(xerrno));
1365 
1366  break;
1367  }
1368 
1369  fd_bytes(fd, len, IoDirection::Read);
1370 
1371  assert(N);
1372  ++(*N);
1373 
1374  debugs(78, 3, "idnsRead: FD " << fd << ": received " << len << " bytes from " << from);
1375 
1376  /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1377  int nsn = idnsFromKnownNameserver(from);
1378 
1379  if (nsn >= 0) {
1380  ++ nameservers[nsn].nreplies;
1381  }
1382 
1383  // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1384  // but after the ++ above to keep statistics right.
1385  if (!lru_list.head)
1386  continue; // Don't process replies if there is no pending query.
1387 
1388  if (nsn < 0 && Config.onoff.ignore_unknown_nameservers) {
1389  static time_t last_warning = 0;
1390 
1391  if (squid_curtime - last_warning > 60) {
1392  debugs(78, DBG_IMPORTANT, "WARNING: Reply from unknown nameserver " << from);
1393  last_warning = squid_curtime;
1394  } else {
1395  debugs(78, DBG_IMPORTANT, "WARNING: Reply from unknown nameserver " << from << " (retrying..." << (squid_curtime-last_warning) << "<=60)" );
1396  }
1397  continue;
1398  }
1399 
1400  idnsGrokReply(rbuf, len, nsn);
1401  }
1402 }
1403 
1404 static void
1406 {
1407  dlink_node *n;
1408  dlink_node *p = nullptr;
1409  idns_query *q;
1410  event_queued = 0;
1411 
1412  if (nameservers.empty())
1413  /* name servers went away; reconfiguring or shutting down */
1414  return;
1415 
1416  const auto nsCount = nameservers.size();
1417  for (n = lru_list.tail; n; n = p) {
1418 
1419  p = n->prev;
1420  q = static_cast<idns_query*>(n->data);
1421 
1422  /* Anything to process in the queue? */
1424  break;
1425 
1426  /* Query timer still running? */
1427  if ((time_msec_t)tvSubMsec(q->sent_t, current_time) < (Config.Timeout.idns_retransmit * 1 << ((q->nsends - 1) / nsCount))) {
1428  dlinkDelete(&q->lru, &lru_list);
1429  q->queue_t = current_time;
1430  dlinkAdd(q, &q->lru, &lru_list);
1431  continue;
1432  }
1433 
1434  debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
1435  " QID 0x" << asHex(q->query_id).minDigits(4) << ": timeout");
1436 
1437  dlinkDelete(&q->lru, &lru_list);
1438  q->pending = 0;
1439 
1441  idnsSendQuery(q);
1442  } else {
1443  debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
1444  " QID 0x" << asHex(q->query_id) <<
1445  ": giving up after " << q->nsends << " tries and " <<
1446  std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
1447 
1448  if (q->rcode != 0)
1450  else
1451  idnsCallback(q, "Timeout");
1452  }
1453  }
1454 
1455  idnsTickleQueue();
1456 }
1457 
1458 static void
1459 idnsReadVC(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int, void *data)
1460 {
1461  nsvc * vc = (nsvc *)data;
1462 
1463  if (flag == Comm::ERR_CLOSING)
1464  return;
1465 
1466  if (flag != Comm::OK || len <= 0) {
1467  if (Comm::IsConnOpen(conn))
1468  conn->close();
1469  return;
1470  }
1471 
1472  vc->msg->size += len; // XXX should not access -> size directly
1473 
1474  if (vc->msg->contentSize() < vc->msglen) {
1475  AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1476  CommIoCbPtrFun(idnsReadVC, vc));
1477  comm_read(conn, buf+len, vc->msglen - vc->msg->contentSize(), call);
1478  return;
1479  }
1480 
1481  assert(vc->ns < nameservers.size());
1482  debugs(78, 3, conn << ": received " << vc->msg->contentSize() << " bytes via TCP from " << nameservers[vc->ns].S << ".");
1483 
1484  idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
1485  vc->msg->clean();
1486  AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1488  comm_read(conn, (char *)&vc->msglen, 2, call);
1489 }
1490 
1491 static void
1492 idnsReadVCHeader(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int, void *data)
1493 {
1494  nsvc * vc = (nsvc *)data;
1495 
1496  if (flag == Comm::ERR_CLOSING)
1497  return;
1498 
1499  if (flag != Comm::OK || len <= 0) {
1500  if (Comm::IsConnOpen(conn))
1501  conn->close();
1502  return;
1503  }
1504 
1505  vc->read_msglen += len;
1506 
1507  assert(vc->read_msglen <= 2);
1508 
1509  if (vc->read_msglen < 2) {
1510  AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1512  comm_read(conn, buf+len, 2 - vc->read_msglen, call);
1513  return;
1514  }
1515 
1516  vc->read_msglen = 0;
1517 
1518  vc->msglen = ntohs(vc->msglen);
1519 
1520  if (!vc->msglen) {
1521  if (Comm::IsConnOpen(conn))
1522  conn->close();
1523  return;
1524  }
1525 
1526  vc->msg->init(vc->msglen, vc->msglen);
1527  AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1528  CommIoCbPtrFun(idnsReadVC, vc));
1529  comm_read(conn, vc->msg->buf, vc->msglen, call);
1530 }
1531 
1532 /*
1533  * rcode < 0 indicates an error, rocde >= 0 indicates success
1534  */
1535 static void
1536 idnsRcodeCount(int rcode, int attempt)
1537 {
1538  if (rcode > 0)
1539  rcode = 0;
1540  else if (rcode < 0)
1541  rcode = -rcode;
1542 
1543  if (rcode < MAX_RCODE)
1544  if (attempt < MAX_ATTEMPT)
1545  ++ RcodeMatrix[rcode][attempt];
1546 }
1547 
1548 void
1550 {
1551  static int init = 0;
1552 
1553  if (DnsSocketA < 0 && DnsSocketB < 0) {
1554  Ip::Address addrV6; // since we do not want to alter Config.Addrs.udp_* and do not have one of our own.
1555 
1557  addrV6 = Config.Addrs.udp_outgoing;
1558  else
1559  addrV6 = Config.Addrs.udp_incoming;
1560 
1561  Ip::Address addrV4 = addrV6;
1562  addrV4.setIPv4();
1563 
1564  if (Ip::EnableIpv6 && addrV6.isIPv6()) {
1565  debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6);
1566  DnsSocketB = comm_open_listener(SOCK_DGRAM,
1567  IPPROTO_UDP,
1568  addrV6,
1570  "DNS Socket IPv6");
1571  }
1572 
1573  if (addrV4.isIPv4()) {
1574  debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4);
1575  DnsSocketA = comm_open_listener(SOCK_DGRAM,
1576  IPPROTO_UDP,
1577  addrV4,
1579  "DNS Socket IPv4");
1580  }
1581 
1582  if (DnsSocketA < 0 && DnsSocketB < 0)
1583  fatal("Could not create a DNS socket");
1584 
1585  /* Ouch... we can't call functions using debug from a debug
1586  * statement. Doing so messes up the internal Debug::level
1587  */
1588  if (DnsSocketB >= 0) {
1590  debugs(78, Important(16), "DNS IPv6 socket created at " << addrV6 << ", FD " << DnsSocketB);
1592  }
1593  if (DnsSocketA >= 0) {
1595  debugs(78, Important(64), "DNS IPv4 socket created at " << addrV4 << ", FD " << DnsSocketA);
1597  }
1598  }
1599 
1600  assert(nameservers.empty());
1602  bool nsFound = idnsParseNameservers();
1603 
1604  if (!nsFound)
1605  nsFound = idnsParseResolvConf();
1606 
1607 #if _SQUID_WINDOWS_
1608  if (!nsFound)
1609  nsFound = idnsParseWIN32Registry();
1610 #endif
1611 
1612  if (!nsFound) {
1613  debugs(78, DBG_IMPORTANT, "WARNING: Could not find any nameservers. Trying to use localhost");
1614 #if _SQUID_WINDOWS_
1615  debugs(78, DBG_IMPORTANT, "Please check your TCP-IP settings or /etc/resolv.conf file");
1616 #else
1617  debugs(78, DBG_IMPORTANT, "Please check your /etc/resolv.conf file");
1618 #endif
1619 
1620  debugs(78, DBG_IMPORTANT, "or use the 'dns_nameservers' option in squid.conf.");
1621  if (Ip::EnableIpv6)
1622  idnsAddNameserver("::1");
1623  idnsAddNameserver("127.0.0.1");
1624  }
1625 
1626  if (!init) {
1627  memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
1628  idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
1629  ++init;
1630  }
1631 
1632 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1633  if (Config.onoff.ignore_unknown_nameservers && max_shared_edns > 0) {
1634  debugs(0, DBG_IMPORTANT, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1635  max_shared_edns = -1; // disable if we might receive random replies.
1636  }
1637 #endif
1638 
1639  Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
1640 }
1641 
1642 static void
1643 idnsShutdownAndFreeState(const char *reason)
1644 {
1645  if (DnsSocketA < 0 && DnsSocketB < 0)
1646  return;
1647 
1648  debugs(78, 2, reason << ": Closing DNS sockets");
1649 
1650  if (DnsSocketA >= 0 ) {
1652  DnsSocketA = -1;
1653  }
1654 
1655  if (DnsSocketB >= 0 ) {
1657  DnsSocketB = -1;
1658  }
1659 
1660  for (const auto &server : nameservers) {
1661  if (const auto vc = server.vc) {
1662  if (Comm::IsConnOpen(vc->conn))
1663  vc->conn->close();
1664  }
1665  }
1666 
1667  // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1668  nameservers.clear();
1670 }
1671 
1672 void
1674 {
1675  idnsShutdownAndFreeState("Shutdown");
1676 }
1677 
1678 void
1680 {
1681  idnsShutdownAndFreeState("Reconfigure");
1682 }
1683 
1684 static int
1685 idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1686 {
1688 
1689  if (!old)
1690  return 0;
1691 
1692  // XXX: We are collapsing this DNS query (B) onto another one (A), but there
1693  // is no code to later send B if the A answer has unshareable 0 TTL records.
1694 
1695  idns_query *q = new idns_query;
1696  // no query_id on this instance.
1697 
1698  q->callback = callback;
1699  q->callback_data = cbdataReference(data);
1700 
1701  q->queue = old->queue;
1702  old->queue = q;
1703 
1704  // This check must follow cbdataReference() above because our callback code
1705  // needs a locked cbdata to call cbdataReferenceValid().
1706  if (idnsStillPending(old))
1707  idnsCallbackNewCallerWithOldAnswers(callback, data, old);
1708  // else: idns_lookup_hash is not a cache so no pending lookups means we are
1709  // in a reentrant lookup and will be called back when dequeued.
1710 
1711  return 1;
1712 }
1713 
1714 static void
1715 idnsStartQuery(idns_query *q, IDNSCB * callback, void *data)
1716 {
1717  q->start_t = current_time;
1718  q->callback = callback;
1719  q->callback_data = cbdataReference(data);
1720 
1721  q->hash.key = q->orig;
1723 
1724  idnsSendQuery(q);
1725 }
1726 
1727 static void
1729 {
1730  idns_query *q = new idns_query;
1731  memcpy(q->name, master->name, sizeof(q->name));
1732  memcpy(q->orig, master->orig, sizeof(q->orig));
1733  q->master = master;
1734  q->query_id = idnsQueryID();
1735  q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query);
1736 
1737  debugs(78, 3, "buf is " << q->sz << " bytes for " << q->name <<
1738  ", id = 0x" << asHex(q->query_id));
1739  if (!q->sz) {
1740  delete q;
1741  return;
1742  }
1743 
1744  q->start_t = master->start_t;
1745  q->slave = master->slave;
1746 
1747  idnsCheckMDNS(q);
1748  master->slave = q;
1749  idnsSendQuery(q);
1750 }
1751 
1752 void
1753 idnsALookup(const char *name, IDNSCB * callback, void *data)
1754 {
1755  size_t nameLength = strlen(name);
1756 
1757  // Prevent buffer overflow on q->name
1758  if (nameLength > NS_MAXDNAME) {
1759  debugs(23, DBG_IMPORTANT, "SECURITY ALERT: DNS name too long to perform lookup: '" << name << "'. see access.log for details.");
1760  idnsCallbackOnEarlyError(callback, data, "huge name");
1761  return;
1762  }
1763 
1764  if (idnsCachedLookup(name, callback, data))
1765  return;
1766 
1767  idns_query *q = new idns_query;
1768  q->query_id = idnsQueryID();
1769 
1770  int nd = 0;
1771  for (size_t i = 0; i < nameLength; ++i)
1772  if (name[i] == '.')
1773  ++nd;
1774 
1775  if (Config.onoff.res_defnames && npc > 0 && name[nameLength-1] != '.') {
1776  q->do_searchpath = 1;
1777  } else {
1778  q->do_searchpath = 0;
1779  }
1780 
1781  strcpy(q->orig, name);
1782  strcpy(q->name, q->orig);
1783 
1784  if (q->do_searchpath && nd < ndots) {
1785  q->domain = 0;
1786  strcat(q->name, ".");
1787  strcat(q->name, searchpath[q->domain].domain);
1788  debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
1789  }
1790 
1791  q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query);
1792 
1793  if (q->sz < 0) {
1794  /* problem with query data -- query not sent */
1795  idnsCallbackOnEarlyError(callback, data, "rfc3596BuildAQuery error");
1796  delete q;
1797  return;
1798  }
1799 
1800  debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
1801  ", id = 0x" << asHex(q->query_id));
1802 
1803  idnsCheckMDNS(q);
1804  idnsStartQuery(q, callback, data);
1805 
1806  if (Ip::EnableIpv6)
1808 }
1809 
1810 void
1811 idnsPTRLookup(const Ip::Address &addr, IDNSCB * callback, void *data)
1812 {
1813  char ip[MAX_IPSTRLEN];
1814 
1815  addr.toStr(ip,MAX_IPSTRLEN);
1816 
1817  idns_query *q = new idns_query;
1818  q->query_id = idnsQueryID();
1819 
1820  if (addr.isIPv6()) {
1821  struct in6_addr addr6;
1822  addr.getInAddr(addr6);
1823  q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), q->query_id, &q->query);
1824  } else {
1825  struct in_addr addr4;
1826  addr.getInAddr(addr4);
1827  q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), q->query_id, &q->query);
1828  }
1829 
1830  if (q->sz < 0) {
1831  /* problem with query data -- query not sent */
1832  idnsCallbackOnEarlyError(callback, data, "rfc3596BuildPTRQuery error");
1833  delete q;
1834  return;
1835  }
1836 
1837  if (idnsCachedLookup(q->query.name, callback, data)) {
1838  delete q;
1839  return;
1840  }
1841 
1842  debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
1843  ", id = 0x" << asHex(q->query_id));
1844 
1846  idnsStartQuery(q, callback, data);
1847 }
1848 
1849 #if SQUID_SNMP
1850 /*
1851  * The function to return the DNS via SNMP
1852  */
1853 variable_list *
1855 {
1856  int n = 0;
1857  variable_list *Answer = nullptr;
1858  MemBuf tmp;
1859  debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var->name, Var->name_length, tmp));
1860  *ErrP = SNMP_ERR_NOERROR;
1861 
1862  switch (Var->name[LEN_SQ_NET + 1]) {
1863 
1864  case DNS_REQ:
1865 
1866  for (const auto &server : nameservers)
1867  n += server.nqueries;
1868 
1869  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1870  n,
1871  SMI_COUNTER32);
1872 
1873  break;
1874 
1875  case DNS_REP:
1876  for (const auto &server : nameservers)
1877  n += server.nreplies;
1878 
1879  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1880  n,
1881  SMI_COUNTER32);
1882 
1883  break;
1884 
1885  case DNS_SERVERS:
1886  Answer = snmp_var_new_integer(Var->name, Var->name_length,
1887  nameservers.size(),
1888  SMI_COUNTER32);
1889 
1890  break;
1891 
1892  default:
1893  *ErrP = SNMP_ERR_NOSUCHNAME;
1894 
1895  break;
1896  }
1897 
1898  return Answer;
1899 }
1900 
1901 #endif /*SQUID_SNMP */
1902 
int DnsSocketB
static void idnsCallbackNewCallerWithOldAnswers(IDNSCB *callback, void *cbdata, const idns_query *const master)
void fatal(const char *message)
Definition: fatal.cc:28
int queries
const char * xstrerr(int error)
Definition: xstrerror.cc:83
Ip::Address S
rfc1035_query * query
Definition: rfc1035.h:68
double tvSubDsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:44
static hash_table * idns_lookup_hash
char * buf
Definition: MemBuf.h:134
static CLCB idnsVCClosed
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:952
unsigned short msglen
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
unsigned short do_searchpath
static EVH idnsCheckQueue
int incoming_sockets_accepted
const char * snmpDebugOid(oid *Name, snint Len, MemBuf &outbuf)
Definition: snmp_core.cc:1056
#define _PATH_RESCONF
Definition: dns_internal.cc:58
#define DBG_CRITICAL
Definition: Stream.h:37
InstanceIdDefinitions(idns_query, "dns")
#define xmalloc
void fd_bytes(const int fd, const int len, const IoDirection direction)
Definition: fd.cc:226
static void idnsGrokReply(const char *buf, size_t sz, int from_ns)
CodeContext::Pointer codeContext
requestor's context
time_t connect
Definition: SquidConfig.h:115
Ip::Address udp_incoming
Definition: SquidConfig.h:235
static bool idnsParseNameservers(void)
hash_link hash
HASHHASH * hash
Definition: hash.h:27
mb_size_t size
Definition: MemBuf.h:135
static OBJH idnsStats
static void idnsAddPathComponent(const char *buf)
void * callback_data
ssize_t rfc3596BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query *query)
Definition: rfc3596.cc:100
void setAddrs(const Ip::Address &aLocal, const Ip::Address &aRemote)
Definition: Connection.h:106
static bool idnsStillPending(const idns_query *master)
static void idnsCallbackAllCallersWithNewAnswer(const idns_query *const answered, const bool lastAnswer)
int DnsSocketA
MemBuf * msg
static unsigned short idnsQueryID(void)
void Init(void)
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:855
HASHHASH hash_string
Definition: hash.h:45
int comm_udp_sendto(int fd, const Ip::Address &to_addr, const void *buf, int len)
Definition: comm.cc:921
void hash_remove_link(hash_table *, hash_link *)
Definition: hash.cc:220
void error(char *format,...)
struct timeval queue_t
bool busy
#define CBDATA_CLASS(type)
Definition: cbdata.h:289
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
rfc1035_rr * answer
Definition: rfc1035.h:69
bool getInAddr(struct in_addr &) const
Definition: Address.cc:1040
void endingShutdown() override
const A & max(A const &lhs, A const &rhs)
rfc1035_query query
MemBuf * queue
Definition: cbdata.cc:37
struct SquidConfig::@97 onoff
static IOCB idnsSentQueryVC
#define comm_close(x)
Definition: comm.h:36
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:270
size_t ns
@ DNS_REQ
Definition: cache_snmp.h:216
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
unsigned int tc
Definition: rfc1035.h:60
@ OK
Definition: Flag.h:16
#define MAX_RCODE
Definition: dns_internal.cc:78
static void idnsAddMDNSNameservers()
hash_link * hash_lookup(hash_table *, const void *)
Definition: hash.cc:146
int HASHCMP(const void *, const void *)
Definition: hash.h:13
bool isIPv4() const
Definition: Address.cc:178
char name[NS_MAXDNAME+1]
void CallBack(const CodeContext::Pointer &callbackContext, Fun &&callback)
Definition: CodeContext.h:126
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:40
@ ERR_CLOSING
Definition: Flag.h:24
#define cbdataReference(var)
Definition: cbdata.h:348
static const char * Rcodes[]
Definition: dns_internal.cc:82
#define NS_MAXDNAME
Definition: dns_internal.cc:65
static bool idnsParseResolvConf(void)
#define w_space
void setHost(const char *)
set the hostname note for this connection
Definition: ConnOpener.cc:100
static int ndots
static void idnsCallback(idns_query *q, const char *error)
#define COMM_NONBLOCKING
Definition: Connection.h:46
variable_list * snmp_netDnsFn(variable_list *Var, snint *ErrP)
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:51
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:812
int rfc1035QueryCompare(const rfc1035_query *a, const rfc1035_query *b)
Definition: rfc1035.cc:555
void idnsALookup(const char *name, IDNSCB *callback, void *data)
const char * error
std::mt19937::result_type RandomSeed32()
Definition: Random.cc:13
int name_length
Definition: snmp_vars.h:71
idns_query * slave
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:25
oid * name
Definition: snmp_vars.h:70
void CNCB(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
Definition: CommCalls.h:33
void comm_open_listener(int sock_type, int proto, Comm::ConnectionPointer &conn, const char *note)
Definition: comm.cc:257
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback)
Definition: Read.h:59
int64_t snint
Definition: cache_snmp.h:14
void Tolower(char *)
Definition: util.cc:28
static void idnsSendQuery(idns_query *q)
idns_query * master
static IOCB idnsReadVC
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
unsigned short query_id
random query ID sent to server; changes with every query sent
int isNull() const
Definition: MemBuf.cc:145
int size
Definition: ModDevPoll.cc:69
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:18
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
void OBJH(StoreEntry *)
Definition: forward.h:44
static void idnsInitVC(size_t nsv)
IDNSCB * callback
#define SQUID_UDP_SO_RCVBUF
Definition: squid.h:49
static void idnsShutdownAndFreeState(const char *reason)
static void idnsSendSlaveAAAAQuery(idns_query *q)
int nqueries
generic DNS API
Definition: forward.h:20
char buf[RESOLV_BUFSZ]
static uint32 A
Definition: md4.c:43
static int event_queued
nsvc(size_t nsv)
unsigned short port() const
Definition: Address.cc:798
bool isIPv6() const
Definition: Address.cc:184
Definition: MemBuf.h:23
Ip::Address local
Definition: Connection.h:146
#define RESOLV_BUFSZ
Definition: dns_internal.cc:74
static sp * searchpath
void clean()
Definition: MemBuf.cc:110
ssize_t rfc3596BuildPTRQuery4(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query *query)
Definition: rfc3596.cc:128
struct variable_list * snmp_var_new_integer(oid *, int, int, unsigned char)
Definition: snmp_vars.c:151
static void idnsStartQuery(idns_query *q, IDNSCB *callback, void *data)
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
Definition: IoManip.h:169
static dlink_list lru_list
Ip::Address udp_outgoing
Definition: SquidConfig.h:236
unsigned short comm_local_port(int fd)
Definition: comm.cc:165
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
Definition: CommCalls.h:34
manage DNS internal component
nsvc * vc
int res_defnames
Definition: SquidConfig.h:279
ssize_t rfc3596BuildPTRQuery6(const struct in6_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query *query)
Definition: rfc3596.cc:144
#define safe_free(x)
Definition: xalloc.h:73
Definition: cf_gen.cc:108
Ip::Address remote
Definition: Connection.h:149
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:312
#define assert(EX)
Definition: assert.h:17
#define RFC1035_DEFAULT_PACKET_SZ
Definition: rfc1035.h:34
#define INCOMING_DNS_MAX
Definition: Loops.h:59
SSL Connection
Definition: Session.h:49
bool setIPv4()
Definition: Address.cc:244
ssize_t sz
static int RcodeMatrix[MAX_RCODE][MAX_ATTEMPT]
Definition: dns_internal.cc:80
bool mDNSResolver
rfc1035_message * message
#define COMM_SELECT_READ
Definition: defines.h:24
#define cbdataReferenceDone(var)
Definition: cbdata.h:357
static CNCB idnsInitVCConnected
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:33
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:325
int rfc1035MessageUnpack(const char *buf, size_t sz, rfc1035_message **answer)
Definition: rfc1035.cc:589
int read_msglen
static void idnsTickleQueue(void)
time_t squid_curtime
Definition: stub_libtime.cc:20
static void idnsFreeSearchpath(void)
static int idnsCachedLookup(const char *key, IDNSCB *callback, void *data)
static std::ostream & Extra(std::ostream &)
Definition: debug.cc:1316
bool isNoAddr() const
Definition: Address.cc:304
#define xfree
static void idnsDoSendQueryVC(nsvc *vc)
unsigned short id
Definition: rfc1035.h:56
char orig[NS_MAXDNAME+1]
struct SquidConfig::@107 dns
void EVH(void *)
Definition: event.h:18
char name[RFC1035_MAXHOSTNAMESZ]
Definition: rfc1035.h:49
Flag
Definition: Flag.h:15
int ignoreErrno(int ierrno)
Definition: comm.cc:1422
static void idnsAddNameserver(const char *buf)
#define fd_table
Definition: fde.h:189
idns_query * queue
const char * rfc1035ErrorMessage(int n)
Definition: rfc1035.cc:449
static std::ostream & operator<<(std::ostream &os, const idns_query &answered)
static idns_query * idnsFindQuery(unsigned short id)
static std::vector< ns > nameservers
unsigned short domain
struct timeval start_t
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:592
time_msec_t idns_retransmit
Definition: SquidConfig.h:130
bool permit_mdns
static IOCB idnsReadVCHeader
@ DNS_SERVERS
Definition: cache_snmp.h:218
#define LEN_SQ_NET
Definition: cache_snmp.h:49
SBufList nameservers
Definition: SquidConfig.h:540
squidaio_request_t * head
Definition: aiops.cc:127
mb_size_t potentialSpaceSize() const
Definition: MemBuf.cc:161
dlink_node lru
struct SquidConfig::@84 Timeout
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:220
static char server[MAXLINE]
void IDNSCB(void *cbdata, const rfc1035_rr *answer, const int recordsInAnswer, const char *error, bool lastAnswer)
Definition: forward.h:17
hash_table * hash_create(HASHCMP *, int, HASHHASH *)
Definition: hash.cc:108
const char * getMyHostname(void)
Definition: tools.cc:467
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
Definition: Registration.cc:54
static void idnsCallbackOnEarlyError(IDNSCB *callback, void *cbdata, const char *error)
#define NS_DEFAULTPORT
Definition: dns_internal.cc:61
#define Important(id)
Definition: Messages.h:93
void idnsPTRLookup(const Ip::Address &addr, IDNSCB *callback, void *data)
#define DBG_IMPORTANT
Definition: Stream.h:38
static int idnsFromKnownNameserver(Ip::Address const &from)
@ DNS_REP
Definition: cache_snmp.h:217
#define MYNAME
Definition: Stream.h:219
void startReconfigure() override
static int npc
int comm_udp_recvfrom(int fd, void *buf, size_t len, int flags, Ip::Address &from)
Definition: comm.cc:126
static int nns_mdns_count
static void idnsSendQueryVC(idns_query *q, size_t nsn)
#define SNMP_ERR_NOSUCHNAME
Definition: snmp_error.h:44
#define MAX_ATTEMPT
Definition: dns_internal.cc:79
char domain[NS_MAXDNAME]
ssize_t rfc3596BuildAAAAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query *query)
Definition: rfc3596.cc:114
InstanceId< idns_query > xact_id
identifies our "transaction", stays constant when query is retried
time_msec_t idns_query
Definition: SquidConfig.h:131
Comm::ConnectionPointer conn
struct SquidConfig::@92 Addrs
DefineRunnerRegistratorIn(Dns, ConfigRr)
struct timeval sent_t
int EnableIpv6
Whether IPv6 is supported and type of support.
Definition: tools.h:25
static void idnsRcodeCount(int, int)
int ignore_unknown_nameservers
Definition: SquidConfig.h:303
uint64_t time_msec_t
Definition: gadgets.h:16
static PF idnsRead
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
const A & min(A const &lhs, A const &rhs)
static void idnsCheckMDNS(idns_query *q)
void hash_join(hash_table *, hash_link *)
Definition: hash.cc:131
static int npc_alloc
static bool idnsCallbackOneWithAnswer(IDNSCB *callback, void *cbdata, const idns_query &answered, const bool lastAnswer)
safely sends one set of DNS records (or an error) to the caller
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 PF(int, void *)
Definition: forward.h:18
class SquidConfig Config
Definition: SquidConfig.cc:12
int nreplies
int unsigned int
Definition: stub_fd.cc:19
#define SMI_COUNTER32
Definition: snmp_vars.h:76
ssize_t packet_max
maximum size EDNS advertised for DNS replies.
Definition: SquidConfig.h:542
static void Start(const Pointer &job)
Definition: AsyncJob.cc:37
void rfc1035MessageDestroy(rfc1035_message **msg)
Definition: rfc1035.cc:535

 

Introduction

Documentation

Support

Miscellaneous