]> git.ipfire.org Git - thirdparty/squid.git/blame - src/dns_internal.cc
Fix GCC4.6 warning unused variables in GnuRegex replacement
[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"
55cbb02b 36#include "comm/Connection.h"
aed188fd 37#include "comm/ConnOpener.h"
063dc1eb 38#include "comm.h"
d841c88d
AJ
39#include "comm/Loops.h"
40#include "comm/Write.h"
cfd66529 41#include "event.h"
985c86bc 42#include "SquidTime.h"
e6ccf245 43#include "Store.h"
2c471ba8 44#include "fde.h"
055421ee 45#include "ip/tools.h"
0eb49b6d 46#include "MemBuf.h"
8822ebee 47#include "mgr/Registration.h"
7176768b 48#include "util.h"
d295d770 49#include "wordlist.h"
91dcbd43 50#include "base/InstanceId.h"
68836b58 51
52#if HAVE_ARPA_NAMESER_H
53#include <arpa/nameser.h>
54#endif
55#if HAVE_RESOLV_H
56#include <resolv.h>
57#endif
58
454e8283 59/* MS Visual Studio Projects are monolithic, so we need the following
1f1ae50a 60 #ifndef to exclude the internal DNS code from compile process when
61 using external DNS process.
62 */
32d002cb 63#if !USE_DNSSERVERS
be266cb2 64#if _SQUID_WINDOWS_
1a774556 65#include "squid_windows.h"
0dde2160
GS
66#define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
67#define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
68#define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
0e6d05ef 69#endif
68836b58 70#ifndef _PATH_RESCONF
71#define _PATH_RESCONF "/etc/resolv.conf"
72#endif
73#ifndef NS_DEFAULTPORT
74#define NS_DEFAULTPORT 53
75#endif
76
77#ifndef NS_MAXDNAME
78#define NS_MAXDNAME 1025
79#endif
80
81#ifndef MAXDNSRCH
82#define MAXDNSRCH 6
7b724b86 83#endif
68836b58 84
85/* The buffer size required to store the maximum allowed search path */
86#ifndef RESOLV_BUFSZ
87#define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
7b724b86 88#endif
89
42b51993 90#define IDNS_MAX_TRIES 20
e210930b 91#define MAX_RCODE 17
558be27a 92#define MAX_ATTEMPT 3
93static int RcodeMatrix[MAX_RCODE][MAX_ATTEMPT];
e210930b
AJ
94// NP: see http://www.iana.org/assignments/dns-parameters
95static const char *Rcodes[] = {
24520b1b
AJ
96 /* RFC 1035 */
97 "Success",
98 "Packet Format Error",
99 "DNS Server Failure",
100 "Non-Existent Domain",
101 "Not Implemented",
102 "Query Refused",
103 /* RFC 2136 */
104 "Name Exists when it should not",
105 "RR Set Exists when it should not",
106 "RR Set that should exist does not",
107 "Server Not Authoritative for zone",
108 "Name not contained in zone",
109 /* unassigned */
110 "","","","","",
111 /* RFC 2671 */
112 "Bad OPT Version or TSIG Signature Failure"
113};
558be27a 114
58a39dc9 115typedef struct _idns_query idns_query;
62e76326 116
7b724b86 117typedef struct _ns ns;
58a39dc9 118
68836b58 119typedef struct _sp sp;
120
d24ef4e9 121typedef struct _nsvc nsvc;
122
26ac0430 123struct _idns_query {
3074b9d1 124 hash_link hash;
9e1f210d 125 rfc1035_query query;
68836b58 126 char buf[RESOLV_BUFSZ];
127 char name[NS_MAXDNAME + 1];
128 char orig[NS_MAXDNAME + 1];
c4a7fa29 129 ssize_t sz;
13b08e1c
A
130 unsigned short msg_id; /// random query ID sent to server; changes with every query sent
131 InstanceId<idns_query> xact_id; /// identifies our "transaction", stays constant when query is retried
91dcbd43 132
58a39dc9 133 int nsends;
d24ef4e9 134 int need_vc;
62e76326 135
58a39dc9 136 struct timeval start_t;
137 struct timeval sent_t;
820ee9fa 138 struct timeval queue_t;
58a39dc9 139 dlink_node lru;
140 IDNSCB *callback;
141 void *callback_data;
558be27a 142 int attempt;
7ba8d0b8 143 int rcode;
3074b9d1 144 idns_query *queue;
68836b58 145 unsigned short domain;
146 unsigned short do_searchpath;
cc192b50 147 bool need_A;
bae9832d 148 struct {
149 int count;
150 rfc1035_rr *answers;
151 } initial_AAAA;
58a39dc9 152};
91dcbd43 153InstanceIdDefinitions(idns_query, "dns");
58a39dc9 154
26ac0430 155struct _nsvc {
d24ef4e9 156 int ns;
00406b24 157 Comm::ConnectionPointer conn;
d24ef4e9 158 unsigned short msglen;
159 int read_msglen;
032785bf 160 MemBuf *msg;
161 MemBuf *queue;
d24ef4e9 162 bool busy;
163};
164
26ac0430 165struct _ns {
b7ac5457 166 Ip::Address S;
7b724b86 167 int nqueries;
168 int nreplies;
e210930b
AJ
169#if WHEN_EDNS_RESPONSES_ARE_PARSED
170 int last_seen_edns;
171#endif
d24ef4e9 172 nsvc *vc;
7b724b86 173};
58a39dc9 174
26ac0430 175struct _sp {
68836b58 176 char domain[NS_MAXDNAME];
177 int queries;
178};
179
d24ef4e9 180CBDATA_TYPE(nsvc);
63a0e6b7 181CBDATA_TYPE(idns_query);
d24ef4e9 182
7b724b86 183static ns *nameservers = NULL;
68836b58 184static sp *searchpath = NULL;
7b724b86 185static int nns = 0;
186static int nns_alloc = 0;
68836b58 187static int npc = 0;
188static int npc_alloc = 0;
189static int ndots = 1;
7b724b86 190static dlink_list lru_list;
7cfc1c9a 191static int event_queued = 0;
3074b9d1 192static hash_table *idns_lookup_hash = NULL;
7b724b86 193
e210930b
AJ
194/*
195 * Notes on EDNS:
196 *
197 * IPv4:
198 * EDNS as specified may be sent as an additional record for any request.
199 * early testing has revealed that it works on common devices, but cannot
200 * be reliably used on any A or PTR requet done for IPv4 addresses.
201 *
202 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
203 *
204 * Squid design:
205 * Squid is optimized to generate one packet and re-send it to all NS
206 * due to this we cannot customize the EDNS size per NS.
207 *
208 * As such we take the configuration option value as fixed.
209 *
210 * FUTURE TODO:
211 * This may not be worth doing, but if/when additional-records are parsed
212 * we will be able to recover the OPT value specific to any one NS and
213 * cache it. Effectively automating the tuning of EDNS advertised to the
214 * size our active NS are capable.
215 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
216 * Responses from the configured NS may cause this to be raised or turned off.
217 */
218#if WHEN_EDNS_RESPONSES_ARE_PARSED
219static int max_shared_edns = RFC1035_DEFAULT_PACKET_SZ;
220#endif
221
7b724b86 222static OBJH idnsStats;
223static void idnsAddNameserver(const char *buf);
68836b58 224static void idnsAddPathComponent(const char *buf);
7b724b86 225static void idnsFreeNameservers(void);
68836b58 226static void idnsFreeSearchpath(void);
efd900cb 227static void idnsParseNameservers(void);
1f1ae50a 228#ifndef _SQUID_MSWIN_
7b724b86 229static void idnsParseResolvConf(void);
1f1ae50a 230#endif
be266cb2 231#if _SQUID_WINDOWS_
0e6d05ef 232static void idnsParseWIN32Registry(void);
d02b72b4 233static void idnsParseWIN32SearchList(const char *);
0e6d05ef 234#endif
68836b58 235static void idnsCacheQuery(idns_query * q);
7b724b86 236static void idnsSendQuery(idns_query * q);
d24ef4e9 237static IOCB idnsReadVCHeader;
e0d28505 238static void idnsDoSendQueryVC(nsvc *vc);
cfd66529 239static CNCB idnsInitVCConnected;
e0d28505
AJ
240static IOCB idnsReadVC;
241static IOCB idnsSentQueryVC;
62e76326 242
b7ac5457 243static int idnsFromKnownNameserver(Ip::Address const &from);
7b724b86 244static idns_query *idnsFindQuery(unsigned short id);
e210930b 245static void idnsGrokReply(const char *buf, size_t sz, int from_ns);
7b724b86 246static PF idnsRead;
7cfc1c9a 247static EVH idnsCheckQueue;
efd900cb 248static void idnsTickleQueue(void);
558be27a 249static void idnsRcodeCount(int, int);
cfd66529 250static void idnsVCClosed(int fd, void *data);
91dcbd43 251static unsigned short idnsQueryID(void);
7b724b86 252
253static void
254idnsAddNameserver(const char *buf)
255{
b7ac5457 256 Ip::Address A;
62e76326 257
cc192b50 258 if (!(A = buf)) {
bf8fe701 259 debugs(78, 0, "WARNING: rejecting '" << buf << "' as a name server, because it is not a numeric IP address");
62e76326 260 return;
d20b1cd0 261 }
62e76326 262
cc192b50 263 if (A.IsAnyAddr()) {
264 debugs(78, 0, "WARNING: Squid does not accept " << A << " in DNS server specifications.");
715b5def 265 A.SetLocalhost();
cc192b50 266 debugs(78, 0, "Will be using " << A << " instead, assuming you meant that DNS is running on the same machine");
5c5a349d 267 }
62e76326 268
715b5def
AJ
269 if (!Ip::EnableIpv6 && !A.SetIPv4()) {
270 debugs(78, DBG_IMPORTANT, "WARNING: IPv6 is disabled. Discarding " << A << " in DNS server specifications.");
271 return;
5c5a349d 272 }
62e76326 273
7b724b86 274 if (nns == nns_alloc) {
62e76326 275 int oldalloc = nns_alloc;
276 ns *oldptr = nameservers;
277
278 if (nns_alloc == 0)
279 nns_alloc = 2;
280 else
281 nns_alloc <<= 1;
282
283 nameservers = (ns *)xcalloc(nns_alloc, sizeof(*nameservers));
284
285 if (oldptr && oldalloc)
41d00cd3 286 memcpy(nameservers, oldptr, oldalloc * sizeof(*nameservers));
62e76326 287
288 if (oldptr)
289 safe_free(oldptr);
7b724b86 290 }
62e76326 291
7b724b86 292 assert(nns < nns_alloc);
cc192b50 293 A.SetPort(NS_DEFAULTPORT);
294 nameservers[nns].S = A;
e210930b
AJ
295#if WHEN_EDNS_RESPONSES_ARE_PARSED
296 nameservers[nns].last_seen_edns = RFC1035_DEFAULT_PACKET_SZ;
297 // TODO generate a test packet to probe this NS from EDNS size and ability.
298#endif
cc192b50 299 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns << " (" << A << ")");
7b724b86 300 nns++;
301}
302
68836b58 303static void
304idnsAddPathComponent(const char *buf)
305{
306 if (npc == npc_alloc) {
307 int oldalloc = npc_alloc;
308 sp *oldptr = searchpath;
309
310 if (0 == npc_alloc)
311 npc_alloc = 2;
312 else
313 npc_alloc <<= 1;
314
315 searchpath = (sp *)xcalloc(npc_alloc, sizeof(*searchpath));
316
317 if (oldptr && oldalloc)
41d00cd3 318 memcpy(searchpath, oldptr, oldalloc * sizeof(*searchpath));
68836b58 319
320 if (oldptr)
321 safe_free(oldptr);
322 }
323
324 assert(npc < npc_alloc);
325 strcpy(searchpath[npc].domain, buf);
7176768b 326 Tolower(searchpath[npc].domain);
bf8fe701 327 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc << ": " << searchpath[npc].domain);
68836b58 328 npc++;
329}
330
2ea84e89 331
7b724b86 332static void
333idnsFreeNameservers(void)
334{
335 safe_free(nameservers);
336 nns = nns_alloc = 0;
337}
338
68836b58 339static void
340idnsFreeSearchpath(void)
341{
342 safe_free(searchpath);
343 npc = npc_alloc = 0;
344}
345
346
347
efd900cb 348static void
349idnsParseNameservers(void)
350{
351 wordlist *w;
62e76326 352
efd900cb 353 for (w = Config.dns_nameservers; w; w = w->next) {
bf8fe701 354 debugs(78, 1, "Adding nameserver " << w->key << " from squid.conf");
62e76326 355 idnsAddNameserver(w->key);
efd900cb 356 }
357}
358
1f1ae50a 359#ifndef _SQUID_MSWIN_
7b724b86 360static void
361idnsParseResolvConf(void)
362{
363 FILE *fp;
68836b58 364 char buf[RESOLV_BUFSZ];
a083e75a 365 const char *t;
68836b58 366 fp = fopen(_PATH_RESCONF, "r");
62e76326 367
7b724b86 368 if (fp == NULL) {
bf8fe701 369 debugs(78, 1, "" << _PATH_RESCONF << ": " << xstrerror());
62e76326 370 return;
7b724b86 371 }
62e76326 372
be266cb2 373#if _SQUID_CYGWIN_
c4aefe96 374 setmode(fileno(fp), O_TEXT);
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
be266cb2 442#if _SQUID_WINDOWS_
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
fd0f51c4
CT
733 const double when = min(Config.Timeout.idns_query, Config.Timeout.idns_retransmit)/1000.0;
734
735 eventAdd("idnsCheckQueue", idnsCheckQueue, NULL, when, 1);
62e76326 736
efd900cb 737 event_queued = 1;
738}
739
d24ef4e9 740static void
e0d28505 741idnsSentQueryVC(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
d24ef4e9 742{
743 nsvc * vc = (nsvc *)data;
744
745 if (flag == COMM_ERR_CLOSING)
746 return;
af6a12ee 747
e0d28505
AJ
748 // XXX: irrelevant now that we have conn pointer?
749 if (!Comm::IsConnOpen(conn) || fd_table[conn->fd].closing())
af6a12ee 750 return;
d24ef4e9 751
752 if (flag != COMM_OK || size <= 0) {
80463bb4 753 conn->close();
d24ef4e9 754 return;
755 }
756
757 vc->busy = 0;
758 idnsDoSendQueryVC(vc);
759}
760
761static void
762idnsDoSendQueryVC(nsvc *vc)
763{
764 if (vc->busy)
765 return;
766
032785bf 767 if (vc->queue->contentSize() == 0)
d24ef4e9 768 return;
769
032785bf 770 MemBuf *mb = vc->queue;
d24ef4e9 771
032785bf 772 vc->queue = new MemBuf;
d24ef4e9 773
774 vc->busy = 1;
775
fd0f51c4 776 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
d4b21972
A
777 const int timeout = (Config.Timeout.idns_query % 1000 ?
778 Config.Timeout.idns_query + 1000 : Config.Timeout.idns_query) / 1000;
8d77a37c 779 AsyncCall::Pointer nil;
d4b21972 780
1b76e6c1 781 commSetConnTimeout(vc->conn, timeout, nil);
d24ef4e9 782
ec41b64c
AJ
783 AsyncCall::Pointer call = commCbCall(78, 5, "idnsSentQueryVC",
784 CommIoCbPtrFun(&idnsSentQueryVC, vc));
b0388924 785 Comm::Write(vc->conn, mb, call);
032785bf 786
787 delete mb;
d24ef4e9 788}
789
790static void
00406b24 791idnsInitVCConnected(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
d24ef4e9 792{
793 nsvc * vc = (nsvc *)data;
794
cfd66529 795 if (status != COMM_OK || !conn) {
dd3fb890
AR
796 char buf[MAX_IPSTRLEN] = "";
797 if (vc->ns < nns)
798 nameservers[vc->ns].S.NtoA(buf,MAX_IPSTRLEN);
00406b24 799 debugs(78, 1, HERE << "Failed to connect to nameserver " << buf << " using TCP.");
d24ef4e9 800 return;
801 }
802
00406b24 803 vc->conn = conn;
cfd66529
AJ
804
805 comm_add_close_handler(conn->fd, idnsVCClosed, vc);
abd8f140
AJ
806 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
807 CommIoCbPtrFun(idnsReadVCHeader, vc));
808 comm_read(conn, (char *)&vc->msglen, 2, call);
d24ef4e9 809 vc->busy = 0;
810 idnsDoSendQueryVC(vc);
811}
812
813static void
814idnsVCClosed(int fd, void *data)
815{
816 nsvc * vc = (nsvc *)data;
032785bf 817 delete vc->queue;
818 delete vc->msg;
00406b24 819 vc->conn = NULL;
dd3fb890
AR
820 if (vc->ns < nns) // XXX: idnsShutdown may have freed nameservers[]
821 nameservers[vc->ns].vc = NULL;
63a0e6b7 822 cbdataFree(vc);
d24ef4e9 823}
824
825static void
826idnsInitVC(int ns)
827{
828 nsvc *vc = cbdataAlloc(nsvc);
dd3fb890 829 assert(ns < nns);
00406b24 830 assert(vc->conn == NULL); // MUST be NULL from the construction process!
d24ef4e9 831 nameservers[ns].vc = vc;
445962f3 832 vc->ns = ns;
032785bf 833 vc->queue = new MemBuf;
032785bf 834 vc->msg = new MemBuf;
cfd66529 835 vc->busy = 1;
d24ef4e9 836
00406b24 837 Comm::ConnectionPointer conn = new Comm::Connection();
105f7a99
AJ
838
839 if (!Config.Addrs.udp_outgoing.IsNoAddr())
840 conn->local = Config.Addrs.udp_outgoing;
841 else
842 conn->local = Config.Addrs.udp_incoming;
843
cfd66529 844 conn->remote = nameservers[ns].S;
d24ef4e9 845
cfd66529 846 AsyncCall::Pointer call = commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected, vc));
d24ef4e9 847
4accd6d8 848 Comm::ConnOpener *cs = new Comm::ConnOpener(conn, call, Config.Timeout.connect);
aed188fd 849 cs->setHost("DNS TCP Socket");
855150a4 850 AsyncJob::Start(cs);
d24ef4e9 851}
852
853static void
854idnsSendQueryVC(idns_query * q, int ns)
855{
dd3fb890 856 assert(ns < nns);
d24ef4e9 857 if (nameservers[ns].vc == NULL)
858 idnsInitVC(ns);
859
860 nsvc *vc = nameservers[ns].vc;
861
445962f3
HN
862 if (!vc) {
863 char buf[MAX_IPSTRLEN];
864 debugs(78, 1, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers[ns].S.NtoA(buf,MAX_IPSTRLEN) << "!");
865
866 return;
867 }
868
2fe7eff9 869 vc->queue->reset();
d24ef4e9 870
871 short head = htons(q->sz);
872
2fe7eff9 873 vc->queue->append((char *)&head, 2);
d24ef4e9 874
2fe7eff9 875 vc->queue->append(q->buf, q->sz);
d24ef4e9 876
877 idnsDoSendQueryVC(vc);
878}
879
7b724b86 880static void
881idnsSendQuery(idns_query * q)
882{
4d6c8504 883 if (DnsSocketA < 0 && DnsSocketB < 0) {
cc192b50 884 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
62e76326 885 return;
0a69973e 886 }
62e76326 887
cc192b50 888 if (nns <= 0) {
889 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
890 return;
891 }
62e76326 892
7b724b86 893 assert(q->lru.next == NULL);
62e76326 894
7b724b86 895 assert(q->lru.prev == NULL);
62e76326 896
4d6c8504
AJ
897 int x = -1, y = -1;
898 int ns;
899
91dcbd43
CT
900 q->start_t = current_time;
901 q->msg_id = idnsQueryID();
902 rfc1035SetQueryID(q->buf, q->msg_id);
903
213b6c90
AJ
904 do {
905 ns = q->nsends % nns;
906
907 if (q->need_vc) {
908 idnsSendQueryVC(q, ns);
4d6c8504 909 x = y = 0;
213b6c90 910 } else {
055421ee 911 if (DnsSocketB >= 0 && nameservers[ns].S.IsIPv6())
4d6c8504 912 y = comm_udp_sendto(DnsSocketB, nameservers[ns].S, q->buf, q->sz);
bd6a0c8f 913 else if (DnsSocketA)
4d6c8504 914 x = comm_udp_sendto(DnsSocketA, nameservers[ns].S, q->buf, q->sz);
213b6c90 915 }
62e76326 916
213b6c90 917 q->nsends++;
62e76326 918
820ee9fa 919 q->queue_t = q->sent_t = current_time;
62e76326 920
4d6c8504
AJ
921 if (y < 0 && nameservers[ns].S.IsIPv6())
922 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketB << ": sendto: " << xstrerror());
923 if (x < 0 && nameservers[ns].S.IsIPv4())
4d6c8504
AJ
924 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketA << ": sendto: " << xstrerror());
925
926 } while ( (x<0 && y<0) && q->nsends % nns != 0);
62e76326 927
bd6a0c8f 928 if (y > 0) {
4d6c8504 929 fd_bytes(DnsSocketB, y, FD_WRITE);
4d6c8504 930 }
bd6a0c8f 931 if (x > 0) {
4d6c8504 932 fd_bytes(DnsSocketA, x, FD_WRITE);
0a69973e 933 }
62e76326 934
7cfc1c9a 935 nameservers[ns].nqueries++;
c131f066 936 q->queue_t = current_time;
7b724b86 937 dlinkAdd(q, &q->lru, &lru_list);
efd900cb 938 idnsTickleQueue();
7b724b86 939}
940
941static int
b7ac5457 942idnsFromKnownNameserver(Ip::Address const &from)
7b724b86 943{
944 int i;
62e76326 945
26ac0430 946 for (i = 0; i < nns; i++) {
cc192b50 947 if (nameservers[i].S != from)
62e76326 948 continue;
949
cc192b50 950 if (nameservers[i].S.GetPort() != from.GetPort())
62e76326 951 continue;
952
953 return i;
7b724b86 954 }
62e76326 955
7cfc1c9a 956 return -1;
7b724b86 957}
958
959static idns_query *
960idnsFindQuery(unsigned short id)
961{
962 dlink_node *n;
963 idns_query *q;
62e76326 964
7b724b86 965 for (n = lru_list.tail; n; n = n->prev) {
62e76326 966 q = (idns_query*)n->data;
967
91dcbd43 968 if (q->msg_id == id)
62e76326 969 return q;
7b724b86 970 }
62e76326 971
7b724b86 972 return NULL;
973}
974
108d67a0 975static unsigned short
976idnsQueryID(void)
977{
978 unsigned short id = squid_random() & 0xFFFF;
979 unsigned short first_id = id;
980
26ac0430 981 while (idnsFindQuery(id)) {
108d67a0 982 id++;
983
846c8960 984 if (id == first_id) {
bf8fe701 985 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
108d67a0 986 break;
846c8960 987 }
108d67a0 988 }
989
846c8960 990 return id;
108d67a0 991}
992
3074b9d1 993static void
994idnsCallback(idns_query *q, rfc1035_rr *answers, int n, const char *error)
995{
996 IDNSCB *callback;
997 void *cbdata;
998
999 callback = q->callback;
1000 q->callback = NULL;
1001
1002 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
1003 callback(cbdata, answers, n, error);
1004
26ac0430 1005 while (q->queue) {
3074b9d1 1006 idns_query *q2 = q->queue;
1007 q->queue = q2->queue;
1008 callback = q2->callback;
1009 q2->callback = NULL;
1010
1011 if (cbdataReferenceValidDone(q2->callback_data, &cbdata))
1012 callback(cbdata, answers, n, error);
1013
63a0e6b7 1014 cbdataFree(q2);
3074b9d1 1015 }
1016
1017 if (q->hash.key) {
1018 hash_remove_link(idns_lookup_hash, &q->hash);
1019 q->hash.key = NULL;
1020 }
1021}
1022
cc192b50 1023void
1024idnsDropMessage(rfc1035_message *message, idns_query *q)
1025{
1026 rfc1035MessageDestroy(&message);
1027 if (q->hash.key) {
1028 hash_remove_link(idns_lookup_hash, &q->hash);
1029 q->hash.key = NULL;
1030 }
1031}
1032
7b724b86 1033static void
e210930b 1034idnsGrokReply(const char *buf, size_t sz, int from_ns)
7b724b86 1035{
1036 int n;
ec7bade0 1037 rfc1035_message *message = NULL;
7b724b86 1038 idns_query *q;
3074b9d1 1039
cc192b50 1040 n = rfc1035MessageUnpack(buf, sz, &message);
62e76326 1041
ec7bade0 1042 if (message == NULL) {
bf8fe701 1043 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
62e76326 1044 return;
7b724b86 1045 }
62e76326 1046
91dcbd43 1047 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex << message->id << ", " << std::dec << n << " answers");
ec7bade0 1048
1049 q = idnsFindQuery(message->id);
1050
7b724b86 1051 if (q == NULL) {
bf8fe701 1052 debugs(78, 3, "idnsGrokReply: Late response");
cc192b50 1053 rfc1035MessageDestroy(&message);
62e76326 1054 return;
7b724b86 1055 }
62e76326 1056
9e1f210d 1057 if (rfc1035QueryCompare(&q->query, message->query) != 0) {
bf8fe701 1058 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q->query.name << " != " << message->query->name << ")");
cc192b50 1059 rfc1035MessageDestroy(&message);
9e1f210d 1060 return;
1061 }
1062
e210930b
AJ
1063#if WHEN_EDNS_RESPONSES_ARE_PARSED
1064// TODO: actually gr the message right here.
1065// pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1066// this is overall better than force-feeding A response with AAAA an section later anyway.
1067// AND allows us to merge AN+AR sections from both responses (one day)
1068
1069 if (q->edns_seen >= 0) {
1070 if (max_shared_edns == nameservers[from_ns].last_seen_edns && max_shared_edns < q->edns_seen) {
1071 nameservers[from_ns].last_seen_edns = q->edns_seen;
1072 // the altered NS was limiting the whole group.
1073 max_shared_edns = q->edns_seen;
1074 // may be limited by one of the others still
1075 for (int i = 0; i < nns; i++)
1076 max_shared_edns = min(max_shared_edns, nameservers[i].last_seen_edns);
1077 } else {
1078 nameservers[from_ns].last_seen_edns = q->edns_seen;
1079 // maybe reduce the global limit downwards to accomodate this NS
1080 max_shared_edns = min(max_shared_edns, q->edns_seen);
1081 }
1082 if (max_shared_edns < RFC1035_DEFAULT_PACKET_SZ)
1083 max_shared_edns = -1;
1084 }
1085#endif
1086
d24ef4e9 1087 if (message->tc) {
bae9832d 1088 debugs(78, 3, HERE << "Resolver requested TC (" << q->query.name << ")");
d24ef4e9 1089 dlinkDelete(&q->lru, &lru_list);
cc192b50 1090 rfc1035MessageDestroy(&message);
d24ef4e9 1091
1092 if (!q->need_vc) {
1093 q->need_vc = 1;
1094 q->nsends--;
1095 idnsSendQuery(q);
91dcbd43
CT
1096 } else {
1097 // Strange: A TCP DNS response with the truncation bit (TC) set.
1098 // Return an error and cleanup; no point in trying TCP again.
1099 debugs(78, 3, HERE << "TCP DNS response");
1100 idnsCallback(q, NULL, 0, "Truncated TCP DNS response");
1101 cbdataFree(q);
d24ef4e9 1102 }
1103
1104 return;
1105 }
9e1f210d 1106
a16b4aa0 1107 dlinkDelete(&q->lru, &lru_list);
558be27a 1108 idnsRcodeCount(n, q->attempt);
62e76326 1109
558be27a 1110 if (n < 0) {
7ba8d0b8 1111 q->rcode = -n;
42687bb2 1112 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n) << " (" << q->rcode << ")");
7ba8d0b8 1113
1114 if (q->rcode == 2 && ++q->attempt < MAX_ATTEMPT) {
62e76326 1115 /*
1116 * RCODE 2 is "Server failure - The name server was
1117 * unable to process this query due to a problem with
1118 * the name server."
1119 */
cc192b50 1120 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1121 rfc1035MessageDestroy(&message);
62e76326 1122 idnsSendQuery(q);
1123 return;
1124 }
68836b58 1125
1126 if (q->rcode == 3 && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
1127 assert(NULL == message->answer);
1128 strcpy(q->name, q->orig);
1129
cc192b50 1130 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q->name );
1131
68836b58 1132 if (q->domain < npc) {
1133 strcat(q->name, ".");
1134 strcat(q->name, searchpath[q->domain].domain);
bf8fe701 1135 debugs(78, 3, "idnsGrokReply: searchpath used for " << q->name);
68836b58 1136 q->domain++;
1137 } else {
1138 q->attempt++;
1139 }
1140
cc192b50 1141 idnsDropMessage(message, q);
1142
055421ee 1143 if (Ip::EnableIpv6 && q->query.qtype == RFC1035_TYPE_AAAA) {
cc192b50 1144 debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q->name);
91dcbd43 1145 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, Config.dns.packet_max);
055421ee 1146 } else {
cc192b50 1147 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
e210930b 1148 // see EDNS notes at top of file why this sends 0
91dcbd43 1149 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, 0);
cc192b50 1150 }
c4a7fa29
AJ
1151
1152 if (q->sz < 0) {
1153 /* problem with query data -- query not sent */
21c5a65e 1154 idnsCallback(static_cast<idns_query *>(q->callback_data), NULL, 0, "Internal error");
c4a7fa29
AJ
1155 cbdataFree(q);
1156 return;
1157 }
1158
68836b58 1159 idnsCacheQuery(q);
1160 idnsSendQuery(q);
1161 return;
1162 }
558be27a 1163 }
62e76326 1164
26ac0430 1165 if (q->need_A && (Config.onoff.dns_require_A == 1 || n <= 0 ) ) {
cc192b50 1166 /* ERROR or NO AAAA exist. Failover to A records. */
bae9832d 1167 /* Apparently its also a good idea to lookup and store the A records
cc192b50 1168 * just in case the AAAA are not available when we need them.
1169 * This could occur due to number of network failings beyond our control
1170 * thus the || above allowing the user to request always both.
1171 */
1172
26ac0430 1173 if (n == 0)
cc192b50 1174 debugs(78, 3, "idnsGrokReply: " << q->name << " has no AAAA records. Looking up A record instead.");
26ac0430 1175 else if (q->need_A && n <= 0)
cc192b50 1176 debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query failed. Trying A now instead.");
1177 else // admin requested this.
1178 debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query done. Configured to retrieve A now also.");
1179
bae9832d 1180 // move the initial message results into the failover query for merging later.
26ac0430 1181 if (n > 0) {
bae9832d 1182 q->initial_AAAA.count = message->ancount;
1183 q->initial_AAAA.answers = message->answer;
1184 message->answer = NULL;
1185 }
1186
1187 // remove the hashed query info
cc192b50 1188 idnsDropMessage(message, q);
1189
ca75572c
HN
1190 // reset the query as an A query
1191 q->nsends = 0;
e210930b 1192 // see EDNS notes at top of file why this sends 0
91dcbd43 1193 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, 0);
cc192b50 1194 q->need_A = false;
c4a7fa29
AJ
1195
1196 if (q->sz < 0) {
1197 /* problem with query data -- query not sent */
21c5a65e 1198 idnsCallback(static_cast<idns_query *>(q->callback_data), NULL, 0, "Internal error");
c4a7fa29
AJ
1199 cbdataFree(q);
1200 return;
1201 }
1202
cc192b50 1203 idnsCacheQuery(q);
1204 idnsSendQuery(q);
1205 return;
1206 }
cc192b50 1207
26ac0430
AJ
1208 /** If there are two result sets from preceeding AAAA and A lookups merge them with a preference for AAAA */
1209 if (q->initial_AAAA.count > 0 && n > 0) {
bae9832d 1210 /* two sets of RR need merging */
1211 rfc1035_rr *result = (rfc1035_rr*) xmalloc( sizeof(rfc1035_rr)*(n + q->initial_AAAA.count) );
1212 rfc1035_rr *tmp = result;
1213
1214 debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
1215
1216 memcpy(tmp, q->initial_AAAA.answers, (sizeof(rfc1035_rr)*(q->initial_AAAA.count)) );
1217 tmp += q->initial_AAAA.count;
1218 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1219 safe_free(q->initial_AAAA.answers);
1220
1221 memcpy( tmp, message->answer, (sizeof(rfc1035_rr)*n) );
1222 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1223 safe_free(message->answer);
1224
1225 message->answer = result;
8be70f52 1226 message->ancount += q->initial_AAAA.count;
bae9832d 1227 n += q->initial_AAAA.count;
1228 q->initial_AAAA.count=0;
26ac0430 1229 } else if (q->initial_AAAA.count > 0 && n <= 0) {
bae9832d 1230 /* initial of dual queries was the only result set. */
1231 debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
1232 rfc1035RRDestroy(&(message->answer), n);
1233 message->answer = q->initial_AAAA.answers;
1234 n = q->initial_AAAA.count;
1235 }
1236 /* else initial results were empty. just use the final set as authoritative */
1237
1238 debugs(78, 6, HERE << "Sending " << n << " DNS results to caller.");
a14eb55e 1239 idnsCallback(q, message->answer, n, rfc1035ErrorMessage(n));
cc192b50 1240 rfc1035MessageDestroy(&message);
63a0e6b7 1241 cbdataFree(q);
7b724b86 1242}
1243
1244static void
1245idnsRead(int fd, void *data)
1246{
d193a436 1247 int *N = &incoming_sockets_accepted;
0b6d1955 1248 int len;
42b51993 1249 int max = INCOMING_DNS_MAX;
d29b40de 1250 static char rbuf[SQUID_UDP_SO_RCVBUF];
7cfc1c9a 1251 int ns;
b7ac5457 1252 Ip::Address from;
cc192b50 1253
d7e7eaa7 1254 debugs(78, 3, "idnsRead: starting with FD " << fd);
cc192b50 1255
bd6a0c8f
HN
1256 // Always keep reading. This stops (or at least makes harder) several
1257 // attacks on the DNS client.
d841c88d 1258 Comm::SetSelect(fd, COMM_SELECT_READ, idnsRead, NULL, 0);
bd6a0c8f 1259
cc192b50 1260 /* BUG (UNRESOLVED)
1261 * two code lines after returning from comm_udprecvfrom()
1262 * something overwrites the memory behind the from parameter.
1263 * NO matter where in the stack declaration list above it is placed
1264 * The cause of this is still unknown, however copying the data appears
1265 * to allow it to be passed further without this erasure.
1266 */
b7ac5457 1267 Ip::Address bugbypass;
62e76326 1268
7b724b86 1269 while (max--) {
cc192b50 1270 len = comm_udp_recvfrom(fd, rbuf, SQUID_UDP_SO_RCVBUF, 0, bugbypass);
62e76326 1271
cc192b50 1272 from = bugbypass; // BUG BYPASS. see notes above.
62e76326 1273
1274 if (len == 0)
1275 break;
1276
1277 if (len < 0) {
1278 if (ignoreErrno(errno))
1279 break;
1280
7b724b86 1281#ifdef _SQUID_LINUX_
62e76326 1282 /* Some Linux systems seem to set the FD for reading and then
1283 * return ECONNREFUSED when sendto() fails and generates an ICMP
1284 * port unreachable message. */
1285 /* or maybe an EHOSTUNREACH "No route to host" message */
1286 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
7b724b86 1287#endif
62e76326 1288
bf8fe701 1289 debugs(50, 1, "idnsRead: FD " << fd << " recvfrom: " << xstrerror());
62e76326 1290
1291 break;
1292 }
1293
055421ee 1294 fd_bytes(fd, len, FD_READ);
4d6c8504 1295
62e76326 1296 assert(N);
1297 (*N)++;
cc192b50 1298
1299 debugs(78, 3, "idnsRead: FD " << fd << ": received " << len << " bytes from " << from);
1300
1301 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1302 ns = idnsFromKnownNameserver(from);
62e76326 1303
1304 if (ns >= 0) {
1305 nameservers[ns].nreplies++;
bd6a0c8f
HN
1306 }
1307
1308 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1309 // but after the ++ above to keep statistics right.
1310 if (!lru_list.head)
1311 continue; // Don't process replies if there is no pending query.
1312
1313 if (ns < 0 && Config.onoff.ignore_unknown_nameservers) {
62e76326 1314 static time_t last_warning = 0;
1315
1316 if (squid_curtime - last_warning > 60) {
cc192b50 1317 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from);
62e76326 1318 last_warning = squid_curtime;
26ac0430 1319 } else {
cc192b50 1320 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from << " (retrying..." << (squid_curtime-last_warning) << "<=60)" );
26ac0430
AJ
1321 }
1322 continue;
62e76326 1323 }
1324
e210930b 1325 idnsGrokReply(rbuf, len, ns);
7b724b86 1326 }
1327}
1328
7cfc1c9a 1329static void
1330idnsCheckQueue(void *unused)
1331{
1332 dlink_node *n;
0c4fe9e4 1333 dlink_node *p = NULL;
7cfc1c9a 1334 idns_query *q;
1335 event_queued = 0;
62e76326 1336
820ee9fa
AJ
1337 if (0 == nns)
1338 /* name servers went away; reconfiguring or shutting down */
1339 return;
1340
0c4fe9e4 1341 for (n = lru_list.tail; n; n = p) {
62e76326 1342
820ee9fa 1343 p = n->prev;
733cedc0 1344 q = static_cast<idns_query*>(n->data);
62e76326 1345
820ee9fa 1346 /* Anything to process in the queue? */
fd0f51c4 1347 if ((time_msec_t)tvSubMsec(q->queue_t, current_time) < Config.Timeout.idns_retransmit )
26ac0430 1348 break;
62e76326 1349
820ee9fa 1350 /* Query timer expired? */
fd0f51c4 1351 if ((time_msec_t)tvSubMsec(q->sent_t, current_time) < (Config.Timeout.idns_retransmit * 1 << ((q->nsends - 1) / nns))) {
820ee9fa
AJ
1352 dlinkDelete(&q->lru, &lru_list);
1353 q->queue_t = current_time;
1354 dlinkAdd(q, &q->lru, &lru_list);
1355 continue;
1356 }
62e76326 1357
91dcbd43
CT
1358 debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
1359 " QID 0x" << std::hex << std::setfill('0') <<
1360 std::setw(4) << q->msg_id << ": timeout" );
62e76326 1361
1362 dlinkDelete(&q->lru, &lru_list);
1363
fd0f51c4 1364 if ((time_msec_t)tvSubMsec(q->start_t, current_time) < Config.Timeout.idns_query) {
62e76326 1365 idnsSendQuery(q);
1366 } else {
91dcbd43
CT
1367 debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
1368 " QID 0x" << std::hex << q->msg_id <<
1369 " : giving up after " << std::dec << q->nsends << " tries and " <<
26ac0430 1370 std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
3074b9d1 1371
1372 if (q->rcode != 0)
a14eb55e 1373 idnsCallback(q, NULL, -q->rcode, rfc1035ErrorMessage(q->rcode));
3074b9d1 1374 else
1375 idnsCallback(q, NULL, -16, "Timeout");
62e76326 1376
63a0e6b7 1377 cbdataFree(q);
62e76326 1378 }
7cfc1c9a 1379 }
62e76326 1380
efd900cb 1381 idnsTickleQueue();
7cfc1c9a 1382}
1383
d24ef4e9 1384static void
e0d28505 1385idnsReadVC(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
d24ef4e9 1386{
1387 nsvc * vc = (nsvc *)data;
1388
1389 if (flag == COMM_ERR_CLOSING)
1390 return;
1391
1392 if (flag != COMM_OK || len <= 0) {
80463bb4
AJ
1393 if (Comm::IsConnOpen(conn))
1394 conn->close();
d24ef4e9 1395 return;
1396 }
1397
bd6a0c8f 1398 vc->msg->size += len; // XXX should not access -> size directly
d24ef4e9 1399
032785bf 1400 if (vc->msg->contentSize() < vc->msglen) {
abd8f140
AJ
1401 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1402 CommIoCbPtrFun(idnsReadVC, vc));
1403 comm_read(conn, buf+len, vc->msglen - vc->msg->contentSize(), call);
d24ef4e9 1404 return;
1405 }
1406
dd3fb890 1407 assert(vc->ns < nns);
e0d28505 1408 debugs(78, 3, HERE << conn << ": received " << vc->msg->contentSize() << " bytes via TCP from " << nameservers[vc->ns].S << ".");
d24ef4e9 1409
e210930b 1410 idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
2fe7eff9 1411 vc->msg->clean();
abd8f140
AJ
1412 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1413 CommIoCbPtrFun(idnsReadVCHeader, vc));
1414 comm_read(conn, (char *)&vc->msglen, 2, call);
d24ef4e9 1415}
1416
1417static void
e0d28505 1418idnsReadVCHeader(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
d24ef4e9 1419{
1420 nsvc * vc = (nsvc *)data;
1421
1422 if (flag == COMM_ERR_CLOSING)
1423 return;
1424
1425 if (flag != COMM_OK || len <= 0) {
80463bb4
AJ
1426 if (Comm::IsConnOpen(conn))
1427 conn->close();
d24ef4e9 1428 return;
1429 }
1430
1431 vc->read_msglen += len;
1432
1433 assert(vc->read_msglen <= 2);
1434
1435 if (vc->read_msglen < 2) {
abd8f140
AJ
1436 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1437 CommIoCbPtrFun(idnsReadVCHeader, vc));
1438 comm_read(conn, buf+len, 2 - vc->read_msglen, call);
d24ef4e9 1439 return;
1440 }
1441
1442 vc->read_msglen = 0;
1443
1444 vc->msglen = ntohs(vc->msglen);
1445
2fe7eff9 1446 vc->msg->init(vc->msglen, vc->msglen);
abd8f140
AJ
1447 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1448 CommIoCbPtrFun(idnsReadVC, vc));
1449 comm_read(conn, vc->msg->buf, vc->msglen, call);
d24ef4e9 1450}
1451
558be27a 1452/*
1453 * rcode < 0 indicates an error, rocde >= 0 indicates success
1454 */
1455static void
1456idnsRcodeCount(int rcode, int attempt)
1457{
1458 if (rcode > 0)
62e76326 1459 rcode = 0;
558be27a 1460 else if (rcode < 0)
62e76326 1461 rcode = -rcode;
1462
558be27a 1463 if (rcode < MAX_RCODE)
62e76326 1464 if (attempt < MAX_ATTEMPT)
1465 RcodeMatrix[rcode][attempt]++;
558be27a 1466}
1467
7b724b86 1468/* ====================================================================== */
1469
5f5e883f
FC
1470static void
1471idnsRegisterWithCacheManager(void)
1472{
8822ebee 1473 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
5f5e883f
FC
1474}
1475
7b724b86 1476void
1477idnsInit(void)
1478{
1479 static int init = 0;
62e76326 1480
d24ef4e9 1481 CBDATA_INIT_TYPE(nsvc);
63a0e6b7 1482 CBDATA_INIT_TYPE(idns_query);
d24ef4e9 1483
4d6c8504 1484 if (DnsSocketA < 0 && DnsSocketB < 0) {
055421ee 1485 Ip::Address addrA; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
62e76326 1486
cc192b50 1487 if (!Config.Addrs.udp_outgoing.IsNoAddr())
055421ee 1488 addrA = Config.Addrs.udp_outgoing;
62e76326 1489 else
055421ee 1490 addrA = Config.Addrs.udp_incoming;
62e76326 1491
055421ee
AJ
1492 Ip::Address addrB = addrA;
1493 addrA.SetIPv4();
7e07ced1 1494
dc7c14ba 1495 if (Ip::EnableIpv6 && addrB.IsIPv6()) {
055421ee 1496 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrB);
4d6c8504 1497 DnsSocketB = comm_open_listener(SOCK_DGRAM,
04f7fd38 1498 IPPROTO_UDP,
055421ee 1499 addrB,
04f7fd38 1500 COMM_NONBLOCKING,
055421ee 1501 "DNS Socket IPv6");
7e07ced1 1502 }
4d6c8504 1503
dc7c14ba 1504 if (addrA.IsIPv4()) {
055421ee 1505 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrA);
4d6c8504 1506 DnsSocketA = comm_open_listener(SOCK_DGRAM,
04f7fd38 1507 IPPROTO_UDP,
055421ee 1508 addrA,
04f7fd38 1509 COMM_NONBLOCKING,
055421ee 1510 "DNS Socket IPv4");
7e07ced1 1511 }
62e76326 1512
4d6c8504 1513 if (DnsSocketA < 0 && DnsSocketB < 0)
62e76326 1514 fatal("Could not create a DNS socket");
1515
1516 /* Ouch... we can't call functions using debug from a debug
1517 * statement. Doing so messes up the internal Debug::level
1518 */
04f7fd38 1519 if (DnsSocketB >= 0) {
e91e2a72 1520 comm_local_port(DnsSocketB);
055421ee 1521 debugs(78, 1, "DNS Socket created at " << addrB << ", FD " << DnsSocketB);
d841c88d 1522 Comm::SetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, NULL, 0);
4d6c8504 1523 }
04f7fd38 1524 if (DnsSocketA >= 0) {
e91e2a72 1525 comm_local_port(DnsSocketA);
055421ee 1526 debugs(78, 1, "DNS Socket created at " << addrA << ", FD " << DnsSocketA);
d841c88d 1527 Comm::SetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, NULL, 0);
4d6c8504 1528 }
7b724b86 1529 }
62e76326 1530
efd900cb 1531 assert(0 == nns);
1532 idnsParseNameservers();
0e6d05ef 1533#ifndef _SQUID_MSWIN_
62e76326 1534
efd900cb 1535 if (0 == nns)
62e76326 1536 idnsParseResolvConf();
1537
0e6d05ef 1538#endif
be266cb2 1539#if _SQUID_WINDOWS_
0e6d05ef 1540 if (0 == nns)
62e76326 1541 idnsParseWIN32Registry();
0e6d05ef 1542#endif
62e76326 1543
29fe9bd5 1544 if (0 == nns) {
1545 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
be266cb2 1546#if _SQUID_WINDOWS_
29fe9bd5 1547 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
0e6d05ef 1548#else
29fe9bd5 1549 debugs(78, 1, "Please check your /etc/resolv.conf file");
0e6d05ef 1550#endif
29fe9bd5 1551
1552 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1553 idnsAddNameserver("127.0.0.1");
1554 }
62e76326 1555
7b724b86 1556 if (!init) {
62e76326 1557 memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
62e76326 1558 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
30abd221 1559 idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
62e76326 1560 init++;
7b724b86 1561 }
372fb44e 1562
e210930b
AJ
1563#if WHEN_EDNS_RESPONSES_ARE_PARSED
1564 if (Config.onoff.ignore_unknown_nameservers && max_shared_edns > 0) {
1565 debugs(0, DBG_IMPORTANT, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1566 max_shared_edns = -1; // disable if we might receive random replies.
1567 }
1568#endif
1569
372fb44e 1570 idnsRegisterWithCacheManager();
7b724b86 1571}
1572
1573void
1574idnsShutdown(void)
1575{
4d6c8504 1576 if (DnsSocketA < 0 && DnsSocketB < 0)
62e76326 1577 return;
1578
04f7fd38 1579 if (DnsSocketA >= 0 ) {
4d6c8504
AJ
1580 comm_close(DnsSocketA);
1581 DnsSocketA = -1;
1582 }
62e76326 1583
055421ee 1584 if (DnsSocketB >= 0 ) {
4d6c8504
AJ
1585 comm_close(DnsSocketB);
1586 DnsSocketB = -1;
1587 }
62e76326 1588
b26754c4 1589 for (int i = 0; i < nns; i++) {
1590 if (nsvc *vc = nameservers[i].vc) {
00406b24
AJ
1591 if (Comm::IsConnOpen(vc->conn))
1592 vc->conn->close();
b26754c4 1593 }
1594 }
1595
dd3fb890 1596 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
efd900cb 1597 idnsFreeNameservers();
68836b58 1598 idnsFreeSearchpath();
7b724b86 1599}
1600
3074b9d1 1601static int
1602idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1603{
1604 idns_query *q;
1605
1606 idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
1607
1608 if (!old)
1609 return 0;
1610
63a0e6b7 1611 q = cbdataAlloc(idns_query);
91dcbd43
CT
1612 // idns_query is POD so no constructors are called after allocation
1613 q->xact_id.change();
3074b9d1 1614
1615 q->callback = callback;
1616
1617 q->callback_data = cbdataReference(data);
1618
1619 q->queue = old->queue;
1620
1621 old->queue = q;
1622
1623 return 1;
1624}
1625
1626static void
9e1f210d 1627idnsCacheQuery(idns_query *q)
3074b9d1 1628{
9e1f210d 1629 q->hash.key = q->query.name;
3074b9d1 1630 hash_join(idns_lookup_hash, &q->hash);
1631}
1632
7b724b86 1633void
1634idnsALookup(const char *name, IDNSCB * callback, void *data)
1635{
68836b58 1636 unsigned int i;
1637 int nd = 0;
3074b9d1 1638 idns_query *q;
1639
1640 if (idnsCachedLookup(name, callback, data))
1641 return;
1642
63a0e6b7 1643 q = cbdataAlloc(idns_query);
91dcbd43
CT
1644 // idns_query is POD so no constructors are called after allocation
1645 q->xact_id.change();
71952967 1646
68836b58 1647 for (i = 0; i < strlen(name); i++)
1648 if (name[i] == '.')
1649 nd++;
1650
1651 if (Config.onoff.res_defnames && npc > 0 && name[strlen(name)-1] != '.') {
1652 q->do_searchpath = 1;
1653 } else {
1654 q->do_searchpath = 0;
1655 }
1656
1657 strcpy(q->orig, name);
1658 strcpy(q->name, q->orig);
1659
1660 if (q->do_searchpath && nd < ndots) {
1661 q->domain = 0;
1662 strcat(q->name, ".");
1663 strcat(q->name, searchpath[q->domain].domain);
bf8fe701 1664 debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
68836b58 1665 }
1666
055421ee 1667 if (Ip::EnableIpv6) {
91dcbd43 1668 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, Config.dns.packet_max);
055421ee
AJ
1669 q->need_A = true;
1670 } else {
e210930b 1671 // see EDNS notes at top of file why this sends 0
91dcbd43 1672 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, 0);
055421ee
AJ
1673 q->need_A = false;
1674 }
62e76326 1675
2041330b 1676 if (q->sz < 0) {
1677 /* problem with query data -- query not sent */
1678 callback(data, NULL, 0, "Internal error");
63a0e6b7 1679 cbdataFree(q);
2041330b 1680 return;
1681 }
1682
26ac0430 1683 debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
91dcbd43 1684 ", id = 0x" << std::hex << q->msg_id);
aa6c61e3 1685
7b724b86 1686 q->callback = callback;
fa80a8ef 1687 q->callback_data = cbdataReference(data);
aa6c61e3 1688
9e1f210d 1689 idnsCacheQuery(q);
7b724b86 1690 idnsSendQuery(q);
1691}
8db71107 1692
1693void
b7ac5457 1694idnsPTRLookup(const Ip::Address &addr, IDNSCB * callback, void *data)
8db71107 1695{
3074b9d1 1696 idns_query *q;
1697
cc192b50 1698 char ip[MAX_IPSTRLEN];
1699
1700 addr.NtoA(ip,MAX_IPSTRLEN);
3074b9d1 1701
63a0e6b7 1702 q = cbdataAlloc(idns_query);
3074b9d1 1703
91dcbd43
CT
1704 // idns_query is POD so no constructors are called after allocation
1705 q->xact_id.change();
71952967 1706
4e6de170 1707 if (addr.IsIPv6()) {
cc192b50 1708 struct in6_addr addr6;
1709 addr.GetInAddr(addr6);
91dcbd43 1710 q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), 0, &q->query, Config.dns.packet_max);
055421ee 1711 } else {
cc192b50 1712 struct in_addr addr4;
1713 addr.GetInAddr(addr4);
e210930b 1714 // see EDNS notes at top of file why this sends 0
91dcbd43 1715 q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), 0, &q->query, 0);
cc192b50 1716 }
1717
1718 /* PTR does not do inbound A/AAAA */
1719 q->need_A = false;
3074b9d1 1720
26ac0430 1721 if (q->sz < 0) {
2041330b 1722 /* problem with query data -- query not sent */
1723 callback(data, NULL, 0, "Internal error");
63a0e6b7 1724 cbdataFree(q);
2041330b 1725 return;
1726 }
1727
37f3da43 1728 if (idnsCachedLookup(q->query.name, callback, data)) {
26ac0430
AJ
1729 cbdataFree(q);
1730 return;
37f3da43 1731 }
1732
26ac0430 1733 debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
91dcbd43 1734 ", id = 0x" << std::hex << q->msg_id);
3074b9d1 1735
8db71107 1736 q->callback = callback;
fa80a8ef 1737 q->callback_data = cbdataReference(data);
3074b9d1 1738
9e1f210d 1739 idnsCacheQuery(q);
8db71107 1740 idnsSendQuery(q);
1741}
eb824054 1742
59ad6d31 1743#if SQUID_SNMP
3c573763 1744/*
1745 * The function to return the DNS via SNMP
1746 */
1747variable_list *
1748snmp_netIdnsFn(variable_list * Var, snint * ErrP)
1749{
1750 int i, n = 0;
1751 variable_list *Answer = NULL;
6a644e75
AJ
1752 MemBuf tmp;
1753 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var->name, Var->name_length, tmp));
3c573763 1754 *ErrP = SNMP_ERR_NOERROR;
62e76326 1755
3c573763 1756 switch (Var->name[LEN_SQ_NET + 1]) {
62e76326 1757
3c573763 1758 case DNS_REQ:
62e76326 1759
1760 for (i = 0; i < nns; i++)
1761 n += nameservers[i].nqueries;
1762
1763 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1764 n,
1765 SMI_COUNTER32);
1766
1767 break;
1768
3c573763 1769 case DNS_REP:
62e76326 1770 for (i = 0; i < nns; i++)
1771 n += nameservers[i].nreplies;
1772
1773 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1774 n,
1775 SMI_COUNTER32);
1776
1777 break;
1778
3c573763 1779 case DNS_SERVERS:
62e76326 1780 Answer = snmp_var_new_integer(Var->name, Var->name_length,
e494f5e9 1781 nns,
62e76326 1782 SMI_COUNTER32);
1783
1784 break;
1785
3c573763 1786 default:
62e76326 1787 *ErrP = SNMP_ERR_NOSUCHNAME;
1788
1789 break;
3c573763 1790 }
62e76326 1791
3c573763 1792 return Answer;
1793}
62e76326 1794
3c573763 1795#endif /*SQUID_SNMP */
1f1ae50a 1796#endif /* USE_DNSSERVERS */