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