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