2 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
3 * AUTHOR: Duane Wessels
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "base/InstanceId.h"
35 #include "comm/Connection.h"
36 #include "comm/ConnOpener.h"
38 #include "comm/Loops.h"
39 #include "comm/Write.h"
46 #include "mgr/Registration.h"
48 #include "SquidConfig.h"
49 #include "SquidTime.h"
56 #include "snmp_core.h"
59 #if HAVE_ARPA_NAMESER_H
60 #include <arpa/nameser.h>
69 /* MS Visual Studio Projects are monolithic, so we need the following
70 #ifndef to exclude the internal DNS code from compile process when
71 using external DNS process.
75 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
76 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
77 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
80 #define _PATH_RESCONF "/etc/resolv.conf"
82 #ifndef NS_DEFAULTPORT
83 #define NS_DEFAULTPORT 53
87 #define NS_MAXDNAME 1025
94 /* The buffer size required to store the maximum allowed search path */
96 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
99 #define IDNS_MAX_TRIES 20
101 #define MAX_ATTEMPT 3
102 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
103 // NP: see http://www.iana.org/assignments/dns-parameters
104 static const char *Rcodes
[] = {
107 "Packet Format Error",
108 "DNS Server Failure",
109 "Non-Existent Domain",
113 "Name Exists when it should not",
114 "RR Set Exists when it should not",
115 "RR Set that should exist does not",
116 "Server Not Authoritative for zone",
117 "Name not contained in zone",
121 "Bad OPT Version or TSIG Signature Failure"
124 typedef struct _idns_query idns_query
;
126 typedef struct _ns ns
;
128 typedef struct _sp sp
;
130 typedef struct _nsvc nsvc
;
135 char buf
[RESOLV_BUFSZ
];
136 char name
[NS_MAXDNAME
+ 1];
137 char orig
[NS_MAXDNAME
+ 1];
139 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
140 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
147 struct timeval start_t
;
148 struct timeval sent_t
;
149 struct timeval queue_t
;
156 idns_query
*slave
; // single linked list
157 idns_query
*master
; // single pointer to a shared master
158 unsigned short domain
;
159 unsigned short do_searchpath
;
160 rfc1035_message
*message
;
164 InstanceIdDefinitions(idns_query
, "dns");
168 Comm::ConnectionPointer conn
;
169 unsigned short msglen
;
180 #if WHEN_EDNS_RESPONSES_ARE_PARSED
188 char domain
[NS_MAXDNAME
];
193 CBDATA_TYPE(idns_query
);
195 static ns
*nameservers
= NULL
;
196 static sp
*searchpath
= NULL
;
198 static int nns_alloc
= 0;
199 static int nns_mdns_count
= 0;
201 static int npc_alloc
= 0;
202 static int ndots
= 1;
203 static dlink_list lru_list
;
204 static int event_queued
= 0;
205 static hash_table
*idns_lookup_hash
= NULL
;
211 * EDNS as specified may be sent as an additional record for any request.
212 * early testing has revealed that it works on common devices, but cannot
213 * be reliably used on any A or PTR requet done for IPv4 addresses.
215 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
218 * Squid is optimized to generate one packet and re-send it to all NS
219 * due to this we cannot customize the EDNS size per NS.
221 * As such we take the configuration option value as fixed.
224 * This may not be worth doing, but if/when additional-records are parsed
225 * we will be able to recover the OPT value specific to any one NS and
226 * cache it. Effectively automating the tuning of EDNS advertised to the
227 * size our active NS are capable.
228 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
229 * Responses from the configured NS may cause this to be raised or turned off.
231 #if WHEN_EDNS_RESPONSES_ARE_PARSED
232 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
235 static OBJH idnsStats
;
236 static void idnsAddNameserver(const char *buf
);
237 static void idnsAddMDNSNameservers();
238 static void idnsAddPathComponent(const char *buf
);
239 static void idnsFreeNameservers(void);
240 static void idnsFreeSearchpath(void);
241 static bool idnsParseNameservers(void);
243 static bool idnsParseResolvConf(void);
246 static bool idnsParseWIN32Registry(void);
247 static void idnsParseWIN32SearchList(const char *);
249 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
250 static void idnsSendQuery(idns_query
* q
);
251 static IOCB idnsReadVCHeader
;
252 static void idnsDoSendQueryVC(nsvc
*vc
);
253 static CNCB idnsInitVCConnected
;
254 static IOCB idnsReadVC
;
255 static IOCB idnsSentQueryVC
;
257 static int idnsFromKnownNameserver(Ip::Address
const &from
);
258 static idns_query
*idnsFindQuery(unsigned short id
);
259 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
261 static EVH idnsCheckQueue
;
262 static void idnsTickleQueue(void);
263 static void idnsRcodeCount(int, int);
264 static CLCB idnsVCClosed
;
265 static unsigned short idnsQueryID(void);
266 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
269 idnsCheckMDNS(idns_query
*q
)
271 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
274 size_t slen
= strlen(q
->name
);
275 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
276 q
->permit_mdns
= true;
281 idnsAddMDNSNameservers()
286 if (!Config
.onoff
.dns_mdns
)
289 // mDNS resolver addresses are explicit multicast group IPs
290 if (Ip::EnableIpv6
) {
291 idnsAddNameserver("FF02::FB");
292 nameservers
[nns
-1].S
.port(5353);
293 nameservers
[nns
-1].mDNSResolver
= true;
297 idnsAddNameserver("224.0.0.251");
298 nameservers
[nns
-1].S
.port(5353);
299 nameservers
[nns
-1].mDNSResolver
= true;
305 idnsAddNameserver(const char *buf
)
310 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
315 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
317 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
320 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
321 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
325 if (nns
== nns_alloc
) {
326 int oldalloc
= nns_alloc
;
327 ns
*oldptr
= nameservers
;
334 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
336 if (oldptr
&& oldalloc
)
337 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
343 assert(nns
< nns_alloc
);
344 A
.port(NS_DEFAULTPORT
);
345 nameservers
[nns
].S
= A
;
346 #if WHEN_EDNS_RESPONSES_ARE_PARSED
347 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
348 // TODO generate a test packet to probe this NS from EDNS size and ability.
350 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
355 idnsAddPathComponent(const char *buf
)
357 if (npc
== npc_alloc
) {
358 int oldalloc
= npc_alloc
;
359 sp
*oldptr
= searchpath
;
366 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
368 if (oldptr
&& oldalloc
)
369 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
375 assert(npc
< npc_alloc
);
376 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
377 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
378 Tolower(searchpath
[npc
].domain
);
379 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
384 idnsFreeNameservers(void)
386 safe_free(nameservers
);
391 idnsFreeSearchpath(void)
393 safe_free(searchpath
);
398 idnsParseNameservers(void)
401 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
402 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
403 idnsAddNameserver(w
->key
);
411 idnsParseResolvConf(void)
414 char buf
[RESOLV_BUFSZ
];
417 fp
= fopen(_PATH_RESCONF
, "r");
420 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
425 setmode(fileno(fp
), O_TEXT
);
428 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
429 t
= strtok(buf
, w_space
);
433 } else if (strcmp(t
, "nameserver") == 0) {
434 t
= strtok(NULL
, w_space
);
439 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
441 idnsAddNameserver(t
);
443 } else if (strcmp(t
, "domain") == 0) {
444 idnsFreeSearchpath();
445 t
= strtok(NULL
, w_space
);
450 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
452 idnsAddPathComponent(t
);
453 } else if (strcmp(t
, "search") == 0) {
454 idnsFreeSearchpath();
456 t
= strtok(NULL
, w_space
);
461 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
463 idnsAddPathComponent(t
);
465 } else if (strcmp(t
, "options") == 0) {
467 t
= strtok(NULL
, w_space
);
472 if (strncmp(t
, "ndots:", 6) == 0) {
478 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
483 if (npc
== 0 && (t
= getMyHostname())) {
486 idnsAddPathComponent(t
+1);
497 idnsParseWIN32SearchList(const char * Separator
)
503 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
507 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
509 if (Result
== ERROR_SUCCESS
&& Size
) {
510 t
= (char *) xmalloc(Size
);
511 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
512 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
513 idnsAddPathComponent(t
);
516 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
518 if (Result
== ERROR_SUCCESS
&& Size
) {
519 t
= (char *) xmalloc(Size
);
520 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
521 token
= strtok(t
, Separator
);
524 idnsAddPathComponent(token
);
525 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
526 token
= strtok(NULL
, Separator
);
533 if (npc
== 0 && (t
= (char *) getMyHostname())) {
536 idnsAddPathComponent(t
+ 1);
541 idnsParseWIN32Registry(void)
545 HKEY hndKey
, hndKey2
;
548 switch (WIN32_OS_version
) {
551 /* get nameservers from the Windows NT registry */
553 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
557 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
559 if (Result
== ERROR_SUCCESS
&& Size
) {
560 t
= (char *) xmalloc(Size
);
561 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
562 token
= strtok(t
, ", ");
565 idnsAddNameserver(token
);
567 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
568 token
= strtok(NULL
, ",");
573 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
575 if (Result
== ERROR_SUCCESS
&& Size
) {
576 t
= (char *) xmalloc(Size
);
577 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
578 token
= strtok(t
, ", ");
581 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
582 idnsAddNameserver(token
);
584 token
= strtok(NULL
, ", ");
592 idnsParseWIN32SearchList(" ");
605 /* get nameservers from the Windows 2000 registry */
606 /* search all interfaces for DNS server addresses */
608 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
610 DWORD MaxSubkeyLen
, InterfacesCount
;
612 FILETIME ftLastWriteTime
;
614 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
615 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
616 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
619 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
621 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
622 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
623 strcat(newkeyname
, "\\");
624 strcat(newkeyname
, keyname
);
625 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
629 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
630 if (Result
== ERROR_SUCCESS
&& Size
) {
631 t
= (char *) xmalloc(Size
);
632 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
633 token
= strtok(t
, ", ");
635 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
636 idnsAddNameserver(token
);
638 token
= strtok(NULL
, ", ");
643 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
644 if (Result
== ERROR_SUCCESS
&& Size
) {
645 t
= (char *) xmalloc(Size
);
646 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
647 token
= strtok(t
, ", ");
649 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
650 idnsAddNameserver(token
);
652 token
= strtok(NULL
, ", ");
658 RegCloseKey(hndKey2
);
671 idnsParseWIN32SearchList(", ");
680 /* get nameservers from the Windows 9X registry */
682 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
686 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
688 if (Result
== ERROR_SUCCESS
&& Size
) {
689 t
= (char *) xmalloc(Size
);
690 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
691 token
= strtok(t
, ", ");
694 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
695 idnsAddNameserver(token
);
697 token
= strtok(NULL
, ", ");
708 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
717 idnsStats(StoreEntry
* sentry
)
723 char buf
[MAX_IPSTRLEN
];
724 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
725 storeAppendPrintf(sentry
, "\nThe Queue:\n");
726 storeAppendPrintf(sentry
, " DELAY SINCE\n");
727 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
728 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
730 for (n
= lru_list
.head
; n
; n
= n
->next
) {
731 q
= (idns_query
*)n
->data
;
732 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
733 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
734 tvSubDsec(q
->start_t
, current_time
),
735 tvSubDsec(q
->sent_t
, current_time
),
736 (q
->permit_mdns
? 'M':' '),
740 if (Config
.dns
.packet_max
> 0)
741 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
743 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
745 storeAppendPrintf(sentry
, "\nNameservers:\n");
746 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
747 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
749 for (i
= 0; i
< nns
; ++i
) {
750 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
751 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
752 nameservers
[i
].nqueries
,
753 nameservers
[i
].nreplies
,
754 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
757 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
758 storeAppendPrintf(sentry
, "RCODE");
760 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
761 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
763 storeAppendPrintf(sentry
, " PROBLEM\n");
765 for (j
= 0; j
< MAX_RCODE
; ++j
) {
766 if (j
> 10 && j
< 16)
767 continue; // unassigned by IANA.
769 storeAppendPrintf(sentry
, "%5d", j
);
771 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
772 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
774 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
778 storeAppendPrintf(sentry
, "\nSearch list:\n");
780 for (i
=0; i
< npc
; ++i
)
781 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
783 storeAppendPrintf(sentry
, "\n");
788 idnsTickleQueue(void)
793 if (NULL
== lru_list
.tail
)
796 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
798 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
804 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
806 nsvc
* vc
= (nsvc
*)data
;
808 if (flag
== COMM_ERR_CLOSING
)
811 // XXX: irrelevant now that we have conn pointer?
812 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
815 if (flag
!= COMM_OK
|| size
<= 0) {
821 idnsDoSendQueryVC(vc
);
825 idnsDoSendQueryVC(nsvc
*vc
)
830 if (vc
->queue
->contentSize() == 0)
833 // if retrying after a TC UDP response, our close handler cb may be pending
834 if (fd_table
[vc
->conn
->fd
].closing())
837 MemBuf
*mb
= vc
->queue
;
839 vc
->queue
= new MemBuf
;
843 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
844 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
845 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
846 AsyncCall::Pointer nil
;
848 commSetConnTimeout(vc
->conn
, timeout
, nil
);
850 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
851 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
852 Comm::Write(vc
->conn
, mb
, call
);
858 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
860 nsvc
* vc
= (nsvc
*)data
;
862 if (status
!= COMM_OK
|| !conn
) {
863 char buf
[MAX_IPSTRLEN
] = "";
865 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
866 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
872 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
873 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
874 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
875 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
877 idnsDoSendQueryVC(vc
);
881 idnsVCClosed(const CommCloseCbParams
¶ms
)
883 nsvc
* vc
= (nsvc
*)params
.data
;
887 if (vc
->ns
< nns
) // XXX: dnsShutdown may have freed nameservers[]
888 nameservers
[vc
->ns
].vc
= NULL
;
895 nsvc
*vc
= cbdataAlloc(nsvc
);
897 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
898 nameservers
[nsv
].vc
= vc
;
900 vc
->queue
= new MemBuf
;
901 vc
->msg
= new MemBuf
;
904 Comm::ConnectionPointer conn
= new Comm::Connection();
906 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
907 conn
->local
= Config
.Addrs
.udp_outgoing
;
909 conn
->local
= Config
.Addrs
.udp_incoming
;
911 conn
->remote
= nameservers
[nsv
].S
;
913 if (conn
->remote
.isIPv4()) {
914 conn
->local
.setIPv4();
917 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
919 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
920 cs
->setHost("DNS TCP Socket");
925 idnsSendQueryVC(idns_query
* q
, int nsn
)
928 if (nameservers
[nsn
].vc
== NULL
)
931 nsvc
*vc
= nameservers
[nsn
].vc
;
934 char buf
[MAX_IPSTRLEN
];
935 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
942 short head
= htons(q
->sz
);
944 vc
->queue
->append((char *)&head
, 2);
946 vc
->queue
->append(q
->buf
, q
->sz
);
948 idnsDoSendQueryVC(vc
);
952 idnsSendQuery(idns_query
* q
)
954 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
955 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
960 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
964 assert(q
->lru
.next
== NULL
);
966 assert(q
->lru
.prev
== NULL
);
972 // only use mDNS resolvers for mDNS compatible queries
974 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
976 nsn
= q
->nsends
% nns
;
979 idnsSendQueryVC(q
, nsn
);
982 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
983 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
984 else if (DnsSocketA
>= 0)
985 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
990 q
->sent_t
= current_time
;
992 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
993 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
994 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
995 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
997 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
1000 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
1003 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
1006 ++ nameservers
[nsn
].nqueries
;
1007 q
->queue_t
= current_time
;
1008 dlinkAdd(q
, &q
->lru
, &lru_list
);
1014 idnsFromKnownNameserver(Ip::Address
const &from
)
1018 for (i
= 0; i
< nns
; ++i
) {
1019 if (nameservers
[i
].S
!= from
)
1022 if (nameservers
[i
].S
.port() != from
.port())
1032 idnsFindQuery(unsigned short id
)
1037 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1038 q
= (idns_query
*)n
->data
;
1040 if (q
->query_id
== id
)
1047 static unsigned short
1050 unsigned short id
= squid_random() & 0xFFFF;
1051 unsigned short first_id
= id
;
1053 while (idnsFindQuery(id
)) {
1056 if (id
== first_id
) {
1057 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1066 idnsCallback(idns_query
*q
, const char *error
)
1077 // If any of our subqueries are still pending then wait for them to complete before continuing
1078 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1085 rfc1035_message
*message
= q
->message
;
1090 while ( idns_query
*q2
= q
->slave
) {
1091 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1092 q
->slave
= q2
->slave
;
1095 // two sets of RR need merging
1096 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1097 if (Config
.dns
.v4_first
) {
1098 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1099 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1101 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1102 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1105 // HACK WARNING, the answer rr:s have been copied in-place to
1106 // result, do not free them here
1107 safe_free(message
->answer
);
1108 safe_free(q2
->message
->answer
);
1109 message
->answer
= result
;
1110 message
->ancount
+= q2
->message
->ancount
;
1112 // first response empty or failed, just use the second
1113 rfc1035MessageDestroy(&message
);
1114 message
= q2
->message
;
1120 rfc1035MessageDestroy(&q2
->message
);
1124 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1126 callback
= q
->callback
;
1128 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1130 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1131 callback(cbdata
, answers
, n
, error
);
1134 idns_query
*q2
= q
->queue
;
1135 q
->queue
= q2
->queue
;
1136 callback
= q2
->callback
;
1137 q2
->callback
= NULL
;
1139 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1140 callback(cbdata
, answers
, n
, error
);
1146 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1150 rfc1035MessageDestroy(&message
);
1155 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1158 rfc1035_message
*message
= NULL
;
1161 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1163 if (message
== NULL
) {
1164 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1168 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1170 q
= idnsFindQuery(message
->id
);
1173 debugs(78, 3, "idnsGrokReply: Late response");
1174 rfc1035MessageDestroy(&message
);
1178 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1179 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1180 rfc1035MessageDestroy(&message
);
1184 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1185 // TODO: actually gr the message right here.
1186 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1187 // this is overall better than force-feeding A response with AAAA an section later anyway.
1188 // AND allows us to merge AN+AR sections from both responses (one day)
1190 if (q
->edns_seen
>= 0) {
1191 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1192 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1193 // the altered NS was limiting the whole group.
1194 max_shared_edns
= q
->edns_seen
;
1195 // may be limited by one of the others still
1196 for (int i
= 0; i
< nns
; ++i
)
1197 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1199 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1200 // maybe reduce the global limit downwards to accomodate this NS
1201 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1203 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1204 max_shared_edns
= -1;
1208 dlinkDelete(&q
->lru
, &lru_list
);
1212 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1213 rfc1035MessageDestroy(&message
);
1220 // Strange: A TCP DNS response with the truncation bit (TC) set.
1221 // Return an error and cleanup; no point in trying TCP again.
1222 debugs(78, 3, HERE
<< "TCP DNS response");
1223 idnsCallback(q
, "Truncated TCP DNS response");
1229 idnsRcodeCount(n
, q
->attempt
);
1233 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1235 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1237 * RCODE 2 is "Server failure - The name server was
1238 * unable to process this query due to a problem with
1241 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1242 rfc1035MessageDestroy(&message
);
1247 // Do searchpath processing on the master A query only to keep
1248 // things simple. NXDOMAIN is authorative for the label, not
1250 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1251 assert(NULL
== message
->answer
);
1252 strcpy(q
->name
, q
->orig
);
1254 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1256 if (q
->domain
< npc
) {
1257 strcat(q
->name
, ".");
1258 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1259 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1265 rfc1035MessageDestroy(&message
);
1267 // cleanup slave AAAA query
1268 while (idns_query
*slave
= q
->slave
) {
1269 dlinkDelete(&slave
->lru
, &lru_list
);
1270 q
->slave
= slave
->slave
;
1271 rfc1035MessageDestroy(&slave
->message
);
1276 q
->query_id
= idnsQueryID();
1277 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1278 // see EDNS notes at top of file why this sends 0
1279 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1281 /* problem with query data -- query not sent */
1282 idnsCallback(q
, "Internal error");
1291 idnsSendSlaveAAAAQuery(q
);
1296 q
->message
= message
;
1300 idnsCallback(q
, NULL
);
1302 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1307 idnsRead(int fd
, void *data
)
1309 int *N
= &incoming_sockets_accepted
;
1311 int max
= INCOMING_DNS_MAX
;
1312 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1315 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1317 // Always keep reading. This stops (or at least makes harder) several
1318 // attacks on the DNS client.
1319 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1322 * two code lines after returning from comm_udprecvfrom()
1323 * something overwrites the memory behind the from parameter.
1324 * NO matter where in the stack declaration list above it is placed
1325 * The cause of this is still unknown, however copying the data appears
1326 * to allow it to be passed further without this erasure.
1328 Ip::Address bugbypass
;
1332 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1334 from
= bugbypass
; // BUG BYPASS. see notes above.
1340 if (ignoreErrno(errno
))
1344 /* Some Linux systems seem to set the FD for reading and then
1345 * return ECONNREFUSED when sendto() fails and generates an ICMP
1346 * port unreachable message. */
1347 /* or maybe an EHOSTUNREACH "No route to host" message */
1348 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1351 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1356 fd_bytes(fd
, len
, FD_READ
);
1361 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1363 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1364 int nsn
= idnsFromKnownNameserver(from
);
1367 ++ nameservers
[nsn
].nreplies
;
1370 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1371 // but after the ++ above to keep statistics right.
1373 continue; // Don't process replies if there is no pending query.
1375 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1376 static time_t last_warning
= 0;
1378 if (squid_curtime
- last_warning
> 60) {
1379 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1380 last_warning
= squid_curtime
;
1382 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1387 idnsGrokReply(rbuf
, len
, nsn
);
1392 idnsCheckQueue(void *unused
)
1395 dlink_node
*p
= NULL
;
1400 /* name servers went away; reconfiguring or shutting down */
1403 for (n
= lru_list
.tail
; n
; n
= p
) {
1406 q
= static_cast<idns_query
*>(n
->data
);
1408 /* Anything to process in the queue? */
1409 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1412 /* Query timer still running? */
1413 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1414 dlinkDelete(&q
->lru
, &lru_list
);
1415 q
->queue_t
= current_time
;
1416 dlinkAdd(q
, &q
->lru
, &lru_list
);
1420 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1421 " QID 0x" << std::hex
<< std::setfill('0') <<
1422 std::setw(4) << q
->query_id
<< ": timeout" );
1424 dlinkDelete(&q
->lru
, &lru_list
);
1427 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1430 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1431 " QID 0x" << std::hex
<< q
->query_id
<<
1432 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1433 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1436 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1438 idnsCallback(q
, "Timeout");
1446 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1448 nsvc
* vc
= (nsvc
*)data
;
1450 if (flag
== COMM_ERR_CLOSING
)
1453 if (flag
!= COMM_OK
|| len
<= 0) {
1454 if (Comm::IsConnOpen(conn
))
1459 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1461 if (vc
->msg
->contentSize() < vc
->msglen
) {
1462 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1463 CommIoCbPtrFun(idnsReadVC
, vc
));
1464 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1468 assert(vc
->ns
< nns
);
1469 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1471 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1473 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1474 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1475 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1479 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1481 nsvc
* vc
= (nsvc
*)data
;
1483 if (flag
== COMM_ERR_CLOSING
)
1486 if (flag
!= COMM_OK
|| len
<= 0) {
1487 if (Comm::IsConnOpen(conn
))
1492 vc
->read_msglen
+= len
;
1494 assert(vc
->read_msglen
<= 2);
1496 if (vc
->read_msglen
< 2) {
1497 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1498 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1499 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1503 vc
->read_msglen
= 0;
1505 vc
->msglen
= ntohs(vc
->msglen
);
1507 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1508 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1509 CommIoCbPtrFun(idnsReadVC
, vc
));
1510 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1514 * rcode < 0 indicates an error, rocde >= 0 indicates success
1517 idnsRcodeCount(int rcode
, int attempt
)
1524 if (rcode
< MAX_RCODE
)
1525 if (attempt
< MAX_ATTEMPT
)
1526 ++ RcodeMatrix
[rcode
][attempt
];
1529 /* ====================================================================== */
1532 idnsRegisterWithCacheManager(void)
1534 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1540 static int init
= 0;
1542 CBDATA_INIT_TYPE(nsvc
);
1543 CBDATA_INIT_TYPE(idns_query
);
1545 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1546 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1548 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1549 addrV6
= Config
.Addrs
.udp_outgoing
;
1551 addrV6
= Config
.Addrs
.udp_incoming
;
1553 Ip::Address addrV4
= addrV6
;
1556 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1557 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1558 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1565 if (addrV4
.isIPv4()) {
1566 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1567 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1574 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1575 fatal("Could not create a DNS socket");
1577 /* Ouch... we can't call functions using debug from a debug
1578 * statement. Doing so messes up the internal Debug::level
1580 if (DnsSocketB
>= 0) {
1581 comm_local_port(DnsSocketB
);
1582 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1583 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1585 if (DnsSocketA
>= 0) {
1586 comm_local_port(DnsSocketA
);
1587 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1588 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1593 idnsAddMDNSNameservers();
1594 bool nsFound
= idnsParseNameservers();
1595 #if !_SQUID_WINDOWS_
1598 nsFound
= idnsParseResolvConf();
1603 nsFound
= idnsParseWIN32Registry();
1607 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1609 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1611 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1614 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1616 idnsAddNameserver("::1");
1617 idnsAddNameserver("127.0.0.1");
1621 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1622 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1623 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1627 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1628 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1629 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1630 max_shared_edns
= -1; // disable if we might receive random replies.
1634 idnsRegisterWithCacheManager();
1640 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1643 if (DnsSocketA
>= 0 ) {
1644 comm_close(DnsSocketA
);
1648 if (DnsSocketB
>= 0 ) {
1649 comm_close(DnsSocketB
);
1653 for (int i
= 0; i
< nns
; ++i
) {
1654 if (nsvc
*vc
= nameservers
[i
].vc
) {
1655 if (Comm::IsConnOpen(vc
->conn
))
1660 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1661 idnsFreeNameservers();
1662 idnsFreeSearchpath();
1666 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1670 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1675 q
= cbdataAlloc(idns_query
);
1676 // idns_query is POD so no constructors are called after allocation
1677 q
->xact_id
.change();
1678 // no query_id on this instance.
1680 q
->callback
= callback
;
1682 q
->callback_data
= cbdataReference(data
);
1684 q
->queue
= old
->queue
;
1692 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1694 q
->start_t
= current_time
;
1695 q
->callback
= callback
;
1696 q
->callback_data
= cbdataReference(data
);
1698 q
->hash
.key
= q
->orig
;
1699 hash_join(idns_lookup_hash
, &q
->hash
);
1705 idnsSendSlaveAAAAQuery(idns_query
*master
)
1707 idns_query
*q
= cbdataAlloc(idns_query
);
1708 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1709 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1711 q
->query_id
= idnsQueryID();
1712 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1713 q
->start_t
= master
->start_t
;
1714 q
->slave
= master
->slave
;
1716 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1717 ", id = 0x" << std::hex
<< q
->query_id
);
1728 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1730 size_t nameLength
= strlen(name
);
1732 // Prevent buffer overflow on q->name
1733 if (nameLength
> NS_MAXDNAME
) {
1734 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1735 callback(data
, NULL
, 0, "Internal error");
1739 if (idnsCachedLookup(name
, callback
, data
))
1742 idns_query
*q
= cbdataAlloc(idns_query
);
1743 // idns_query is POD so no constructors are called after allocation
1744 q
->xact_id
.change();
1745 q
->query_id
= idnsQueryID();
1748 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1752 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1753 q
->do_searchpath
= 1;
1755 q
->do_searchpath
= 0;
1758 strcpy(q
->orig
, name
);
1759 strcpy(q
->name
, q
->orig
);
1761 if (q
->do_searchpath
&& nd
< ndots
) {
1763 strcat(q
->name
, ".");
1764 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1765 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1768 // see EDNS notes at top of file why this sends 0
1769 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1772 /* problem with query data -- query not sent */
1773 callback(data
, NULL
, 0, "Internal error");
1778 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1779 ", id = 0x" << std::hex
<< q
->query_id
);
1782 idnsStartQuery(q
, callback
, data
);
1785 idnsSendSlaveAAAAQuery(q
);
1790 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1794 char ip
[MAX_IPSTRLEN
];
1796 addr
.toStr(ip
,MAX_IPSTRLEN
);
1798 q
= cbdataAlloc(idns_query
);
1800 // idns_query is POD so no constructors are called after allocation
1801 q
->xact_id
.change();
1802 q
->query_id
= idnsQueryID();
1804 if (addr
.isIPv6()) {
1805 struct in6_addr addr6
;
1806 addr
.getInAddr(addr6
);
1807 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1809 struct in_addr addr4
;
1810 addr
.getInAddr(addr4
);
1811 // see EDNS notes at top of file why this sends 0
1812 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1816 /* problem with query data -- query not sent */
1817 callback(data
, NULL
, 0, "Internal error");
1822 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1827 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1828 ", id = 0x" << std::hex
<< q
->query_id
);
1830 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1831 idnsStartQuery(q
, callback
, data
);
1836 * The function to return the DNS via SNMP
1839 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1842 variable_list
*Answer
= NULL
;
1844 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1845 *ErrP
= SNMP_ERR_NOERROR
;
1847 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1851 for (i
= 0; i
< nns
; ++i
)
1852 n
+= nameservers
[i
].nqueries
;
1854 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1861 for (i
= 0; i
< nns
; ++i
)
1862 n
+= nameservers
[i
].nreplies
;
1864 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1871 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1878 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1886 #endif /*SQUID_SNMP */
1887 #endif /* USE_DNSHELPER */