4 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
5 * AUTHOR: Duane Wessels
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37 #include "comm/Loops.h"
38 #include "comm/Write.h"
40 #include "SquidTime.h"
45 #include "mgr/Registration.h"
48 #include "base/InstanceId.h"
50 #if HAVE_ARPA_NAMESER_H
51 #include <arpa/nameser.h>
57 /* MS Visual Studio Projects are monolithic, so we need the following
58 #ifndef to exclude the internal DNS code from compile process when
59 using external DNS process.
63 #include "squid_windows.h"
64 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
65 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
66 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
69 #define _PATH_RESCONF "/etc/resolv.conf"
71 #ifndef NS_DEFAULTPORT
72 #define NS_DEFAULTPORT 53
76 #define NS_MAXDNAME 1025
83 /* The buffer size required to store the maximum allowed search path */
85 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
88 #define IDNS_MAX_TRIES 20
91 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
92 // NP: see http://www.iana.org/assignments/dns-parameters
93 static const char *Rcodes
[] = {
96 "Packet Format Error",
98 "Non-Existent Domain",
102 "Name Exists when it should not",
103 "RR Set Exists when it should not",
104 "RR Set that should exist does not",
105 "Server Not Authoritative for zone",
106 "Name not contained in zone",
110 "Bad OPT Version or TSIG Signature Failure"
113 typedef struct _idns_query idns_query
;
115 typedef struct _ns ns
;
117 typedef struct _sp sp
;
119 typedef struct _nsvc nsvc
;
124 char buf
[RESOLV_BUFSZ
];
125 char name
[NS_MAXDNAME
+ 1];
126 char orig
[NS_MAXDNAME
+ 1];
128 unsigned short msg_id
; /// random query ID sent to server; changes with every query sent
129 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
134 struct timeval start_t
;
135 struct timeval sent_t
;
136 struct timeval queue_t
;
143 unsigned short domain
;
144 unsigned short do_searchpath
;
151 InstanceIdDefinitions(idns_query
, "dns");
156 unsigned short msglen
;
167 #if WHEN_EDNS_RESPONSES_ARE_PARSED
174 char domain
[NS_MAXDNAME
];
179 CBDATA_TYPE(idns_query
);
181 static ns
*nameservers
= NULL
;
182 static sp
*searchpath
= NULL
;
184 static int nns_alloc
= 0;
186 static int npc_alloc
= 0;
187 static int ndots
= 1;
188 static dlink_list lru_list
;
189 static int event_queued
= 0;
190 static hash_table
*idns_lookup_hash
= NULL
;
196 * EDNS as specified may be sent as an additional record for any request.
197 * early testing has revealed that it works on common devices, but cannot
198 * be reliably used on any A or PTR requet done for IPv4 addresses.
200 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
203 * Squid is optimized to generate one packet and re-send it to all NS
204 * due to this we cannot customize the EDNS size per NS.
206 * As such we take the configuration option value as fixed.
209 * This may not be worth doing, but if/when additional-records are parsed
210 * we will be able to recover the OPT value specific to any one NS and
211 * cache it. Effectively automating the tuning of EDNS advertised to the
212 * size our active NS are capable.
213 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
214 * Responses from the configured NS may cause this to be raised or turned off.
216 #if WHEN_EDNS_RESPONSES_ARE_PARSED
217 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
220 static OBJH idnsStats
;
221 static void idnsAddNameserver(const char *buf
);
222 static void idnsAddPathComponent(const char *buf
);
223 static void idnsFreeNameservers(void);
224 static void idnsFreeSearchpath(void);
225 static void idnsParseNameservers(void);
226 #ifndef _SQUID_MSWIN_
227 static void idnsParseResolvConf(void);
230 static void idnsParseWIN32Registry(void);
231 static void idnsParseWIN32SearchList(const char *);
233 static void idnsCacheQuery(idns_query
* q
);
234 static void idnsSendQuery(idns_query
* q
);
235 static IOCB idnsReadVCHeader
;
236 static void idnsDoSendQueryVC(nsvc
*vc
);
238 static int idnsFromKnownNameserver(Ip::Address
const &from
);
239 static idns_query
*idnsFindQuery(unsigned short id
);
240 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
242 static EVH idnsCheckQueue
;
243 static void idnsTickleQueue(void);
244 static void idnsRcodeCount(int, int);
245 static unsigned short idnsQueryID(void);
248 idnsAddNameserver(const char *buf
)
253 debugs(78, 0, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
258 debugs(78, 0, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
260 debugs(78, 0, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
263 if (!Ip::EnableIpv6
&& !A
.SetIPv4()) {
264 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
268 if (nns
== nns_alloc
) {
269 int oldalloc
= nns_alloc
;
270 ns
*oldptr
= nameservers
;
277 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
279 if (oldptr
&& oldalloc
)
280 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
286 assert(nns
< nns_alloc
);
287 A
.SetPort(NS_DEFAULTPORT
);
288 nameservers
[nns
].S
= A
;
289 #if WHEN_EDNS_RESPONSES_ARE_PARSED
290 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
291 // TODO generate a test packet to probe this NS from EDNS size and ability.
293 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
298 idnsAddPathComponent(const char *buf
)
300 if (npc
== npc_alloc
) {
301 int oldalloc
= npc_alloc
;
302 sp
*oldptr
= searchpath
;
309 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
311 if (oldptr
&& oldalloc
)
312 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
318 assert(npc
< npc_alloc
);
319 strcpy(searchpath
[npc
].domain
, buf
);
320 Tolower(searchpath
[npc
].domain
);
321 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
327 idnsFreeNameservers(void)
329 safe_free(nameservers
);
334 idnsFreeSearchpath(void)
336 safe_free(searchpath
);
343 idnsParseNameservers(void)
347 for (w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
348 debugs(78, 1, "Adding nameserver " << w
->key
<< " from squid.conf");
349 idnsAddNameserver(w
->key
);
353 #ifndef _SQUID_MSWIN_
355 idnsParseResolvConf(void)
358 char buf
[RESOLV_BUFSZ
];
360 fp
= fopen(_PATH_RESCONF
, "r");
363 debugs(78, 1, "" << _PATH_RESCONF
<< ": " << xstrerror());
368 setmode(fileno(fp
), O_TEXT
);
371 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
372 t
= strtok(buf
, w_space
);
376 } else if (strcasecmp(t
, "nameserver") == 0) {
377 t
= strtok(NULL
, w_space
);
382 debugs(78, 1, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
384 idnsAddNameserver(t
);
385 } else if (strcasecmp(t
, "domain") == 0) {
386 idnsFreeSearchpath();
387 t
= strtok(NULL
, w_space
);
392 debugs(78, 1, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
394 idnsAddPathComponent(t
);
395 } else if (strcasecmp(t
, "search") == 0) {
396 idnsFreeSearchpath();
398 t
= strtok(NULL
, w_space
);
403 debugs(78, 1, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
405 idnsAddPathComponent(t
);
407 } else if (strcasecmp(t
, "options") == 0) {
409 t
= strtok(NULL
, w_space
);
414 if (strncmp(t
, "ndots:", 6) == 0) {
420 debugs(78, 1, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
425 if (npc
== 0 && (t
= getMyHostname())) {
428 idnsAddPathComponent(t
+1);
438 idnsParseWIN32SearchList(const char * Separator
)
444 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
448 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
450 if (Result
== ERROR_SUCCESS
&& Size
) {
451 t
= (char *) xmalloc(Size
);
452 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
453 debugs(78, 1, "Adding domain " << t
<< " from Registry");
454 idnsAddPathComponent(t
);
457 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
459 if (Result
== ERROR_SUCCESS
&& Size
) {
460 t
= (char *) xmalloc(Size
);
461 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
462 token
= strtok(t
, Separator
);
465 idnsAddPathComponent(token
);
466 debugs(78, 1, "Adding domain " << token
<< " from Registry");
467 token
= strtok(NULL
, Separator
);
474 if (npc
== 0 && (t
= (char *) getMyHostname())) {
477 idnsAddPathComponent(t
+ 1);
482 idnsParseWIN32Registry(void)
486 HKEY hndKey
, hndKey2
;
488 switch (WIN32_OS_version
) {
491 /* get nameservers from the Windows NT registry */
493 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
497 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
499 if (Result
== ERROR_SUCCESS
&& Size
) {
500 t
= (char *) xmalloc(Size
);
501 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
502 token
= strtok(t
, ", ");
505 idnsAddNameserver(token
);
506 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
507 token
= strtok(NULL
, ",");
512 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
514 if (Result
== ERROR_SUCCESS
&& Size
) {
515 t
= (char *) xmalloc(Size
);
516 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
517 token
= strtok(t
, ", ");
520 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
521 idnsAddNameserver(token
);
522 token
= strtok(NULL
, ", ");
530 idnsParseWIN32SearchList(" ");
543 /* get nameservers from the Windows 2000 registry */
544 /* search all interfaces for DNS server addresses */
546 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
548 DWORD MaxSubkeyLen
, InterfacesCount
;
550 FILETIME ftLastWriteTime
;
552 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
553 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
554 for (i
= 0; i
< (int) InterfacesCount
; i
++) {
557 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
559 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
560 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
561 strcat(newkeyname
, "\\");
562 strcat(newkeyname
, keyname
);
563 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
567 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
568 if (Result
== ERROR_SUCCESS
&& Size
) {
569 t
= (char *) xmalloc(Size
);
570 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
571 token
= strtok(t
, ", ");
573 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
574 idnsAddNameserver(token
);
575 token
= strtok(NULL
, ", ");
580 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
581 if (Result
== ERROR_SUCCESS
&& Size
) {
582 t
= (char *) xmalloc(Size
);
583 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
584 token
= strtok(t
, ", ");
586 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
587 idnsAddNameserver(token
);
588 token
= strtok(NULL
, ", ");
594 RegCloseKey(hndKey2
);
607 idnsParseWIN32SearchList(", ");
616 /* get nameservers from the Windows 9X registry */
618 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
622 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
624 if (Result
== ERROR_SUCCESS
&& Size
) {
625 t
= (char *) xmalloc(Size
);
626 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
627 token
= strtok(t
, ", ");
630 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
631 idnsAddNameserver(token
);
632 token
= strtok(NULL
, ", ");
643 debugs(78, 1, "Failed to read nameserver from Registry: Unknown System Type.");
651 idnsStats(StoreEntry
* sentry
)
657 char buf
[MAX_IPSTRLEN
];
658 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
659 storeAppendPrintf(sentry
, "\nThe Queue:\n");
660 storeAppendPrintf(sentry
, " DELAY SINCE\n");
661 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND\n");
662 storeAppendPrintf(sentry
, "------ ---- ----- ---------- ---------\n");
664 for (n
= lru_list
.head
; n
; n
= n
->next
) {
665 q
= (idns_query
*)n
->data
;
666 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f\n",
667 (int) q
->msg_id
, (int) q
->sz
, q
->nsends
,
668 tvSubDsec(q
->start_t
, current_time
),
669 tvSubDsec(q
->sent_t
, current_time
));
672 if (Config
.dns
.packet_max
> 0)
673 storeAppendPrintf(sentry
, "DNS jumbo-grams: %Zd Bytes\n", Config
.dns
.packet_max
);
675 storeAppendPrintf(sentry
, "DNS jumbo-grams: not working\n");
677 storeAppendPrintf(sentry
, "\nNameservers:\n");
678 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES\n");
679 storeAppendPrintf(sentry
, "---------------------------------------------- --------- ---------\n");
681 for (i
= 0; i
< nns
; i
++) {
682 storeAppendPrintf(sentry
, "%-45s %9d %9d\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
683 nameservers
[i
].S
.NtoA(buf
,MAX_IPSTRLEN
),
684 nameservers
[i
].nqueries
,
685 nameservers
[i
].nreplies
);
688 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
689 storeAppendPrintf(sentry
, "RCODE");
691 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
692 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
694 storeAppendPrintf(sentry
, " PROBLEM\n");
696 for (j
= 0; j
< MAX_RCODE
; j
++) {
697 if (j
> 10 && j
< 16)
698 continue; // unassigned by IANA.
700 storeAppendPrintf(sentry
, "%5d", j
);
702 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
703 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
705 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
709 storeAppendPrintf(sentry
, "\nSearch list:\n");
711 for (i
=0; i
< npc
; i
++)
712 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
714 storeAppendPrintf(sentry
, "\n");
719 idnsTickleQueue(void)
724 if (NULL
== lru_list
.tail
)
727 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, 1.0, 1);
733 idnsSentQueryVC(int fd
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
735 nsvc
* vc
= (nsvc
*)data
;
737 if (flag
== COMM_ERR_CLOSING
)
740 if (fd_table
[fd
].closing())
743 if (flag
!= COMM_OK
|| size
<= 0) {
749 idnsDoSendQueryVC(vc
);
753 idnsDoSendQueryVC(nsvc
*vc
)
758 if (vc
->queue
->contentSize() == 0)
761 MemBuf
*mb
= vc
->queue
;
763 vc
->queue
= new MemBuf
;
767 commSetTimeout(vc
->fd
, Config
.Timeout
.idns_query
, NULL
, NULL
);
769 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
770 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
772 Comm::Write(vc
->fd
, mb
, call
);
778 idnsInitVCConnected(int fd
, const DnsLookupDetails
&details
, comm_err_t status
, int xerrno
, void *data
)
780 nsvc
* vc
= (nsvc
*)data
;
782 if (status
!= COMM_OK
) {
783 char buf
[MAX_IPSTRLEN
] = "";
785 nameservers
[vc
->ns
].S
.NtoA(buf
,MAX_IPSTRLEN
);
786 debugs(78, 1, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP: " << details
);
791 comm_read(fd
, (char *)&vc
->msglen
, 2 , idnsReadVCHeader
, vc
);
793 idnsDoSendQueryVC(vc
);
797 idnsVCClosed(int fd
, void *data
)
799 nsvc
* vc
= (nsvc
*)data
;
802 if (vc
->ns
< nns
) // XXX: idnsShutdown may have freed nameservers[]
803 nameservers
[vc
->ns
].vc
= NULL
;
810 char buf
[MAX_IPSTRLEN
];
812 nsvc
*vc
= cbdataAlloc(nsvc
);
814 nameservers
[ns
].vc
= vc
;
819 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
820 addr
= Config
.Addrs
.udp_outgoing
;
822 addr
= Config
.Addrs
.udp_incoming
;
824 if (nameservers
[ns
].S
.IsIPv4() && !addr
.SetIPv4()) {
825 debugs(31, DBG_CRITICAL
, "ERROR: Cannot contact DNS nameserver " << nameservers
[ns
].S
<< " from " << addr
);
830 vc
->queue
= new MemBuf
;
832 vc
->msg
= new MemBuf
;
834 vc
->fd
= comm_open(SOCK_STREAM
,
841 fatal("Could not create a DNS socket");
843 comm_add_close_handler(vc
->fd
, idnsVCClosed
, vc
);
847 commConnectStart(vc
->fd
, nameservers
[ns
].S
.NtoA(buf
,MAX_IPSTRLEN
), nameservers
[ns
].S
.GetPort(), idnsInitVCConnected
, vc
);
851 idnsSendQueryVC(idns_query
* q
, int ns
)
854 if (nameservers
[ns
].vc
== NULL
)
857 nsvc
*vc
= nameservers
[ns
].vc
;
860 char buf
[MAX_IPSTRLEN
];
861 debugs(78, 1, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[ns
].S
.NtoA(buf
,MAX_IPSTRLEN
) << "!");
868 short head
= htons(q
->sz
);
870 vc
->queue
->append((char *)&head
, 2);
872 vc
->queue
->append(q
->buf
, q
->sz
);
874 idnsDoSendQueryVC(vc
);
878 idnsSendQuery(idns_query
* q
)
880 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
881 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
886 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
890 assert(q
->lru
.next
== NULL
);
892 assert(q
->lru
.prev
== NULL
);
897 q
->start_t
= current_time
;
898 q
->msg_id
= idnsQueryID();
899 rfc1035SetQueryID(q
->buf
, q
->msg_id
);
902 ns
= q
->nsends
% nns
;
905 idnsSendQueryVC(q
, ns
);
908 if (DnsSocketB
>= 0 && nameservers
[ns
].S
.IsIPv6())
909 y
= comm_udp_sendto(DnsSocketB
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
911 x
= comm_udp_sendto(DnsSocketA
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
916 q
->queue_t
= q
->sent_t
= current_time
;
918 if (y
< 0 && nameservers
[ns
].S
.IsIPv6())
919 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
920 if (x
< 0 && nameservers
[ns
].S
.IsIPv4())
921 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
923 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
926 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
929 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
932 nameservers
[ns
].nqueries
++;
933 q
->queue_t
= current_time
;
934 dlinkAdd(q
, &q
->lru
, &lru_list
);
939 idnsFromKnownNameserver(Ip::Address
const &from
)
943 for (i
= 0; i
< nns
; i
++) {
944 if (nameservers
[i
].S
!= from
)
947 if (nameservers
[i
].S
.GetPort() != from
.GetPort())
957 idnsFindQuery(unsigned short id
)
962 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
963 q
= (idns_query
*)n
->data
;
972 static unsigned short
975 unsigned short id
= squid_random() & 0xFFFF;
976 unsigned short first_id
= id
;
978 while (idnsFindQuery(id
)) {
981 if (id
== first_id
) {
982 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
991 idnsCallback(idns_query
*q
, rfc1035_rr
*answers
, int n
, const char *error
)
996 callback
= q
->callback
;
999 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1000 callback(cbdata
, answers
, n
, error
);
1003 idns_query
*q2
= q
->queue
;
1004 q
->queue
= q2
->queue
;
1005 callback
= q2
->callback
;
1006 q2
->callback
= NULL
;
1008 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1009 callback(cbdata
, answers
, n
, error
);
1015 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1021 idnsDropMessage(rfc1035_message
*message
, idns_query
*q
)
1023 rfc1035MessageDestroy(&message
);
1025 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1031 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1034 rfc1035_message
*message
= NULL
;
1037 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1039 if (message
== NULL
) {
1040 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
1044 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1046 q
= idnsFindQuery(message
->id
);
1049 debugs(78, 3, "idnsGrokReply: Late response");
1050 rfc1035MessageDestroy(&message
);
1054 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1055 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1056 rfc1035MessageDestroy(&message
);
1060 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1061 // TODO: actually gr the message right here.
1062 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1063 // this is overall better than force-feeding A response with AAAA an section later anyway.
1064 // AND allows us to merge AN+AR sections from both responses (one day)
1066 if (q
->edns_seen
>= 0) {
1067 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1068 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1069 // the altered NS was limiting the whole group.
1070 max_shared_edns
= q
->edns_seen
;
1071 // may be limited by one of the others still
1072 for (int i
= 0; i
< nns
; i
++)
1073 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1075 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1076 // maybe reduce the global limit downwards to accomodate this NS
1077 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1079 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1080 max_shared_edns
= -1;
1085 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1086 dlinkDelete(&q
->lru
, &lru_list
);
1087 rfc1035MessageDestroy(&message
);
1094 // Strange: A TCP DNS response with the truncation bit (TC) set.
1095 // Return an error and cleanup; no point in trying TCP again.
1096 debugs(78, 3, HERE
<< "TCP DNS response");
1097 idnsCallback(q
, NULL
, 0, "Truncated TCP DNS response");
1104 dlinkDelete(&q
->lru
, &lru_list
);
1105 idnsRcodeCount(n
, q
->attempt
);
1109 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1111 if (q
->rcode
== 2 && ++q
->attempt
< MAX_ATTEMPT
) {
1113 * RCODE 2 is "Server failure - The name server was
1114 * unable to process this query due to a problem with
1117 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1118 rfc1035MessageDestroy(&message
);
1123 if (q
->rcode
== 3 && q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1124 assert(NULL
== message
->answer
);
1125 strcpy(q
->name
, q
->orig
);
1127 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1129 if (q
->domain
< npc
) {
1130 strcat(q
->name
, ".");
1131 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1132 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1138 idnsDropMessage(message
, q
);
1140 if (Ip::EnableIpv6
&& q
->query
.qtype
== RFC1035_TYPE_AAAA
) {
1141 debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q
->name
);
1142 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1144 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1145 // see EDNS notes at top of file why this sends 0
1146 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1150 /* problem with query data -- query not sent */
1151 idnsCallback(static_cast<idns_query
*>(q
->callback_data
), NULL
, 0, "Internal error");
1162 if (q
->need_A
&& (Config
.onoff
.dns_require_A
== 1 || n
<= 0 ) ) {
1163 /* ERROR or NO AAAA exist. Failover to A records. */
1164 /* Apparently its also a good idea to lookup and store the A records
1165 * just in case the AAAA are not available when we need them.
1166 * This could occur due to number of network failings beyond our control
1167 * thus the || above allowing the user to request always both.
1171 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " has no AAAA records. Looking up A record instead.");
1172 else if (q
->need_A
&& n
<= 0)
1173 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query failed. Trying A now instead.");
1174 else // admin requested this.
1175 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query done. Configured to retrieve A now also.");
1177 // move the initial message results into the failover query for merging later.
1179 q
->initial_AAAA
.count
= message
->ancount
;
1180 q
->initial_AAAA
.answers
= message
->answer
;
1181 message
->answer
= NULL
;
1184 // remove the hashed query info
1185 idnsDropMessage(message
, q
);
1187 // reset the query as an A query
1189 // see EDNS notes at top of file why this sends 0
1190 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1194 /* problem with query data -- query not sent */
1195 idnsCallback(static_cast<idns_query
*>(q
->callback_data
), NULL
, 0, "Internal error");
1205 /** If there are two result sets from preceeding AAAA and A lookups merge them with a preference for AAAA */
1206 if (q
->initial_AAAA
.count
> 0 && n
> 0) {
1207 /* two sets of RR need merging */
1208 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q
->initial_AAAA
.count
) );
1209 rfc1035_rr
*tmp
= result
;
1211 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " AAAA has " << q
->initial_AAAA
.count
<< " RR, A has " << n
<< " RR");
1213 memcpy(tmp
, q
->initial_AAAA
.answers
, (sizeof(rfc1035_rr
)*(q
->initial_AAAA
.count
)) );
1214 tmp
+= q
->initial_AAAA
.count
;
1215 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1216 safe_free(q
->initial_AAAA
.answers
);
1218 memcpy( tmp
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1219 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1220 safe_free(message
->answer
);
1222 message
->answer
= result
;
1223 message
->ancount
+= q
->initial_AAAA
.count
;
1224 n
+= q
->initial_AAAA
.count
;
1225 q
->initial_AAAA
.count
=0;
1226 } else if (q
->initial_AAAA
.count
> 0 && n
<= 0) {
1227 /* initial of dual queries was the only result set. */
1228 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " AAAA has " << q
->initial_AAAA
.count
<< " RR, A has " << n
<< " RR");
1229 rfc1035RRDestroy(&(message
->answer
), n
);
1230 message
->answer
= q
->initial_AAAA
.answers
;
1231 n
= q
->initial_AAAA
.count
;
1233 /* else initial results were empty. just use the final set as authoritative */
1235 debugs(78, 6, HERE
<< "Sending " << n
<< " DNS results to caller.");
1236 idnsCallback(q
, message
->answer
, n
, rfc1035ErrorMessage(n
));
1237 rfc1035MessageDestroy(&message
);
1242 idnsRead(int fd
, void *data
)
1244 int *N
= &incoming_sockets_accepted
;
1246 int max
= INCOMING_DNS_MAX
;
1247 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1251 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1253 // Always keep reading. This stops (or at least makes harder) several
1254 // attacks on the DNS client.
1255 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1258 * two code lines after returning from comm_udprecvfrom()
1259 * something overwrites the memory behind the from parameter.
1260 * NO matter where in the stack declaration list above it is placed
1261 * The cause of this is still unknown, however copying the data appears
1262 * to allow it to be passed further without this erasure.
1264 Ip::Address bugbypass
;
1267 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1269 from
= bugbypass
; // BUG BYPASS. see notes above.
1275 if (ignoreErrno(errno
))
1278 #ifdef _SQUID_LINUX_
1279 /* Some Linux systems seem to set the FD for reading and then
1280 * return ECONNREFUSED when sendto() fails and generates an ICMP
1281 * port unreachable message. */
1282 /* or maybe an EHOSTUNREACH "No route to host" message */
1283 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1286 debugs(50, 1, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1291 fd_bytes(fd
, len
, FD_READ
);
1296 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1298 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1299 ns
= idnsFromKnownNameserver(from
);
1302 nameservers
[ns
].nreplies
++;
1305 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1306 // but after the ++ above to keep statistics right.
1308 continue; // Don't process replies if there is no pending query.
1310 if (ns
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1311 static time_t last_warning
= 0;
1313 if (squid_curtime
- last_warning
> 60) {
1314 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
);
1315 last_warning
= squid_curtime
;
1317 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1322 idnsGrokReply(rbuf
, len
, ns
);
1327 idnsCheckQueue(void *unused
)
1330 dlink_node
*p
= NULL
;
1335 /* name servers went away; reconfiguring or shutting down */
1338 for (n
= lru_list
.tail
; n
; n
= p
) {
1341 q
= static_cast<idns_query
*>(n
->data
);
1343 /* Anything to process in the queue? */
1344 if (tvSubDsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1347 /* Query timer expired? */
1348 if (tvSubDsec(q
->sent_t
, current_time
) < Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
)) {
1349 dlinkDelete(&q
->lru
, &lru_list
);
1350 q
->queue_t
= current_time
;
1351 dlinkAdd(q
, &q
->lru
, &lru_list
);
1355 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1356 " QID 0x" << std::hex
<< std::setfill('0') <<
1357 std::setw(4) << q
->msg_id
<< ": timeout" );
1359 dlinkDelete(&q
->lru
, &lru_list
);
1361 if (tvSubDsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1364 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1365 " QID 0x" << std::hex
<< q
->msg_id
<<
1366 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1367 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1370 idnsCallback(q
, NULL
, -q
->rcode
, rfc1035ErrorMessage(q
->rcode
));
1372 idnsCallback(q
, NULL
, -16, "Timeout");
1382 idnsReadVC(int fd
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1384 nsvc
* vc
= (nsvc
*)data
;
1386 if (flag
== COMM_ERR_CLOSING
)
1389 if (flag
!= COMM_OK
|| len
<= 0) {
1394 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1396 if (vc
->msg
->contentSize() < vc
->msglen
) {
1397 comm_read(fd
, buf
+ len
, vc
->msglen
- vc
->msg
->contentSize(), idnsReadVC
, vc
);
1401 assert(vc
->ns
< nns
);
1402 debugs(78, 3, "idnsReadVC: FD " << fd
<< ": received " <<
1403 (int) vc
->msg
->contentSize() << " bytes via tcp from " <<
1404 nameservers
[vc
->ns
].S
<< ".");
1406 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1408 comm_read(fd
, (char *)&vc
->msglen
, 2 , idnsReadVCHeader
, vc
);
1412 idnsReadVCHeader(int fd
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1414 nsvc
* vc
= (nsvc
*)data
;
1416 if (flag
== COMM_ERR_CLOSING
)
1419 if (flag
!= COMM_OK
|| len
<= 0) {
1424 vc
->read_msglen
+= len
;
1426 assert(vc
->read_msglen
<= 2);
1428 if (vc
->read_msglen
< 2) {
1429 comm_read(fd
, buf
+ len
, 2 - vc
->read_msglen
, idnsReadVCHeader
, vc
);
1433 vc
->read_msglen
= 0;
1435 vc
->msglen
= ntohs(vc
->msglen
);
1437 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1438 comm_read(fd
, vc
->msg
->buf
, vc
->msglen
, idnsReadVC
, vc
);
1442 * rcode < 0 indicates an error, rocde >= 0 indicates success
1445 idnsRcodeCount(int rcode
, int attempt
)
1452 if (rcode
< MAX_RCODE
)
1453 if (attempt
< MAX_ATTEMPT
)
1454 RcodeMatrix
[rcode
][attempt
]++;
1457 /* ====================================================================== */
1460 idnsRegisterWithCacheManager(void)
1462 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1468 static int init
= 0;
1470 CBDATA_INIT_TYPE(nsvc
);
1471 CBDATA_INIT_TYPE(idns_query
);
1473 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1476 Ip::Address addrA
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1478 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
1479 addrA
= Config
.Addrs
.udp_outgoing
;
1481 addrA
= Config
.Addrs
.udp_incoming
;
1483 Ip::Address addrB
= addrA
;
1486 if (Ip::EnableIpv6
&& (addrB
.IsAnyAddr() || addrB
.IsIPv6())) {
1487 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrB
);
1488 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1495 if (addrA
.IsAnyAddr() || addrA
.IsIPv4()) {
1496 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrA
);
1497 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1504 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1505 fatal("Could not create a DNS socket");
1507 /* Ouch... we can't call functions using debug from a debug
1508 * statement. Doing so messes up the internal Debug::level
1510 if (DnsSocketB
>= 0) {
1511 port
= comm_local_port(DnsSocketB
);
1512 debugs(78, 1, "DNS Socket created at " << addrB
<< ", FD " << DnsSocketB
);
1513 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1515 if (DnsSocketA
>= 0) {
1516 port
= comm_local_port(DnsSocketA
);
1517 debugs(78, 1, "DNS Socket created at " << addrA
<< ", FD " << DnsSocketA
);
1518 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1523 idnsParseNameservers();
1524 #ifndef _SQUID_MSWIN_
1527 idnsParseResolvConf();
1532 idnsParseWIN32Registry();
1536 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
1538 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
1540 debugs(78, 1, "Please check your /etc/resolv.conf file");
1543 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1544 idnsAddNameserver("127.0.0.1");
1548 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1549 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1550 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1554 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1555 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1556 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1557 max_shared_edns
= -1; // disable if we might receive random replies.
1561 idnsRegisterWithCacheManager();
1567 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1570 if (DnsSocketA
>= 0 ) {
1571 comm_close(DnsSocketA
);
1575 if (DnsSocketB
>= 0 ) {
1576 comm_close(DnsSocketB
);
1580 for (int i
= 0; i
< nns
; i
++) {
1581 if (nsvc
*vc
= nameservers
[i
].vc
) {
1587 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1588 idnsFreeNameservers();
1589 idnsFreeSearchpath();
1593 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1597 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1602 q
= cbdataAlloc(idns_query
);
1603 // idns_query is POD so no constructors are called after allocation
1604 q
->xact_id
.change();
1606 q
->callback
= callback
;
1608 q
->callback_data
= cbdataReference(data
);
1610 q
->queue
= old
->queue
;
1618 idnsCacheQuery(idns_query
*q
)
1620 q
->hash
.key
= q
->query
.name
;
1621 hash_join(idns_lookup_hash
, &q
->hash
);
1625 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1631 if (idnsCachedLookup(name
, callback
, data
))
1634 q
= cbdataAlloc(idns_query
);
1635 // idns_query is POD so no constructors are called after allocation
1636 q
->xact_id
.change();
1638 for (i
= 0; i
< strlen(name
); i
++)
1642 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[strlen(name
)-1] != '.') {
1643 q
->do_searchpath
= 1;
1645 q
->do_searchpath
= 0;
1648 strcpy(q
->orig
, name
);
1649 strcpy(q
->name
, q
->orig
);
1651 if (q
->do_searchpath
&& nd
< ndots
) {
1653 strcat(q
->name
, ".");
1654 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1655 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1658 if (Ip::EnableIpv6
) {
1659 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1662 // see EDNS notes at top of file why this sends 0
1663 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1668 /* problem with query data -- query not sent */
1669 callback(data
, NULL
, 0, "Internal error");
1674 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1675 ", id = 0x" << std::hex
<< q
->msg_id
);
1677 q
->callback
= callback
;
1678 q
->callback_data
= cbdataReference(data
);
1685 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1689 char ip
[MAX_IPSTRLEN
];
1691 addr
.NtoA(ip
,MAX_IPSTRLEN
);
1693 q
= cbdataAlloc(idns_query
);
1695 // idns_query is POD so no constructors are called after allocation
1696 q
->xact_id
.change();
1698 if (addr
.IsIPv6()) {
1699 struct in6_addr addr6
;
1700 addr
.GetInAddr(addr6
);
1701 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1703 struct in_addr addr4
;
1704 addr
.GetInAddr(addr4
);
1705 // see EDNS notes at top of file why this sends 0
1706 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1709 /* PTR does not do inbound A/AAAA */
1713 /* problem with query data -- query not sent */
1714 callback(data
, NULL
, 0, "Internal error");
1719 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1724 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1725 ", id = 0x" << std::hex
<< q
->msg_id
);
1727 q
->callback
= callback
;
1728 q
->callback_data
= cbdataReference(data
);
1736 * The function to return the DNS via SNMP
1739 snmp_netIdnsFn(variable_list
* Var
, snint
* ErrP
)
1742 variable_list
*Answer
= NULL
;
1744 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1745 *ErrP
= SNMP_ERR_NOERROR
;
1747 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1751 for (i
= 0; i
< nns
; i
++)
1752 n
+= nameservers
[i
].nqueries
;
1754 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1761 for (i
= 0; i
< nns
; i
++)
1762 n
+= nameservers
[i
].nreplies
;
1764 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1771 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1778 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1786 #endif /*SQUID_SNMP */
1787 #endif /* USE_DNSSERVERS */