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