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