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