]> git.ipfire.org Git - thirdparty/squid.git/blame - src/dns_internal.cc
Maintenance: Consistent use of C++11 "override" specifier (#1224)
[thirdparty/squid.git] / src / dns_internal.cc
CommitLineData
7b724b86 1/*
bf95c10a 2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
7b724b86 3 *
bbc27441
AJ
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.
7b724b86 7 */
8
4a3b98d7 9/* DEBUG: section 78 DNS lookups; interacts with dns/rfc1035.cc */
bbc27441 10
582c2af2 11#include "squid.h"
cd2a20f7 12#include "base/CodeContext.h"
582c2af2 13#include "base/InstanceId.h"
4a28fc55 14#include "base/Random.h"
ee58de20 15#include "base/RunnersRegistry.h"
602d9612 16#include "comm.h"
55cbb02b 17#include "comm/Connection.h"
aed188fd 18#include "comm/ConnOpener.h"
d841c88d 19#include "comm/Loops.h"
7e66d5e2 20#include "comm/Read.h"
d841c88d 21#include "comm/Write.h"
675b8408 22#include "debug/Messages.h"
17852883 23#include "dlink.h"
4a3b98d7
AJ
24#include "dns/forward.h"
25#include "dns/rfc3596.h"
cfd66529 26#include "event.h"
c4ad1349 27#include "fd.h"
2c471ba8 28#include "fde.h"
055421ee 29#include "ip/tools.h"
0eb49b6d 30#include "MemBuf.h"
8822ebee 31#include "mgr/Registration.h"
8b082ed9 32#include "snmp_agent.h"
4d5904f7 33#include "SquidConfig.h"
582c2af2 34#include "Store.h"
8d03bdb4 35#include "tools.h"
7176768b 36#include "util.h"
d295d770 37#include "wordlist.h"
68836b58 38
9c0a2256
FC
39#if SQUID_SNMP
40#include "snmp_core.h"
41#endif
42
68836b58 43#if HAVE_ARPA_NAMESER_H
44#include <arpa/nameser.h>
45#endif
1a30fdf5 46#include <cerrno>
68836b58 47#if HAVE_RESOLV_H
48#include <resolv.h>
49#endif
50
be266cb2 51#if _SQUID_WINDOWS_
0dde2160
GS
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"
0e6d05ef 55#endif
68836b58 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
7b724b86 69#endif
68836b58 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
7b724b86 74#endif
75
42b51993 76#define IDNS_MAX_TRIES 20
e210930b 77#define MAX_RCODE 17
558be27a 78#define MAX_ATTEMPT 3
79static int RcodeMatrix[MAX_RCODE][MAX_ATTEMPT];
e210930b
AJ
80// NP: see http://www.iana.org/assignments/dns-parameters
81static const char *Rcodes[] = {
24520b1b
AJ
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};
558be27a 100
68836b58 101typedef struct _sp sp;
102
907a7a05
AJ
103class idns_query
104{
105 CBDATA_CLASS(idns_query);
106
107public:
cd2a20f7
AR
108 idns_query():
109 codeContext(CodeContext::Current())
110 {
1cb1b2d3 111 callback = nullptr;
907a7a05
AJ
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
121 ~idns_query() {
122 if (message)
123 rfc1035MessageDestroy(&message);
124 delete queue;
125 delete slave;
126 // master is just a back-reference
127 cbdataReferenceDone(callback_data);
128 }
d24ef4e9 129
3074b9d1 130 hash_link hash;
9e1f210d 131 rfc1035_query query;
68836b58 132 char buf[RESOLV_BUFSZ];
133 char name[NS_MAXDNAME + 1];
134 char orig[NS_MAXDNAME + 1];
1cb1b2d3
AJ
135 ssize_t sz = 0;
136 unsigned short query_id = 0; ///< random query ID sent to server; changes with every query sent
137 InstanceId<idns_query> xact_id; ///< identifies our "transaction", stays constant when query is retried
91dcbd43 138
1cb1b2d3
AJ
139 int nsends = 0;
140 int need_vc = 0;
141 bool permit_mdns = false;
142 int pending = 0;
62e76326 143
58a39dc9 144 struct timeval start_t;
145 struct timeval sent_t;
820ee9fa 146 struct timeval queue_t;
58a39dc9 147 dlink_node lru;
cd2a20f7 148
58a39dc9 149 IDNSCB *callback;
1cb1b2d3 150 void *callback_data = nullptr;
cd2a20f7
AR
151 CodeContext::Pointer codeContext; ///< requestor's context
152
1cb1b2d3
AJ
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;
160 rfc1035_message *message = nullptr;
161 int ancount = 0;
162 const char *error = nullptr;
58a39dc9 163};
907a7a05 164
91dcbd43 165InstanceIdDefinitions(idns_query, "dns");
58a39dc9 166
907a7a05
AJ
167CBDATA_CLASS_INIT(idns_query);
168
169class nsvc
170{
171 CBDATA_CLASS(nsvc);
172
173public:
b56b37cf 174 explicit nsvc(size_t nsv) : ns(nsv), msg(new MemBuf()), queue(new MemBuf()) {}
907a7a05
AJ
175 ~nsvc();
176
b56b37cf 177 size_t ns = 0;
00406b24 178 Comm::ConnectionPointer conn;
1cb1b2d3
AJ
179 unsigned short msglen = 0;
180 int read_msglen = 0;
181 MemBuf *msg = nullptr;
182 MemBuf *queue = nullptr;
183 bool busy = true;
d24ef4e9 184};
185
907a7a05
AJ
186CBDATA_CLASS_INIT(nsvc);
187
b56b37cf
AJ
188class ns
189{
190public:
b7ac5457 191 Ip::Address S;
b56b37cf
AJ
192 int nqueries = 0;
193 int nreplies = 0;
e210930b 194#if WHEN_EDNS_RESPONSES_ARE_PARSED
b56b37cf 195 int last_seen_edns = 0;
e210930b 196#endif
b56b37cf
AJ
197 bool mDNSResolver = false;
198 nsvc *vc = nullptr;
7b724b86 199};
58a39dc9 200
ee58de20
AJ
201namespace Dns
202{
203
204/// manage DNS internal component
205class ConfigRr : public RegisteredRunner
206{
207public:
208 /* RegisteredRunner API */
337b9aa4
AR
209 void startReconfigure() override;
210 void endingShutdown() override;
ee58de20
AJ
211};
212
213RunnerRegistrationEntry(ConfigRr);
214
215} // namespace Dns
216
26ac0430 217struct _sp {
68836b58 218 char domain[NS_MAXDNAME];
219 int queries;
220};
221
b56b37cf 222static std::vector<ns> nameservers;
aee3523a 223static sp *searchpath = nullptr;
51aee437 224static int nns_mdns_count = 0;
68836b58 225static int npc = 0;
226static int npc_alloc = 0;
227static int ndots = 1;
7b724b86 228static dlink_list lru_list;
7cfc1c9a 229static int event_queued = 0;
aee3523a 230static hash_table *idns_lookup_hash = nullptr;
7b724b86 231
e210930b
AJ
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
257static int max_shared_edns = RFC1035_DEFAULT_PACKET_SZ;
258#endif
259
7b724b86 260static OBJH idnsStats;
261static void idnsAddNameserver(const char *buf);
a079e38b 262static void idnsAddMDNSNameservers();
68836b58 263static void idnsAddPathComponent(const char *buf);
68836b58 264static void idnsFreeSearchpath(void);
a079e38b 265static bool idnsParseNameservers(void);
a079e38b 266static bool idnsParseResolvConf(void);
be266cb2 267#if _SQUID_WINDOWS_
a079e38b 268static bool idnsParseWIN32Registry(void);
d02b72b4 269static void idnsParseWIN32SearchList(const char *);
0e6d05ef 270#endif
33ab4aaf 271static void idnsStartQuery(idns_query * q, IDNSCB * callback, void *data);
7b724b86 272static void idnsSendQuery(idns_query * q);
d24ef4e9 273static IOCB idnsReadVCHeader;
e0d28505 274static void idnsDoSendQueryVC(nsvc *vc);
cfd66529 275static CNCB idnsInitVCConnected;
e0d28505
AJ
276static IOCB idnsReadVC;
277static IOCB idnsSentQueryVC;
62e76326 278
b7ac5457 279static int idnsFromKnownNameserver(Ip::Address const &from);
7b724b86 280static idns_query *idnsFindQuery(unsigned short id);
e210930b 281static void idnsGrokReply(const char *buf, size_t sz, int from_ns);
7b724b86 282static PF idnsRead;
7cfc1c9a 283static EVH idnsCheckQueue;
efd900cb 284static void idnsTickleQueue(void);
558be27a 285static void idnsRcodeCount(int, int);
575d05c4 286static CLCB idnsVCClosed;
91dcbd43 287static unsigned short idnsQueryID(void);
049441d9 288static void idnsSendSlaveAAAAQuery(idns_query *q);
fd9c47d1 289static void idnsCallbackOnEarlyError(IDNSCB *callback, void *cbdata, const char *error);
7b724b86 290
a079e38b
AJ
291static void
292idnsCheckMDNS(idns_query *q)
293{
bce61b00
AJ
294 if (!Config.onoff.dns_mdns || q->permit_mdns)
295 return;
296
a079e38b
AJ
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
303static void
304idnsAddMDNSNameservers()
305{
51aee437 306 nns_mdns_count=0;
a079e38b 307
bce61b00
AJ
308 // mDNS is disabled
309 if (!Config.onoff.dns_mdns)
310 return;
311
a079e38b 312 // mDNS resolver addresses are explicit multicast group IPs
51aee437
AJ
313 if (Ip::EnableIpv6) {
314 idnsAddNameserver("FF02::FB");
b56b37cf
AJ
315 nameservers.back().S.port(5353);
316 nameservers.back().mDNSResolver = true;
51aee437
AJ
317 ++nns_mdns_count;
318 }
a079e38b
AJ
319
320 idnsAddNameserver("224.0.0.251");
b56b37cf
AJ
321 nameservers.back().S.port(5353);
322 nameservers.back().mDNSResolver = true;
51aee437
AJ
323
324 ++nns_mdns_count;
a079e38b
AJ
325}
326
7b724b86 327static void
328idnsAddNameserver(const char *buf)
329{
b7ac5457 330 Ip::Address A;
62e76326 331
cc192b50 332 if (!(A = buf)) {
fa84c01d 333 debugs(78, DBG_CRITICAL, "WARNING: rejecting '" << buf << "' as a name server, because it is not a numeric IP address");
62e76326 334 return;
d20b1cd0 335 }
62e76326 336
4dd643d5 337 if (A.isAnyAddr()) {
fa84c01d 338 debugs(78, DBG_CRITICAL, "WARNING: Squid does not accept " << A << " in DNS server specifications.");
4dd643d5 339 A.setLocalhost();
fa84c01d 340 debugs(78, DBG_CRITICAL, "Will be using " << A << " instead, assuming you meant that DNS is running on the same machine");
5c5a349d 341 }
62e76326 342
4dd643d5 343 if (!Ip::EnableIpv6 && !A.setIPv4()) {
715b5def
AJ
344 debugs(78, DBG_IMPORTANT, "WARNING: IPv6 is disabled. Discarding " << A << " in DNS server specifications.");
345 return;
5c5a349d 346 }
62e76326 347
09835feb 348 auto &nameserver = nameservers.emplace_back(ns());
4dd643d5 349 A.port(NS_DEFAULTPORT);
09835feb 350 nameserver.S = A;
e210930b 351#if WHEN_EDNS_RESPONSES_ARE_PARSED
09835feb 352 nameserver.last_seen_edns = RFC1035_DEFAULT_PACKET_SZ;
e210930b
AJ
353 // TODO generate a test packet to probe this NS from EDNS size and ability.
354#endif
b56b37cf 355 debugs(78, 3, "Added nameserver #" << nameservers.size()-1 << " (" << A << ")");
7b724b86 356}
357
68836b58 358static void
359idnsAddPathComponent(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)
41d00cd3 373 memcpy(searchpath, oldptr, oldalloc * sizeof(*searchpath));
68836b58 374
375 if (oldptr)
376 safe_free(oldptr);
377 }
378
379 assert(npc < npc_alloc);
0a84e4fb
AJ
380 strncpy(searchpath[npc].domain, buf, sizeof(searchpath[npc].domain)-1);
381 searchpath[npc].domain[sizeof(searchpath[npc].domain)-1] = '\0';
7176768b 382 Tolower(searchpath[npc].domain);
bf8fe701 383 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc << ": " << searchpath[npc].domain);
95dc7ff4 384 ++npc;
68836b58 385}
386
68836b58 387static void
388idnsFreeSearchpath(void)
389{
390 safe_free(searchpath);
391 npc = npc_alloc = 0;
392}
393
a079e38b 394static bool
efd900cb 395idnsParseNameservers(void)
396{
a079e38b 397 bool result = false;
5a1098fb 398 for (auto &i : Config.dns.nameservers) {
c59baaa8 399 debugs(78, Important(15), "Adding nameserver " << i << " from squid.conf");
5a1098fb 400 idnsAddNameserver(i.c_str());
a079e38b 401 result = true;
efd900cb 402 }
a079e38b 403 return result;
efd900cb 404}
405
a079e38b 406static bool
7b724b86 407idnsParseResolvConf(void)
408{
a079e38b 409 bool result = false;
a396d1f8 410#if !_SQUID_WINDOWS_
aa0ca030 411 FILE *fp = fopen(_PATH_RESCONF, "r");
62e76326 412
b69e9ffa
AJ
413 if (!fp) {
414 int xerrno = errno;
415 debugs(78, DBG_IMPORTANT, "" << _PATH_RESCONF << ": " << xstrerr(xerrno));
a079e38b 416 return false;
7b724b86 417 }
62e76326 418
aa0ca030 419 char buf[RESOLV_BUFSZ];
aee3523a 420 const char *t = nullptr;
68836b58 421 while (fgets(buf, RESOLV_BUFSZ, fp)) {
62e76326 422 t = strtok(buf, w_space);
423
aee3523a 424 if (nullptr == t) {
62e76326 425 continue;
a37d6070 426 } else if (strcmp(t, "nameserver") == 0) {
aee3523a 427 t = strtok(nullptr, w_space);
62e76326 428
aee3523a 429 if (nullptr == t)
68836b58 430 continue;
62e76326 431
e0236918 432 debugs(78, DBG_IMPORTANT, "Adding nameserver " << t << " from " << _PATH_RESCONF);
62e76326 433
68836b58 434 idnsAddNameserver(t);
a079e38b 435 result = true;
a37d6070 436 } else if (strcmp(t, "domain") == 0) {
26ac0430 437 idnsFreeSearchpath();
aee3523a 438 t = strtok(nullptr, w_space);
a083e75a 439
aee3523a 440 if (nullptr == t)
26ac0430 441 continue;
a083e75a 442
e0236918 443 debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from " << _PATH_RESCONF);
a083e75a 444
26ac0430 445 idnsAddPathComponent(t);
a37d6070 446 } else if (strcmp(t, "search") == 0) {
26ac0430 447 idnsFreeSearchpath();
aee3523a
AR
448 while (nullptr != t) {
449 t = strtok(nullptr, w_space);
68836b58 450
aee3523a 451 if (nullptr == t)
68836b58 452 continue;
453
e0236918 454 debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from " << _PATH_RESCONF);
68836b58 455
456 idnsAddPathComponent(t);
457 }
a37d6070 458 } else if (strcmp(t, "options") == 0) {
aee3523a
AR
459 while (nullptr != t) {
460 t = strtok(nullptr, w_space);
62e76326 461
aee3523a 462 if (nullptr == t)
68836b58 463 continue;
62e76326 464
2c2da7d3 465 if (strncmp(t, "ndots:", 6) == 0) {
68836b58 466 ndots = atoi(t + 6);
467
468 if (ndots < 1)
469 ndots = 1;
470
e0236918 471 debugs(78, DBG_IMPORTANT, "Adding ndots " << ndots << " from " << _PATH_RESCONF);
68836b58 472 }
473 }
474 }
7b724b86 475 }
a083e75a 476 if (npc == 0 && (t = getMyHostname())) {
26ac0430
AJ
477 t = strchr(t, '.');
478 if (t)
479 idnsAddPathComponent(t+1);
a083e75a 480 }
62e76326 481
7b724b86 482 fclose(fp);
aa0ca030 483#endif
a079e38b 484 return result;
7b724b86 485}
486
be266cb2 487#if _SQUID_WINDOWS_
6b610e34 488static void
d02b72b4 489idnsParseWIN32SearchList(const char * Separator)
6b610e34 490{
a16cb11f 491 char *t;
6b610e34 492 char *token;
493 HKEY hndKey;
494
0dde2160 495 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
6b610e34 496 DWORD Type = 0;
497 DWORD Size = 0;
498 LONG Result;
04f7fd38 499 Result = RegQueryValueEx(hndKey, "Domain", NULL, &Type, NULL, &Size);
26ac0430
AJ
500
501 if (Result == ERROR_SUCCESS && Size) {
502 t = (char *) xmalloc(Size);
0dde2160 503 RegQueryValueEx(hndKey, "Domain", NULL, &Type, (LPBYTE) t, &Size);
e0236918 504 debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from Registry");
26ac0430
AJ
505 idnsAddPathComponent(t);
506 xfree(t);
507 }
04f7fd38 508 Result = RegQueryValueEx(hndKey, "SearchList", NULL, &Type, NULL, &Size);
6b610e34 509
510 if (Result == ERROR_SUCCESS && Size) {
a16cb11f 511 t = (char *) xmalloc(Size);
04f7fd38 512 RegQueryValueEx(hndKey, "SearchList", NULL, &Type, (LPBYTE) t, &Size);
a16cb11f 513 token = strtok(t, Separator);
6b610e34 514
515 while (token) {
516 idnsAddPathComponent(token);
e0236918 517 debugs(78, DBG_IMPORTANT, "Adding domain " << token << " from Registry");
6b610e34 518 token = strtok(NULL, Separator);
519 }
26ac0430 520 xfree(t);
6b610e34 521 }
522
523 RegCloseKey(hndKey);
524 }
a6cae565 525 if (npc == 0 && (t = (char *) getMyHostname())) {
26ac0430
AJ
526 t = strchr(t, '.');
527 if (t)
528 idnsAddPathComponent(t + 1);
a16cb11f 529 }
6b610e34 530}
531
a079e38b 532static bool
0e6d05ef 533idnsParseWIN32Registry(void)
534{
a16cb11f 535 char *t;
0e6d05ef 536 char *token;
537 HKEY hndKey, hndKey2;
a079e38b 538 bool result = false;
0e6d05ef 539
0e6d05ef 540 switch (WIN32_OS_version) {
62e76326 541
0e6d05ef 542 case _WIN_OS_WINNT:
62e76326 543 /* get nameservers from the Windows NT registry */
544
04f7fd38 545 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
62e76326 546 DWORD Type = 0;
547 DWORD Size = 0;
548 LONG Result;
04f7fd38 549 Result = RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, NULL, &Size);
62e76326 550
551 if (Result == ERROR_SUCCESS && Size) {
a16cb11f 552 t = (char *) xmalloc(Size);
0dde2160 553 RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, (LPBYTE) t, &Size);
a16cb11f 554 token = strtok(t, ", ");
62e76326 555
556 while (token) {
557 idnsAddNameserver(token);
a079e38b 558 result = true;
e0236918 559 debugs(78, DBG_IMPORTANT, "Adding DHCP nameserver " << token << " from Registry");
6b610e34 560 token = strtok(NULL, ",");
62e76326 561 }
26ac0430 562 xfree(t);
62e76326 563 }
564
0dde2160 565 Result = RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
62e76326 566
567 if (Result == ERROR_SUCCESS && Size) {
a16cb11f 568 t = (char *) xmalloc(Size);
a6cae565 569 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, (LPBYTE) t, &Size);
a16cb11f 570 token = strtok(t, ", ");
62e76326 571
572 while (token) {
e0236918 573 debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
62e76326 574 idnsAddNameserver(token);
a079e38b 575 result = true;
62e76326 576 token = strtok(NULL, ", ");
577 }
26ac0430 578 xfree(t);
62e76326 579 }
580
581 RegCloseKey(hndKey);
582 }
583
6b610e34 584 idnsParseWIN32SearchList(" ");
585
62e76326 586 break;
587
0e6d05ef 588 case _WIN_OS_WIN2K:
62e76326 589
b671cc68 590 case _WIN_OS_WINXP:
62e76326 591
6b1846cf 592 case _WIN_OS_WINNET:
28170269 593
594 case _WIN_OS_WINLON:
4f5320f2
GS
595
596 case _WIN_OS_WIN7:
62e76326 597 /* get nameservers from the Windows 2000 registry */
598 /* search all interfaces for DNS server addresses */
599
04f7fd38 600 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA_INTERFACES, 0, KEY_READ, &hndKey) == ERROR_SUCCESS) {
62e76326 601 int i;
04f7fd38
AJ
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);
95dc7ff4 608 for (i = 0; i < (int) InterfacesCount; ++i) {
04f7fd38
AJ
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) {
e0236918 627 debugs(78, DBG_IMPORTANT, "Adding DHCP nameserver " << token << " from Registry");
04f7fd38 628 idnsAddNameserver(token);
a079e38b 629 result = true;
04f7fd38
AJ
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) {
e0236918 641 debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
04f7fd38 642 idnsAddNameserver(token);
a079e38b 643 result = true;
04f7fd38
AJ
644 token = strtok(NULL, ", ");
645 }
646
647 xfree(t);
62e76326 648 }
62e76326 649
0dde2160 650 RegCloseKey(hndKey2);
62e76326 651 }
652
04f7fd38 653 xfree(newkeyname);
62e76326 654 }
655 }
0dde2160 656
04f7fd38 657 xfree(keyname);
62e76326 658 }
659
660 RegCloseKey(hndKey);
661 }
662
6b610e34 663 idnsParseWIN32SearchList(", ");
664
62e76326 665 break;
666
0e6d05ef 667 case _WIN_OS_WIN95:
62e76326 668
0e6d05ef 669 case _WIN_OS_WIN98:
62e76326 670
be20dac7 671 case _WIN_OS_WINME:
62e76326 672 /* get nameservers from the Windows 9X registry */
673
04f7fd38 674 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_VXD_MSTCP, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
62e76326 675 DWORD Type = 0;
676 DWORD Size = 0;
677 LONG Result;
04f7fd38 678 Result = RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
62e76326 679
680 if (Result == ERROR_SUCCESS && Size) {
a16cb11f 681 t = (char *) xmalloc(Size);
a6cae565 682 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, (LPBYTE) t, &Size);
a16cb11f 683 token = strtok(t, ", ");
62e76326 684
685 while (token) {
e0236918 686 debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
62e76326 687 idnsAddNameserver(token);
a079e38b 688 result = true;
62e76326 689 token = strtok(NULL, ", ");
690 }
26ac0430 691 xfree(t);
62e76326 692 }
693
694 RegCloseKey(hndKey);
695 }
696
697 break;
698
0e6d05ef 699 default:
d816f28d 700 debugs(78, DBG_IMPORTANT, "ERROR: Failed to read nameserver from Registry: Unknown System Type.");
0e6d05ef 701 }
a079e38b
AJ
702
703 return result;
0e6d05ef 704}
62e76326 705
0e6d05ef 706#endif
707
7b724b86 708static void
709idnsStats(StoreEntry * sentry)
710{
a16b4aa0 711 dlink_node *n;
712 idns_query *q;
7cfc1c9a 713 int i;
558be27a 714 int j;
cc192b50 715 char buf[MAX_IPSTRLEN];
7b724b86 716 storeAppendPrintf(sentry, "Internal DNS Statistics:\n");
a16b4aa0 717 storeAppendPrintf(sentry, "\nThe Queue:\n");
0a69973e 718 storeAppendPrintf(sentry, " DELAY SINCE\n");
bce61b00
AJ
719 storeAppendPrintf(sentry, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
720 storeAppendPrintf(sentry, "------ ---- ----- ---------- --------- - ----\n");
62e76326 721
a16b4aa0 722 for (n = lru_list.head; n; n = n->next) {
62e76326 723 q = (idns_query *)n->data;
bce61b00 724 storeAppendPrintf(sentry, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
049441d9 725 (int) q->query_id, (int) q->sz, q->nsends,
62e76326 726 tvSubDsec(q->start_t, current_time),
bce61b00
AJ
727 tvSubDsec(q->sent_t, current_time),
728 (q->permit_mdns? 'M':' '),
729 q->name);
7cfc1c9a 730 }
62e76326 731
e210930b 732 if (Config.dns.packet_max > 0)
bce61b00 733 storeAppendPrintf(sentry, "\nDNS jumbo-grams: %zd Bytes\n", Config.dns.packet_max);
e210930b 734 else
bce61b00 735 storeAppendPrintf(sentry, "\nDNS jumbo-grams: not working\n");
e210930b 736
7cfc1c9a 737 storeAppendPrintf(sentry, "\nNameservers:\n");
a079e38b
AJ
738 storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES Type\n");
739 storeAppendPrintf(sentry, "---------------------------------------------- --------- --------- --------\n");
62e76326 740
b56b37cf 741 for (const auto &server : nameservers) {
a079e38b 742 storeAppendPrintf(sentry, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
b56b37cf
AJ
743 server.S.toStr(buf,MAX_IPSTRLEN),
744 server.nqueries,
745 server.nreplies,
746 server.mDNSResolver?"multicast":"recurse");
a16b4aa0 747 }
62e76326 748
558be27a 749 storeAppendPrintf(sentry, "\nRcode Matrix:\n");
750 storeAppendPrintf(sentry, "RCODE");
62e76326 751
95dc7ff4 752 for (i = 0; i < MAX_ATTEMPT; ++i)
62e76326 753 storeAppendPrintf(sentry, " ATTEMPT%d", i + 1);
754
e210930b 755 storeAppendPrintf(sentry, " PROBLEM\n");
62e76326 756
95dc7ff4 757 for (j = 0; j < MAX_RCODE; ++j) {
e210930b
AJ
758 if (j > 10 && j < 16)
759 continue; // unassigned by IANA.
760
62e76326 761 storeAppendPrintf(sentry, "%5d", j);
762
95dc7ff4 763 for (i = 0; i < MAX_ATTEMPT; ++i)
62e76326 764 storeAppendPrintf(sentry, " %8d", RcodeMatrix[j][i]);
765
e210930b 766 storeAppendPrintf(sentry, " : %s\n",Rcodes[j]);
558be27a 767 }
6b610e34 768
769 if (npc) {
770 storeAppendPrintf(sentry, "\nSearch list:\n");
771
95dc7ff4 772 for (i=0; i < npc; ++i)
6b610e34 773 storeAppendPrintf(sentry, "%s\n", searchpath[i].domain);
774
775 storeAppendPrintf(sentry, "\n");
776 }
7b724b86 777}
778
efd900cb 779static void
780idnsTickleQueue(void)
781{
782 if (event_queued)
62e76326 783 return;
784
aee3523a 785 if (nullptr == lru_list.tail)
62e76326 786 return;
787
fd0f51c4
CT
788 const double when = min(Config.Timeout.idns_query, Config.Timeout.idns_retransmit)/1000.0;
789
aee3523a 790 eventAdd("idnsCheckQueue", idnsCheckQueue, nullptr, when, 1);
62e76326 791
efd900cb 792 event_queued = 1;
793}
794
d24ef4e9 795static void
ced8def3 796idnsSentQueryVC(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int, void *data)
d24ef4e9 797{
798 nsvc * vc = (nsvc *)data;
799
c8407295 800 if (flag == Comm::ERR_CLOSING)
d24ef4e9 801 return;
af6a12ee 802
e0d28505
AJ
803 // XXX: irrelevant now that we have conn pointer?
804 if (!Comm::IsConnOpen(conn) || fd_table[conn->fd].closing())
af6a12ee 805 return;
d24ef4e9 806
c8407295 807 if (flag != Comm::OK || size <= 0) {
80463bb4 808 conn->close();
d24ef4e9 809 return;
810 }
811
812 vc->busy = 0;
813 idnsDoSendQueryVC(vc);
814}
815
816static void
817idnsDoSendQueryVC(nsvc *vc)
818{
819 if (vc->busy)
820 return;
821
032785bf 822 if (vc->queue->contentSize() == 0)
d24ef4e9 823 return;
824
8401d6fc
AR
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
032785bf 829 MemBuf *mb = vc->queue;
d24ef4e9 830
032785bf 831 vc->queue = new MemBuf;
d24ef4e9 832
833 vc->busy = 1;
834
fd0f51c4 835 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
d4b21972
A
836 const int timeout = (Config.Timeout.idns_query % 1000 ?
837 Config.Timeout.idns_query + 1000 : Config.Timeout.idns_query) / 1000;
8d77a37c 838 AsyncCall::Pointer nil;
d4b21972 839
1b76e6c1 840 commSetConnTimeout(vc->conn, timeout, nil);
d24ef4e9 841
ec41b64c
AJ
842 AsyncCall::Pointer call = commCbCall(78, 5, "idnsSentQueryVC",
843 CommIoCbPtrFun(&idnsSentQueryVC, vc));
b0388924 844 Comm::Write(vc->conn, mb, call);
032785bf 845
846 delete mb;
d24ef4e9 847}
848
849static void
ced8def3 850idnsInitVCConnected(const Comm::ConnectionPointer &conn, Comm::Flag status, int, void *data)
d24ef4e9 851{
852 nsvc * vc = (nsvc *)data;
853
c8407295 854 if (status != Comm::OK || !conn) {
dd3fb890 855 char buf[MAX_IPSTRLEN] = "";
b56b37cf 856 if (vc->ns < nameservers.size())
4dd643d5 857 nameservers[vc->ns].S.toStr(buf,MAX_IPSTRLEN);
d816f28d 858 debugs(78, DBG_IMPORTANT, "ERROR: Failed to connect to nameserver " << buf << " using TCP.");
d24ef4e9 859 return;
860 }
861
00406b24 862 vc->conn = conn;
cfd66529
AJ
863
864 comm_add_close_handler(conn->fd, idnsVCClosed, vc);
abd8f140
AJ
865 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
866 CommIoCbPtrFun(idnsReadVCHeader, vc));
867 comm_read(conn, (char *)&vc->msglen, 2, call);
d24ef4e9 868 vc->busy = 0;
869 idnsDoSendQueryVC(vc);
870}
871
872static void
575d05c4 873idnsVCClosed(const CommCloseCbParams &params)
d24ef4e9 874{
575d05c4 875 nsvc * vc = (nsvc *)params.data;
2b6b1bcb
AR
876 if (vc->conn) {
877 vc->conn->noteClosure();
878 vc->conn = nullptr;
879 }
907a7a05
AJ
880 delete vc;
881}
882
883nsvc::~nsvc()
884{
885 delete queue;
886 delete msg;
b56b37cf 887 if (ns < nameservers.size()) // XXX: idnsShutdownAndFreeState may have freed nameservers[]
aee3523a 888 nameservers[ns].vc = nullptr;
d24ef4e9 889}
890
891static void
b56b37cf 892idnsInitVC(size_t nsv)
d24ef4e9 893{
b56b37cf 894 assert(nsv < nameservers.size());
907a7a05 895 nsvc *vc = new nsvc(nsv);
aee3523a 896 assert(vc->conn == nullptr); // MUST be NULL from the construction process!
9dca980d 897 nameservers[nsv].vc = vc;
d24ef4e9 898
00406b24 899 Comm::ConnectionPointer conn = new Comm::Connection();
105f7a99 900
4dd643d5 901 if (!Config.Addrs.udp_outgoing.isNoAddr())
7fb5be3e 902 conn->setAddrs(Config.Addrs.udp_outgoing, nameservers[nsv].S);
105f7a99 903 else
7fb5be3e 904 conn->setAddrs(Config.Addrs.udp_incoming, nameservers[nsv].S);
105f7a99 905
7fb5be3e 906 if (conn->remote.isIPv4())
4dd643d5 907 conn->local.setIPv4();
f5ba22ff 908
cfd66529 909 AsyncCall::Pointer call = commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected, vc));
d24ef4e9 910
4accd6d8 911 Comm::ConnOpener *cs = new Comm::ConnOpener(conn, call, Config.Timeout.connect);
aed188fd 912 cs->setHost("DNS TCP Socket");
855150a4 913 AsyncJob::Start(cs);
d24ef4e9 914}
915
916static void
b56b37cf 917idnsSendQueryVC(idns_query * q, size_t nsn)
d24ef4e9 918{
b56b37cf 919 assert(nsn < nameservers.size());
aee3523a 920 if (nameservers[nsn].vc == nullptr)
9dca980d 921 idnsInitVC(nsn);
d24ef4e9 922
9dca980d 923 nsvc *vc = nameservers[nsn].vc;
d24ef4e9 924
445962f3
HN
925 if (!vc) {
926 char buf[MAX_IPSTRLEN];
d816f28d 927 debugs(78, DBG_IMPORTANT, "ERROR: idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers[nsn].S.toStr(buf,MAX_IPSTRLEN) << "!");
445962f3
HN
928
929 return;
930 }
931
2fe7eff9 932 vc->queue->reset();
d24ef4e9 933
934 short head = htons(q->sz);
935
2fe7eff9 936 vc->queue->append((char *)&head, 2);
d24ef4e9 937
2fe7eff9 938 vc->queue->append(q->buf, q->sz);
d24ef4e9 939
940 idnsDoSendQueryVC(vc);
941}
942
7b724b86 943static void
944idnsSendQuery(idns_query * q)
945{
ee58de20
AJ
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
4d6c8504 953 if (DnsSocketA < 0 && DnsSocketB < 0) {
e0236918 954 debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
62e76326 955 return;
0a69973e 956 }
62e76326 957
b56b37cf 958 if (nameservers.empty()) {
e0236918 959 debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
cc192b50 960 return;
961 }
62e76326 962
aee3523a 963 assert(q->lru.next == nullptr);
62e76326 964
aee3523a 965 assert(q->lru.prev == nullptr);
62e76326 966
4d6c8504 967 int x = -1, y = -1;
b56b37cf
AJ
968 size_t nsn;
969 const auto nsCount = nameservers.size();
4d6c8504 970
213b6c90 971 do {
a079e38b
AJ
972 // only use mDNS resolvers for mDNS compatible queries
973 if (!q->permit_mdns)
b56b37cf 974 nsn = nns_mdns_count + q->nsends % (nsCount - nns_mdns_count);
a079e38b 975 else
b56b37cf 976 nsn = q->nsends % nsCount;
213b6c90
AJ
977
978 if (q->need_vc) {
9dca980d 979 idnsSendQueryVC(q, nsn);
4d6c8504 980 x = y = 0;
213b6c90 981 } else {
4dd643d5 982 if (DnsSocketB >= 0 && nameservers[nsn].S.isIPv6())
9dca980d 983 y = comm_udp_sendto(DnsSocketB, nameservers[nsn].S, q->buf, q->sz);
049441d9 984 else if (DnsSocketA >= 0)
9dca980d 985 x = comm_udp_sendto(DnsSocketA, nameservers[nsn].S, q->buf, q->sz);
213b6c90 986 }
b69e9ffa 987 int xerrno = errno;
62e76326 988
95dc7ff4 989 ++ q->nsends;
62e76326 990
33ab4aaf 991 q->sent_t = current_time;
62e76326 992
4dd643d5 993 if (y < 0 && nameservers[nsn].S.isIPv6())
b69e9ffa 994 debugs(50, DBG_IMPORTANT, MYNAME << "FD " << DnsSocketB << ": sendto: " << xstrerr(xerrno));
4dd643d5 995 if (x < 0 && nameservers[nsn].S.isIPv4())
b69e9ffa 996 debugs(50, DBG_IMPORTANT, MYNAME << "FD " << DnsSocketA << ": sendto: " << xstrerr(xerrno));
4d6c8504 997
b56b37cf 998 } while ( (x<0 && y<0) && q->nsends % nsCount != 0);
62e76326 999
bd6a0c8f 1000 if (y > 0) {
4d6c8504 1001 fd_bytes(DnsSocketB, y, FD_WRITE);
4d6c8504 1002 }
bd6a0c8f 1003 if (x > 0) {
4d6c8504 1004 fd_bytes(DnsSocketA, x, FD_WRITE);
0a69973e 1005 }
62e76326 1006
9dca980d 1007 ++ nameservers[nsn].nqueries;
c131f066 1008 q->queue_t = current_time;
7b724b86 1009 dlinkAdd(q, &q->lru, &lru_list);
049441d9 1010 q->pending = 1;
efd900cb 1011 idnsTickleQueue();
7b724b86 1012}
1013
1014static int
b7ac5457 1015idnsFromKnownNameserver(Ip::Address const &from)
7b724b86 1016{
b56b37cf 1017 for (int i = 0; static_cast<size_t>(i) < nameservers.size(); ++i) {
cc192b50 1018 if (nameservers[i].S != from)
62e76326 1019 continue;
1020
4dd643d5 1021 if (nameservers[i].S.port() != from.port())
62e76326 1022 continue;
1023
1024 return i;
7b724b86 1025 }
62e76326 1026
7cfc1c9a 1027 return -1;
7b724b86 1028}
1029
1030static idns_query *
1031idnsFindQuery(unsigned short id)
1032{
1033 dlink_node *n;
1034 idns_query *q;
62e76326 1035
7b724b86 1036 for (n = lru_list.tail; n; n = n->prev) {
62e76326 1037 q = (idns_query*)n->data;
1038
049441d9 1039 if (q->query_id == id)
62e76326 1040 return q;
7b724b86 1041 }
62e76326 1042
aee3523a 1043 return nullptr;
7b724b86 1044}
1045
108d67a0 1046static unsigned short
011b1672 1047idnsQueryID()
108d67a0 1048{
011b1672 1049 // NP: apparently ranlux are faster, but not quite as "proven"
4a28fc55 1050 static std::mt19937 mt(RandomSeed32());
011b1672 1051 unsigned short id = mt() & 0xFFFF;
108d67a0 1052 unsigned short first_id = id;
1053
011b1672 1054 // ensure temporal uniqueness by looking for an existing use
26ac0430 1055 while (idnsFindQuery(id)) {
95dc7ff4 1056 ++id;
108d67a0 1057
846c8960 1058 if (id == first_id) {
d816f28d 1059 debugs(78, DBG_IMPORTANT, "WARNING: idnsQueryID: too many pending DNS requests");
108d67a0 1060 break;
846c8960 1061 }
108d67a0 1062 }
1063
846c8960 1064 return id;
108d67a0 1065}
1066
fd9c47d1
AR
1067/// \returns whether master or associated queries are still waiting for replies
1068static bool
1069idnsStillPending(const idns_query *master)
3074b9d1 1070{
fd9c47d1
AR
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}
3074b9d1 1078
fd9c47d1
AR
1079static std::ostream &
1080operator <<(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}
33ab4aaf 1088
fd9c47d1
AR
1089static void
1090idnsCallbackOnEarlyError(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}
33ab4aaf 1097
fd9c47d1
AR
1098/// safely sends one set of DNS records (or an error) to the caller
1099static bool
1100idnsCallbackOneWithAnswer(IDNSCB *callback, void *cbdata, const idns_query &answered, const bool lastAnswer)
1101{
1102 if (!cbdataReferenceValid(cbdata))
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}
33ab4aaf 1109
fd9c47d1
AR
1110static void
1111idnsCallbackNewCallerWithOldAnswers(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
cd2a20f7 1118 // no CallBack(CodeContext...) -- we always run in requestor's context
fd9c47d1
AR
1119 if (!idnsCallbackOneWithAnswer(callback, cbdata, *query, lastAnswer))
1120 break; // the caller disappeared
33ab4aaf 1121 }
fd9c47d1 1122}
33ab4aaf 1123
fd9c47d1
AR
1124static void
1125idnsCallbackAllCallersWithNewAnswer(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) {
cd2a20f7
AR
1131 CallBack(looker->codeContext, [&] {
1132 (void)idnsCallbackOneWithAnswer(looker->callback, looker->callback_data,
b6388dfd 1133 *answered, lastAnswer);
cd2a20f7 1134 });
fd9c47d1
AR
1135 }
1136}
3074b9d1 1137
fd9c47d1
AR
1138static void
1139idnsCallback(idns_query *q, const char *error)
1140{
1141 if (error)
1142 q->error = error;
907a7a05 1143
fd9c47d1 1144 auto master = q->master ? q->master : q;
3074b9d1 1145
fd9c47d1
AR
1146 const bool lastAnswer = !idnsStillPending(master);
1147 idnsCallbackAllCallersWithNewAnswer(q, lastAnswer);
3074b9d1 1148
fd9c47d1
AR
1149 if (!lastAnswer)
1150 return; // wait for more answers
3074b9d1 1151
fd9c47d1
AR
1152 if (master->hash.key) {
1153 hash_remove_link(idns_lookup_hash, &master->hash);
1154 master->hash.key = nullptr;
3074b9d1 1155 }
33ab4aaf 1156
fd9c47d1 1157 delete master;
3074b9d1 1158}
1159
7b724b86 1160static void
ced8def3 1161idnsGrokReply(const char *buf, size_t sz, int /*from_ns*/)
7b724b86 1162{
aee3523a 1163 rfc1035_message *message = nullptr;
3074b9d1 1164
907a7a05 1165 int n = rfc1035MessageUnpack(buf, sz, &message);
62e76326 1166
aee3523a 1167 if (message == nullptr) {
d816f28d 1168 debugs(78, DBG_IMPORTANT, "ERROR: idnsGrokReply: Malformed DNS response");
62e76326 1169 return;
7b724b86 1170 }
62e76326 1171
91dcbd43 1172 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex << message->id << ", " << std::dec << n << " answers");
ec7bade0 1173
907a7a05 1174 idns_query *q = idnsFindQuery(message->id);
ec7bade0 1175
aee3523a 1176 if (q == nullptr) {
bf8fe701 1177 debugs(78, 3, "idnsGrokReply: Late response");
cc192b50 1178 rfc1035MessageDestroy(&message);
62e76326 1179 return;
7b724b86 1180 }
62e76326 1181
9e1f210d 1182 if (rfc1035QueryCompare(&q->query, message->query) != 0) {
bf8fe701 1183 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q->query.name << " != " << message->query->name << ")");
cc192b50 1184 rfc1035MessageDestroy(&message);
9e1f210d 1185 return;
1186 }
1187
e210930b
AJ
1188#if WHEN_EDNS_RESPONSES_ARE_PARSED
1189// TODO: actually gr the message right here.
f53969cc
SM
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)
e210930b
AJ
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
b56b37cf
AJ
1200 for (const auto &server : nameservers)
1201 max_shared_edns = min(max_shared_edns, server.last_seen_edns);
e210930b
AJ
1202 } else {
1203 nameservers[from_ns].last_seen_edns = q->edns_seen;
2f8abb64 1204 // maybe reduce the global limit downwards to accommodate this NS
e210930b
AJ
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
049441d9
HN
1212 dlinkDelete(&q->lru, &lru_list);
1213 q->pending = 0;
1214
d24ef4e9 1215 if (message->tc) {
bf95c10a 1216 debugs(78, 3, "Resolver requested TC (" << q->query.name << ")");
cc192b50 1217 rfc1035MessageDestroy(&message);
d24ef4e9 1218
1219 if (!q->need_vc) {
1220 q->need_vc = 1;
5e263176 1221 -- q->nsends;
d24ef4e9 1222 idnsSendQuery(q);
91dcbd43
CT
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.
bf95c10a 1226 debugs(78, 3, "TCP DNS response");
33ab4aaf 1227 idnsCallback(q, "Truncated TCP DNS response");
d24ef4e9 1228 }
1229
1230 return;
1231 }
9e1f210d 1232
558be27a 1233 idnsRcodeCount(n, q->attempt);
62e76326 1234
558be27a 1235 if (n < 0) {
7ba8d0b8 1236 q->rcode = -n;
42687bb2 1237 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n) << " (" << q->rcode << ")");
7ba8d0b8 1238
95dc7ff4 1239 if (q->rcode == 2 && (++ q->attempt) < MAX_ATTEMPT) {
62e76326 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 */
cc192b50 1245 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1246 rfc1035MessageDestroy(&message);
62e76326 1247 idnsSendQuery(q);
1248 return;
1249 }
68836b58 1250
0e6432d0 1251 // Do searchpath processing on the master A query only to keep
2f8abb64 1252 // things simple. NXDOMAIN is authoritative for the label, not
0e6432d0 1253 // the record type.
049441d9 1254 if (q->rcode == 3 && !q->master && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
aee3523a 1255 assert(nullptr == message->answer);
68836b58 1256 strcpy(q->name, q->orig);
1257
cc192b50 1258 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q->name );
1259
68836b58 1260 if (q->domain < npc) {
1261 strcat(q->name, ".");
1262 strcat(q->name, searchpath[q->domain].domain);
bf8fe701 1263 debugs(78, 3, "idnsGrokReply: searchpath used for " << q->name);
95dc7ff4 1264 ++ q->domain;
68836b58 1265 } else {
95dc7ff4 1266 ++ q->attempt;
68836b58 1267 }
1268
049441d9 1269 rfc1035MessageDestroy(&message);
cc192b50 1270
33ab4aaf 1271 // cleanup slave AAAA query
049441d9
HN
1272 while (idns_query *slave = q->slave) {
1273 dlinkDelete(&slave->lru, &lru_list);
1274 q->slave = slave->slave;
aee3523a 1275 slave->slave = nullptr;
907a7a05 1276 delete slave;
cc192b50 1277 }
c7ba545e 1278
049441d9
HN
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);
c4a7fa29
AJ
1284 if (q->sz < 0) {
1285 /* problem with query data -- query not sent */
33ab4aaf 1286 idnsCallback(q, "Internal error");
c4a7fa29
AJ
1287 return;
1288 }
1289
33ab4aaf
HN
1290 q->nsends = 0;
1291
a079e38b 1292 idnsCheckMDNS(q);
68836b58 1293 idnsSendQuery(q);
049441d9
HN
1294 if (Ip::EnableIpv6)
1295 idnsSendSlaveAAAAQuery(q);
68836b58 1296 return;
1297 }
558be27a 1298 }
62e76326 1299
049441d9
HN
1300 q->message = message;
1301 q->ancount = n;
cc192b50 1302
33ab4aaf 1303 if (n >= 0)
aee3523a 1304 idnsCallback(q, nullptr);
33ab4aaf
HN
1305 else
1306 idnsCallback(q, rfc1035ErrorMessage(q->rcode));
bae9832d 1307
7b724b86 1308}
1309
1310static void
ced8def3 1311idnsRead(int fd, void *)
7b724b86 1312{
d193a436 1313 int *N = &incoming_sockets_accepted;
0b6d1955 1314 int len;
42b51993 1315 int max = INCOMING_DNS_MAX;
d29b40de 1316 static char rbuf[SQUID_UDP_SO_RCVBUF];
b7ac5457 1317 Ip::Address from;
cc192b50 1318
d7e7eaa7 1319 debugs(78, 3, "idnsRead: starting with FD " << fd);
cc192b50 1320
bd6a0c8f
HN
1321 // Always keep reading. This stops (or at least makes harder) several
1322 // attacks on the DNS client.
aee3523a 1323 Comm::SetSelect(fd, COMM_SELECT_READ, idnsRead, nullptr, 0);
bd6a0c8f 1324
cc192b50 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 */
b7ac5457 1332 Ip::Address bugbypass;
62e76326 1333
5e263176
FC
1334 while (max) {
1335 --max;
cc192b50 1336 len = comm_udp_recvfrom(fd, rbuf, SQUID_UDP_SO_RCVBUF, 0, bugbypass);
62e76326 1337
cc192b50 1338 from = bugbypass; // BUG BYPASS. see notes above.
62e76326 1339
1340 if (len == 0)
1341 break;
1342
1343 if (len < 0) {
b69e9ffa
AJ
1344 int xerrno = errno;
1345 if (ignoreErrno(xerrno))
62e76326 1346 break;
1347
1191b93b 1348#if _SQUID_LINUX_
62e76326 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 */
b69e9ffa 1353 if (xerrno != ECONNREFUSED && xerrno != EHOSTUNREACH)
7b724b86 1354#endif
b69e9ffa 1355 debugs(50, DBG_IMPORTANT, MYNAME << "FD " << fd << " recvfrom: " << xstrerr(xerrno));
62e76326 1356
1357 break;
1358 }
1359
055421ee 1360 fd_bytes(fd, len, FD_READ);
4d6c8504 1361
62e76326 1362 assert(N);
aec55359 1363 ++(*N);
cc192b50 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. */
9dca980d 1368 int nsn = idnsFromKnownNameserver(from);
62e76326 1369
9dca980d
AJ
1370 if (nsn >= 0) {
1371 ++ nameservers[nsn].nreplies;
bd6a0c8f
HN
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
9dca980d 1379 if (nsn < 0 && Config.onoff.ignore_unknown_nameservers) {
62e76326 1380 static time_t last_warning = 0;
1381
1382 if (squid_curtime - last_warning > 60) {
e0236918 1383 debugs(78, DBG_IMPORTANT, "WARNING: Reply from unknown nameserver " << from);
62e76326 1384 last_warning = squid_curtime;
26ac0430 1385 } else {
e0236918 1386 debugs(78, DBG_IMPORTANT, "WARNING: Reply from unknown nameserver " << from << " (retrying..." << (squid_curtime-last_warning) << "<=60)" );
26ac0430
AJ
1387 }
1388 continue;
62e76326 1389 }
1390
9dca980d 1391 idnsGrokReply(rbuf, len, nsn);
7b724b86 1392 }
1393}
1394
7cfc1c9a 1395static void
ced8def3 1396idnsCheckQueue(void *)
7cfc1c9a 1397{
1398 dlink_node *n;
aee3523a 1399 dlink_node *p = nullptr;
7cfc1c9a 1400 idns_query *q;
1401 event_queued = 0;
62e76326 1402
b56b37cf 1403 if (nameservers.empty())
820ee9fa
AJ
1404 /* name servers went away; reconfiguring or shutting down */
1405 return;
1406
b56b37cf 1407 const auto nsCount = nameservers.size();
0c4fe9e4 1408 for (n = lru_list.tail; n; n = p) {
62e76326 1409
820ee9fa 1410 p = n->prev;
733cedc0 1411 q = static_cast<idns_query*>(n->data);
62e76326 1412
820ee9fa 1413 /* Anything to process in the queue? */
fd0f51c4 1414 if ((time_msec_t)tvSubMsec(q->queue_t, current_time) < Config.Timeout.idns_retransmit )
26ac0430 1415 break;
62e76326 1416
33ab4aaf 1417 /* Query timer still running? */
b56b37cf 1418 if ((time_msec_t)tvSubMsec(q->sent_t, current_time) < (Config.Timeout.idns_retransmit * 1 << ((q->nsends - 1) / nsCount))) {
820ee9fa
AJ
1419 dlinkDelete(&q->lru, &lru_list);
1420 q->queue_t = current_time;
1421 dlinkAdd(q, &q->lru, &lru_list);
1422 continue;
1423 }
62e76326 1424
91dcbd43
CT
1425 debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
1426 " QID 0x" << std::hex << std::setfill('0') <<
049441d9 1427 std::setw(4) << q->query_id << ": timeout" );
62e76326 1428
1429 dlinkDelete(&q->lru, &lru_list);
33ab4aaf 1430 q->pending = 0;
62e76326 1431
fd0f51c4 1432 if ((time_msec_t)tvSubMsec(q->start_t, current_time) < Config.Timeout.idns_query) {
62e76326 1433 idnsSendQuery(q);
1434 } else {
91dcbd43 1435 debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
049441d9 1436 " QID 0x" << std::hex << q->query_id <<
91dcbd43 1437 " : giving up after " << std::dec << q->nsends << " tries and " <<
26ac0430 1438 std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
3074b9d1 1439
1440 if (q->rcode != 0)
33ab4aaf 1441 idnsCallback(q, rfc1035ErrorMessage(q->rcode));
3074b9d1 1442 else
33ab4aaf 1443 idnsCallback(q, "Timeout");
62e76326 1444 }
7cfc1c9a 1445 }
62e76326 1446
efd900cb 1447 idnsTickleQueue();
7cfc1c9a 1448}
1449
d24ef4e9 1450static void
ced8def3 1451idnsReadVC(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int, void *data)
d24ef4e9 1452{
1453 nsvc * vc = (nsvc *)data;
1454
c8407295 1455 if (flag == Comm::ERR_CLOSING)
d24ef4e9 1456 return;
1457
c8407295 1458 if (flag != Comm::OK || len <= 0) {
80463bb4
AJ
1459 if (Comm::IsConnOpen(conn))
1460 conn->close();
d24ef4e9 1461 return;
1462 }
1463
bd6a0c8f 1464 vc->msg->size += len; // XXX should not access -> size directly
d24ef4e9 1465
032785bf 1466 if (vc->msg->contentSize() < vc->msglen) {
abd8f140
AJ
1467 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1468 CommIoCbPtrFun(idnsReadVC, vc));
1469 comm_read(conn, buf+len, vc->msglen - vc->msg->contentSize(), call);
d24ef4e9 1470 return;
1471 }
1472
b56b37cf 1473 assert(vc->ns < nameservers.size());
bf95c10a 1474 debugs(78, 3, conn << ": received " << vc->msg->contentSize() << " bytes via TCP from " << nameservers[vc->ns].S << ".");
d24ef4e9 1475
e210930b 1476 idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
2fe7eff9 1477 vc->msg->clean();
abd8f140
AJ
1478 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1479 CommIoCbPtrFun(idnsReadVCHeader, vc));
1480 comm_read(conn, (char *)&vc->msglen, 2, call);
d24ef4e9 1481}
1482
1483static void
ced8def3 1484idnsReadVCHeader(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int, void *data)
d24ef4e9 1485{
1486 nsvc * vc = (nsvc *)data;
1487
c8407295 1488 if (flag == Comm::ERR_CLOSING)
d24ef4e9 1489 return;
1490
c8407295 1491 if (flag != Comm::OK || len <= 0) {
80463bb4
AJ
1492 if (Comm::IsConnOpen(conn))
1493 conn->close();
d24ef4e9 1494 return;
1495 }
1496
1497 vc->read_msglen += len;
1498
1499 assert(vc->read_msglen <= 2);
1500
1501 if (vc->read_msglen < 2) {
abd8f140
AJ
1502 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1503 CommIoCbPtrFun(idnsReadVCHeader, vc));
1504 comm_read(conn, buf+len, 2 - vc->read_msglen, call);
d24ef4e9 1505 return;
1506 }
1507
1508 vc->read_msglen = 0;
1509
1510 vc->msglen = ntohs(vc->msglen);
1511
8185c30b
SS
1512 if (!vc->msglen) {
1513 if (Comm::IsConnOpen(conn))
1514 conn->close();
1515 return;
1516 }
1517
2fe7eff9 1518 vc->msg->init(vc->msglen, vc->msglen);
abd8f140
AJ
1519 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1520 CommIoCbPtrFun(idnsReadVC, vc));
1521 comm_read(conn, vc->msg->buf, vc->msglen, call);
d24ef4e9 1522}
1523
558be27a 1524/*
1525 * rcode < 0 indicates an error, rocde >= 0 indicates success
1526 */
1527static void
1528idnsRcodeCount(int rcode, int attempt)
1529{
1530 if (rcode > 0)
62e76326 1531 rcode = 0;
558be27a 1532 else if (rcode < 0)
62e76326 1533 rcode = -rcode;
1534
558be27a 1535 if (rcode < MAX_RCODE)
62e76326 1536 if (attempt < MAX_ATTEMPT)
95dc7ff4 1537 ++ RcodeMatrix[rcode][attempt];
558be27a 1538}
1539
7b724b86 1540void
4a3b98d7 1541Dns::Init(void)
7b724b86 1542{
1543 static int init = 0;
62e76326 1544
4d6c8504 1545 if (DnsSocketA < 0 && DnsSocketB < 0) {
61beade2 1546 Ip::Address addrV6; // since we do not want to alter Config.Addrs.udp_* and do not have one of our own.
62e76326 1547
4dd643d5 1548 if (!Config.Addrs.udp_outgoing.isNoAddr())
049441d9 1549 addrV6 = Config.Addrs.udp_outgoing;
62e76326 1550 else
049441d9 1551 addrV6 = Config.Addrs.udp_incoming;
62e76326 1552
049441d9 1553 Ip::Address addrV4 = addrV6;
4dd643d5 1554 addrV4.setIPv4();
7e07ced1 1555
4dd643d5 1556 if (Ip::EnableIpv6 && addrV6.isIPv6()) {
049441d9 1557 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6);
4d6c8504 1558 DnsSocketB = comm_open_listener(SOCK_DGRAM,
04f7fd38 1559 IPPROTO_UDP,
049441d9 1560 addrV6,
04f7fd38 1561 COMM_NONBLOCKING,
055421ee 1562 "DNS Socket IPv6");
7e07ced1 1563 }
4d6c8504 1564
4dd643d5 1565 if (addrV4.isIPv4()) {
049441d9 1566 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4);
4d6c8504 1567 DnsSocketA = comm_open_listener(SOCK_DGRAM,
04f7fd38 1568 IPPROTO_UDP,
049441d9 1569 addrV4,
04f7fd38 1570 COMM_NONBLOCKING,
055421ee 1571 "DNS Socket IPv4");
7e07ced1 1572 }
62e76326 1573
4d6c8504 1574 if (DnsSocketA < 0 && DnsSocketB < 0)
62e76326 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 */
04f7fd38 1580 if (DnsSocketB >= 0) {
e91e2a72 1581 comm_local_port(DnsSocketB);
c59baaa8 1582 debugs(78, Important(16), "DNS IPv6 socket created at " << addrV6 << ", FD " << DnsSocketB);
aee3523a 1583 Comm::SetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, nullptr, 0);
4d6c8504 1584 }
04f7fd38 1585 if (DnsSocketA >= 0) {
e91e2a72 1586 comm_local_port(DnsSocketA);
c59baaa8 1587 debugs(78, Important(64), "DNS IPv4 socket created at " << addrV4 << ", FD " << DnsSocketA);
aee3523a 1588 Comm::SetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, nullptr, 0);
4d6c8504 1589 }
7b724b86 1590 }
62e76326 1591
b56b37cf 1592 assert(nameservers.empty());
a079e38b
AJ
1593 idnsAddMDNSNameservers();
1594 bool nsFound = idnsParseNameservers();
62e76326 1595
a079e38b
AJ
1596 if (!nsFound)
1597 nsFound = idnsParseResolvConf();
62e76326 1598
be266cb2 1599#if _SQUID_WINDOWS_
a079e38b
AJ
1600 if (!nsFound)
1601 nsFound = idnsParseWIN32Registry();
0e6d05ef 1602#endif
62e76326 1603
a079e38b 1604 if (!nsFound) {
d816f28d 1605 debugs(78, DBG_IMPORTANT, "WARNING: Could not find any nameservers. Trying to use localhost");
be266cb2 1606#if _SQUID_WINDOWS_
e0236918 1607 debugs(78, DBG_IMPORTANT, "Please check your TCP-IP settings or /etc/resolv.conf file");
0e6d05ef 1608#else
e0236918 1609 debugs(78, DBG_IMPORTANT, "Please check your /etc/resolv.conf file");
0e6d05ef 1610#endif
29fe9bd5 1611
e0236918 1612 debugs(78, DBG_IMPORTANT, "or use the 'dns_nameservers' option in squid.conf.");
747552d8
AJ
1613 if (Ip::EnableIpv6)
1614 idnsAddNameserver("::1");
29fe9bd5 1615 idnsAddNameserver("127.0.0.1");
1616 }
62e76326 1617
7b724b86 1618 if (!init) {
62e76326 1619 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
30abd221 1620 idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
95dc7ff4 1621 ++init;
7b724b86 1622 }
372fb44e 1623
e210930b
AJ
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
4a3b98d7 1631 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
7b724b86 1632}
1633
ee58de20
AJ
1634static void
1635idnsShutdownAndFreeState(const char *reason)
7b724b86 1636{
4d6c8504 1637 if (DnsSocketA < 0 && DnsSocketB < 0)
62e76326 1638 return;
1639
ee58de20
AJ
1640 debugs(78, 2, reason << ": Closing DNS sockets");
1641
04f7fd38 1642 if (DnsSocketA >= 0 ) {
4d6c8504
AJ
1643 comm_close(DnsSocketA);
1644 DnsSocketA = -1;
1645 }
62e76326 1646
055421ee 1647 if (DnsSocketB >= 0 ) {
4d6c8504
AJ
1648 comm_close(DnsSocketB);
1649 DnsSocketB = -1;
1650 }
62e76326 1651
b56b37cf
AJ
1652 for (const auto &server : nameservers) {
1653 if (const auto vc = server.vc) {
00406b24
AJ
1654 if (Comm::IsConnOpen(vc->conn))
1655 vc->conn->close();
b26754c4 1656 }
1657 }
1658
dd3fb890 1659 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
b56b37cf 1660 nameservers.clear();
68836b58 1661 idnsFreeSearchpath();
7b724b86 1662}
1663
ee58de20
AJ
1664void
1665Dns::ConfigRr::endingShutdown()
1666{
1667 idnsShutdownAndFreeState("Shutdown");
1668}
1669
1670void
1671Dns::ConfigRr::startReconfigure()
1672{
1673 idnsShutdownAndFreeState("Reconfigure");
1674}
1675
3074b9d1 1676static int
1677idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1678{
3074b9d1 1679 idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
1680
1681 if (!old)
1682 return 0;
1683
55622953
CT
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
907a7a05 1687 idns_query *q = new idns_query;
049441d9 1688 // no query_id on this instance.
3074b9d1 1689
1690 q->callback = callback;
3074b9d1 1691 q->callback_data = cbdataReference(data);
1692
1693 q->queue = old->queue;
3074b9d1 1694 old->queue = q;
1695
fd9c47d1
AR
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
3074b9d1 1703 return 1;
1704}
1705
1706static void
33ab4aaf 1707idnsStartQuery(idns_query *q, IDNSCB * callback, void *data)
3074b9d1 1708{
33ab4aaf
HN
1709 q->start_t = current_time;
1710 q->callback = callback;
1711 q->callback_data = cbdataReference(data);
1712
049441d9 1713 q->hash.key = q->orig;
3074b9d1 1714 hash_join(idns_lookup_hash, &q->hash);
33ab4aaf
HN
1715
1716 idnsSendQuery(q);
3074b9d1 1717}
1718
049441d9
HN
1719static void
1720idnsSendSlaveAAAAQuery(idns_query *master)
1721{
907a7a05 1722 idns_query *q = new idns_query;
049441d9
HN
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);
c7ba545e 1728
bf95c10a 1729 debugs(78, 3, "buf is " << q->sz << " bytes for " << q->name <<
049441d9
HN
1730 ", id = 0x" << std::hex << q->query_id);
1731 if (!q->sz) {
907a7a05 1732 delete q;
049441d9
HN
1733 return;
1734 }
907a7a05
AJ
1735
1736 q->start_t = master->start_t;
1737 q->slave = master->slave;
1738
a079e38b 1739 idnsCheckMDNS(q);
049441d9
HN
1740 master->slave = q;
1741 idnsSendQuery(q);
1742}
1743
7b724b86 1744void
1745idnsALookup(const char *name, IDNSCB * callback, void *data)
1746{
32f89713
NH
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.");
fd9c47d1 1752 idnsCallbackOnEarlyError(callback, data, "huge name");
32f89713
NH
1753 return;
1754 }
3074b9d1 1755
1756 if (idnsCachedLookup(name, callback, data))
1757 return;
1758
907a7a05 1759 idns_query *q = new idns_query;
049441d9 1760 q->query_id = idnsQueryID();
71952967 1761
32f89713 1762 int nd = 0;
b56b37cf 1763 for (size_t i = 0; i < nameLength; ++i)
68836b58 1764 if (name[i] == '.')
95dc7ff4 1765 ++nd;
68836b58 1766
32f89713 1767 if (Config.onoff.res_defnames && npc > 0 && name[nameLength-1] != '.') {
68836b58 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);
bf8fe701 1780 debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
68836b58 1781 }
1782
049441d9
HN
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);
62e76326 1785
2041330b 1786 if (q->sz < 0) {
1787 /* problem with query data -- query not sent */
fd9c47d1 1788 idnsCallbackOnEarlyError(callback, data, "rfc3596BuildAQuery error");
907a7a05 1789 delete q;
2041330b 1790 return;
1791 }
1792
26ac0430 1793 debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
049441d9 1794 ", id = 0x" << std::hex << q->query_id);
aa6c61e3 1795
a079e38b 1796 idnsCheckMDNS(q);
33ab4aaf 1797 idnsStartQuery(q, callback, data);
049441d9
HN
1798
1799 if (Ip::EnableIpv6)
1800 idnsSendSlaveAAAAQuery(q);
7b724b86 1801}
8db71107 1802
1803void
b7ac5457 1804idnsPTRLookup(const Ip::Address &addr, IDNSCB * callback, void *data)
8db71107 1805{
cc192b50 1806 char ip[MAX_IPSTRLEN];
1807
4dd643d5 1808 addr.toStr(ip,MAX_IPSTRLEN);
3074b9d1 1809
907a7a05 1810 idns_query *q = new idns_query;
049441d9 1811 q->query_id = idnsQueryID();
71952967 1812
4dd643d5 1813 if (addr.isIPv6()) {
cc192b50 1814 struct in6_addr addr6;
4dd643d5 1815 addr.getInAddr(addr6);
546ae352 1816 q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
055421ee 1817 } else {
cc192b50 1818 struct in_addr addr4;
4dd643d5 1819 addr.getInAddr(addr4);
e210930b 1820 // see EDNS notes at top of file why this sends 0
546ae352 1821 q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
cc192b50 1822 }
1823
26ac0430 1824 if (q->sz < 0) {
2041330b 1825 /* problem with query data -- query not sent */
fd9c47d1 1826 idnsCallbackOnEarlyError(callback, data, "rfc3596BuildPTRQuery error");
907a7a05 1827 delete q;
2041330b 1828 return;
1829 }
1830
37f3da43 1831 if (idnsCachedLookup(q->query.name, callback, data)) {
907a7a05 1832 delete q;
26ac0430 1833 return;
37f3da43 1834 }
1835
26ac0430 1836 debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
049441d9 1837 ", id = 0x" << std::hex << q->query_id);
3074b9d1 1838
bce61b00 1839 q->permit_mdns = Config.onoff.dns_mdns;
33ab4aaf 1840 idnsStartQuery(q, callback, data);
8db71107 1841}
eb824054 1842
59ad6d31 1843#if SQUID_SNMP
3c573763 1844/*
1845 * The function to return the DNS via SNMP
1846 */
1847variable_list *
f64091a7 1848snmp_netDnsFn(variable_list * Var, snint * ErrP)
3c573763 1849{
b56b37cf 1850 int n = 0;
aee3523a 1851 variable_list *Answer = nullptr;
6a644e75
AJ
1852 MemBuf tmp;
1853 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var->name, Var->name_length, tmp));
3c573763 1854 *ErrP = SNMP_ERR_NOERROR;
62e76326 1855
3c573763 1856 switch (Var->name[LEN_SQ_NET + 1]) {
62e76326 1857
3c573763 1858 case DNS_REQ:
62e76326 1859
b56b37cf
AJ
1860 for (const auto &server : nameservers)
1861 n += server.nqueries;
62e76326 1862
1863 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1864 n,
1865 SMI_COUNTER32);
1866
1867 break;
1868
3c573763 1869 case DNS_REP:
b56b37cf
AJ
1870 for (const auto &server : nameservers)
1871 n += server.nreplies;
62e76326 1872
1873 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1874 n,
1875 SMI_COUNTER32);
1876
1877 break;
1878
3c573763 1879 case DNS_SERVERS:
62e76326 1880 Answer = snmp_var_new_integer(Var->name, Var->name_length,
b56b37cf 1881 nameservers.size(),
62e76326 1882 SMI_COUNTER32);
1883
1884 break;
1885
3c573763 1886 default:
62e76326 1887 *ErrP = SNMP_ERR_NOSUCHNAME;
1888
1889 break;
3c573763 1890 }
62e76326 1891
3c573763 1892 return Answer;
1893}
62e76326 1894
3c573763 1895#endif /*SQUID_SNMP */
f53969cc 1896