]> git.ipfire.org Git - thirdparty/squid.git/blame - src/dns_internal.cc
squidclient: Fix -N option to correctly read argument
[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())
105f7a99
AJ
902 conn->local = Config.Addrs.udp_outgoing;
903 else
904 conn->local = Config.Addrs.udp_incoming;
905
9dca980d 906 conn->remote = nameservers[nsv].S;
d24ef4e9 907
4dd643d5
AJ
908 if (conn->remote.isIPv4()) {
909 conn->local.setIPv4();
f5ba22ff
AJ
910 }
911
cfd66529 912 AsyncCall::Pointer call = commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected, vc));
d24ef4e9 913
4accd6d8 914 Comm::ConnOpener *cs = new Comm::ConnOpener(conn, call, Config.Timeout.connect);
aed188fd 915 cs->setHost("DNS TCP Socket");
855150a4 916 AsyncJob::Start(cs);
d24ef4e9 917}
918
919static void
9dca980d 920idnsSendQueryVC(idns_query * q, int nsn)
d24ef4e9 921{
9dca980d
AJ
922 assert(nsn < nns);
923 if (nameservers[nsn].vc == NULL)
924 idnsInitVC(nsn);
d24ef4e9 925
9dca980d 926 nsvc *vc = nameservers[nsn].vc;
d24ef4e9 927
445962f3
HN
928 if (!vc) {
929 char buf[MAX_IPSTRLEN];
4dd643d5 930 debugs(78, DBG_IMPORTANT, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers[nsn].S.toStr(buf,MAX_IPSTRLEN) << "!");
445962f3
HN
931
932 return;
933 }
934
2fe7eff9 935 vc->queue->reset();
d24ef4e9 936
937 short head = htons(q->sz);
938
2fe7eff9 939 vc->queue->append((char *)&head, 2);
d24ef4e9 940
2fe7eff9 941 vc->queue->append(q->buf, q->sz);
d24ef4e9 942
943 idnsDoSendQueryVC(vc);
944}
945
7b724b86 946static void
947idnsSendQuery(idns_query * q)
948{
4d6c8504 949 if (DnsSocketA < 0 && DnsSocketB < 0) {
e0236918 950 debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
62e76326 951 return;
0a69973e 952 }
62e76326 953
cc192b50 954 if (nns <= 0) {
e0236918 955 debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
cc192b50 956 return;
957 }
62e76326 958
7b724b86 959 assert(q->lru.next == NULL);
62e76326 960
7b724b86 961 assert(q->lru.prev == NULL);
62e76326 962
4d6c8504 963 int x = -1, y = -1;
9dca980d 964 int nsn;
4d6c8504 965
213b6c90 966 do {
a079e38b
AJ
967 // only use mDNS resolvers for mDNS compatible queries
968 if (!q->permit_mdns)
51aee437 969 nsn = nns_mdns_count + q->nsends % (nns-nns_mdns_count);
a079e38b
AJ
970 else
971 nsn = q->nsends % nns;
213b6c90
AJ
972
973 if (q->need_vc) {
9dca980d 974 idnsSendQueryVC(q, nsn);
4d6c8504 975 x = y = 0;
213b6c90 976 } else {
4dd643d5 977 if (DnsSocketB >= 0 && nameservers[nsn].S.isIPv6())
9dca980d 978 y = comm_udp_sendto(DnsSocketB, nameservers[nsn].S, q->buf, q->sz);
049441d9 979 else if (DnsSocketA >= 0)
9dca980d 980 x = comm_udp_sendto(DnsSocketA, nameservers[nsn].S, q->buf, q->sz);
213b6c90 981 }
62e76326 982
95dc7ff4 983 ++ q->nsends;
62e76326 984
33ab4aaf 985 q->sent_t = current_time;
62e76326 986
4dd643d5 987 if (y < 0 && nameservers[nsn].S.isIPv6())
e0236918 988 debugs(50, DBG_IMPORTANT, "idnsSendQuery: FD " << DnsSocketB << ": sendto: " << xstrerror());
4dd643d5 989 if (x < 0 && nameservers[nsn].S.isIPv4())
e0236918 990 debugs(50, DBG_IMPORTANT, "idnsSendQuery: FD " << DnsSocketA << ": sendto: " << xstrerror());
4d6c8504
AJ
991
992 } while ( (x<0 && y<0) && q->nsends % nns != 0);
62e76326 993
bd6a0c8f 994 if (y > 0) {
4d6c8504 995 fd_bytes(DnsSocketB, y, FD_WRITE);
4d6c8504 996 }
bd6a0c8f 997 if (x > 0) {
4d6c8504 998 fd_bytes(DnsSocketA, x, FD_WRITE);
0a69973e 999 }
62e76326 1000
9dca980d 1001 ++ nameservers[nsn].nqueries;
c131f066 1002 q->queue_t = current_time;
7b724b86 1003 dlinkAdd(q, &q->lru, &lru_list);
049441d9 1004 q->pending = 1;
efd900cb 1005 idnsTickleQueue();
7b724b86 1006}
1007
1008static int
b7ac5457 1009idnsFromKnownNameserver(Ip::Address const &from)
7b724b86 1010{
1011 int i;
62e76326 1012
95dc7ff4 1013 for (i = 0; i < nns; ++i) {
cc192b50 1014 if (nameservers[i].S != from)
62e76326 1015 continue;
1016
4dd643d5 1017 if (nameservers[i].S.port() != from.port())
62e76326 1018 continue;
1019
1020 return i;
7b724b86 1021 }
62e76326 1022
7cfc1c9a 1023 return -1;
7b724b86 1024}
1025
1026static idns_query *
1027idnsFindQuery(unsigned short id)
1028{
1029 dlink_node *n;
1030 idns_query *q;
62e76326 1031
7b724b86 1032 for (n = lru_list.tail; n; n = n->prev) {
62e76326 1033 q = (idns_query*)n->data;
1034
049441d9 1035 if (q->query_id == id)
62e76326 1036 return q;
7b724b86 1037 }
62e76326 1038
7b724b86 1039 return NULL;
1040}
1041
108d67a0 1042static unsigned short
1043idnsQueryID(void)
1044{
1045 unsigned short id = squid_random() & 0xFFFF;
1046 unsigned short first_id = id;
1047
26ac0430 1048 while (idnsFindQuery(id)) {
95dc7ff4 1049 ++id;
108d67a0 1050
846c8960 1051 if (id == first_id) {
e0236918 1052 debugs(78, DBG_IMPORTANT, "idnsQueryID: Warning, too many pending DNS requests");
108d67a0 1053 break;
846c8960 1054 }
108d67a0 1055 }
1056
846c8960 1057 return id;
108d67a0 1058}
1059
3074b9d1 1060static void
33ab4aaf 1061idnsCallback(idns_query *q, const char *error)
3074b9d1 1062{
1063 IDNSCB *callback;
1064 void *cbdata;
1065
33ab4aaf
HN
1066 if (error)
1067 q->error = error;
1068
1069 if (q->master)
1070 q = q->master;
1071
33ab4aaf 1072 // If any of our subqueries are still pending then wait for them to complete before continuing
9dca980d 1073 for (idns_query *q2 = q; q2; q2 = q2->slave) {
33ab4aaf
HN
1074 if (q2->pending) {
1075 return;
1076 }
1077 }
1078
1079 /* Merge results */
1080 rfc1035_message *message = q->message;
1081 q->message = NULL;
1082 int n = q->ancount;
1083 error = q->error;
1084
9dca980d 1085 while ( idns_query *q2 = q->slave ) {
33ab4aaf
HN
1086 debugs(78, 6, HERE << "Merging DNS results " << q->name << " A has " << n << " RR, AAAA has " << q2->ancount << " RR");
1087 q->slave = q2->slave;
1088 if ( !q2->error ) {
1089 if (n > 0) {
1090 // two sets of RR need merging
1091 rfc1035_rr *result = (rfc1035_rr*) xmalloc( sizeof(rfc1035_rr)*(n + q2->ancount) );
1092 if (Config.dns.v4_first) {
1093 memcpy(result, message->answer, (sizeof(rfc1035_rr)*n) );
1094 memcpy(result+n, q2->message->answer, (sizeof(rfc1035_rr)*q2->ancount) );
1095 } else {
1096 memcpy(result, q2->message->answer, (sizeof(rfc1035_rr)*q2->ancount) );
1097 memcpy(result+q2->ancount, message->answer, (sizeof(rfc1035_rr)*n) );
1098 }
1099 n += q2->ancount;
1100 // HACK WARNING, the answer rr:s have been copied in-place to
1101 // result, do not free them here
1102 safe_free(message->answer);
1103 safe_free(q2->message->answer);
1104 message->answer = result;
1105 message->ancount += q2->message->ancount;
1106 } else {
1107 // first response empty or failed, just use the second
1108 rfc1035MessageDestroy(&message);
1109 message = q2->message;
1110 q2->message = NULL;
1111 n = q2->ancount;
1112 error = NULL;
1113 }
1114 }
1115 rfc1035MessageDestroy(&q2->message);
1116 cbdataFree(q2);
1117 }
1118
1119 debugs(78, 6, HERE << "Sending " << n << " (" << (error ? error : "OK") << ") DNS results to caller.");
1120
3074b9d1 1121 callback = q->callback;
1122 q->callback = NULL;
33ab4aaf 1123 const rfc1035_rr *answers = message ? message->answer : NULL;
3074b9d1 1124
1125 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
1126 callback(cbdata, answers, n, error);
1127
26ac0430 1128 while (q->queue) {
3074b9d1 1129 idns_query *q2 = q->queue;
1130 q->queue = q2->queue;
1131 callback = q2->callback;
1132 q2->callback = NULL;
1133
1134 if (cbdataReferenceValidDone(q2->callback_data, &cbdata))
1135 callback(cbdata, answers, n, error);
1136
63a0e6b7 1137 cbdataFree(q2);
3074b9d1 1138 }
1139
1140 if (q->hash.key) {
1141 hash_remove_link(idns_lookup_hash, &q->hash);
1142 q->hash.key = NULL;
1143 }
33ab4aaf
HN
1144
1145 rfc1035MessageDestroy(&message);
1146 cbdataFree(q);
3074b9d1 1147}
1148
7b724b86 1149static void
e210930b 1150idnsGrokReply(const char *buf, size_t sz, int from_ns)
7b724b86 1151{
1152 int n;
ec7bade0 1153 rfc1035_message *message = NULL;
7b724b86 1154 idns_query *q;
3074b9d1 1155
cc192b50 1156 n = rfc1035MessageUnpack(buf, sz, &message);
62e76326 1157
ec7bade0 1158 if (message == NULL) {
e0236918 1159 debugs(78, DBG_IMPORTANT, "idnsGrokReply: Malformed DNS response");
62e76326 1160 return;
7b724b86 1161 }
62e76326 1162
91dcbd43 1163 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex << message->id << ", " << std::dec << n << " answers");
ec7bade0 1164
1165 q = idnsFindQuery(message->id);
1166
7b724b86 1167 if (q == NULL) {
bf8fe701 1168 debugs(78, 3, "idnsGrokReply: Late response");
cc192b50 1169 rfc1035MessageDestroy(&message);
62e76326 1170 return;
7b724b86 1171 }
62e76326 1172
9e1f210d 1173 if (rfc1035QueryCompare(&q->query, message->query) != 0) {
bf8fe701 1174 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q->query.name << " != " << message->query->name << ")");
cc192b50 1175 rfc1035MessageDestroy(&message);
9e1f210d 1176 return;
1177 }
1178
e210930b
AJ
1179#if WHEN_EDNS_RESPONSES_ARE_PARSED
1180// TODO: actually gr the message right here.
1181// pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1182// this is overall better than force-feeding A response with AAAA an section later anyway.
1183// AND allows us to merge AN+AR sections from both responses (one day)
1184
1185 if (q->edns_seen >= 0) {
1186 if (max_shared_edns == nameservers[from_ns].last_seen_edns && max_shared_edns < q->edns_seen) {
1187 nameservers[from_ns].last_seen_edns = q->edns_seen;
1188 // the altered NS was limiting the whole group.
1189 max_shared_edns = q->edns_seen;
1190 // may be limited by one of the others still
95dc7ff4 1191 for (int i = 0; i < nns; ++i)
e210930b
AJ
1192 max_shared_edns = min(max_shared_edns, nameservers[i].last_seen_edns);
1193 } else {
1194 nameservers[from_ns].last_seen_edns = q->edns_seen;
1195 // maybe reduce the global limit downwards to accomodate this NS
1196 max_shared_edns = min(max_shared_edns, q->edns_seen);
1197 }
1198 if (max_shared_edns < RFC1035_DEFAULT_PACKET_SZ)
1199 max_shared_edns = -1;
1200 }
1201#endif
1202
049441d9
HN
1203 dlinkDelete(&q->lru, &lru_list);
1204 q->pending = 0;
1205
d24ef4e9 1206 if (message->tc) {
bae9832d 1207 debugs(78, 3, HERE << "Resolver requested TC (" << q->query.name << ")");
cc192b50 1208 rfc1035MessageDestroy(&message);
d24ef4e9 1209
1210 if (!q->need_vc) {
1211 q->need_vc = 1;
5e263176 1212 -- q->nsends;
d24ef4e9 1213 idnsSendQuery(q);
91dcbd43
CT
1214 } else {
1215 // Strange: A TCP DNS response with the truncation bit (TC) set.
1216 // Return an error and cleanup; no point in trying TCP again.
1217 debugs(78, 3, HERE << "TCP DNS response");
33ab4aaf 1218 idnsCallback(q, "Truncated TCP DNS response");
d24ef4e9 1219 }
1220
1221 return;
1222 }
9e1f210d 1223
558be27a 1224 idnsRcodeCount(n, q->attempt);
62e76326 1225
558be27a 1226 if (n < 0) {
7ba8d0b8 1227 q->rcode = -n;
42687bb2 1228 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n) << " (" << q->rcode << ")");
7ba8d0b8 1229
95dc7ff4 1230 if (q->rcode == 2 && (++ q->attempt) < MAX_ATTEMPT) {
62e76326 1231 /*
1232 * RCODE 2 is "Server failure - The name server was
1233 * unable to process this query due to a problem with
1234 * the name server."
1235 */
cc192b50 1236 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1237 rfc1035MessageDestroy(&message);
62e76326 1238 idnsSendQuery(q);
1239 return;
1240 }
68836b58 1241
0e6432d0
HN
1242 // Do searchpath processing on the master A query only to keep
1243 // things simple. NXDOMAIN is authorative for the label, not
1244 // the record type.
049441d9 1245 if (q->rcode == 3 && !q->master && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
68836b58 1246 assert(NULL == message->answer);
1247 strcpy(q->name, q->orig);
1248
cc192b50 1249 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q->name );
1250
68836b58 1251 if (q->domain < npc) {
1252 strcat(q->name, ".");
1253 strcat(q->name, searchpath[q->domain].domain);
bf8fe701 1254 debugs(78, 3, "idnsGrokReply: searchpath used for " << q->name);
95dc7ff4 1255 ++ q->domain;
68836b58 1256 } else {
95dc7ff4 1257 ++ q->attempt;
68836b58 1258 }
1259
049441d9 1260 rfc1035MessageDestroy(&message);
cc192b50 1261
33ab4aaf 1262 // cleanup slave AAAA query
049441d9
HN
1263 while (idns_query *slave = q->slave) {
1264 dlinkDelete(&slave->lru, &lru_list);
1265 q->slave = slave->slave;
1266 rfc1035MessageDestroy(&slave->message);
1267 cbdataFree(slave);
cc192b50 1268 }
c7ba545e 1269
049441d9
HN
1270 // Build new query
1271 q->query_id = idnsQueryID();
1272 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
1273 // see EDNS notes at top of file why this sends 0
1274 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
c4a7fa29
AJ
1275 if (q->sz < 0) {
1276 /* problem with query data -- query not sent */
33ab4aaf 1277 idnsCallback(q, "Internal error");
c4a7fa29
AJ
1278 return;
1279 }
1280
33ab4aaf
HN
1281 q->nsends = 0;
1282
a079e38b 1283 idnsCheckMDNS(q);
68836b58 1284 idnsSendQuery(q);
049441d9
HN
1285 if (Ip::EnableIpv6)
1286 idnsSendSlaveAAAAQuery(q);
68836b58 1287 return;
1288 }
558be27a 1289 }
62e76326 1290
049441d9
HN
1291 q->message = message;
1292 q->ancount = n;
cc192b50 1293
33ab4aaf
HN
1294 if (n >= 0)
1295 idnsCallback(q, NULL);
1296 else
1297 idnsCallback(q, rfc1035ErrorMessage(q->rcode));
bae9832d 1298
7b724b86 1299}
1300
1301static void
1302idnsRead(int fd, void *data)
1303{
d193a436 1304 int *N = &incoming_sockets_accepted;
0b6d1955 1305 int len;
42b51993 1306 int max = INCOMING_DNS_MAX;
d29b40de 1307 static char rbuf[SQUID_UDP_SO_RCVBUF];
b7ac5457 1308 Ip::Address from;
cc192b50 1309
d7e7eaa7 1310 debugs(78, 3, "idnsRead: starting with FD " << fd);
cc192b50 1311
bd6a0c8f
HN
1312 // Always keep reading. This stops (or at least makes harder) several
1313 // attacks on the DNS client.
d841c88d 1314 Comm::SetSelect(fd, COMM_SELECT_READ, idnsRead, NULL, 0);
bd6a0c8f 1315
cc192b50 1316 /* BUG (UNRESOLVED)
1317 * two code lines after returning from comm_udprecvfrom()
1318 * something overwrites the memory behind the from parameter.
1319 * NO matter where in the stack declaration list above it is placed
1320 * The cause of this is still unknown, however copying the data appears
1321 * to allow it to be passed further without this erasure.
1322 */
b7ac5457 1323 Ip::Address bugbypass;
62e76326 1324
5e263176
FC
1325 while (max) {
1326 --max;
cc192b50 1327 len = comm_udp_recvfrom(fd, rbuf, SQUID_UDP_SO_RCVBUF, 0, bugbypass);
62e76326 1328
cc192b50 1329 from = bugbypass; // BUG BYPASS. see notes above.
62e76326 1330
1331 if (len == 0)
1332 break;
1333
1334 if (len < 0) {
1335 if (ignoreErrno(errno))
1336 break;
1337
1191b93b 1338#if _SQUID_LINUX_
62e76326 1339 /* Some Linux systems seem to set the FD for reading and then
1340 * return ECONNREFUSED when sendto() fails and generates an ICMP
1341 * port unreachable message. */
1342 /* or maybe an EHOSTUNREACH "No route to host" message */
1343 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
7b724b86 1344#endif
62e76326 1345
e0236918 1346 debugs(50, DBG_IMPORTANT, "idnsRead: FD " << fd << " recvfrom: " << xstrerror());
62e76326 1347
1348 break;
1349 }
1350
055421ee 1351 fd_bytes(fd, len, FD_READ);
4d6c8504 1352
62e76326 1353 assert(N);
aec55359 1354 ++(*N);
cc192b50 1355
1356 debugs(78, 3, "idnsRead: FD " << fd << ": received " << len << " bytes from " << from);
1357
1358 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
9dca980d 1359 int nsn = idnsFromKnownNameserver(from);
62e76326 1360
9dca980d
AJ
1361 if (nsn >= 0) {
1362 ++ nameservers[nsn].nreplies;
bd6a0c8f
HN
1363 }
1364
1365 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1366 // but after the ++ above to keep statistics right.
1367 if (!lru_list.head)
1368 continue; // Don't process replies if there is no pending query.
1369
9dca980d 1370 if (nsn < 0 && Config.onoff.ignore_unknown_nameservers) {
62e76326 1371 static time_t last_warning = 0;
1372
1373 if (squid_curtime - last_warning > 60) {
e0236918 1374 debugs(78, DBG_IMPORTANT, "WARNING: Reply from unknown nameserver " << from);
62e76326 1375 last_warning = squid_curtime;
26ac0430 1376 } else {
e0236918 1377 debugs(78, DBG_IMPORTANT, "WARNING: Reply from unknown nameserver " << from << " (retrying..." << (squid_curtime-last_warning) << "<=60)" );
26ac0430
AJ
1378 }
1379 continue;
62e76326 1380 }
1381
9dca980d 1382 idnsGrokReply(rbuf, len, nsn);
7b724b86 1383 }
1384}
1385
7cfc1c9a 1386static void
1387idnsCheckQueue(void *unused)
1388{
1389 dlink_node *n;
0c4fe9e4 1390 dlink_node *p = NULL;
7cfc1c9a 1391 idns_query *q;
1392 event_queued = 0;
62e76326 1393
820ee9fa
AJ
1394 if (0 == nns)
1395 /* name servers went away; reconfiguring or shutting down */
1396 return;
1397
0c4fe9e4 1398 for (n = lru_list.tail; n; n = p) {
62e76326 1399
820ee9fa 1400 p = n->prev;
733cedc0 1401 q = static_cast<idns_query*>(n->data);
62e76326 1402
820ee9fa 1403 /* Anything to process in the queue? */
fd0f51c4 1404 if ((time_msec_t)tvSubMsec(q->queue_t, current_time) < Config.Timeout.idns_retransmit )
26ac0430 1405 break;
62e76326 1406
33ab4aaf 1407 /* Query timer still running? */
fd0f51c4 1408 if ((time_msec_t)tvSubMsec(q->sent_t, current_time) < (Config.Timeout.idns_retransmit * 1 << ((q->nsends - 1) / nns))) {
820ee9fa
AJ
1409 dlinkDelete(&q->lru, &lru_list);
1410 q->queue_t = current_time;
1411 dlinkAdd(q, &q->lru, &lru_list);
1412 continue;
1413 }
62e76326 1414
91dcbd43
CT
1415 debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
1416 " QID 0x" << std::hex << std::setfill('0') <<
049441d9 1417 std::setw(4) << q->query_id << ": timeout" );
62e76326 1418
1419 dlinkDelete(&q->lru, &lru_list);
33ab4aaf 1420 q->pending = 0;
62e76326 1421
fd0f51c4 1422 if ((time_msec_t)tvSubMsec(q->start_t, current_time) < Config.Timeout.idns_query) {
62e76326 1423 idnsSendQuery(q);
1424 } else {
91dcbd43 1425 debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
049441d9 1426 " QID 0x" << std::hex << q->query_id <<
91dcbd43 1427 " : giving up after " << std::dec << q->nsends << " tries and " <<
26ac0430 1428 std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
3074b9d1 1429
1430 if (q->rcode != 0)
33ab4aaf 1431 idnsCallback(q, rfc1035ErrorMessage(q->rcode));
3074b9d1 1432 else
33ab4aaf 1433 idnsCallback(q, "Timeout");
62e76326 1434 }
7cfc1c9a 1435 }
62e76326 1436
efd900cb 1437 idnsTickleQueue();
7cfc1c9a 1438}
1439
d24ef4e9 1440static void
c8407295 1441idnsReadVC(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
d24ef4e9 1442{
1443 nsvc * vc = (nsvc *)data;
1444
c8407295 1445 if (flag == Comm::ERR_CLOSING)
d24ef4e9 1446 return;
1447
c8407295 1448 if (flag != Comm::OK || len <= 0) {
80463bb4
AJ
1449 if (Comm::IsConnOpen(conn))
1450 conn->close();
d24ef4e9 1451 return;
1452 }
1453
bd6a0c8f 1454 vc->msg->size += len; // XXX should not access -> size directly
d24ef4e9 1455
032785bf 1456 if (vc->msg->contentSize() < vc->msglen) {
abd8f140
AJ
1457 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1458 CommIoCbPtrFun(idnsReadVC, vc));
1459 comm_read(conn, buf+len, vc->msglen - vc->msg->contentSize(), call);
d24ef4e9 1460 return;
1461 }
1462
dd3fb890 1463 assert(vc->ns < nns);
e0d28505 1464 debugs(78, 3, HERE << conn << ": received " << vc->msg->contentSize() << " bytes via TCP from " << nameservers[vc->ns].S << ".");
d24ef4e9 1465
e210930b 1466 idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
2fe7eff9 1467 vc->msg->clean();
abd8f140
AJ
1468 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1469 CommIoCbPtrFun(idnsReadVCHeader, vc));
1470 comm_read(conn, (char *)&vc->msglen, 2, call);
d24ef4e9 1471}
1472
1473static void
c8407295 1474idnsReadVCHeader(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
d24ef4e9 1475{
1476 nsvc * vc = (nsvc *)data;
1477
c8407295 1478 if (flag == Comm::ERR_CLOSING)
d24ef4e9 1479 return;
1480
c8407295 1481 if (flag != Comm::OK || len <= 0) {
80463bb4
AJ
1482 if (Comm::IsConnOpen(conn))
1483 conn->close();
d24ef4e9 1484 return;
1485 }
1486
1487 vc->read_msglen += len;
1488
1489 assert(vc->read_msglen <= 2);
1490
1491 if (vc->read_msglen < 2) {
abd8f140
AJ
1492 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1493 CommIoCbPtrFun(idnsReadVCHeader, vc));
1494 comm_read(conn, buf+len, 2 - vc->read_msglen, call);
d24ef4e9 1495 return;
1496 }
1497
1498 vc->read_msglen = 0;
1499
1500 vc->msglen = ntohs(vc->msglen);
1501
8185c30b
SS
1502 if (!vc->msglen) {
1503 if (Comm::IsConnOpen(conn))
1504 conn->close();
1505 return;
1506 }
1507
2fe7eff9 1508 vc->msg->init(vc->msglen, vc->msglen);
abd8f140
AJ
1509 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1510 CommIoCbPtrFun(idnsReadVC, vc));
1511 comm_read(conn, vc->msg->buf, vc->msglen, call);
d24ef4e9 1512}
1513
558be27a 1514/*
1515 * rcode < 0 indicates an error, rocde >= 0 indicates success
1516 */
1517static void
1518idnsRcodeCount(int rcode, int attempt)
1519{
1520 if (rcode > 0)
62e76326 1521 rcode = 0;
558be27a 1522 else if (rcode < 0)
62e76326 1523 rcode = -rcode;
1524
558be27a 1525 if (rcode < MAX_RCODE)
62e76326 1526 if (attempt < MAX_ATTEMPT)
95dc7ff4 1527 ++ RcodeMatrix[rcode][attempt];
558be27a 1528}
1529
7b724b86 1530/* ====================================================================== */
1531
5f5e883f
FC
1532static void
1533idnsRegisterWithCacheManager(void)
1534{
8822ebee 1535 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
5f5e883f
FC
1536}
1537
7b724b86 1538void
f64091a7 1539dnsInit(void)
7b724b86 1540{
1541 static int init = 0;
62e76326 1542
d24ef4e9 1543 CBDATA_INIT_TYPE(nsvc);
63a0e6b7 1544 CBDATA_INIT_TYPE(idns_query);
d24ef4e9 1545
4d6c8504 1546 if (DnsSocketA < 0 && DnsSocketB < 0) {
049441d9 1547 Ip::Address addrV6; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
62e76326 1548
4dd643d5 1549 if (!Config.Addrs.udp_outgoing.isNoAddr())
049441d9 1550 addrV6 = Config.Addrs.udp_outgoing;
62e76326 1551 else
049441d9 1552 addrV6 = Config.Addrs.udp_incoming;
62e76326 1553
049441d9 1554 Ip::Address addrV4 = addrV6;
4dd643d5 1555 addrV4.setIPv4();
7e07ced1 1556
4dd643d5 1557 if (Ip::EnableIpv6 && addrV6.isIPv6()) {
049441d9 1558 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6);
4d6c8504 1559 DnsSocketB = comm_open_listener(SOCK_DGRAM,
04f7fd38 1560 IPPROTO_UDP,
049441d9 1561 addrV6,
04f7fd38 1562 COMM_NONBLOCKING,
055421ee 1563 "DNS Socket IPv6");
7e07ced1 1564 }
4d6c8504 1565
4dd643d5 1566 if (addrV4.isIPv4()) {
049441d9 1567 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4);
4d6c8504 1568 DnsSocketA = comm_open_listener(SOCK_DGRAM,
04f7fd38 1569 IPPROTO_UDP,
049441d9 1570 addrV4,
04f7fd38 1571 COMM_NONBLOCKING,
055421ee 1572 "DNS Socket IPv4");
7e07ced1 1573 }
62e76326 1574
4d6c8504 1575 if (DnsSocketA < 0 && DnsSocketB < 0)
62e76326 1576 fatal("Could not create a DNS socket");
1577
1578 /* Ouch... we can't call functions using debug from a debug
1579 * statement. Doing so messes up the internal Debug::level
1580 */
04f7fd38 1581 if (DnsSocketB >= 0) {
e91e2a72 1582 comm_local_port(DnsSocketB);
e0236918 1583 debugs(78, DBG_IMPORTANT, "DNS Socket created at " << addrV6 << ", FD " << DnsSocketB);
d841c88d 1584 Comm::SetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, NULL, 0);
4d6c8504 1585 }
04f7fd38 1586 if (DnsSocketA >= 0) {
e91e2a72 1587 comm_local_port(DnsSocketA);
e0236918 1588 debugs(78, DBG_IMPORTANT, "DNS Socket created at " << addrV4 << ", FD " << DnsSocketA);
d841c88d 1589 Comm::SetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, NULL, 0);
4d6c8504 1590 }
7b724b86 1591 }
62e76326 1592
efd900cb 1593 assert(0 == nns);
a079e38b
AJ
1594 idnsAddMDNSNameservers();
1595 bool nsFound = idnsParseNameservers();
7aa9bb3e 1596#if !_SQUID_WINDOWS_
62e76326 1597
a079e38b
AJ
1598 if (!nsFound)
1599 nsFound = idnsParseResolvConf();
62e76326 1600
0e6d05ef 1601#endif
be266cb2 1602#if _SQUID_WINDOWS_
a079e38b
AJ
1603 if (!nsFound)
1604 nsFound = idnsParseWIN32Registry();
0e6d05ef 1605#endif
62e76326 1606
a079e38b 1607 if (!nsFound) {
e0236918 1608 debugs(78, DBG_IMPORTANT, "Warning: Could not find any nameservers. Trying to use localhost");
be266cb2 1609#if _SQUID_WINDOWS_
e0236918 1610 debugs(78, DBG_IMPORTANT, "Please check your TCP-IP settings or /etc/resolv.conf file");
0e6d05ef 1611#else
e0236918 1612 debugs(78, DBG_IMPORTANT, "Please check your /etc/resolv.conf file");
0e6d05ef 1613#endif
29fe9bd5 1614
e0236918 1615 debugs(78, DBG_IMPORTANT, "or use the 'dns_nameservers' option in squid.conf.");
747552d8
AJ
1616 if (Ip::EnableIpv6)
1617 idnsAddNameserver("::1");
29fe9bd5 1618 idnsAddNameserver("127.0.0.1");
1619 }
62e76326 1620
7b724b86 1621 if (!init) {
62e76326 1622 memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
62e76326 1623 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
30abd221 1624 idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
95dc7ff4 1625 ++init;
7b724b86 1626 }
372fb44e 1627
e210930b
AJ
1628#if WHEN_EDNS_RESPONSES_ARE_PARSED
1629 if (Config.onoff.ignore_unknown_nameservers && max_shared_edns > 0) {
1630 debugs(0, DBG_IMPORTANT, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1631 max_shared_edns = -1; // disable if we might receive random replies.
1632 }
1633#endif
1634
372fb44e 1635 idnsRegisterWithCacheManager();
7b724b86 1636}
1637
1638void
f64091a7 1639dnsShutdown(void)
7b724b86 1640{
4d6c8504 1641 if (DnsSocketA < 0 && DnsSocketB < 0)
62e76326 1642 return;
1643
04f7fd38 1644 if (DnsSocketA >= 0 ) {
4d6c8504
AJ
1645 comm_close(DnsSocketA);
1646 DnsSocketA = -1;
1647 }
62e76326 1648
055421ee 1649 if (DnsSocketB >= 0 ) {
4d6c8504
AJ
1650 comm_close(DnsSocketB);
1651 DnsSocketB = -1;
1652 }
62e76326 1653
95dc7ff4 1654 for (int i = 0; i < nns; ++i) {
b26754c4 1655 if (nsvc *vc = nameservers[i].vc) {
00406b24
AJ
1656 if (Comm::IsConnOpen(vc->conn))
1657 vc->conn->close();
b26754c4 1658 }
1659 }
1660
dd3fb890 1661 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
efd900cb 1662 idnsFreeNameservers();
68836b58 1663 idnsFreeSearchpath();
7b724b86 1664}
1665
3074b9d1 1666static int
1667idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1668{
1669 idns_query *q;
1670
1671 idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
1672
1673 if (!old)
1674 return 0;
1675
63a0e6b7 1676 q = cbdataAlloc(idns_query);
91dcbd43
CT
1677 // idns_query is POD so no constructors are called after allocation
1678 q->xact_id.change();
049441d9 1679 // no query_id on this instance.
3074b9d1 1680
1681 q->callback = callback;
1682
1683 q->callback_data = cbdataReference(data);
1684
1685 q->queue = old->queue;
1686
1687 old->queue = q;
1688
1689 return 1;
1690}
1691
1692static void
33ab4aaf 1693idnsStartQuery(idns_query *q, IDNSCB * callback, void *data)
3074b9d1 1694{
33ab4aaf
HN
1695 q->start_t = current_time;
1696 q->callback = callback;
1697 q->callback_data = cbdataReference(data);
1698
049441d9 1699 q->hash.key = q->orig;
3074b9d1 1700 hash_join(idns_lookup_hash, &q->hash);
33ab4aaf
HN
1701
1702 idnsSendQuery(q);
3074b9d1 1703}
1704
049441d9
HN
1705static void
1706idnsSendSlaveAAAAQuery(idns_query *master)
1707{
1708 idns_query *q = cbdataAlloc(idns_query);
1709 memcpy(q->name, master->name, sizeof(q->name));
1710 memcpy(q->orig, master->orig, sizeof(q->orig));
1711 q->master = master;
1712 q->query_id = idnsQueryID();
1713 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
33ab4aaf 1714 q->start_t = master->start_t;
049441d9 1715 q->slave = master->slave;
c7ba545e 1716
cafb131e 1717 debugs(78, 3, HERE << "buf is " << q->sz << " bytes for " << q->name <<
049441d9
HN
1718 ", id = 0x" << std::hex << q->query_id);
1719 if (!q->sz) {
1720 cbdataFree(q);
1721 return;
1722 }
a079e38b 1723 idnsCheckMDNS(q);
049441d9
HN
1724 master->slave = q;
1725 idnsSendQuery(q);
1726}
1727
7b724b86 1728void
1729idnsALookup(const char *name, IDNSCB * callback, void *data)
1730{
32f89713
NH
1731 size_t nameLength = strlen(name);
1732
1733 // Prevent buffer overflow on q->name
1734 if (nameLength > NS_MAXDNAME) {
1735 debugs(23, DBG_IMPORTANT, "SECURITY ALERT: DNS name too long to perform lookup: '" << name << "'. see access.log for details.");
1736 callback(data, NULL, 0, "Internal error");
1737 return;
1738 }
3074b9d1 1739
1740 if (idnsCachedLookup(name, callback, data))
1741 return;
1742
32f89713 1743 idns_query *q = cbdataAlloc(idns_query);
91dcbd43
CT
1744 // idns_query is POD so no constructors are called after allocation
1745 q->xact_id.change();
049441d9 1746 q->query_id = idnsQueryID();
71952967 1747
32f89713
NH
1748 int nd = 0;
1749 for (unsigned int i = 0; i < nameLength; ++i)
68836b58 1750 if (name[i] == '.')
95dc7ff4 1751 ++nd;
68836b58 1752
32f89713 1753 if (Config.onoff.res_defnames && npc > 0 && name[nameLength-1] != '.') {
68836b58 1754 q->do_searchpath = 1;
1755 } else {
1756 q->do_searchpath = 0;
1757 }
1758
1759 strcpy(q->orig, name);
1760 strcpy(q->name, q->orig);
1761
1762 if (q->do_searchpath && nd < ndots) {
1763 q->domain = 0;
1764 strcat(q->name, ".");
1765 strcat(q->name, searchpath[q->domain].domain);
bf8fe701 1766 debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
68836b58 1767 }
1768
049441d9
HN
1769 // see EDNS notes at top of file why this sends 0
1770 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
62e76326 1771
2041330b 1772 if (q->sz < 0) {
1773 /* problem with query data -- query not sent */
1774 callback(data, NULL, 0, "Internal error");
63a0e6b7 1775 cbdataFree(q);
2041330b 1776 return;
1777 }
1778
26ac0430 1779 debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
049441d9 1780 ", id = 0x" << std::hex << q->query_id);
aa6c61e3 1781
a079e38b 1782 idnsCheckMDNS(q);
33ab4aaf 1783 idnsStartQuery(q, callback, data);
049441d9
HN
1784
1785 if (Ip::EnableIpv6)
1786 idnsSendSlaveAAAAQuery(q);
1787
7b724b86 1788}
8db71107 1789
1790void
b7ac5457 1791idnsPTRLookup(const Ip::Address &addr, IDNSCB * callback, void *data)
8db71107 1792{
3074b9d1 1793 idns_query *q;
1794
cc192b50 1795 char ip[MAX_IPSTRLEN];
1796
4dd643d5 1797 addr.toStr(ip,MAX_IPSTRLEN);
3074b9d1 1798
63a0e6b7 1799 q = cbdataAlloc(idns_query);
3074b9d1 1800
91dcbd43
CT
1801 // idns_query is POD so no constructors are called after allocation
1802 q->xact_id.change();
049441d9 1803 q->query_id = idnsQueryID();
71952967 1804
4dd643d5 1805 if (addr.isIPv6()) {
cc192b50 1806 struct in6_addr addr6;
4dd643d5 1807 addr.getInAddr(addr6);
546ae352 1808 q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
055421ee 1809 } else {
cc192b50 1810 struct in_addr addr4;
4dd643d5 1811 addr.getInAddr(addr4);
e210930b 1812 // see EDNS notes at top of file why this sends 0
546ae352 1813 q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
cc192b50 1814 }
1815
26ac0430 1816 if (q->sz < 0) {
2041330b 1817 /* problem with query data -- query not sent */
1818 callback(data, NULL, 0, "Internal error");
63a0e6b7 1819 cbdataFree(q);
2041330b 1820 return;
1821 }
1822
37f3da43 1823 if (idnsCachedLookup(q->query.name, callback, data)) {
26ac0430
AJ
1824 cbdataFree(q);
1825 return;
37f3da43 1826 }
1827
26ac0430 1828 debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
049441d9 1829 ", id = 0x" << std::hex << q->query_id);
3074b9d1 1830
bce61b00 1831 q->permit_mdns = Config.onoff.dns_mdns;
33ab4aaf 1832 idnsStartQuery(q, callback, data);
8db71107 1833}
eb824054 1834
59ad6d31 1835#if SQUID_SNMP
3c573763 1836/*
1837 * The function to return the DNS via SNMP
1838 */
1839variable_list *
f64091a7 1840snmp_netDnsFn(variable_list * Var, snint * ErrP)
3c573763 1841{
1842 int i, n = 0;
1843 variable_list *Answer = NULL;
6a644e75
AJ
1844 MemBuf tmp;
1845 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var->name, Var->name_length, tmp));
3c573763 1846 *ErrP = SNMP_ERR_NOERROR;
62e76326 1847
3c573763 1848 switch (Var->name[LEN_SQ_NET + 1]) {
62e76326 1849
3c573763 1850 case DNS_REQ:
62e76326 1851
95dc7ff4 1852 for (i = 0; i < nns; ++i)
62e76326 1853 n += nameservers[i].nqueries;
1854
1855 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1856 n,
1857 SMI_COUNTER32);
1858
1859 break;
1860
3c573763 1861 case DNS_REP:
95dc7ff4 1862 for (i = 0; i < nns; ++i)
62e76326 1863 n += nameservers[i].nreplies;
1864
1865 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1866 n,
1867 SMI_COUNTER32);
1868
1869 break;
1870
3c573763 1871 case DNS_SERVERS:
62e76326 1872 Answer = snmp_var_new_integer(Var->name, Var->name_length,
e494f5e9 1873 nns,
62e76326 1874 SMI_COUNTER32);
1875
1876 break;
1877
3c573763 1878 default:
62e76326 1879 *ErrP = SNMP_ERR_NOSUCHNAME;
1880
1881 break;
3c573763 1882 }
62e76326 1883
3c573763 1884 return Answer;
1885}
62e76326 1886
3c573763 1887#endif /*SQUID_SNMP */