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