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