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