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