]> git.ipfire.org Git - thirdparty/squid.git/blame_incremental - src/dns_internal.cc
Fix build error using --enable-linux-tproxy
[thirdparty/squid.git] / src / dns_internal.cc
... / ...
CommitLineData
1
2/*
3 * $Id: dns_internal.cc,v 1.104 2008/01/11 03:49:22 amosjeffries Exp $
4 *
5 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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.
24 *
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.
29 *
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
36#include "config.h"
37#include "squid.h"
38#include "event.h"
39#include "CacheManager.h"
40#include "SquidTime.h"
41#include "Store.h"
42#include "comm.h"
43#include "MemBuf.h"
44
45#include "wordlist.h"
46
47#if HAVE_ARPA_NAMESER_H
48#include <arpa/nameser.h>
49#endif
50#if HAVE_RESOLV_H
51#include <resolv.h>
52#endif
53
54/* MS VisualStudio Projects are monolithic, so we need the following
55 #ifndef to exclude the internal DNS code from compile process when
56 using external DNS process.
57 */
58#ifndef USE_DNSSERVERS
59#ifdef _SQUID_WIN32_
60#include "squid_windows.h"
61#endif
62#ifndef _PATH_RESCONF
63#define _PATH_RESCONF "/etc/resolv.conf"
64#endif
65#ifndef NS_DEFAULTPORT
66#define NS_DEFAULTPORT 53
67#endif
68
69#ifndef NS_MAXDNAME
70#define NS_MAXDNAME 1025
71#endif
72
73#ifndef MAXDNSRCH
74#define MAXDNSRCH 6
75#endif
76
77/* The buffer size required to store the maximum allowed search path */
78#ifndef RESOLV_BUFSZ
79#define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
80#endif
81
82#define IDNS_MAX_TRIES 20
83#define MAX_RCODE 6
84#define MAX_ATTEMPT 3
85static int RcodeMatrix[MAX_RCODE][MAX_ATTEMPT];
86
87typedef struct _idns_query idns_query;
88
89typedef struct _ns ns;
90
91typedef struct _sp sp;
92
93typedef struct _nsvc nsvc;
94
95struct _idns_query
96{
97 hash_link hash;
98 rfc1035_query query;
99 char buf[RESOLV_BUFSZ];
100 char name[NS_MAXDNAME + 1];
101 char orig[NS_MAXDNAME + 1];
102 size_t sz;
103 unsigned short id;
104 int nsends;
105 int need_vc;
106
107 struct timeval start_t;
108
109 struct timeval sent_t;
110 dlink_node lru;
111 IDNSCB *callback;
112 void *callback_data;
113 int attempt;
114 const char *error;
115 int rcode;
116 idns_query *queue;
117 unsigned short domain;
118 unsigned short do_searchpath;
119 bool need_A;
120 struct {
121 int count;
122 rfc1035_rr *answers;
123 } initial_AAAA;
124};
125
126struct _nsvc
127{
128 int ns;
129 int fd;
130 unsigned short msglen;
131 int read_msglen;
132 MemBuf *msg;
133 MemBuf *queue;
134 bool busy;
135};
136
137struct _ns
138{
139 IPAddress S;
140 int nqueries;
141 int nreplies;
142 nsvc *vc;
143};
144
145struct _sp
146{
147 char domain[NS_MAXDNAME];
148 int queries;
149};
150
151CBDATA_TYPE(nsvc);
152CBDATA_TYPE(idns_query);
153
154static ns *nameservers = NULL;
155static sp *searchpath = NULL;
156static int nns = 0;
157static int nns_alloc = 0;
158static int npc = 0;
159static int npc_alloc = 0;
160static int ndots = 1;
161static dlink_list lru_list;
162static int event_queued = 0;
163static hash_table *idns_lookup_hash = NULL;
164
165static OBJH idnsStats;
166static void idnsAddNameserver(const char *buf);
167static void idnsAddPathComponent(const char *buf);
168static void idnsFreeNameservers(void);
169static void idnsFreeSearchpath(void);
170static void idnsParseNameservers(void);
171#ifndef _SQUID_MSWIN_
172static void idnsParseResolvConf(void);
173#endif
174#ifdef _SQUID_WIN32_
175static void idnsParseWIN32Registry(void);
176static void idnsParseWIN32SearchList(const char *);
177#endif
178static void idnsCacheQuery(idns_query * q);
179static void idnsSendQuery(idns_query * q);
180static IOCB idnsReadVCHeader;
181static void idnsDoSendQueryVC(nsvc *vc);
182
183static int idnsFromKnownNameserver(IPAddress const &from);
184static idns_query *idnsFindQuery(unsigned short id);
185static void idnsGrokReply(const char *buf, size_t sz);
186static PF idnsRead;
187static EVH idnsCheckQueue;
188static void idnsTickleQueue(void);
189static void idnsRcodeCount(int, int);
190
191static void
192idnsAddNameserver(const char *buf)
193{
194 IPAddress A;
195
196 if (!(A = buf)) {
197 debugs(78, 0, "WARNING: rejecting '" << buf << "' as a name server, because it is not a numeric IP address");
198 return;
199 }
200
201 if (A.IsAnyAddr()) {
202 debugs(78, 0, "WARNING: Squid does not accept " << A << " in DNS server specifications.");
203 A = "127.0.0.1";
204 debugs(78, 0, "Will be using " << A << " instead, assuming you meant that DNS is running on the same machine");
205 }
206
207 if (nns == nns_alloc) {
208 int oldalloc = nns_alloc;
209 ns *oldptr = nameservers;
210
211 if (nns_alloc == 0)
212 nns_alloc = 2;
213 else
214 nns_alloc <<= 1;
215
216 nameservers = (ns *)xcalloc(nns_alloc, sizeof(*nameservers));
217
218 if (oldptr && oldalloc)
219 xmemcpy(nameservers, oldptr, oldalloc * sizeof(*nameservers));
220
221 if (oldptr)
222 safe_free(oldptr);
223 }
224
225 assert(nns < nns_alloc);
226 A.SetPort(NS_DEFAULTPORT);
227 nameservers[nns].S = A;
228 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns << " (" << A << ")");
229 nns++;
230}
231
232static void
233idnsAddPathComponent(const char *buf)
234{
235 if (npc == npc_alloc) {
236 int oldalloc = npc_alloc;
237 sp *oldptr = searchpath;
238
239 if (0 == npc_alloc)
240 npc_alloc = 2;
241 else
242 npc_alloc <<= 1;
243
244 searchpath = (sp *)xcalloc(npc_alloc, sizeof(*searchpath));
245
246 if (oldptr && oldalloc)
247 xmemcpy(searchpath, oldptr, oldalloc * sizeof(*searchpath));
248
249 if (oldptr)
250 safe_free(oldptr);
251 }
252
253 assert(npc < npc_alloc);
254 strcpy(searchpath[npc].domain, buf);
255 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc << ": " << searchpath[npc].domain);
256 npc++;
257}
258
259
260static void
261idnsFreeNameservers(void)
262{
263 safe_free(nameservers);
264 nns = nns_alloc = 0;
265}
266
267static void
268idnsFreeSearchpath(void)
269{
270 safe_free(searchpath);
271 npc = npc_alloc = 0;
272}
273
274
275
276static void
277idnsParseNameservers(void)
278{
279 wordlist *w;
280
281 for (w = Config.dns_nameservers; w; w = w->next) {
282 debugs(78, 1, "Adding nameserver " << w->key << " from squid.conf");
283 idnsAddNameserver(w->key);
284 }
285}
286
287#ifndef _SQUID_MSWIN_
288static void
289idnsParseResolvConf(void)
290{
291 FILE *fp;
292 char buf[RESOLV_BUFSZ];
293 char *t;
294 fp = fopen(_PATH_RESCONF, "r");
295
296 if (fp == NULL) {
297 debugs(78, 1, "" << _PATH_RESCONF << ": " << xstrerror());
298 return;
299 }
300
301#if defined(_SQUID_CYGWIN_)
302 setmode(fileno(fp), O_TEXT);
303
304#endif
305
306 while (fgets(buf, RESOLV_BUFSZ, fp)) {
307 t = strtok(buf, w_space);
308
309 if (NULL == t) {
310 continue;
311 } else if (strcasecmp(t, "nameserver") == 0) {
312 t = strtok(NULL, w_space);
313
314 if (NULL == t)
315 continue;
316
317 debugs(78, 1, "Adding nameserver " << t << " from " << _PATH_RESCONF);
318
319 idnsAddNameserver(t);
320 } else if (strcasecmp(t, "search") == 0) {
321 while (NULL != t) {
322 t = strtok(NULL, w_space);
323
324 if (NULL == t)
325 continue;
326
327 debugs(78, 1, "Adding domain " << t << " from " << _PATH_RESCONF);
328
329 idnsAddPathComponent(t);
330 }
331 } else if (strcasecmp(t, "options") == 0) {
332 while (NULL != t) {
333 t = strtok(NULL, w_space);
334
335 if (NULL == t)
336 continue;
337
338 if (strncmp(t, "ndots:", 6) != 0) {
339 ndots = atoi(t + 6);
340
341 if (ndots < 1)
342 ndots = 1;
343
344 debugs(78, 1, "Adding ndots " << ndots << " from " << _PATH_RESCONF);
345 }
346 }
347 }
348 }
349
350 fclose(fp);
351}
352
353#endif
354
355#ifdef _SQUID_WIN32_
356static void
357idnsParseWIN32SearchList(const char * Separator)
358{
359 BYTE *t;
360 char *token;
361 HKEY hndKey;
362
363 if (RegOpenKey(HKEY_LOCAL_MACHINE,
364 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
365 &hndKey) == ERROR_SUCCESS) {
366 DWORD Type = 0;
367 DWORD Size = 0;
368 LONG Result;
369 Result =
370 RegQueryValueEx(hndKey, "SearchList", NULL, &Type, NULL,
371 &Size);
372
373 if (Result == ERROR_SUCCESS && Size) {
374 t = (unsigned char *) xmalloc(Size);
375 RegQueryValueEx(hndKey, "SearchList", NULL, &Type, t,
376 &Size);
377 token = strtok((char *) t, Separator);
378
379 while (token) {
380 idnsAddPathComponent(token);
381 debugs(78, 1, "Adding domain " << token << " from Registry");
382 token = strtok(NULL, Separator);
383 }
384 }
385
386 RegCloseKey(hndKey);
387 }
388}
389
390static void
391idnsParseWIN32Registry(void)
392{
393 BYTE *t;
394 char *token;
395 HKEY hndKey, hndKey2;
396
397 idnsFreeNameservers();
398
399 switch (WIN32_OS_version) {
400
401 case _WIN_OS_WINNT:
402 /* get nameservers from the Windows NT registry */
403
404 if (RegOpenKey(HKEY_LOCAL_MACHINE,
405 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
406 &hndKey) == ERROR_SUCCESS) {
407 DWORD Type = 0;
408 DWORD Size = 0;
409 LONG Result;
410 Result =
411 RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, NULL,
412 &Size);
413
414 if (Result == ERROR_SUCCESS && Size) {
415 t = (unsigned char *) xmalloc(Size);
416 RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, t,
417 &Size);
418 token = strtok((char *) t, ", ");
419
420 while (token) {
421 idnsAddNameserver(token);
422 debugs(78, 1, "Adding DHCP nameserver " << token << " from Registry");
423 token = strtok(NULL, ",");
424 }
425 }
426
427 Result =
428 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
429
430 if (Result == ERROR_SUCCESS && Size) {
431 t = (unsigned char *) xmalloc(Size);
432 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, t, &Size);
433 token = strtok((char *) t, ", ");
434
435 while (token) {
436 debugs(78, 1, "Adding nameserver " << token << " from Registry");
437 idnsAddNameserver(token);
438 token = strtok(NULL, ", ");
439 }
440 }
441
442 RegCloseKey(hndKey);
443 }
444
445 idnsParseWIN32SearchList(" ");
446
447 break;
448
449 case _WIN_OS_WIN2K:
450
451 case _WIN_OS_WINXP:
452
453 case _WIN_OS_WINNET:
454
455 case _WIN_OS_WINLON:
456 /* get nameservers from the Windows 2000 registry */
457 /* search all interfaces for DNS server addresses */
458
459 if (RegOpenKey(HKEY_LOCAL_MACHINE,
460 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces",
461 &hndKey) == ERROR_SUCCESS) {
462 int i;
463 char keyname[255];
464
465 for (i = 0; i < 10; i++) {
466 if (RegEnumKey(hndKey, i, (char *) &keyname,
467 255) == ERROR_SUCCESS) {
468 char newkeyname[255];
469 strcpy(newkeyname,
470 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
471 strcat(newkeyname, keyname);
472
473 if (RegOpenKey(HKEY_LOCAL_MACHINE, newkeyname,
474 &hndKey2) == ERROR_SUCCESS) {
475 DWORD Type = 0;
476 DWORD Size = 0;
477 LONG Result;
478 Result =
479 RegQueryValueEx(hndKey2, "DhcpNameServer", NULL,
480 &Type, NULL, &Size);
481
482 if (Result == ERROR_SUCCESS && Size) {
483 t = (unsigned char *) xmalloc(Size);
484 RegQueryValueEx(hndKey2, "DhcpNameServer", NULL,
485 &Type, t, &Size);
486 token = strtok((char *) t, ", ");
487
488 while (token) {
489 debugs(78, 1, "Adding DHCP nameserver " << token << " from Registry");
490 idnsAddNameserver(token);
491 token = strtok(NULL, ", ");
492 }
493 }
494
495 Result =
496 RegQueryValueEx(hndKey2, "NameServer", NULL, &Type,
497 NULL, &Size);
498
499 if (Result == ERROR_SUCCESS && Size) {
500 t = (unsigned char *) xmalloc(Size);
501 RegQueryValueEx(hndKey2, "NameServer", NULL, &Type,
502 t, &Size);
503 token = strtok((char *) t, ", ");
504
505 while (token) {
506 debugs(78, 1, "Adding nameserver " << token << " from Registry");
507 idnsAddNameserver(token);
508 token = strtok(NULL, ", ");
509 }
510 }
511
512 RegCloseKey(hndKey2);
513 }
514 }
515 }
516
517 RegCloseKey(hndKey);
518 }
519
520 idnsParseWIN32SearchList(", ");
521
522 break;
523
524 case _WIN_OS_WIN95:
525
526 case _WIN_OS_WIN98:
527
528 case _WIN_OS_WINME:
529 /* get nameservers from the Windows 9X registry */
530
531 if (RegOpenKey(HKEY_LOCAL_MACHINE,
532 "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
533 &hndKey) == ERROR_SUCCESS) {
534 DWORD Type = 0;
535 DWORD Size = 0;
536 LONG Result;
537 Result =
538 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
539
540 if (Result == ERROR_SUCCESS && Size) {
541 t = (unsigned char *) xmalloc(Size);
542 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, t, &Size);
543 token = strtok((char *) t, ", ");
544
545 while (token) {
546 debugs(78, 1, "Adding nameserver " << token << " from Registry");
547 idnsAddNameserver(token);
548 token = strtok(NULL, ", ");
549 }
550 }
551
552 RegCloseKey(hndKey);
553 }
554
555 break;
556
557 default:
558 debugs(78, 1, "Failed to read nameserver from Registry: Unknown System Type.");
559 return;
560 }
561}
562
563#endif
564
565static void
566idnsStats(StoreEntry * sentry)
567{
568 dlink_node *n;
569 idns_query *q;
570 int i;
571 int j;
572 char buf[MAX_IPSTRLEN];
573 storeAppendPrintf(sentry, "Internal DNS Statistics:\n");
574 storeAppendPrintf(sentry, "\nThe Queue:\n");
575 storeAppendPrintf(sentry, " DELAY SINCE\n");
576 storeAppendPrintf(sentry, " ID SIZE SENDS FIRST SEND LAST SEND\n");
577 storeAppendPrintf(sentry, "------ ---- ----- ---------- ---------\n");
578
579 for (n = lru_list.head; n; n = n->next) {
580 q = (idns_query *)n->data;
581 storeAppendPrintf(sentry, "%#06x %4d %5d %10.3f %9.3f\n",
582 (int) q->id, (int) q->sz, q->nsends,
583 tvSubDsec(q->start_t, current_time),
584 tvSubDsec(q->sent_t, current_time));
585 }
586
587 storeAppendPrintf(sentry, "\nNameservers:\n");
588 storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES\n");
589 storeAppendPrintf(sentry, "---------------------------------------------- --------- ---------\n");
590
591 for (i = 0; i < nns; i++) {
592 storeAppendPrintf(sentry, "%-45s %9d %9d\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
593 nameservers[i].S.NtoA(buf,MAX_IPSTRLEN),
594 nameservers[i].nqueries,
595 nameservers[i].nreplies);
596 }
597
598 storeAppendPrintf(sentry, "\nRcode Matrix:\n");
599 storeAppendPrintf(sentry, "RCODE");
600
601 for (i = 0; i < MAX_ATTEMPT; i++)
602 storeAppendPrintf(sentry, " ATTEMPT%d", i + 1);
603
604 storeAppendPrintf(sentry, "\n");
605
606 for (j = 0; j < MAX_RCODE; j++) {
607 storeAppendPrintf(sentry, "%5d", j);
608
609 for (i = 0; i < MAX_ATTEMPT; i++)
610 storeAppendPrintf(sentry, " %8d", RcodeMatrix[j][i]);
611
612 storeAppendPrintf(sentry, "\n");
613 }
614
615 if (npc) {
616 storeAppendPrintf(sentry, "\nSearch list:\n");
617
618 for (i=0; i < npc; i++)
619 storeAppendPrintf(sentry, "%s\n", searchpath[i].domain);
620
621 storeAppendPrintf(sentry, "\n");
622 }
623}
624
625static void
626idnsTickleQueue(void)
627{
628 if (event_queued)
629 return;
630
631 if (NULL == lru_list.tail)
632 return;
633
634 eventAdd("idnsCheckQueue", idnsCheckQueue, NULL, 1.0, 1);
635
636 event_queued = 1;
637}
638
639static void
640idnsSentQueryVC(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
641{
642 nsvc * vc = (nsvc *)data;
643
644 if (flag == COMM_ERR_CLOSING)
645 return;
646
647 if (flag != COMM_OK || size <= 0) {
648 comm_close(fd);
649 return;
650 }
651
652 vc->busy = 0;
653 idnsDoSendQueryVC(vc);
654}
655
656static void
657idnsDoSendQueryVC(nsvc *vc)
658{
659 if (vc->busy)
660 return;
661
662 if (vc->queue->contentSize() == 0)
663 return;
664
665 MemBuf *mb = vc->queue;
666
667 vc->queue = new MemBuf;
668
669 vc->busy = 1;
670
671 commSetTimeout(vc->fd, Config.Timeout.idns_query, NULL, NULL);
672
673 comm_write_mbuf(vc->fd, mb, idnsSentQueryVC, vc);
674
675 delete mb;
676}
677
678static void
679idnsInitVCConnected(int fd, comm_err_t status, int xerrno, void *data)
680{
681 nsvc * vc = (nsvc *)data;
682
683 if (status != COMM_OK) {
684 comm_close(fd);
685 return;
686 }
687
688 comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
689 vc->busy = 0;
690 idnsDoSendQueryVC(vc);
691}
692
693static void
694idnsVCClosed(int fd, void *data)
695{
696 nsvc * vc = (nsvc *)data;
697 delete vc->queue;
698 delete vc->msg;
699 nameservers[vc->ns].vc = NULL;
700 cbdataFree(vc);
701}
702
703static void
704idnsInitVC(int ns)
705{
706 char buf[MAX_IPSTRLEN];
707
708 nsvc *vc = cbdataAlloc(nsvc);
709 nameservers[ns].vc = vc;
710
711 IPAddress addr;
712
713 if (!Config.Addrs.udp_outgoing.IsNoAddr())
714 addr = Config.Addrs.udp_outgoing;
715 else
716 addr = Config.Addrs.udp_incoming;
717
718 vc->queue = new MemBuf;
719
720 vc->msg = new MemBuf;
721
722 vc->fd = comm_open(SOCK_STREAM,
723 IPPROTO_TCP,
724 addr,
725 COMM_NONBLOCKING,
726 "DNS TCP Socket");
727
728 if (vc->fd < 0)
729 fatal("Could not create a DNS socket");
730
731 comm_add_close_handler(vc->fd, idnsVCClosed, vc);
732
733 vc->busy = 1;
734
735 commConnectStart(vc->fd, nameservers[ns].S.NtoA(buf,MAX_IPSTRLEN), nameservers[ns].S.GetPort(), idnsInitVCConnected, vc);
736}
737
738static void
739idnsSendQueryVC(idns_query * q, int ns)
740{
741 if (nameservers[ns].vc == NULL)
742 idnsInitVC(ns);
743
744 nsvc *vc = nameservers[ns].vc;
745
746 vc->queue->reset();
747
748 short head = htons(q->sz);
749
750 vc->queue->append((char *)&head, 2);
751
752 vc->queue->append(q->buf, q->sz);
753
754 idnsDoSendQueryVC(vc);
755}
756
757static void
758idnsSendQuery(idns_query * q)
759{
760 int x;
761 int ns;
762
763 if (DnsSocket < 0) {
764 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
765 return;
766 }
767
768 if (nns <= 0) {
769 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
770 return;
771 }
772
773 assert(q->lru.next == NULL);
774
775 assert(q->lru.prev == NULL);
776
777try_again:
778 ns = q->nsends % nns;
779
780 if (q->need_vc) {
781 idnsSendQueryVC(q, ns);
782 x = 0;
783 } else
784 x = comm_udp_sendto(DnsSocket,
785 nameservers[ns].S,
786 q->buf,
787 q->sz);
788
789 q->nsends++;
790
791 q->sent_t = current_time;
792
793 if (x < 0) {
794 debugs(50, 1, "idnsSendQuery: FD " << DnsSocket << ": sendto: " << xstrerror());
795
796 if (q->nsends % nns != 0)
797 goto try_again;
798 } else {
799 fd_bytes(DnsSocket, x, FD_WRITE);
800 commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0);
801 }
802
803 nameservers[ns].nqueries++;
804 dlinkAdd(q, &q->lru, &lru_list);
805 idnsTickleQueue();
806}
807
808static int
809idnsFromKnownNameserver(IPAddress const &from)
810{
811 int i;
812
813 for (i = 0; i < nns; i++)
814 {
815 if (nameservers[i].S != from)
816 continue;
817
818 if (nameservers[i].S.GetPort() != from.GetPort())
819 continue;
820
821 return i;
822 }
823
824 return -1;
825}
826
827static idns_query *
828idnsFindQuery(unsigned short id)
829{
830 dlink_node *n;
831 idns_query *q;
832
833 for (n = lru_list.tail; n; n = n->prev) {
834 q = (idns_query*)n->data;
835
836 if (q->id == id)
837 return q;
838 }
839
840 return NULL;
841}
842
843static unsigned short
844idnsQueryID(void)
845{
846 unsigned short id = squid_random() & 0xFFFF;
847 unsigned short first_id = id;
848
849 while(idnsFindQuery(id)) {
850 id++;
851
852 if (id == first_id) {
853 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
854 break;
855 }
856 }
857
858 return id;
859}
860
861static void
862idnsCallback(idns_query *q, rfc1035_rr *answers, int n, const char *error)
863{
864 IDNSCB *callback;
865 void *cbdata;
866
867 callback = q->callback;
868 q->callback = NULL;
869
870 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
871 callback(cbdata, answers, n, error);
872
873 while(q->queue) {
874 idns_query *q2 = q->queue;
875 q->queue = q2->queue;
876 callback = q2->callback;
877 q2->callback = NULL;
878
879 if (cbdataReferenceValidDone(q2->callback_data, &cbdata))
880 callback(cbdata, answers, n, error);
881
882 cbdataFree(q2);
883 }
884
885 if (q->hash.key) {
886 hash_remove_link(idns_lookup_hash, &q->hash);
887 q->hash.key = NULL;
888 }
889}
890
891void
892idnsDropMessage(rfc1035_message *message, idns_query *q)
893{
894 rfc1035MessageDestroy(&message);
895 if (q->hash.key) {
896 hash_remove_link(idns_lookup_hash, &q->hash);
897 q->hash.key = NULL;
898 }
899}
900
901static void
902idnsGrokReply(const char *buf, size_t sz)
903{
904 int n;
905 rfc1035_message *message = NULL;
906 idns_query *q;
907
908 n = rfc1035MessageUnpack(buf, sz, &message);
909
910 if (message == NULL) {
911 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
912 return;
913 }
914
915 debugs(78, 3, "idnsGrokReply: ID 0x" << std::hex << message->id << ", " << std::dec << n << " answers");
916
917 q = idnsFindQuery(message->id);
918
919 if (q == NULL) {
920 debugs(78, 3, "idnsGrokReply: Late response");
921 rfc1035MessageDestroy(&message);
922 return;
923 }
924
925 if (rfc1035QueryCompare(&q->query, message->query) != 0) {
926 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q->query.name << " != " << message->query->name << ")");
927 rfc1035MessageDestroy(&message);
928 return;
929 }
930
931 if (message->tc) {
932 debugs(78, 3, HERE << "Resolver requested TC (" << q->query.name << ")");
933 dlinkDelete(&q->lru, &lru_list);
934 rfc1035MessageDestroy(&message);
935
936 if (!q->need_vc) {
937 q->need_vc = 1;
938 q->nsends--;
939 idnsSendQuery(q);
940 }
941
942 return;
943 }
944
945 dlinkDelete(&q->lru, &lru_list);
946 idnsRcodeCount(n, q->attempt);
947 q->error = NULL;
948
949 if (n < 0) {
950 debugs(78, 3, "idnsGrokReply: error " << rfc1035_error_message << " (" << rfc1035_errno << ")");
951
952 q->error = rfc1035_error_message;
953 q->rcode = -n;
954
955 if (q->rcode == 2 && ++q->attempt < MAX_ATTEMPT) {
956 /*
957 * RCODE 2 is "Server failure - The name server was
958 * unable to process this query due to a problem with
959 * the name server."
960 */
961 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
962 rfc1035MessageDestroy(&message);
963 q->start_t = current_time;
964 q->id = idnsQueryID();
965 rfc1035SetQueryID(q->buf, q->id);
966 idnsSendQuery(q);
967 return;
968 }
969
970 if (q->rcode == 3 && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
971 assert(NULL == message->answer);
972 strcpy(q->name, q->orig);
973
974 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q->name );
975
976 if (q->domain < npc) {
977 strcat(q->name, ".");
978 strcat(q->name, searchpath[q->domain].domain);
979 debugs(78, 3, "idnsGrokReply: searchpath used for " << q->name);
980 q->domain++;
981 } else {
982 q->attempt++;
983 }
984
985 idnsDropMessage(message, q);
986
987 q->start_t = current_time;
988 q->id = idnsQueryID();
989 rfc1035SetQueryID(q->buf, q->id);
990#if USE_IPV6
991 if(q->query.qtype == RFC1035_TYPE_AAAA) {
992 debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q->name);
993 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
994 }
995 else
996#endif
997 {
998 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
999 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
1000 }
1001 idnsCacheQuery(q);
1002 idnsSendQuery(q);
1003 return;
1004 }
1005 }
1006
1007#if USE_IPV6
1008 if(q->need_A && (Config.onoff.dns_require_A == 1 || n <= 0 ) )
1009 {
1010 /* ERROR or NO AAAA exist. Failover to A records. */
1011 /* Apparently its also a good idea to lookup and store the A records
1012 * just in case the AAAA are not available when we need them.
1013 * This could occur due to number of network failings beyond our control
1014 * thus the || above allowing the user to request always both.
1015 */
1016
1017 if(n == 0)
1018 debugs(78, 3, "idnsGrokReply: " << q->name << " has no AAAA records. Looking up A record instead.");
1019 else if(q->need_A && n <= 0)
1020 debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query failed. Trying A now instead.");
1021 else // admin requested this.
1022 debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query done. Configured to retrieve A now also.");
1023
1024 // move the initial message results into the failover query for merging later.
1025 if(n > 0) {
1026 q->initial_AAAA.count = message->ancount;
1027 q->initial_AAAA.answers = message->answer;
1028 message->answer = NULL;
1029 }
1030
1031 // remove the hashed query info
1032 idnsDropMessage(message, q);
1033
1034 q->start_t = current_time;
1035 q->id = idnsQueryID();
1036 rfc1035SetQueryID(q->buf, q->id);
1037 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
1038 q->need_A = false;
1039 idnsCacheQuery(q);
1040 idnsSendQuery(q);
1041 return;
1042 }
1043#endif
1044
1045 /** If there are two result sets from preceeding AAAA and A lookups merge them with a preference for AAAA */
1046 if(q->initial_AAAA.count > 0 && n > 0) {
1047 /* two sets of RR need merging */
1048 rfc1035_rr *result = (rfc1035_rr*) xmalloc( sizeof(rfc1035_rr)*(n + q->initial_AAAA.count) );
1049 rfc1035_rr *tmp = result;
1050
1051 debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
1052
1053 memcpy(tmp, q->initial_AAAA.answers, (sizeof(rfc1035_rr)*(q->initial_AAAA.count)) );
1054 tmp += q->initial_AAAA.count;
1055 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1056 safe_free(q->initial_AAAA.answers);
1057
1058 memcpy( tmp, message->answer, (sizeof(rfc1035_rr)*n) );
1059 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1060 safe_free(message->answer);
1061
1062 message->answer = result;
1063 n += q->initial_AAAA.count;
1064 q->initial_AAAA.count=0;
1065 }
1066 else if(q->initial_AAAA.count > 0 && n <= 0) {
1067 /* initial of dual queries was the only result set. */
1068 debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
1069 rfc1035RRDestroy(&(message->answer), n);
1070 message->answer = q->initial_AAAA.answers;
1071 n = q->initial_AAAA.count;
1072 }
1073 /* else initial results were empty. just use the final set as authoritative */
1074
1075 debugs(78, 6, HERE << "Sending " << n << " DNS results to caller.");
1076 idnsCallback(q, message->answer, n, q->error);
1077 rfc1035MessageDestroy(&message);
1078 cbdataFree(q);
1079}
1080
1081static void
1082idnsRead(int fd, void *data)
1083{
1084 int *N = &incoming_sockets_accepted;
1085 int len;
1086 int max = INCOMING_DNS_MAX;
1087 static char rbuf[SQUID_UDP_SO_RCVBUF];
1088 int ns;
1089 IPAddress from;
1090
1091 debugs(78, 3, "idnsRead: starting with FD " << fd);
1092
1093 /* BUG (UNRESOLVED)
1094 * two code lines after returning from comm_udprecvfrom()
1095 * something overwrites the memory behind the from parameter.
1096 * NO matter where in the stack declaration list above it is placed
1097 * The cause of this is still unknown, however copying the data appears
1098 * to allow it to be passed further without this erasure.
1099 */
1100 IPAddress bugbypass;
1101
1102 while (max--) {
1103 len = comm_udp_recvfrom(fd, rbuf, SQUID_UDP_SO_RCVBUF, 0, bugbypass);
1104
1105 from = bugbypass; // BUG BYPASS. see notes above.
1106
1107 if (len == 0)
1108 break;
1109
1110 if (len < 0) {
1111 if (ignoreErrno(errno))
1112 break;
1113
1114#ifdef _SQUID_LINUX_
1115 /* Some Linux systems seem to set the FD for reading and then
1116 * return ECONNREFUSED when sendto() fails and generates an ICMP
1117 * port unreachable message. */
1118 /* or maybe an EHOSTUNREACH "No route to host" message */
1119 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
1120#endif
1121
1122 debugs(50, 1, "idnsRead: FD " << fd << " recvfrom: " << xstrerror());
1123
1124 break;
1125 }
1126
1127 fd_bytes(DnsSocket, len, FD_READ);
1128 assert(N);
1129 (*N)++;
1130
1131 debugs(78, 3, "idnsRead: FD " << fd << ": received " << len << " bytes from " << from);
1132
1133 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1134 ns = idnsFromKnownNameserver(from);
1135
1136 if (ns >= 0) {
1137 nameservers[ns].nreplies++;
1138 } else if (Config.onoff.ignore_unknown_nameservers) {
1139 static time_t last_warning = 0;
1140
1141 if (squid_curtime - last_warning > 60) {
1142 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from);
1143 last_warning = squid_curtime;
1144 }
1145 else {
1146 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from << " (retrying..." << (squid_curtime-last_warning) << "<=60)" );
1147 }
1148
1149 continue;
1150 }
1151
1152 idnsGrokReply(rbuf, len);
1153 }
1154
1155 if (lru_list.head)
1156 commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0);
1157}
1158
1159static void
1160idnsCheckQueue(void *unused)
1161{
1162 dlink_node *n;
1163 dlink_node *p = NULL;
1164 idns_query *q;
1165 event_queued = 0;
1166
1167 for (n = lru_list.tail; n; n = p) {
1168 if (0 == nns)
1169 /* name servers went away; reconfiguring or shutting down */
1170 break;
1171
1172 q = (idns_query *)n->data;
1173
1174 if (tvSubDsec(q->sent_t, current_time) < Config.Timeout.idns_retransmit * (1 << (q->nsends - 1) % nns))
1175 break;
1176
1177 debugs(78, 3, "idnsCheckQueue: ID 0x" << std::hex << std::setfill('0') << std::setw(4) << q->id << "timeout" );
1178
1179 p = n->prev;
1180
1181 dlinkDelete(&q->lru, &lru_list);
1182
1183 if (tvSubDsec(q->start_t, current_time) < Config.Timeout.idns_query) {
1184 idnsSendQuery(q);
1185 } else {
1186 debugs(78, 2, "idnsCheckQueue: ID " << std::hex << q->id <<
1187 ": giving up after " << std::dec << q->nsends << " tries and " <<
1188 std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
1189
1190 if (q->rcode != 0)
1191 idnsCallback(q, NULL, -q->rcode, q->error);
1192 else
1193 idnsCallback(q, NULL, -16, "Timeout");
1194
1195 cbdataFree(q);
1196 }
1197 }
1198
1199 idnsTickleQueue();
1200}
1201
1202static void
1203idnsReadVC(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1204{
1205 nsvc * vc = (nsvc *)data;
1206
1207 if (flag == COMM_ERR_CLOSING)
1208 return;
1209
1210 if (flag != COMM_OK || len <= 0) {
1211 comm_close(fd);
1212 return;
1213 }
1214
1215 vc->msg->size += len; // XXX should not access -> size directly
1216
1217 if (vc->msg->contentSize() < vc->msglen) {
1218 comm_read(fd, buf + len, vc->msglen - vc->msg->contentSize(), idnsReadVC, vc);
1219 return;
1220 }
1221
1222 debugs(78, 3, "idnsReadVC: FD " << fd << ": received " <<
1223 (int) vc->msg->contentSize() << " bytes via tcp from " <<
1224 nameservers[vc->ns].S << ".");
1225
1226 idnsGrokReply(vc->msg->buf, vc->msg->contentSize());
1227 vc->msg->clean();
1228 comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
1229}
1230
1231static void
1232idnsReadVCHeader(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1233{
1234 nsvc * vc = (nsvc *)data;
1235
1236 if (flag == COMM_ERR_CLOSING)
1237 return;
1238
1239 if (flag != COMM_OK || len <= 0) {
1240 comm_close(fd);
1241 return;
1242 }
1243
1244 vc->read_msglen += len;
1245
1246 assert(vc->read_msglen <= 2);
1247
1248 if (vc->read_msglen < 2) {
1249 comm_read(fd, buf + len, 2 - vc->read_msglen, idnsReadVCHeader, vc);
1250 return;
1251 }
1252
1253 vc->read_msglen = 0;
1254
1255 vc->msglen = ntohs(vc->msglen);
1256
1257 vc->msg->init(vc->msglen, vc->msglen);
1258 comm_read(fd, vc->msg->buf, vc->msglen, idnsReadVC, vc);
1259}
1260
1261/*
1262 * rcode < 0 indicates an error, rocde >= 0 indicates success
1263 */
1264static void
1265idnsRcodeCount(int rcode, int attempt)
1266{
1267 if (rcode > 0)
1268 rcode = 0;
1269 else if (rcode < 0)
1270 rcode = -rcode;
1271
1272 if (rcode < MAX_RCODE)
1273 if (attempt < MAX_ATTEMPT)
1274 RcodeMatrix[rcode][attempt]++;
1275}
1276
1277/* ====================================================================== */
1278
1279void
1280idnsInit(void)
1281{
1282 static int init = 0;
1283
1284 CBDATA_INIT_TYPE(nsvc);
1285 CBDATA_INIT_TYPE(idns_query);
1286
1287 if (DnsSocket < 0) {
1288 int port;
1289
1290 IPAddress addr;
1291
1292 if (!Config.Addrs.udp_outgoing.IsNoAddr())
1293 addr = Config.Addrs.udp_outgoing;
1294 else
1295 addr = Config.Addrs.udp_incoming;
1296
1297 DnsSocket = comm_open(SOCK_DGRAM,
1298 IPPROTO_UDP,
1299 addr,
1300 COMM_NONBLOCKING,
1301 "DNS Socket");
1302
1303 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addr);
1304
1305 if (DnsSocket < 0)
1306 fatal("Could not create a DNS socket");
1307
1308 /* Ouch... we can't call functions using debug from a debug
1309 * statement. Doing so messes up the internal Debug::level
1310 */
1311 port = comm_local_port(DnsSocket);
1312
1313 debugs(78, 1, "DNS Socket created at " << addr << ", FD " << DnsSocket);
1314 }
1315
1316 assert(0 == nns);
1317 idnsParseNameservers();
1318#ifndef _SQUID_MSWIN_
1319
1320 if (0 == nns)
1321 idnsParseResolvConf();
1322
1323#endif
1324#ifdef _SQUID_WIN32_
1325
1326 if (0 == nns)
1327 idnsParseWIN32Registry();
1328
1329#endif
1330
1331 if (0 == nns) {
1332 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
1333#ifdef _SQUID_WIN32_
1334
1335 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
1336#else
1337
1338 debugs(78, 1, "Please check your /etc/resolv.conf file");
1339#endif
1340
1341 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1342 idnsAddNameserver("127.0.0.1");
1343 }
1344
1345 if (!init) {
1346 memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
1347 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
1348 idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
1349 init++;
1350 }
1351}
1352
1353void
1354idnsRegisterWithCacheManager(CacheManager & manager)
1355{
1356 manager.registerAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
1357}
1358
1359void
1360idnsShutdown(void)
1361{
1362 if (DnsSocket < 0)
1363 return;
1364
1365 comm_close(DnsSocket);
1366
1367 DnsSocket = -1;
1368
1369 for (int i = 0; i < nns; i++) {
1370 if (nsvc *vc = nameservers[i].vc) {
1371 if (vc->fd >= 0)
1372 comm_close(vc->fd);
1373 }
1374 }
1375
1376 idnsFreeNameservers();
1377
1378 idnsFreeSearchpath();
1379}
1380
1381static int
1382idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1383{
1384 idns_query *q;
1385
1386 idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
1387
1388 if (!old)
1389 return 0;
1390
1391 q = cbdataAlloc(idns_query);
1392
1393 q->callback = callback;
1394
1395 q->callback_data = cbdataReference(data);
1396
1397 q->queue = old->queue;
1398
1399 old->queue = q;
1400
1401 return 1;
1402}
1403
1404static void
1405idnsCacheQuery(idns_query *q)
1406{
1407 q->hash.key = q->query.name;
1408 hash_join(idns_lookup_hash, &q->hash);
1409}
1410
1411void
1412idnsALookup(const char *name, IDNSCB * callback, void *data)
1413{
1414 unsigned int i;
1415 int nd = 0;
1416 idns_query *q;
1417
1418 if (idnsCachedLookup(name, callback, data))
1419 return;
1420
1421 q = cbdataAlloc(idns_query);
1422
1423 q->id = idnsQueryID();
1424
1425 for (i = 0; i < strlen(name); i++)
1426 if (name[i] == '.')
1427 nd++;
1428
1429 if (Config.onoff.res_defnames && npc > 0 && name[strlen(name)-1] != '.') {
1430 q->do_searchpath = 1;
1431 } else {
1432 q->do_searchpath = 0;
1433 }
1434
1435 strcpy(q->orig, name);
1436 strcpy(q->name, q->orig);
1437
1438 if (q->do_searchpath && nd < ndots) {
1439 q->domain = 0;
1440 strcat(q->name, ".");
1441 strcat(q->name, searchpath[q->domain].domain);
1442 debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
1443 }
1444
1445#if USE_IPV6
1446 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
1447 q->need_A = true;
1448#else
1449 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
1450 q->need_A = false;
1451#endif
1452
1453 if (q->sz < 0) {
1454 /* problem with query data -- query not sent */
1455 callback(data, NULL, 0, "Internal error");
1456 cbdataFree(q);
1457 return;
1458 }
1459
1460 debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
1461 ", id = 0x" << std::hex << q->id);
1462
1463 q->callback = callback;
1464
1465 q->callback_data = cbdataReference(data);
1466
1467 q->start_t = current_time;
1468
1469 idnsCacheQuery(q);
1470
1471 idnsSendQuery(q);
1472}
1473
1474void
1475idnsPTRLookup(const IPAddress &addr, IDNSCB * callback, void *data)
1476{
1477 idns_query *q;
1478
1479 char ip[MAX_IPSTRLEN];
1480
1481 addr.NtoA(ip,MAX_IPSTRLEN);
1482
1483 q = cbdataAlloc(idns_query);
1484
1485 q->id = idnsQueryID();
1486
1487#if USE_IPV6
1488 if( addr.IsIPv6() ) {
1489 struct in6_addr addr6;
1490 addr.GetInAddr(addr6);
1491 q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), q->id, &q->query);
1492 }
1493 else
1494#endif
1495 {
1496 struct in_addr addr4;
1497 addr.GetInAddr(addr4);
1498 q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), q->id, &q->query);
1499 }
1500
1501 /* PTR does not do inbound A/AAAA */
1502 q->need_A = false;
1503
1504 if (q->sz < 0)
1505 {
1506 /* problem with query data -- query not sent */
1507 callback(data, NULL, 0, "Internal error");
1508 cbdataFree(q);
1509 return;
1510 }
1511
1512 if (idnsCachedLookup(q->query.name, callback, data)) {
1513 cbdataFree(q);
1514 return;
1515 }
1516
1517 debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
1518 ", id = 0x" << std::hex << q->id);
1519
1520 q->callback = callback;
1521
1522 q->callback_data = cbdataReference(data);
1523
1524 q->start_t = current_time;
1525
1526 idnsCacheQuery(q);
1527
1528 idnsSendQuery(q);
1529}
1530
1531#ifdef SQUID_SNMP
1532/*
1533 * The function to return the DNS via SNMP
1534 */
1535variable_list *
1536snmp_netIdnsFn(variable_list * Var, snint * ErrP)
1537{
1538 int i, n = 0;
1539 variable_list *Answer = NULL;
1540 debugs(49, 5, "snmp_netDnsFn: Processing request: ");
1541 snmpDebugOid(5, Var->name, Var->name_length);
1542 *ErrP = SNMP_ERR_NOERROR;
1543
1544 switch (Var->name[LEN_SQ_NET + 1]) {
1545
1546 case DNS_REQ:
1547
1548 for (i = 0; i < nns; i++)
1549 n += nameservers[i].nqueries;
1550
1551 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1552 n,
1553 SMI_COUNTER32);
1554
1555 break;
1556
1557 case DNS_REP:
1558 for (i = 0; i < nns; i++)
1559 n += nameservers[i].nreplies;
1560
1561 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1562 n,
1563 SMI_COUNTER32);
1564
1565 break;
1566
1567 case DNS_SERVERS:
1568 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1569 nns,
1570 SMI_COUNTER32);
1571
1572 break;
1573
1574 default:
1575 *ErrP = SNMP_ERR_NOSUCHNAME;
1576
1577 break;
1578 }
1579
1580 return Answer;
1581}
1582
1583#endif /*SQUID_SNMP */
1584#endif /* USE_DNSSERVERS */