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