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