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