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