]> git.ipfire.org Git - thirdparty/squid.git/blame - src/dns_internal.cc
Improve support for clang compilers
[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;
5e263176 1153 -- q->nsends;
d24ef4e9 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
5e263176
FC
1266 while (max) {
1267 --max;
cc192b50 1268 len = comm_udp_recvfrom(fd, rbuf, SQUID_UDP_SO_RCVBUF, 0, bugbypass);
62e76326 1269
cc192b50 1270 from = bugbypass; // BUG BYPASS. see notes above.
62e76326 1271
1272 if (len == 0)
1273 break;
1274
1275 if (len < 0) {
1276 if (ignoreErrno(errno))
1277 break;
1278
1191b93b 1279#if _SQUID_LINUX_
62e76326 1280 /* Some Linux systems seem to set the FD for reading and then
1281 * return ECONNREFUSED when sendto() fails and generates an ICMP
1282 * port unreachable message. */
1283 /* or maybe an EHOSTUNREACH "No route to host" message */
1284 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
7b724b86 1285#endif
62e76326 1286
bf8fe701 1287 debugs(50, 1, "idnsRead: FD " << fd << " recvfrom: " << xstrerror());
62e76326 1288
1289 break;
1290 }
1291
055421ee 1292 fd_bytes(fd, len, FD_READ);
4d6c8504 1293
62e76326 1294 assert(N);
aec55359 1295 ++(*N);
cc192b50 1296
1297 debugs(78, 3, "idnsRead: FD " << fd << ": received " << len << " bytes from " << from);
1298
1299 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1300 ns = idnsFromKnownNameserver(from);
62e76326 1301
1302 if (ns >= 0) {
95dc7ff4 1303 ++ nameservers[ns].nreplies;
bd6a0c8f
HN
1304 }
1305
1306 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1307 // but after the ++ above to keep statistics right.
1308 if (!lru_list.head)
1309 continue; // Don't process replies if there is no pending query.
1310
1311 if (ns < 0 && Config.onoff.ignore_unknown_nameservers) {
62e76326 1312 static time_t last_warning = 0;
1313
1314 if (squid_curtime - last_warning > 60) {
cc192b50 1315 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from);
62e76326 1316 last_warning = squid_curtime;
26ac0430 1317 } else {
cc192b50 1318 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from << " (retrying..." << (squid_curtime-last_warning) << "<=60)" );
26ac0430
AJ
1319 }
1320 continue;
62e76326 1321 }
1322
e210930b 1323 idnsGrokReply(rbuf, len, ns);
7b724b86 1324 }
1325}
1326
7cfc1c9a 1327static void
1328idnsCheckQueue(void *unused)
1329{
1330 dlink_node *n;
0c4fe9e4 1331 dlink_node *p = NULL;
7cfc1c9a 1332 idns_query *q;
1333 event_queued = 0;
62e76326 1334
820ee9fa
AJ
1335 if (0 == nns)
1336 /* name servers went away; reconfiguring or shutting down */
1337 return;
1338
0c4fe9e4 1339 for (n = lru_list.tail; n; n = p) {
62e76326 1340
820ee9fa 1341 p = n->prev;
733cedc0 1342 q = static_cast<idns_query*>(n->data);
62e76326 1343
820ee9fa 1344 /* Anything to process in the queue? */
fd0f51c4 1345 if ((time_msec_t)tvSubMsec(q->queue_t, current_time) < Config.Timeout.idns_retransmit )
26ac0430 1346 break;
62e76326 1347
33ab4aaf 1348 /* Query timer still running? */
fd0f51c4 1349 if ((time_msec_t)tvSubMsec(q->sent_t, current_time) < (Config.Timeout.idns_retransmit * 1 << ((q->nsends - 1) / nns))) {
820ee9fa
AJ
1350 dlinkDelete(&q->lru, &lru_list);
1351 q->queue_t = current_time;
1352 dlinkAdd(q, &q->lru, &lru_list);
1353 continue;
1354 }
62e76326 1355
91dcbd43
CT
1356 debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
1357 " QID 0x" << std::hex << std::setfill('0') <<
049441d9 1358 std::setw(4) << q->query_id << ": timeout" );
62e76326 1359
1360 dlinkDelete(&q->lru, &lru_list);
33ab4aaf 1361 q->pending = 0;
62e76326 1362
fd0f51c4 1363 if ((time_msec_t)tvSubMsec(q->start_t, current_time) < Config.Timeout.idns_query) {
62e76326 1364 idnsSendQuery(q);
1365 } else {
91dcbd43 1366 debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
049441d9 1367 " QID 0x" << std::hex << q->query_id <<
91dcbd43 1368 " : giving up after " << std::dec << q->nsends << " tries and " <<
26ac0430 1369 std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
3074b9d1 1370
1371 if (q->rcode != 0)
33ab4aaf 1372 idnsCallback(q, rfc1035ErrorMessage(q->rcode));
3074b9d1 1373 else
33ab4aaf 1374 idnsCallback(q, "Timeout");
62e76326 1375 }
7cfc1c9a 1376 }
62e76326 1377
efd900cb 1378 idnsTickleQueue();
7cfc1c9a 1379}
1380
d24ef4e9 1381static void
e0d28505 1382idnsReadVC(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
d24ef4e9 1383{
1384 nsvc * vc = (nsvc *)data;
1385
1386 if (flag == COMM_ERR_CLOSING)
1387 return;
1388
1389 if (flag != COMM_OK || len <= 0) {
80463bb4
AJ
1390 if (Comm::IsConnOpen(conn))
1391 conn->close();
d24ef4e9 1392 return;
1393 }
1394
bd6a0c8f 1395 vc->msg->size += len; // XXX should not access -> size directly
d24ef4e9 1396
032785bf 1397 if (vc->msg->contentSize() < vc->msglen) {
abd8f140
AJ
1398 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1399 CommIoCbPtrFun(idnsReadVC, vc));
1400 comm_read(conn, buf+len, vc->msglen - vc->msg->contentSize(), call);
d24ef4e9 1401 return;
1402 }
1403
dd3fb890 1404 assert(vc->ns < nns);
e0d28505 1405 debugs(78, 3, HERE << conn << ": received " << vc->msg->contentSize() << " bytes via TCP from " << nameservers[vc->ns].S << ".");
d24ef4e9 1406
e210930b 1407 idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
2fe7eff9 1408 vc->msg->clean();
abd8f140
AJ
1409 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1410 CommIoCbPtrFun(idnsReadVCHeader, vc));
1411 comm_read(conn, (char *)&vc->msglen, 2, call);
d24ef4e9 1412}
1413
1414static void
e0d28505 1415idnsReadVCHeader(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
d24ef4e9 1416{
1417 nsvc * vc = (nsvc *)data;
1418
1419 if (flag == COMM_ERR_CLOSING)
1420 return;
1421
1422 if (flag != COMM_OK || len <= 0) {
80463bb4
AJ
1423 if (Comm::IsConnOpen(conn))
1424 conn->close();
d24ef4e9 1425 return;
1426 }
1427
1428 vc->read_msglen += len;
1429
1430 assert(vc->read_msglen <= 2);
1431
1432 if (vc->read_msglen < 2) {
abd8f140
AJ
1433 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1434 CommIoCbPtrFun(idnsReadVCHeader, vc));
1435 comm_read(conn, buf+len, 2 - vc->read_msglen, call);
d24ef4e9 1436 return;
1437 }
1438
1439 vc->read_msglen = 0;
1440
1441 vc->msglen = ntohs(vc->msglen);
1442
2fe7eff9 1443 vc->msg->init(vc->msglen, vc->msglen);
abd8f140
AJ
1444 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1445 CommIoCbPtrFun(idnsReadVC, vc));
1446 comm_read(conn, vc->msg->buf, vc->msglen, call);
d24ef4e9 1447}
1448
558be27a 1449/*
1450 * rcode < 0 indicates an error, rocde >= 0 indicates success
1451 */
1452static void
1453idnsRcodeCount(int rcode, int attempt)
1454{
1455 if (rcode > 0)
62e76326 1456 rcode = 0;
558be27a 1457 else if (rcode < 0)
62e76326 1458 rcode = -rcode;
1459
558be27a 1460 if (rcode < MAX_RCODE)
62e76326 1461 if (attempt < MAX_ATTEMPT)
95dc7ff4 1462 ++ RcodeMatrix[rcode][attempt];
558be27a 1463}
1464
7b724b86 1465/* ====================================================================== */
1466
5f5e883f
FC
1467static void
1468idnsRegisterWithCacheManager(void)
1469{
8822ebee 1470 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
5f5e883f
FC
1471}
1472
7b724b86 1473void
f64091a7 1474dnsInit(void)
7b724b86 1475{
1476 static int init = 0;
62e76326 1477
d24ef4e9 1478 CBDATA_INIT_TYPE(nsvc);
63a0e6b7 1479 CBDATA_INIT_TYPE(idns_query);
d24ef4e9 1480
4d6c8504 1481 if (DnsSocketA < 0 && DnsSocketB < 0) {
049441d9 1482 Ip::Address addrV6; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
62e76326 1483
cc192b50 1484 if (!Config.Addrs.udp_outgoing.IsNoAddr())
049441d9 1485 addrV6 = Config.Addrs.udp_outgoing;
62e76326 1486 else
049441d9 1487 addrV6 = Config.Addrs.udp_incoming;
62e76326 1488
049441d9
HN
1489 Ip::Address addrV4 = addrV6;
1490 addrV4.SetIPv4();
7e07ced1 1491
049441d9
HN
1492 if (Ip::EnableIpv6 && addrV6.IsIPv6()) {
1493 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6);
4d6c8504 1494 DnsSocketB = comm_open_listener(SOCK_DGRAM,
04f7fd38 1495 IPPROTO_UDP,
049441d9 1496 addrV6,
04f7fd38 1497 COMM_NONBLOCKING,
055421ee 1498 "DNS Socket IPv6");
7e07ced1 1499 }
4d6c8504 1500
049441d9
HN
1501 if (addrV4.IsIPv4()) {
1502 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4);
4d6c8504 1503 DnsSocketA = comm_open_listener(SOCK_DGRAM,
04f7fd38 1504 IPPROTO_UDP,
049441d9 1505 addrV4,
04f7fd38 1506 COMM_NONBLOCKING,
055421ee 1507 "DNS Socket IPv4");
7e07ced1 1508 }
62e76326 1509
4d6c8504 1510 if (DnsSocketA < 0 && DnsSocketB < 0)
62e76326 1511 fatal("Could not create a DNS socket");
1512
1513 /* Ouch... we can't call functions using debug from a debug
1514 * statement. Doing so messes up the internal Debug::level
1515 */
04f7fd38 1516 if (DnsSocketB >= 0) {
e91e2a72 1517 comm_local_port(DnsSocketB);
049441d9 1518 debugs(78, 1, "DNS Socket created at " << addrV6 << ", FD " << DnsSocketB);
d841c88d 1519 Comm::SetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, NULL, 0);
4d6c8504 1520 }
04f7fd38 1521 if (DnsSocketA >= 0) {
e91e2a72 1522 comm_local_port(DnsSocketA);
049441d9 1523 debugs(78, 1, "DNS Socket created at " << addrV4 << ", FD " << DnsSocketA);
d841c88d 1524 Comm::SetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, NULL, 0);
4d6c8504 1525 }
7b724b86 1526 }
62e76326 1527
efd900cb 1528 assert(0 == nns);
1529 idnsParseNameservers();
1191b93b 1530#if !_SQUID_MSWIN_
62e76326 1531
efd900cb 1532 if (0 == nns)
62e76326 1533 idnsParseResolvConf();
1534
0e6d05ef 1535#endif
be266cb2 1536#if _SQUID_WINDOWS_
0e6d05ef 1537 if (0 == nns)
62e76326 1538 idnsParseWIN32Registry();
0e6d05ef 1539#endif
62e76326 1540
29fe9bd5 1541 if (0 == nns) {
1542 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
be266cb2 1543#if _SQUID_WINDOWS_
29fe9bd5 1544 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
0e6d05ef 1545#else
29fe9bd5 1546 debugs(78, 1, "Please check your /etc/resolv.conf file");
0e6d05ef 1547#endif
29fe9bd5 1548
1549 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1550 idnsAddNameserver("127.0.0.1");
1551 }
62e76326 1552
7b724b86 1553 if (!init) {
62e76326 1554 memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
62e76326 1555 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
30abd221 1556 idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
95dc7ff4 1557 ++init;
7b724b86 1558 }
372fb44e 1559
e210930b
AJ
1560#if WHEN_EDNS_RESPONSES_ARE_PARSED
1561 if (Config.onoff.ignore_unknown_nameservers && max_shared_edns > 0) {
1562 debugs(0, DBG_IMPORTANT, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1563 max_shared_edns = -1; // disable if we might receive random replies.
1564 }
1565#endif
1566
372fb44e 1567 idnsRegisterWithCacheManager();
7b724b86 1568}
1569
1570void
f64091a7 1571dnsShutdown(void)
7b724b86 1572{
4d6c8504 1573 if (DnsSocketA < 0 && DnsSocketB < 0)
62e76326 1574 return;
1575
04f7fd38 1576 if (DnsSocketA >= 0 ) {
4d6c8504
AJ
1577 comm_close(DnsSocketA);
1578 DnsSocketA = -1;
1579 }
62e76326 1580
055421ee 1581 if (DnsSocketB >= 0 ) {
4d6c8504
AJ
1582 comm_close(DnsSocketB);
1583 DnsSocketB = -1;
1584 }
62e76326 1585
95dc7ff4 1586 for (int i = 0; i < nns; ++i) {
b26754c4 1587 if (nsvc *vc = nameservers[i].vc) {
00406b24
AJ
1588 if (Comm::IsConnOpen(vc->conn))
1589 vc->conn->close();
b26754c4 1590 }
1591 }
1592
dd3fb890 1593 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
efd900cb 1594 idnsFreeNameservers();
68836b58 1595 idnsFreeSearchpath();
7b724b86 1596}
1597
3074b9d1 1598static int
1599idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1600{
1601 idns_query *q;
1602
1603 idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
1604
1605 if (!old)
1606 return 0;
1607
63a0e6b7 1608 q = cbdataAlloc(idns_query);
91dcbd43
CT
1609 // idns_query is POD so no constructors are called after allocation
1610 q->xact_id.change();
049441d9 1611 // no query_id on this instance.
3074b9d1 1612
1613 q->callback = callback;
1614
1615 q->callback_data = cbdataReference(data);
1616
1617 q->queue = old->queue;
1618
1619 old->queue = q;
1620
1621 return 1;
1622}
1623
1624static void
33ab4aaf 1625idnsStartQuery(idns_query *q, IDNSCB * callback, void *data)
3074b9d1 1626{
33ab4aaf
HN
1627 q->start_t = current_time;
1628 q->callback = callback;
1629 q->callback_data = cbdataReference(data);
1630
049441d9 1631 q->hash.key = q->orig;
3074b9d1 1632 hash_join(idns_lookup_hash, &q->hash);
33ab4aaf
HN
1633
1634 idnsSendQuery(q);
3074b9d1 1635}
1636
049441d9
HN
1637static void
1638idnsSendSlaveAAAAQuery(idns_query *master)
1639{
1640 idns_query *q = cbdataAlloc(idns_query);
1641 memcpy(q->name, master->name, sizeof(q->name));
1642 memcpy(q->orig, master->orig, sizeof(q->orig));
1643 q->master = master;
1644 q->query_id = idnsQueryID();
1645 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
33ab4aaf 1646 q->start_t = master->start_t;
049441d9 1647 q->slave = master->slave;
c7ba545e 1648
cafb131e 1649 debugs(78, 3, HERE << "buf is " << q->sz << " bytes for " << q->name <<
049441d9
HN
1650 ", id = 0x" << std::hex << q->query_id);
1651 if (!q->sz) {
1652 cbdataFree(q);
1653 return;
1654 }
1655 master->slave = q;
1656 idnsSendQuery(q);
1657}
1658
7b724b86 1659void
1660idnsALookup(const char *name, IDNSCB * callback, void *data)
1661{
68836b58 1662 unsigned int i;
1663 int nd = 0;
3074b9d1 1664 idns_query *q;
1665
1666 if (idnsCachedLookup(name, callback, data))
1667 return;
1668
63a0e6b7 1669 q = cbdataAlloc(idns_query);
91dcbd43
CT
1670 // idns_query is POD so no constructors are called after allocation
1671 q->xact_id.change();
049441d9 1672 q->query_id = idnsQueryID();
71952967 1673
95dc7ff4 1674 for (i = 0; i < strlen(name); ++i)
68836b58 1675 if (name[i] == '.')
95dc7ff4 1676 ++nd;
68836b58 1677
1678 if (Config.onoff.res_defnames && npc > 0 && name[strlen(name)-1] != '.') {
1679 q->do_searchpath = 1;
1680 } else {
1681 q->do_searchpath = 0;
1682 }
1683
1684 strcpy(q->orig, name);
1685 strcpy(q->name, q->orig);
1686
1687 if (q->do_searchpath && nd < ndots) {
1688 q->domain = 0;
1689 strcat(q->name, ".");
1690 strcat(q->name, searchpath[q->domain].domain);
bf8fe701 1691 debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
68836b58 1692 }
1693
049441d9
HN
1694 // see EDNS notes at top of file why this sends 0
1695 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
62e76326 1696
2041330b 1697 if (q->sz < 0) {
1698 /* problem with query data -- query not sent */
1699 callback(data, NULL, 0, "Internal error");
63a0e6b7 1700 cbdataFree(q);
2041330b 1701 return;
1702 }
1703
26ac0430 1704 debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
049441d9 1705 ", id = 0x" << std::hex << q->query_id);
aa6c61e3 1706
33ab4aaf 1707 idnsStartQuery(q, callback, data);
049441d9
HN
1708
1709 if (Ip::EnableIpv6)
1710 idnsSendSlaveAAAAQuery(q);
1711
7b724b86 1712}
8db71107 1713
1714void
b7ac5457 1715idnsPTRLookup(const Ip::Address &addr, IDNSCB * callback, void *data)
8db71107 1716{
3074b9d1 1717 idns_query *q;
1718
cc192b50 1719 char ip[MAX_IPSTRLEN];
1720
1721 addr.NtoA(ip,MAX_IPSTRLEN);
3074b9d1 1722
63a0e6b7 1723 q = cbdataAlloc(idns_query);
3074b9d1 1724
91dcbd43
CT
1725 // idns_query is POD so no constructors are called after allocation
1726 q->xact_id.change();
049441d9 1727 q->query_id = idnsQueryID();
71952967 1728
4e6de170 1729 if (addr.IsIPv6()) {
cc192b50 1730 struct in6_addr addr6;
1731 addr.GetInAddr(addr6);
546ae352 1732 q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
055421ee 1733 } else {
cc192b50 1734 struct in_addr addr4;
1735 addr.GetInAddr(addr4);
e210930b 1736 // see EDNS notes at top of file why this sends 0
546ae352 1737 q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
cc192b50 1738 }
1739
26ac0430 1740 if (q->sz < 0) {
2041330b 1741 /* problem with query data -- query not sent */
1742 callback(data, NULL, 0, "Internal error");
63a0e6b7 1743 cbdataFree(q);
2041330b 1744 return;
1745 }
1746
37f3da43 1747 if (idnsCachedLookup(q->query.name, callback, data)) {
26ac0430
AJ
1748 cbdataFree(q);
1749 return;
37f3da43 1750 }
1751
26ac0430 1752 debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
049441d9 1753 ", id = 0x" << std::hex << q->query_id);
3074b9d1 1754
33ab4aaf 1755 idnsStartQuery(q, callback, data);
8db71107 1756}
eb824054 1757
59ad6d31 1758#if SQUID_SNMP
3c573763 1759/*
1760 * The function to return the DNS via SNMP
1761 */
1762variable_list *
f64091a7 1763snmp_netDnsFn(variable_list * Var, snint * ErrP)
3c573763 1764{
1765 int i, n = 0;
1766 variable_list *Answer = NULL;
6a644e75
AJ
1767 MemBuf tmp;
1768 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var->name, Var->name_length, tmp));
3c573763 1769 *ErrP = SNMP_ERR_NOERROR;
62e76326 1770
3c573763 1771 switch (Var->name[LEN_SQ_NET + 1]) {
62e76326 1772
3c573763 1773 case DNS_REQ:
62e76326 1774
95dc7ff4 1775 for (i = 0; i < nns; ++i)
62e76326 1776 n += nameservers[i].nqueries;
1777
1778 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1779 n,
1780 SMI_COUNTER32);
1781
1782 break;
1783
3c573763 1784 case DNS_REP:
95dc7ff4 1785 for (i = 0; i < nns; ++i)
62e76326 1786 n += nameservers[i].nreplies;
1787
1788 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1789 n,
1790 SMI_COUNTER32);
1791
1792 break;
1793
3c573763 1794 case DNS_SERVERS:
62e76326 1795 Answer = snmp_var_new_integer(Var->name, Var->name_length,
e494f5e9 1796 nns,
62e76326 1797 SMI_COUNTER32);
1798
1799 break;
1800
3c573763 1801 default:
62e76326 1802 *ErrP = SNMP_ERR_NOSUCHNAME;
1803
1804 break;
3c573763 1805 }
62e76326 1806
3c573763 1807 return Answer;
1808}
62e76326 1809
3c573763 1810#endif /*SQUID_SNMP */
f64091a7 1811#endif /* USE_DNSHELPER */