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