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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors