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