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"
36 #include "comm/Connection.h"
37 #include "comm/ConnOpener.h"
38 #include "comm/Loops.h"
39 #include "comm/Read.h"
40 #include "comm/Write.h"
48 #include "mgr/Registration.h"
50 #include "SquidConfig.h"
51 #include "SquidTime.h"
58 #include "snmp_core.h"
61 #if HAVE_ARPA_NAMESER_H
62 #include <arpa/nameser.h>
70 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
71 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
72 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
75 #define _PATH_RESCONF "/etc/resolv.conf"
77 #ifndef NS_DEFAULTPORT
78 #define NS_DEFAULTPORT 53
82 #define NS_MAXDNAME 1025
89 /* The buffer size required to store the maximum allowed search path */
91 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
94 #define IDNS_MAX_TRIES 20
97 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
98 // NP: see http://www.iana.org/assignments/dns-parameters
99 static const char *Rcodes
[] = {
102 "Packet Format Error",
103 "DNS Server Failure",
104 "Non-Existent Domain",
108 "Name Exists when it should not",
109 "RR Set Exists when it should not",
110 "RR Set that should exist does not",
111 "Server Not Authoritative for zone",
112 "Name not contained in zone",
116 "Bad OPT Version or TSIG Signature Failure"
119 typedef struct _idns_query idns_query
;
121 typedef struct _ns ns
;
123 typedef struct _sp sp
;
125 typedef struct _nsvc nsvc
;
130 char buf
[RESOLV_BUFSZ
];
131 char name
[NS_MAXDNAME
+ 1];
132 char orig
[NS_MAXDNAME
+ 1];
134 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
135 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
142 struct timeval start_t
;
143 struct timeval sent_t
;
144 struct timeval queue_t
;
151 idns_query
*slave
; // single linked list
152 idns_query
*master
; // single pointer to a shared master
153 unsigned short domain
;
154 unsigned short do_searchpath
;
155 rfc1035_message
*message
;
159 InstanceIdDefinitions(idns_query
, "dns");
163 Comm::ConnectionPointer conn
;
164 unsigned short msglen
;
175 #if WHEN_EDNS_RESPONSES_ARE_PARSED
183 char domain
[NS_MAXDNAME
];
188 CBDATA_TYPE(idns_query
);
190 static ns
*nameservers
= NULL
;
191 static sp
*searchpath
= NULL
;
193 static int nns_alloc
= 0;
194 static int nns_mdns_count
= 0;
196 static int npc_alloc
= 0;
197 static int ndots
= 1;
198 static dlink_list lru_list
;
199 static int event_queued
= 0;
200 static hash_table
*idns_lookup_hash
= NULL
;
206 * EDNS as specified may be sent as an additional record for any request.
207 * early testing has revealed that it works on common devices, but cannot
208 * be reliably used on any A or PTR requet done for IPv4 addresses.
210 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
213 * Squid is optimized to generate one packet and re-send it to all NS
214 * due to this we cannot customize the EDNS size per NS.
216 * As such we take the configuration option value as fixed.
219 * This may not be worth doing, but if/when additional-records are parsed
220 * we will be able to recover the OPT value specific to any one NS and
221 * cache it. Effectively automating the tuning of EDNS advertised to the
222 * size our active NS are capable.
223 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
224 * Responses from the configured NS may cause this to be raised or turned off.
226 #if WHEN_EDNS_RESPONSES_ARE_PARSED
227 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
230 static OBJH idnsStats
;
231 static void idnsAddNameserver(const char *buf
);
232 static void idnsAddMDNSNameservers();
233 static void idnsAddPathComponent(const char *buf
);
234 static void idnsFreeNameservers(void);
235 static void idnsFreeSearchpath(void);
236 static bool idnsParseNameservers(void);
238 static bool idnsParseResolvConf(void);
241 static bool idnsParseWIN32Registry(void);
242 static void idnsParseWIN32SearchList(const char *);
244 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
245 static void idnsSendQuery(idns_query
* q
);
246 static IOCB idnsReadVCHeader
;
247 static void idnsDoSendQueryVC(nsvc
*vc
);
248 static CNCB idnsInitVCConnected
;
249 static IOCB idnsReadVC
;
250 static IOCB idnsSentQueryVC
;
252 static int idnsFromKnownNameserver(Ip::Address
const &from
);
253 static idns_query
*idnsFindQuery(unsigned short id
);
254 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
256 static EVH idnsCheckQueue
;
257 static void idnsTickleQueue(void);
258 static void idnsRcodeCount(int, int);
259 static CLCB idnsVCClosed
;
260 static unsigned short idnsQueryID(void);
261 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
264 idnsCheckMDNS(idns_query
*q
)
266 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
269 size_t slen
= strlen(q
->name
);
270 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
271 q
->permit_mdns
= true;
276 idnsAddMDNSNameservers()
281 if (!Config
.onoff
.dns_mdns
)
284 // mDNS resolver addresses are explicit multicast group IPs
285 if (Ip::EnableIpv6
) {
286 idnsAddNameserver("FF02::FB");
287 nameservers
[nns
-1].S
.port(5353);
288 nameservers
[nns
-1].mDNSResolver
= true;
292 idnsAddNameserver("224.0.0.251");
293 nameservers
[nns
-1].S
.port(5353);
294 nameservers
[nns
-1].mDNSResolver
= true;
300 idnsAddNameserver(const char *buf
)
305 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
310 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
312 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
315 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
316 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
320 if (nns
== nns_alloc
) {
321 int oldalloc
= nns_alloc
;
322 ns
*oldptr
= nameservers
;
329 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
331 if (oldptr
&& oldalloc
)
332 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
338 assert(nns
< nns_alloc
);
339 A
.port(NS_DEFAULTPORT
);
340 nameservers
[nns
].S
= A
;
341 #if WHEN_EDNS_RESPONSES_ARE_PARSED
342 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
343 // TODO generate a test packet to probe this NS from EDNS size and ability.
345 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
350 idnsAddPathComponent(const char *buf
)
352 if (npc
== npc_alloc
) {
353 int oldalloc
= npc_alloc
;
354 sp
*oldptr
= searchpath
;
361 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
363 if (oldptr
&& oldalloc
)
364 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
370 assert(npc
< npc_alloc
);
371 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
372 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
373 Tolower(searchpath
[npc
].domain
);
374 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
379 idnsFreeNameservers(void)
381 safe_free(nameservers
);
386 idnsFreeSearchpath(void)
388 safe_free(searchpath
);
393 idnsParseNameservers(void)
396 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
397 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
398 idnsAddNameserver(w
->key
);
406 idnsParseResolvConf(void)
409 char buf
[RESOLV_BUFSZ
];
412 fp
= fopen(_PATH_RESCONF
, "r");
415 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
420 setmode(fileno(fp
), O_TEXT
);
423 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
424 t
= strtok(buf
, w_space
);
428 } else if (strcmp(t
, "nameserver") == 0) {
429 t
= strtok(NULL
, w_space
);
434 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
436 idnsAddNameserver(t
);
438 } else if (strcmp(t
, "domain") == 0) {
439 idnsFreeSearchpath();
440 t
= strtok(NULL
, w_space
);
445 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
447 idnsAddPathComponent(t
);
448 } else if (strcmp(t
, "search") == 0) {
449 idnsFreeSearchpath();
451 t
= strtok(NULL
, w_space
);
456 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
458 idnsAddPathComponent(t
);
460 } else if (strcmp(t
, "options") == 0) {
462 t
= strtok(NULL
, w_space
);
467 if (strncmp(t
, "ndots:", 6) == 0) {
473 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
478 if (npc
== 0 && (t
= getMyHostname())) {
481 idnsAddPathComponent(t
+1);
492 idnsParseWIN32SearchList(const char * Separator
)
498 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
502 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
504 if (Result
== ERROR_SUCCESS
&& Size
) {
505 t
= (char *) xmalloc(Size
);
506 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
507 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
508 idnsAddPathComponent(t
);
511 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
513 if (Result
== ERROR_SUCCESS
&& Size
) {
514 t
= (char *) xmalloc(Size
);
515 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
516 token
= strtok(t
, Separator
);
519 idnsAddPathComponent(token
);
520 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
521 token
= strtok(NULL
, Separator
);
528 if (npc
== 0 && (t
= (char *) getMyHostname())) {
531 idnsAddPathComponent(t
+ 1);
536 idnsParseWIN32Registry(void)
540 HKEY hndKey
, hndKey2
;
543 switch (WIN32_OS_version
) {
546 /* get nameservers from the Windows NT registry */
548 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
552 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
554 if (Result
== ERROR_SUCCESS
&& Size
) {
555 t
= (char *) xmalloc(Size
);
556 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
557 token
= strtok(t
, ", ");
560 idnsAddNameserver(token
);
562 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
563 token
= strtok(NULL
, ",");
568 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
570 if (Result
== ERROR_SUCCESS
&& Size
) {
571 t
= (char *) xmalloc(Size
);
572 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
573 token
= strtok(t
, ", ");
576 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
577 idnsAddNameserver(token
);
579 token
= strtok(NULL
, ", ");
587 idnsParseWIN32SearchList(" ");
600 /* get nameservers from the Windows 2000 registry */
601 /* search all interfaces for DNS server addresses */
603 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
605 DWORD MaxSubkeyLen
, InterfacesCount
;
607 FILETIME ftLastWriteTime
;
609 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
610 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
611 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
614 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
616 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
617 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
618 strcat(newkeyname
, "\\");
619 strcat(newkeyname
, keyname
);
620 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
624 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
625 if (Result
== ERROR_SUCCESS
&& Size
) {
626 t
= (char *) xmalloc(Size
);
627 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
628 token
= strtok(t
, ", ");
630 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
631 idnsAddNameserver(token
);
633 token
= strtok(NULL
, ", ");
638 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
639 if (Result
== ERROR_SUCCESS
&& Size
) {
640 t
= (char *) xmalloc(Size
);
641 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
642 token
= strtok(t
, ", ");
644 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
645 idnsAddNameserver(token
);
647 token
= strtok(NULL
, ", ");
653 RegCloseKey(hndKey2
);
666 idnsParseWIN32SearchList(", ");
675 /* get nameservers from the Windows 9X registry */
677 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
681 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
683 if (Result
== ERROR_SUCCESS
&& Size
) {
684 t
= (char *) xmalloc(Size
);
685 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
686 token
= strtok(t
, ", ");
689 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
690 idnsAddNameserver(token
);
692 token
= strtok(NULL
, ", ");
703 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
712 idnsStats(StoreEntry
* sentry
)
718 char buf
[MAX_IPSTRLEN
];
719 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
720 storeAppendPrintf(sentry
, "\nThe Queue:\n");
721 storeAppendPrintf(sentry
, " DELAY SINCE\n");
722 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
723 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
725 for (n
= lru_list
.head
; n
; n
= n
->next
) {
726 q
= (idns_query
*)n
->data
;
727 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
728 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
729 tvSubDsec(q
->start_t
, current_time
),
730 tvSubDsec(q
->sent_t
, current_time
),
731 (q
->permit_mdns
? 'M':' '),
735 if (Config
.dns
.packet_max
> 0)
736 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
738 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
740 storeAppendPrintf(sentry
, "\nNameservers:\n");
741 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
742 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
744 for (i
= 0; i
< nns
; ++i
) {
745 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
746 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
747 nameservers
[i
].nqueries
,
748 nameservers
[i
].nreplies
,
749 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
752 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
753 storeAppendPrintf(sentry
, "RCODE");
755 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
756 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
758 storeAppendPrintf(sentry
, " PROBLEM\n");
760 for (j
= 0; j
< MAX_RCODE
; ++j
) {
761 if (j
> 10 && j
< 16)
762 continue; // unassigned by IANA.
764 storeAppendPrintf(sentry
, "%5d", j
);
766 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
767 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
769 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
773 storeAppendPrintf(sentry
, "\nSearch list:\n");
775 for (i
=0; i
< npc
; ++i
)
776 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
778 storeAppendPrintf(sentry
, "\n");
783 idnsTickleQueue(void)
788 if (NULL
== lru_list
.tail
)
791 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
793 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
799 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, Comm::Flag flag
, int xerrno
, void *data
)
801 nsvc
* vc
= (nsvc
*)data
;
803 if (flag
== Comm::ERR_CLOSING
)
806 // XXX: irrelevant now that we have conn pointer?
807 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
810 if (flag
!= Comm::OK
|| size
<= 0) {
816 idnsDoSendQueryVC(vc
);
820 idnsDoSendQueryVC(nsvc
*vc
)
825 if (vc
->queue
->contentSize() == 0)
828 // if retrying after a TC UDP response, our close handler cb may be pending
829 if (fd_table
[vc
->conn
->fd
].closing())
832 MemBuf
*mb
= vc
->queue
;
834 vc
->queue
= new MemBuf
;
838 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
839 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
840 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
841 AsyncCall::Pointer nil
;
843 commSetConnTimeout(vc
->conn
, timeout
, nil
);
845 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
846 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
847 Comm::Write(vc
->conn
, mb
, call
);
853 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int xerrno
, void *data
)
855 nsvc
* vc
= (nsvc
*)data
;
857 if (status
!= Comm::OK
|| !conn
) {
858 char buf
[MAX_IPSTRLEN
] = "";
860 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
861 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
867 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
868 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
869 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
870 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
872 idnsDoSendQueryVC(vc
);
876 idnsVCClosed(const CommCloseCbParams
¶ms
)
878 nsvc
* vc
= (nsvc
*)params
.data
;
882 if (vc
->ns
< nns
) // XXX: dnsShutdown may have freed nameservers[]
883 nameservers
[vc
->ns
].vc
= NULL
;
890 nsvc
*vc
= cbdataAlloc(nsvc
);
892 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
893 nameservers
[nsv
].vc
= vc
;
895 vc
->queue
= new MemBuf
;
896 vc
->msg
= new MemBuf
;
899 Comm::ConnectionPointer conn
= new Comm::Connection();
901 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
902 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
904 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
906 if (conn
->remote
.isIPv4())
907 conn
->local
.setIPv4();
909 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
911 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
912 cs
->setHost("DNS TCP Socket");
917 idnsSendQueryVC(idns_query
* q
, int nsn
)
920 if (nameservers
[nsn
].vc
== NULL
)
923 nsvc
*vc
= nameservers
[nsn
].vc
;
926 char buf
[MAX_IPSTRLEN
];
927 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
934 short head
= htons(q
->sz
);
936 vc
->queue
->append((char *)&head
, 2);
938 vc
->queue
->append(q
->buf
, q
->sz
);
940 idnsDoSendQueryVC(vc
);
944 idnsSendQuery(idns_query
* q
)
946 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
947 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
952 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
956 assert(q
->lru
.next
== NULL
);
958 assert(q
->lru
.prev
== NULL
);
964 // only use mDNS resolvers for mDNS compatible queries
966 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
968 nsn
= q
->nsends
% nns
;
971 idnsSendQueryVC(q
, nsn
);
974 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
975 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
976 else if (DnsSocketA
>= 0)
977 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
982 q
->sent_t
= current_time
;
984 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
985 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
986 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
987 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
989 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
992 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
995 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
998 ++ nameservers
[nsn
].nqueries
;
999 q
->queue_t
= current_time
;
1000 dlinkAdd(q
, &q
->lru
, &lru_list
);
1006 idnsFromKnownNameserver(Ip::Address
const &from
)
1010 for (i
= 0; i
< nns
; ++i
) {
1011 if (nameservers
[i
].S
!= from
)
1014 if (nameservers
[i
].S
.port() != from
.port())
1024 idnsFindQuery(unsigned short id
)
1029 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1030 q
= (idns_query
*)n
->data
;
1032 if (q
->query_id
== id
)
1039 static unsigned short
1042 unsigned short id
= squid_random() & 0xFFFF;
1043 unsigned short first_id
= id
;
1045 while (idnsFindQuery(id
)) {
1048 if (id
== first_id
) {
1049 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1058 idnsCallback(idns_query
*q
, const char *error
)
1069 // If any of our subqueries are still pending then wait for them to complete before continuing
1070 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1077 rfc1035_message
*message
= q
->message
;
1082 while ( idns_query
*q2
= q
->slave
) {
1083 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1084 q
->slave
= q2
->slave
;
1087 // two sets of RR need merging
1088 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1089 if (Config
.dns
.v4_first
) {
1090 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1091 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1093 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1094 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1097 // HACK WARNING, the answer rr:s have been copied in-place to
1098 // result, do not free them here
1099 safe_free(message
->answer
);
1100 safe_free(q2
->message
->answer
);
1101 message
->answer
= result
;
1102 message
->ancount
+= q2
->message
->ancount
;
1104 // first response empty or failed, just use the second
1105 rfc1035MessageDestroy(&message
);
1106 message
= q2
->message
;
1112 rfc1035MessageDestroy(&q2
->message
);
1116 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1118 callback
= q
->callback
;
1120 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1122 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1123 callback(cbdata
, answers
, n
, error
);
1126 idns_query
*q2
= q
->queue
;
1127 q
->queue
= q2
->queue
;
1128 callback
= q2
->callback
;
1129 q2
->callback
= NULL
;
1131 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1132 callback(cbdata
, answers
, n
, error
);
1138 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1142 rfc1035MessageDestroy(&message
);
1147 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1150 rfc1035_message
*message
= NULL
;
1153 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1155 if (message
== NULL
) {
1156 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1160 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1162 q
= idnsFindQuery(message
->id
);
1165 debugs(78, 3, "idnsGrokReply: Late response");
1166 rfc1035MessageDestroy(&message
);
1170 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1171 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1172 rfc1035MessageDestroy(&message
);
1176 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1177 // TODO: actually gr the message right here.
1178 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1179 // this is overall better than force-feeding A response with AAAA an section later anyway.
1180 // AND allows us to merge AN+AR sections from both responses (one day)
1182 if (q
->edns_seen
>= 0) {
1183 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1184 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1185 // the altered NS was limiting the whole group.
1186 max_shared_edns
= q
->edns_seen
;
1187 // may be limited by one of the others still
1188 for (int i
= 0; i
< nns
; ++i
)
1189 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1191 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1192 // maybe reduce the global limit downwards to accomodate this NS
1193 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1195 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1196 max_shared_edns
= -1;
1200 dlinkDelete(&q
->lru
, &lru_list
);
1204 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1205 rfc1035MessageDestroy(&message
);
1212 // Strange: A TCP DNS response with the truncation bit (TC) set.
1213 // Return an error and cleanup; no point in trying TCP again.
1214 debugs(78, 3, HERE
<< "TCP DNS response");
1215 idnsCallback(q
, "Truncated TCP DNS response");
1221 idnsRcodeCount(n
, q
->attempt
);
1225 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1227 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1229 * RCODE 2 is "Server failure - The name server was
1230 * unable to process this query due to a problem with
1233 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1234 rfc1035MessageDestroy(&message
);
1239 // Do searchpath processing on the master A query only to keep
1240 // things simple. NXDOMAIN is authorative for the label, not
1242 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1243 assert(NULL
== message
->answer
);
1244 strcpy(q
->name
, q
->orig
);
1246 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1248 if (q
->domain
< npc
) {
1249 strcat(q
->name
, ".");
1250 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1251 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1257 rfc1035MessageDestroy(&message
);
1259 // cleanup slave AAAA query
1260 while (idns_query
*slave
= q
->slave
) {
1261 dlinkDelete(&slave
->lru
, &lru_list
);
1262 q
->slave
= slave
->slave
;
1263 rfc1035MessageDestroy(&slave
->message
);
1268 q
->query_id
= idnsQueryID();
1269 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1270 // see EDNS notes at top of file why this sends 0
1271 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1273 /* problem with query data -- query not sent */
1274 idnsCallback(q
, "Internal error");
1283 idnsSendSlaveAAAAQuery(q
);
1288 q
->message
= message
;
1292 idnsCallback(q
, NULL
);
1294 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1299 idnsRead(int fd
, void *data
)
1301 int *N
= &incoming_sockets_accepted
;
1303 int max
= INCOMING_DNS_MAX
;
1304 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1307 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1309 // Always keep reading. This stops (or at least makes harder) several
1310 // attacks on the DNS client.
1311 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1314 * two code lines after returning from comm_udprecvfrom()
1315 * something overwrites the memory behind the from parameter.
1316 * NO matter where in the stack declaration list above it is placed
1317 * The cause of this is still unknown, however copying the data appears
1318 * to allow it to be passed further without this erasure.
1320 Ip::Address bugbypass
;
1324 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1326 from
= bugbypass
; // BUG BYPASS. see notes above.
1332 if (ignoreErrno(errno
))
1336 /* Some Linux systems seem to set the FD for reading and then
1337 * return ECONNREFUSED when sendto() fails and generates an ICMP
1338 * port unreachable message. */
1339 /* or maybe an EHOSTUNREACH "No route to host" message */
1340 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1343 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1348 fd_bytes(fd
, len
, FD_READ
);
1353 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1355 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1356 int nsn
= idnsFromKnownNameserver(from
);
1359 ++ nameservers
[nsn
].nreplies
;
1362 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1363 // but after the ++ above to keep statistics right.
1365 continue; // Don't process replies if there is no pending query.
1367 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1368 static time_t last_warning
= 0;
1370 if (squid_curtime
- last_warning
> 60) {
1371 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1372 last_warning
= squid_curtime
;
1374 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1379 idnsGrokReply(rbuf
, len
, nsn
);
1384 idnsCheckQueue(void *unused
)
1387 dlink_node
*p
= NULL
;
1392 /* name servers went away; reconfiguring or shutting down */
1395 for (n
= lru_list
.tail
; n
; n
= p
) {
1398 q
= static_cast<idns_query
*>(n
->data
);
1400 /* Anything to process in the queue? */
1401 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1404 /* Query timer still running? */
1405 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1406 dlinkDelete(&q
->lru
, &lru_list
);
1407 q
->queue_t
= current_time
;
1408 dlinkAdd(q
, &q
->lru
, &lru_list
);
1412 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1413 " QID 0x" << std::hex
<< std::setfill('0') <<
1414 std::setw(4) << q
->query_id
<< ": timeout" );
1416 dlinkDelete(&q
->lru
, &lru_list
);
1419 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1422 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1423 " QID 0x" << std::hex
<< q
->query_id
<<
1424 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1425 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1428 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1430 idnsCallback(q
, "Timeout");
1438 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
1440 nsvc
* vc
= (nsvc
*)data
;
1442 if (flag
== Comm::ERR_CLOSING
)
1445 if (flag
!= Comm::OK
|| len
<= 0) {
1446 if (Comm::IsConnOpen(conn
))
1451 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1453 if (vc
->msg
->contentSize() < vc
->msglen
) {
1454 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1455 CommIoCbPtrFun(idnsReadVC
, vc
));
1456 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1460 assert(vc
->ns
< nns
);
1461 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1463 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1465 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1466 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1467 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1471 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
1473 nsvc
* vc
= (nsvc
*)data
;
1475 if (flag
== Comm::ERR_CLOSING
)
1478 if (flag
!= Comm::OK
|| len
<= 0) {
1479 if (Comm::IsConnOpen(conn
))
1484 vc
->read_msglen
+= len
;
1486 assert(vc
->read_msglen
<= 2);
1488 if (vc
->read_msglen
< 2) {
1489 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1490 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1491 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1495 vc
->read_msglen
= 0;
1497 vc
->msglen
= ntohs(vc
->msglen
);
1500 if (Comm::IsConnOpen(conn
))
1505 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1506 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1507 CommIoCbPtrFun(idnsReadVC
, vc
));
1508 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1512 * rcode < 0 indicates an error, rocde >= 0 indicates success
1515 idnsRcodeCount(int rcode
, int attempt
)
1522 if (rcode
< MAX_RCODE
)
1523 if (attempt
< MAX_ATTEMPT
)
1524 ++ RcodeMatrix
[rcode
][attempt
];
1527 /* ====================================================================== */
1530 idnsRegisterWithCacheManager(void)
1532 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1538 static int init
= 0;
1540 CBDATA_INIT_TYPE(nsvc
);
1541 CBDATA_INIT_TYPE(idns_query
);
1543 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1544 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1546 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1547 addrV6
= Config
.Addrs
.udp_outgoing
;
1549 addrV6
= Config
.Addrs
.udp_incoming
;
1551 Ip::Address addrV4
= addrV6
;
1554 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1555 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1556 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1563 if (addrV4
.isIPv4()) {
1564 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1565 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1572 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1573 fatal("Could not create a DNS socket");
1575 /* Ouch... we can't call functions using debug from a debug
1576 * statement. Doing so messes up the internal Debug::level
1578 if (DnsSocketB
>= 0) {
1579 comm_local_port(DnsSocketB
);
1580 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1581 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1583 if (DnsSocketA
>= 0) {
1584 comm_local_port(DnsSocketA
);
1585 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1586 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1591 idnsAddMDNSNameservers();
1592 bool nsFound
= idnsParseNameservers();
1593 #if !_SQUID_WINDOWS_
1596 nsFound
= idnsParseResolvConf();
1601 nsFound
= idnsParseWIN32Registry();
1605 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1607 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1609 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1612 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1614 idnsAddNameserver("::1");
1615 idnsAddNameserver("127.0.0.1");
1619 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1620 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1621 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1625 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1626 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1627 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1628 max_shared_edns
= -1; // disable if we might receive random replies.
1632 idnsRegisterWithCacheManager();
1638 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1641 if (DnsSocketA
>= 0 ) {
1642 comm_close(DnsSocketA
);
1646 if (DnsSocketB
>= 0 ) {
1647 comm_close(DnsSocketB
);
1651 for (int i
= 0; i
< nns
; ++i
) {
1652 if (nsvc
*vc
= nameservers
[i
].vc
) {
1653 if (Comm::IsConnOpen(vc
->conn
))
1658 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1659 idnsFreeNameservers();
1660 idnsFreeSearchpath();
1664 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1668 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1673 q
= cbdataAlloc(idns_query
);
1674 // idns_query is POD so no constructors are called after allocation
1675 q
->xact_id
.change();
1676 // no query_id on this instance.
1678 q
->callback
= callback
;
1680 q
->callback_data
= cbdataReference(data
);
1682 q
->queue
= old
->queue
;
1690 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1692 q
->start_t
= current_time
;
1693 q
->callback
= callback
;
1694 q
->callback_data
= cbdataReference(data
);
1696 q
->hash
.key
= q
->orig
;
1697 hash_join(idns_lookup_hash
, &q
->hash
);
1703 idnsSendSlaveAAAAQuery(idns_query
*master
)
1705 idns_query
*q
= cbdataAlloc(idns_query
);
1706 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1707 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1709 q
->query_id
= idnsQueryID();
1710 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1711 q
->start_t
= master
->start_t
;
1712 q
->slave
= master
->slave
;
1714 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1715 ", id = 0x" << std::hex
<< q
->query_id
);
1726 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1728 size_t nameLength
= strlen(name
);
1730 // Prevent buffer overflow on q->name
1731 if (nameLength
> NS_MAXDNAME
) {
1732 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1733 callback(data
, NULL
, 0, "Internal error");
1737 if (idnsCachedLookup(name
, callback
, data
))
1740 idns_query
*q
= cbdataAlloc(idns_query
);
1741 // idns_query is POD so no constructors are called after allocation
1742 q
->xact_id
.change();
1743 q
->query_id
= idnsQueryID();
1746 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1750 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1751 q
->do_searchpath
= 1;
1753 q
->do_searchpath
= 0;
1756 strcpy(q
->orig
, name
);
1757 strcpy(q
->name
, q
->orig
);
1759 if (q
->do_searchpath
&& nd
< ndots
) {
1761 strcat(q
->name
, ".");
1762 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1763 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1766 // see EDNS notes at top of file why this sends 0
1767 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1770 /* problem with query data -- query not sent */
1771 callback(data
, NULL
, 0, "Internal error");
1776 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1777 ", id = 0x" << std::hex
<< q
->query_id
);
1780 idnsStartQuery(q
, callback
, data
);
1783 idnsSendSlaveAAAAQuery(q
);
1788 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1792 char ip
[MAX_IPSTRLEN
];
1794 addr
.toStr(ip
,MAX_IPSTRLEN
);
1796 q
= cbdataAlloc(idns_query
);
1798 // idns_query is POD so no constructors are called after allocation
1799 q
->xact_id
.change();
1800 q
->query_id
= idnsQueryID();
1802 if (addr
.isIPv6()) {
1803 struct in6_addr addr6
;
1804 addr
.getInAddr(addr6
);
1805 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1807 struct in_addr addr4
;
1808 addr
.getInAddr(addr4
);
1809 // see EDNS notes at top of file why this sends 0
1810 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1814 /* problem with query data -- query not sent */
1815 callback(data
, NULL
, 0, "Internal error");
1820 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1825 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1826 ", id = 0x" << std::hex
<< q
->query_id
);
1828 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1829 idnsStartQuery(q
, callback
, data
);
1834 * The function to return the DNS via SNMP
1837 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1840 variable_list
*Answer
= NULL
;
1842 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1843 *ErrP
= SNMP_ERR_NOERROR
;
1845 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1849 for (i
= 0; i
< nns
; ++i
)
1850 n
+= nameservers
[i
].nqueries
;
1852 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1859 for (i
= 0; i
< nns
; ++i
)
1860 n
+= nameservers
[i
].nreplies
;
1862 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1869 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1876 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1884 #endif /*SQUID_SNMP */