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;
200 static int npc_alloc
= 0;
201 static int ndots
= 1;
202 static dlink_list lru_list
;
203 static int event_queued
= 0;
204 static hash_table
*idns_lookup_hash
= NULL
;
210 * EDNS as specified may be sent as an additional record for any request.
211 * early testing has revealed that it works on common devices, but cannot
212 * be reliably used on any A or PTR requet done for IPv4 addresses.
214 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
217 * Squid is optimized to generate one packet and re-send it to all NS
218 * due to this we cannot customize the EDNS size per NS.
220 * As such we take the configuration option value as fixed.
223 * This may not be worth doing, but if/when additional-records are parsed
224 * we will be able to recover the OPT value specific to any one NS and
225 * cache it. Effectively automating the tuning of EDNS advertised to the
226 * size our active NS are capable.
227 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
228 * Responses from the configured NS may cause this to be raised or turned off.
230 #if WHEN_EDNS_RESPONSES_ARE_PARSED
231 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
234 static OBJH idnsStats
;
235 static void idnsAddNameserver(const char *buf
);
236 static void idnsAddMDNSNameservers();
237 static void idnsAddPathComponent(const char *buf
);
238 static void idnsFreeNameservers(void);
239 static void idnsFreeSearchpath(void);
240 static bool idnsParseNameservers(void);
242 static bool idnsParseResolvConf(void);
245 static bool idnsParseWIN32Registry(void);
246 static void idnsParseWIN32SearchList(const char *);
248 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
249 static void idnsSendQuery(idns_query
* q
);
250 static IOCB idnsReadVCHeader
;
251 static void idnsDoSendQueryVC(nsvc
*vc
);
252 static CNCB idnsInitVCConnected
;
253 static IOCB idnsReadVC
;
254 static IOCB idnsSentQueryVC
;
256 static int idnsFromKnownNameserver(Ip::Address
const &from
);
257 static idns_query
*idnsFindQuery(unsigned short id
);
258 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
260 static EVH idnsCheckQueue
;
261 static void idnsTickleQueue(void);
262 static void idnsRcodeCount(int, int);
263 static CLCB idnsVCClosed
;
264 static unsigned short idnsQueryID(void);
265 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
268 idnsCheckMDNS(idns_query
*q
)
270 size_t slen
= strlen(q
->name
);
271 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
272 q
->permit_mdns
= true;
277 idnsAddMDNSNameservers()
279 #define MDNS_RESOLVER_COUNT 2
281 // mDNS resolver addresses are explicit multicast group IPs
282 idnsAddNameserver("FF02::FB");
283 nameservers
[nns
-1].S
.port(5353);
284 nameservers
[nns
-1].mDNSResolver
= true;
286 idnsAddNameserver("224.0.0.251");
287 nameservers
[nns
-1].S
.port(5353);
288 nameservers
[nns
-1].mDNSResolver
= true;
292 idnsAddNameserver(const char *buf
)
297 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
302 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
304 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
307 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
308 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
312 if (nns
== nns_alloc
) {
313 int oldalloc
= nns_alloc
;
314 ns
*oldptr
= nameservers
;
321 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
323 if (oldptr
&& oldalloc
)
324 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
330 assert(nns
< nns_alloc
);
331 A
.port(NS_DEFAULTPORT
);
332 nameservers
[nns
].S
= A
;
333 #if WHEN_EDNS_RESPONSES_ARE_PARSED
334 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
335 // TODO generate a test packet to probe this NS from EDNS size and ability.
337 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
342 idnsAddPathComponent(const char *buf
)
344 if (npc
== npc_alloc
) {
345 int oldalloc
= npc_alloc
;
346 sp
*oldptr
= searchpath
;
353 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
355 if (oldptr
&& oldalloc
)
356 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
362 assert(npc
< npc_alloc
);
363 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
364 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
365 Tolower(searchpath
[npc
].domain
);
366 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
371 idnsFreeNameservers(void)
373 safe_free(nameservers
);
378 idnsFreeSearchpath(void)
380 safe_free(searchpath
);
385 idnsParseNameservers(void)
388 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
389 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
390 idnsAddNameserver(w
->key
);
398 idnsParseResolvConf(void)
401 char buf
[RESOLV_BUFSZ
];
404 fp
= fopen(_PATH_RESCONF
, "r");
407 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
412 setmode(fileno(fp
), O_TEXT
);
415 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
416 t
= strtok(buf
, w_space
);
420 } else if (strcmp(t
, "nameserver") == 0) {
421 t
= strtok(NULL
, w_space
);
426 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
428 idnsAddNameserver(t
);
430 } else if (strcmp(t
, "domain") == 0) {
431 idnsFreeSearchpath();
432 t
= strtok(NULL
, w_space
);
437 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
439 idnsAddPathComponent(t
);
440 } else if (strcmp(t
, "search") == 0) {
441 idnsFreeSearchpath();
443 t
= strtok(NULL
, w_space
);
448 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
450 idnsAddPathComponent(t
);
452 } else if (strcmp(t
, "options") == 0) {
454 t
= strtok(NULL
, w_space
);
459 if (strncmp(t
, "ndots:", 6) == 0) {
465 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
470 if (npc
== 0 && (t
= getMyHostname())) {
473 idnsAddPathComponent(t
+1);
484 idnsParseWIN32SearchList(const char * Separator
)
490 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
494 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
496 if (Result
== ERROR_SUCCESS
&& Size
) {
497 t
= (char *) xmalloc(Size
);
498 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
499 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
500 idnsAddPathComponent(t
);
503 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
505 if (Result
== ERROR_SUCCESS
&& Size
) {
506 t
= (char *) xmalloc(Size
);
507 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
508 token
= strtok(t
, Separator
);
511 idnsAddPathComponent(token
);
512 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
513 token
= strtok(NULL
, Separator
);
520 if (npc
== 0 && (t
= (char *) getMyHostname())) {
523 idnsAddPathComponent(t
+ 1);
528 idnsParseWIN32Registry(void)
532 HKEY hndKey
, hndKey2
;
535 switch (WIN32_OS_version
) {
538 /* get nameservers from the Windows NT registry */
540 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
544 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
546 if (Result
== ERROR_SUCCESS
&& Size
) {
547 t
= (char *) xmalloc(Size
);
548 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
549 token
= strtok(t
, ", ");
552 idnsAddNameserver(token
);
554 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
555 token
= strtok(NULL
, ",");
560 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
562 if (Result
== ERROR_SUCCESS
&& Size
) {
563 t
= (char *) xmalloc(Size
);
564 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
565 token
= strtok(t
, ", ");
568 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
569 idnsAddNameserver(token
);
571 token
= strtok(NULL
, ", ");
579 idnsParseWIN32SearchList(" ");
592 /* get nameservers from the Windows 2000 registry */
593 /* search all interfaces for DNS server addresses */
595 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
597 DWORD MaxSubkeyLen
, InterfacesCount
;
599 FILETIME ftLastWriteTime
;
601 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
602 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
603 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
606 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
608 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
609 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
610 strcat(newkeyname
, "\\");
611 strcat(newkeyname
, keyname
);
612 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
616 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
617 if (Result
== ERROR_SUCCESS
&& Size
) {
618 t
= (char *) xmalloc(Size
);
619 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
620 token
= strtok(t
, ", ");
622 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
623 idnsAddNameserver(token
);
625 token
= strtok(NULL
, ", ");
630 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
631 if (Result
== ERROR_SUCCESS
&& Size
) {
632 t
= (char *) xmalloc(Size
);
633 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
634 token
= strtok(t
, ", ");
636 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
637 idnsAddNameserver(token
);
639 token
= strtok(NULL
, ", ");
645 RegCloseKey(hndKey2
);
658 idnsParseWIN32SearchList(", ");
667 /* get nameservers from the Windows 9X registry */
669 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
673 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
675 if (Result
== ERROR_SUCCESS
&& Size
) {
676 t
= (char *) xmalloc(Size
);
677 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
678 token
= strtok(t
, ", ");
681 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
682 idnsAddNameserver(token
);
684 token
= strtok(NULL
, ", ");
695 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
704 idnsStats(StoreEntry
* sentry
)
710 char buf
[MAX_IPSTRLEN
];
711 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
712 storeAppendPrintf(sentry
, "\nThe Queue:\n");
713 storeAppendPrintf(sentry
, " DELAY SINCE\n");
714 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND\n");
715 storeAppendPrintf(sentry
, "------ ---- ----- ---------- ---------\n");
717 for (n
= lru_list
.head
; n
; n
= n
->next
) {
718 q
= (idns_query
*)n
->data
;
719 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f\n",
720 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
721 tvSubDsec(q
->start_t
, current_time
),
722 tvSubDsec(q
->sent_t
, current_time
));
725 if (Config
.dns
.packet_max
> 0)
726 storeAppendPrintf(sentry
, "DNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
728 storeAppendPrintf(sentry
, "DNS jumbo-grams: not working\n");
730 storeAppendPrintf(sentry
, "\nNameservers:\n");
731 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
732 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
734 for (i
= 0; i
< nns
; ++i
) {
735 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
736 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
737 nameservers
[i
].nqueries
,
738 nameservers
[i
].nreplies
,
739 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
742 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
743 storeAppendPrintf(sentry
, "RCODE");
745 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
746 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
748 storeAppendPrintf(sentry
, " PROBLEM\n");
750 for (j
= 0; j
< MAX_RCODE
; ++j
) {
751 if (j
> 10 && j
< 16)
752 continue; // unassigned by IANA.
754 storeAppendPrintf(sentry
, "%5d", j
);
756 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
757 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
759 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
763 storeAppendPrintf(sentry
, "\nSearch list:\n");
765 for (i
=0; i
< npc
; ++i
)
766 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
768 storeAppendPrintf(sentry
, "\n");
773 idnsTickleQueue(void)
778 if (NULL
== lru_list
.tail
)
781 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
783 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
789 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
791 nsvc
* vc
= (nsvc
*)data
;
793 if (flag
== COMM_ERR_CLOSING
)
796 // XXX: irrelevant now that we have conn pointer?
797 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
800 if (flag
!= COMM_OK
|| size
<= 0) {
806 idnsDoSendQueryVC(vc
);
810 idnsDoSendQueryVC(nsvc
*vc
)
815 if (vc
->queue
->contentSize() == 0)
818 // if retrying after a TC UDP response, our close handler cb may be pending
819 if (fd_table
[vc
->conn
->fd
].closing())
822 MemBuf
*mb
= vc
->queue
;
824 vc
->queue
= new MemBuf
;
828 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
829 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
830 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
831 AsyncCall::Pointer nil
;
833 commSetConnTimeout(vc
->conn
, timeout
, nil
);
835 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
836 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
837 Comm::Write(vc
->conn
, mb
, call
);
843 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
845 nsvc
* vc
= (nsvc
*)data
;
847 if (status
!= COMM_OK
|| !conn
) {
848 char buf
[MAX_IPSTRLEN
] = "";
850 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
851 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
857 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
858 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
859 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
860 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
862 idnsDoSendQueryVC(vc
);
866 idnsVCClosed(const CommCloseCbParams
¶ms
)
868 nsvc
* vc
= (nsvc
*)params
.data
;
872 if (vc
->ns
< nns
) // XXX: dnsShutdown may have freed nameservers[]
873 nameservers
[vc
->ns
].vc
= NULL
;
880 nsvc
*vc
= cbdataAlloc(nsvc
);
882 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
883 nameservers
[nsv
].vc
= vc
;
885 vc
->queue
= new MemBuf
;
886 vc
->msg
= new MemBuf
;
889 Comm::ConnectionPointer conn
= new Comm::Connection();
891 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
892 conn
->local
= Config
.Addrs
.udp_outgoing
;
894 conn
->local
= Config
.Addrs
.udp_incoming
;
896 conn
->remote
= nameservers
[nsv
].S
;
898 if (conn
->remote
.isIPv4()) {
899 conn
->local
.setIPv4();
902 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
904 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
905 cs
->setHost("DNS TCP Socket");
910 idnsSendQueryVC(idns_query
* q
, int nsn
)
913 if (nameservers
[nsn
].vc
== NULL
)
916 nsvc
*vc
= nameservers
[nsn
].vc
;
919 char buf
[MAX_IPSTRLEN
];
920 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
927 short head
= htons(q
->sz
);
929 vc
->queue
->append((char *)&head
, 2);
931 vc
->queue
->append(q
->buf
, q
->sz
);
933 idnsDoSendQueryVC(vc
);
937 idnsSendQuery(idns_query
* q
)
939 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
940 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
945 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
949 assert(q
->lru
.next
== NULL
);
951 assert(q
->lru
.prev
== NULL
);
957 // only use mDNS resolvers for mDNS compatible queries
959 nsn
= MDNS_RESOLVER_COUNT
+ q
->nsends
% (nns
-MDNS_RESOLVER_COUNT
);
961 nsn
= q
->nsends
% nns
;
964 idnsSendQueryVC(q
, nsn
);
967 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
968 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
969 else if (DnsSocketA
>= 0)
970 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
975 q
->sent_t
= current_time
;
977 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
978 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
979 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
980 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
982 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
985 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
988 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
991 ++ nameservers
[nsn
].nqueries
;
992 q
->queue_t
= current_time
;
993 dlinkAdd(q
, &q
->lru
, &lru_list
);
999 idnsFromKnownNameserver(Ip::Address
const &from
)
1003 for (i
= 0; i
< nns
; ++i
) {
1004 if (nameservers
[i
].S
!= from
)
1007 if (nameservers
[i
].S
.port() != from
.port())
1017 idnsFindQuery(unsigned short id
)
1022 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1023 q
= (idns_query
*)n
->data
;
1025 if (q
->query_id
== id
)
1032 static unsigned short
1035 unsigned short id
= squid_random() & 0xFFFF;
1036 unsigned short first_id
= id
;
1038 while (idnsFindQuery(id
)) {
1041 if (id
== first_id
) {
1042 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1051 idnsCallback(idns_query
*q
, const char *error
)
1062 // If any of our subqueries are still pending then wait for them to complete before continuing
1063 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1070 rfc1035_message
*message
= q
->message
;
1075 while ( idns_query
*q2
= q
->slave
) {
1076 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1077 q
->slave
= q2
->slave
;
1080 // two sets of RR need merging
1081 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1082 if (Config
.dns
.v4_first
) {
1083 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1084 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1086 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1087 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1090 // HACK WARNING, the answer rr:s have been copied in-place to
1091 // result, do not free them here
1092 safe_free(message
->answer
);
1093 safe_free(q2
->message
->answer
);
1094 message
->answer
= result
;
1095 message
->ancount
+= q2
->message
->ancount
;
1097 // first response empty or failed, just use the second
1098 rfc1035MessageDestroy(&message
);
1099 message
= q2
->message
;
1105 rfc1035MessageDestroy(&q2
->message
);
1109 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1111 callback
= q
->callback
;
1113 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1115 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1116 callback(cbdata
, answers
, n
, error
);
1119 idns_query
*q2
= q
->queue
;
1120 q
->queue
= q2
->queue
;
1121 callback
= q2
->callback
;
1122 q2
->callback
= NULL
;
1124 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1125 callback(cbdata
, answers
, n
, error
);
1131 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1135 rfc1035MessageDestroy(&message
);
1140 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1143 rfc1035_message
*message
= NULL
;
1146 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1148 if (message
== NULL
) {
1149 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1153 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1155 q
= idnsFindQuery(message
->id
);
1158 debugs(78, 3, "idnsGrokReply: Late response");
1159 rfc1035MessageDestroy(&message
);
1163 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1164 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1165 rfc1035MessageDestroy(&message
);
1169 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1170 // TODO: actually gr the message right here.
1171 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1172 // this is overall better than force-feeding A response with AAAA an section later anyway.
1173 // AND allows us to merge AN+AR sections from both responses (one day)
1175 if (q
->edns_seen
>= 0) {
1176 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1177 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1178 // the altered NS was limiting the whole group.
1179 max_shared_edns
= q
->edns_seen
;
1180 // may be limited by one of the others still
1181 for (int i
= 0; i
< nns
; ++i
)
1182 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1184 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1185 // maybe reduce the global limit downwards to accomodate this NS
1186 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1188 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1189 max_shared_edns
= -1;
1193 dlinkDelete(&q
->lru
, &lru_list
);
1197 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1198 rfc1035MessageDestroy(&message
);
1205 // Strange: A TCP DNS response with the truncation bit (TC) set.
1206 // Return an error and cleanup; no point in trying TCP again.
1207 debugs(78, 3, HERE
<< "TCP DNS response");
1208 idnsCallback(q
, "Truncated TCP DNS response");
1214 idnsRcodeCount(n
, q
->attempt
);
1218 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1220 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1222 * RCODE 2 is "Server failure - The name server was
1223 * unable to process this query due to a problem with
1226 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1227 rfc1035MessageDestroy(&message
);
1232 // Do searchpath processing on the master A query only to keep
1233 // things simple. NXDOMAIN is authorative for the label, not
1235 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1236 assert(NULL
== message
->answer
);
1237 strcpy(q
->name
, q
->orig
);
1239 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1241 if (q
->domain
< npc
) {
1242 strcat(q
->name
, ".");
1243 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1244 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1250 rfc1035MessageDestroy(&message
);
1252 // cleanup slave AAAA query
1253 while (idns_query
*slave
= q
->slave
) {
1254 dlinkDelete(&slave
->lru
, &lru_list
);
1255 q
->slave
= slave
->slave
;
1256 rfc1035MessageDestroy(&slave
->message
);
1261 q
->query_id
= idnsQueryID();
1262 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1263 // see EDNS notes at top of file why this sends 0
1264 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1266 /* problem with query data -- query not sent */
1267 idnsCallback(q
, "Internal error");
1276 idnsSendSlaveAAAAQuery(q
);
1281 q
->message
= message
;
1285 idnsCallback(q
, NULL
);
1287 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1292 idnsRead(int fd
, void *data
)
1294 int *N
= &incoming_sockets_accepted
;
1296 int max
= INCOMING_DNS_MAX
;
1297 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1300 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1302 // Always keep reading. This stops (or at least makes harder) several
1303 // attacks on the DNS client.
1304 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1307 * two code lines after returning from comm_udprecvfrom()
1308 * something overwrites the memory behind the from parameter.
1309 * NO matter where in the stack declaration list above it is placed
1310 * The cause of this is still unknown, however copying the data appears
1311 * to allow it to be passed further without this erasure.
1313 Ip::Address bugbypass
;
1317 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1319 from
= bugbypass
; // BUG BYPASS. see notes above.
1325 if (ignoreErrno(errno
))
1329 /* Some Linux systems seem to set the FD for reading and then
1330 * return ECONNREFUSED when sendto() fails and generates an ICMP
1331 * port unreachable message. */
1332 /* or maybe an EHOSTUNREACH "No route to host" message */
1333 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1336 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1341 fd_bytes(fd
, len
, FD_READ
);
1346 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1348 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1349 int nsn
= idnsFromKnownNameserver(from
);
1352 ++ nameservers
[nsn
].nreplies
;
1355 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1356 // but after the ++ above to keep statistics right.
1358 continue; // Don't process replies if there is no pending query.
1360 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1361 static time_t last_warning
= 0;
1363 if (squid_curtime
- last_warning
> 60) {
1364 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1365 last_warning
= squid_curtime
;
1367 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1372 idnsGrokReply(rbuf
, len
, nsn
);
1377 idnsCheckQueue(void *unused
)
1380 dlink_node
*p
= NULL
;
1385 /* name servers went away; reconfiguring or shutting down */
1388 for (n
= lru_list
.tail
; n
; n
= p
) {
1391 q
= static_cast<idns_query
*>(n
->data
);
1393 /* Anything to process in the queue? */
1394 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1397 /* Query timer still running? */
1398 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1399 dlinkDelete(&q
->lru
, &lru_list
);
1400 q
->queue_t
= current_time
;
1401 dlinkAdd(q
, &q
->lru
, &lru_list
);
1405 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1406 " QID 0x" << std::hex
<< std::setfill('0') <<
1407 std::setw(4) << q
->query_id
<< ": timeout" );
1409 dlinkDelete(&q
->lru
, &lru_list
);
1412 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1415 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1416 " QID 0x" << std::hex
<< q
->query_id
<<
1417 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1418 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1421 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1423 idnsCallback(q
, "Timeout");
1431 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1433 nsvc
* vc
= (nsvc
*)data
;
1435 if (flag
== COMM_ERR_CLOSING
)
1438 if (flag
!= COMM_OK
|| len
<= 0) {
1439 if (Comm::IsConnOpen(conn
))
1444 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1446 if (vc
->msg
->contentSize() < vc
->msglen
) {
1447 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1448 CommIoCbPtrFun(idnsReadVC
, vc
));
1449 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1453 assert(vc
->ns
< nns
);
1454 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1456 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1458 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1459 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1460 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1464 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1466 nsvc
* vc
= (nsvc
*)data
;
1468 if (flag
== COMM_ERR_CLOSING
)
1471 if (flag
!= COMM_OK
|| len
<= 0) {
1472 if (Comm::IsConnOpen(conn
))
1477 vc
->read_msglen
+= len
;
1479 assert(vc
->read_msglen
<= 2);
1481 if (vc
->read_msglen
< 2) {
1482 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1483 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1484 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1488 vc
->read_msglen
= 0;
1490 vc
->msglen
= ntohs(vc
->msglen
);
1492 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1493 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1494 CommIoCbPtrFun(idnsReadVC
, vc
));
1495 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1499 * rcode < 0 indicates an error, rocde >= 0 indicates success
1502 idnsRcodeCount(int rcode
, int attempt
)
1509 if (rcode
< MAX_RCODE
)
1510 if (attempt
< MAX_ATTEMPT
)
1511 ++ RcodeMatrix
[rcode
][attempt
];
1514 /* ====================================================================== */
1517 idnsRegisterWithCacheManager(void)
1519 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1525 static int init
= 0;
1527 CBDATA_INIT_TYPE(nsvc
);
1528 CBDATA_INIT_TYPE(idns_query
);
1530 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1531 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1533 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1534 addrV6
= Config
.Addrs
.udp_outgoing
;
1536 addrV6
= Config
.Addrs
.udp_incoming
;
1538 Ip::Address addrV4
= addrV6
;
1541 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1542 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1543 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1550 if (addrV4
.isIPv4()) {
1551 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1552 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1559 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1560 fatal("Could not create a DNS socket");
1562 /* Ouch... we can't call functions using debug from a debug
1563 * statement. Doing so messes up the internal Debug::level
1565 if (DnsSocketB
>= 0) {
1566 comm_local_port(DnsSocketB
);
1567 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1568 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1570 if (DnsSocketA
>= 0) {
1571 comm_local_port(DnsSocketA
);
1572 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1573 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1578 idnsAddMDNSNameservers();
1579 bool nsFound
= idnsParseNameservers();
1580 #if !_SQUID_WINDOWS_
1583 nsFound
= idnsParseResolvConf();
1588 nsFound
= idnsParseWIN32Registry();
1592 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1594 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1596 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1599 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1600 idnsAddNameserver("127.0.0.1");
1604 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1605 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1606 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1610 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1611 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1612 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1613 max_shared_edns
= -1; // disable if we might receive random replies.
1617 idnsRegisterWithCacheManager();
1623 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1626 if (DnsSocketA
>= 0 ) {
1627 comm_close(DnsSocketA
);
1631 if (DnsSocketB
>= 0 ) {
1632 comm_close(DnsSocketB
);
1636 for (int i
= 0; i
< nns
; ++i
) {
1637 if (nsvc
*vc
= nameservers
[i
].vc
) {
1638 if (Comm::IsConnOpen(vc
->conn
))
1643 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1644 idnsFreeNameservers();
1645 idnsFreeSearchpath();
1649 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1653 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1658 q
= cbdataAlloc(idns_query
);
1659 // idns_query is POD so no constructors are called after allocation
1660 q
->xact_id
.change();
1661 // no query_id on this instance.
1663 q
->callback
= callback
;
1665 q
->callback_data
= cbdataReference(data
);
1667 q
->queue
= old
->queue
;
1675 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1677 q
->start_t
= current_time
;
1678 q
->callback
= callback
;
1679 q
->callback_data
= cbdataReference(data
);
1681 q
->hash
.key
= q
->orig
;
1682 hash_join(idns_lookup_hash
, &q
->hash
);
1688 idnsSendSlaveAAAAQuery(idns_query
*master
)
1690 idns_query
*q
= cbdataAlloc(idns_query
);
1691 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1692 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1694 q
->query_id
= idnsQueryID();
1695 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1696 q
->start_t
= master
->start_t
;
1697 q
->slave
= master
->slave
;
1699 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1700 ", id = 0x" << std::hex
<< q
->query_id
);
1711 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1717 if (idnsCachedLookup(name
, callback
, data
))
1720 q
= cbdataAlloc(idns_query
);
1721 // idns_query is POD so no constructors are called after allocation
1722 q
->xact_id
.change();
1723 q
->query_id
= idnsQueryID();
1725 for (i
= 0; i
< strlen(name
); ++i
)
1729 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[strlen(name
)-1] != '.') {
1730 q
->do_searchpath
= 1;
1732 q
->do_searchpath
= 0;
1735 strcpy(q
->orig
, name
);
1736 strcpy(q
->name
, q
->orig
);
1738 if (q
->do_searchpath
&& nd
< ndots
) {
1740 strcat(q
->name
, ".");
1741 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1742 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1745 // see EDNS notes at top of file why this sends 0
1746 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1749 /* problem with query data -- query not sent */
1750 callback(data
, NULL
, 0, "Internal error");
1755 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1756 ", id = 0x" << std::hex
<< q
->query_id
);
1759 idnsStartQuery(q
, callback
, data
);
1762 idnsSendSlaveAAAAQuery(q
);
1767 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1771 char ip
[MAX_IPSTRLEN
];
1773 addr
.toStr(ip
,MAX_IPSTRLEN
);
1775 q
= cbdataAlloc(idns_query
);
1777 // idns_query is POD so no constructors are called after allocation
1778 q
->xact_id
.change();
1779 q
->query_id
= idnsQueryID();
1781 if (addr
.isIPv6()) {
1782 struct in6_addr addr6
;
1783 addr
.getInAddr(addr6
);
1784 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1786 struct in_addr addr4
;
1787 addr
.getInAddr(addr4
);
1788 // see EDNS notes at top of file why this sends 0
1789 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1793 /* problem with query data -- query not sent */
1794 callback(data
, NULL
, 0, "Internal error");
1799 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1804 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1805 ", id = 0x" << std::hex
<< q
->query_id
);
1807 q
->permit_mdns
= true;
1808 idnsStartQuery(q
, callback
, data
);
1813 * The function to return the DNS via SNMP
1816 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1819 variable_list
*Answer
= NULL
;
1821 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1822 *ErrP
= SNMP_ERR_NOERROR
;
1824 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1828 for (i
= 0; i
< nns
; ++i
)
1829 n
+= nameservers
[i
].nqueries
;
1831 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1838 for (i
= 0; i
< nns
; ++i
)
1839 n
+= nameservers
[i
].nreplies
;
1841 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1848 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1855 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1863 #endif /*SQUID_SNMP */
1864 #endif /* USE_DNSHELPER */