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 size_t slen
= strlen(q
->name
);
272 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
273 q
->permit_mdns
= true;
278 idnsAddMDNSNameservers()
282 // mDNS resolver addresses are explicit multicast group IPs
283 if (Ip::EnableIpv6
) {
284 idnsAddNameserver("FF02::FB");
285 nameservers
[nns
-1].S
.port(5353);
286 nameservers
[nns
-1].mDNSResolver
= true;
290 idnsAddNameserver("224.0.0.251");
291 nameservers
[nns
-1].S
.port(5353);
292 nameservers
[nns
-1].mDNSResolver
= true;
298 idnsAddNameserver(const char *buf
)
303 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
308 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
310 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
313 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
314 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
318 if (nns
== nns_alloc
) {
319 int oldalloc
= nns_alloc
;
320 ns
*oldptr
= nameservers
;
327 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
329 if (oldptr
&& oldalloc
)
330 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
336 assert(nns
< nns_alloc
);
337 A
.port(NS_DEFAULTPORT
);
338 nameservers
[nns
].S
= A
;
339 #if WHEN_EDNS_RESPONSES_ARE_PARSED
340 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
341 // TODO generate a test packet to probe this NS from EDNS size and ability.
343 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
348 idnsAddPathComponent(const char *buf
)
350 if (npc
== npc_alloc
) {
351 int oldalloc
= npc_alloc
;
352 sp
*oldptr
= searchpath
;
359 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
361 if (oldptr
&& oldalloc
)
362 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
368 assert(npc
< npc_alloc
);
369 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
370 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
371 Tolower(searchpath
[npc
].domain
);
372 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
377 idnsFreeNameservers(void)
379 safe_free(nameservers
);
384 idnsFreeSearchpath(void)
386 safe_free(searchpath
);
391 idnsParseNameservers(void)
394 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
395 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
396 idnsAddNameserver(w
->key
);
404 idnsParseResolvConf(void)
407 char buf
[RESOLV_BUFSZ
];
410 fp
= fopen(_PATH_RESCONF
, "r");
413 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
418 setmode(fileno(fp
), O_TEXT
);
421 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
422 t
= strtok(buf
, w_space
);
426 } else if (strcmp(t
, "nameserver") == 0) {
427 t
= strtok(NULL
, w_space
);
432 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
434 idnsAddNameserver(t
);
436 } else if (strcmp(t
, "domain") == 0) {
437 idnsFreeSearchpath();
438 t
= strtok(NULL
, w_space
);
443 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
445 idnsAddPathComponent(t
);
446 } else if (strcmp(t
, "search") == 0) {
447 idnsFreeSearchpath();
449 t
= strtok(NULL
, w_space
);
454 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
456 idnsAddPathComponent(t
);
458 } else if (strcmp(t
, "options") == 0) {
460 t
= strtok(NULL
, w_space
);
465 if (strncmp(t
, "ndots:", 6) == 0) {
471 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
476 if (npc
== 0 && (t
= getMyHostname())) {
479 idnsAddPathComponent(t
+1);
490 idnsParseWIN32SearchList(const char * Separator
)
496 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
500 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
502 if (Result
== ERROR_SUCCESS
&& Size
) {
503 t
= (char *) xmalloc(Size
);
504 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
505 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
506 idnsAddPathComponent(t
);
509 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
511 if (Result
== ERROR_SUCCESS
&& Size
) {
512 t
= (char *) xmalloc(Size
);
513 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
514 token
= strtok(t
, Separator
);
517 idnsAddPathComponent(token
);
518 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
519 token
= strtok(NULL
, Separator
);
526 if (npc
== 0 && (t
= (char *) getMyHostname())) {
529 idnsAddPathComponent(t
+ 1);
534 idnsParseWIN32Registry(void)
538 HKEY hndKey
, hndKey2
;
541 switch (WIN32_OS_version
) {
544 /* get nameservers from the Windows NT registry */
546 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
550 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
552 if (Result
== ERROR_SUCCESS
&& Size
) {
553 t
= (char *) xmalloc(Size
);
554 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
555 token
= strtok(t
, ", ");
558 idnsAddNameserver(token
);
560 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
561 token
= strtok(NULL
, ",");
566 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
568 if (Result
== ERROR_SUCCESS
&& Size
) {
569 t
= (char *) xmalloc(Size
);
570 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
571 token
= strtok(t
, ", ");
574 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
575 idnsAddNameserver(token
);
577 token
= strtok(NULL
, ", ");
585 idnsParseWIN32SearchList(" ");
598 /* get nameservers from the Windows 2000 registry */
599 /* search all interfaces for DNS server addresses */
601 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
603 DWORD MaxSubkeyLen
, InterfacesCount
;
605 FILETIME ftLastWriteTime
;
607 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
608 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
609 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
612 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
614 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
615 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
616 strcat(newkeyname
, "\\");
617 strcat(newkeyname
, keyname
);
618 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
622 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
623 if (Result
== ERROR_SUCCESS
&& Size
) {
624 t
= (char *) xmalloc(Size
);
625 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
626 token
= strtok(t
, ", ");
628 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
629 idnsAddNameserver(token
);
631 token
= strtok(NULL
, ", ");
636 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
637 if (Result
== ERROR_SUCCESS
&& Size
) {
638 t
= (char *) xmalloc(Size
);
639 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
640 token
= strtok(t
, ", ");
642 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
643 idnsAddNameserver(token
);
645 token
= strtok(NULL
, ", ");
651 RegCloseKey(hndKey2
);
664 idnsParseWIN32SearchList(", ");
673 /* get nameservers from the Windows 9X registry */
675 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
679 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
681 if (Result
== ERROR_SUCCESS
&& Size
) {
682 t
= (char *) xmalloc(Size
);
683 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
684 token
= strtok(t
, ", ");
687 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
688 idnsAddNameserver(token
);
690 token
= strtok(NULL
, ", ");
701 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
710 idnsStats(StoreEntry
* sentry
)
716 char buf
[MAX_IPSTRLEN
];
717 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
718 storeAppendPrintf(sentry
, "\nThe Queue:\n");
719 storeAppendPrintf(sentry
, " DELAY SINCE\n");
720 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND\n");
721 storeAppendPrintf(sentry
, "------ ---- ----- ---------- ---------\n");
723 for (n
= lru_list
.head
; n
; n
= n
->next
) {
724 q
= (idns_query
*)n
->data
;
725 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f\n",
726 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
727 tvSubDsec(q
->start_t
, current_time
),
728 tvSubDsec(q
->sent_t
, current_time
));
731 if (Config
.dns
.packet_max
> 0)
732 storeAppendPrintf(sentry
, "DNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
734 storeAppendPrintf(sentry
, "DNS jumbo-grams: not working\n");
736 storeAppendPrintf(sentry
, "\nNameservers:\n");
737 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
738 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
740 for (i
= 0; i
< nns
; ++i
) {
741 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
742 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
743 nameservers
[i
].nqueries
,
744 nameservers
[i
].nreplies
,
745 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
748 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
749 storeAppendPrintf(sentry
, "RCODE");
751 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
752 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
754 storeAppendPrintf(sentry
, " PROBLEM\n");
756 for (j
= 0; j
< MAX_RCODE
; ++j
) {
757 if (j
> 10 && j
< 16)
758 continue; // unassigned by IANA.
760 storeAppendPrintf(sentry
, "%5d", j
);
762 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
763 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
765 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
769 storeAppendPrintf(sentry
, "\nSearch list:\n");
771 for (i
=0; i
< npc
; ++i
)
772 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
774 storeAppendPrintf(sentry
, "\n");
779 idnsTickleQueue(void)
784 if (NULL
== lru_list
.tail
)
787 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
789 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
795 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
797 nsvc
* vc
= (nsvc
*)data
;
799 if (flag
== COMM_ERR_CLOSING
)
802 // XXX: irrelevant now that we have conn pointer?
803 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
806 if (flag
!= COMM_OK
|| size
<= 0) {
812 idnsDoSendQueryVC(vc
);
816 idnsDoSendQueryVC(nsvc
*vc
)
821 if (vc
->queue
->contentSize() == 0)
824 // if retrying after a TC UDP response, our close handler cb may be pending
825 if (fd_table
[vc
->conn
->fd
].closing())
828 MemBuf
*mb
= vc
->queue
;
830 vc
->queue
= new MemBuf
;
834 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
835 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
836 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
837 AsyncCall::Pointer nil
;
839 commSetConnTimeout(vc
->conn
, timeout
, nil
);
841 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
842 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
843 Comm::Write(vc
->conn
, mb
, call
);
849 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
851 nsvc
* vc
= (nsvc
*)data
;
853 if (status
!= COMM_OK
|| !conn
) {
854 char buf
[MAX_IPSTRLEN
] = "";
856 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
857 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
863 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
864 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
865 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
866 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
868 idnsDoSendQueryVC(vc
);
872 idnsVCClosed(const CommCloseCbParams
¶ms
)
874 nsvc
* vc
= (nsvc
*)params
.data
;
878 if (vc
->ns
< nns
) // XXX: dnsShutdown may have freed nameservers[]
879 nameservers
[vc
->ns
].vc
= NULL
;
886 nsvc
*vc
= cbdataAlloc(nsvc
);
888 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
889 nameservers
[nsv
].vc
= vc
;
891 vc
->queue
= new MemBuf
;
892 vc
->msg
= new MemBuf
;
895 Comm::ConnectionPointer conn
= new Comm::Connection();
897 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
898 conn
->local
= Config
.Addrs
.udp_outgoing
;
900 conn
->local
= Config
.Addrs
.udp_incoming
;
902 conn
->remote
= nameservers
[nsv
].S
;
904 if (conn
->remote
.isIPv4()) {
905 conn
->local
.setIPv4();
908 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
910 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
911 cs
->setHost("DNS TCP Socket");
916 idnsSendQueryVC(idns_query
* q
, int nsn
)
919 if (nameservers
[nsn
].vc
== NULL
)
922 nsvc
*vc
= nameservers
[nsn
].vc
;
925 char buf
[MAX_IPSTRLEN
];
926 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
933 short head
= htons(q
->sz
);
935 vc
->queue
->append((char *)&head
, 2);
937 vc
->queue
->append(q
->buf
, q
->sz
);
939 idnsDoSendQueryVC(vc
);
943 idnsSendQuery(idns_query
* q
)
945 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
946 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
951 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
955 assert(q
->lru
.next
== NULL
);
957 assert(q
->lru
.prev
== NULL
);
963 // only use mDNS resolvers for mDNS compatible queries
965 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
967 nsn
= q
->nsends
% nns
;
970 idnsSendQueryVC(q
, nsn
);
973 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
974 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
975 else if (DnsSocketA
>= 0)
976 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
981 q
->sent_t
= current_time
;
983 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
984 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
985 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
986 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
988 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
991 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
994 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
997 ++ nameservers
[nsn
].nqueries
;
998 q
->queue_t
= current_time
;
999 dlinkAdd(q
, &q
->lru
, &lru_list
);
1005 idnsFromKnownNameserver(Ip::Address
const &from
)
1009 for (i
= 0; i
< nns
; ++i
) {
1010 if (nameservers
[i
].S
!= from
)
1013 if (nameservers
[i
].S
.port() != from
.port())
1023 idnsFindQuery(unsigned short id
)
1028 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1029 q
= (idns_query
*)n
->data
;
1031 if (q
->query_id
== id
)
1038 static unsigned short
1041 unsigned short id
= squid_random() & 0xFFFF;
1042 unsigned short first_id
= id
;
1044 while (idnsFindQuery(id
)) {
1047 if (id
== first_id
) {
1048 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1057 idnsCallback(idns_query
*q
, const char *error
)
1068 // If any of our subqueries are still pending then wait for them to complete before continuing
1069 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1076 rfc1035_message
*message
= q
->message
;
1081 while ( idns_query
*q2
= q
->slave
) {
1082 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1083 q
->slave
= q2
->slave
;
1086 // two sets of RR need merging
1087 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1088 if (Config
.dns
.v4_first
) {
1089 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1090 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1092 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1093 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1096 // HACK WARNING, the answer rr:s have been copied in-place to
1097 // result, do not free them here
1098 safe_free(message
->answer
);
1099 safe_free(q2
->message
->answer
);
1100 message
->answer
= result
;
1101 message
->ancount
+= q2
->message
->ancount
;
1103 // first response empty or failed, just use the second
1104 rfc1035MessageDestroy(&message
);
1105 message
= q2
->message
;
1111 rfc1035MessageDestroy(&q2
->message
);
1115 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1117 callback
= q
->callback
;
1119 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1121 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1122 callback(cbdata
, answers
, n
, error
);
1125 idns_query
*q2
= q
->queue
;
1126 q
->queue
= q2
->queue
;
1127 callback
= q2
->callback
;
1128 q2
->callback
= NULL
;
1130 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1131 callback(cbdata
, answers
, n
, error
);
1137 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1141 rfc1035MessageDestroy(&message
);
1146 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1149 rfc1035_message
*message
= NULL
;
1152 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1154 if (message
== NULL
) {
1155 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1159 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1161 q
= idnsFindQuery(message
->id
);
1164 debugs(78, 3, "idnsGrokReply: Late response");
1165 rfc1035MessageDestroy(&message
);
1169 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1170 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1171 rfc1035MessageDestroy(&message
);
1175 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1176 // TODO: actually gr the message right here.
1177 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1178 // this is overall better than force-feeding A response with AAAA an section later anyway.
1179 // AND allows us to merge AN+AR sections from both responses (one day)
1181 if (q
->edns_seen
>= 0) {
1182 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1183 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1184 // the altered NS was limiting the whole group.
1185 max_shared_edns
= q
->edns_seen
;
1186 // may be limited by one of the others still
1187 for (int i
= 0; i
< nns
; ++i
)
1188 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1190 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1191 // maybe reduce the global limit downwards to accomodate this NS
1192 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1194 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1195 max_shared_edns
= -1;
1199 dlinkDelete(&q
->lru
, &lru_list
);
1203 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1204 rfc1035MessageDestroy(&message
);
1211 // Strange: A TCP DNS response with the truncation bit (TC) set.
1212 // Return an error and cleanup; no point in trying TCP again.
1213 debugs(78, 3, HERE
<< "TCP DNS response");
1214 idnsCallback(q
, "Truncated TCP DNS response");
1220 idnsRcodeCount(n
, q
->attempt
);
1224 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1226 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1228 * RCODE 2 is "Server failure - The name server was
1229 * unable to process this query due to a problem with
1232 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1233 rfc1035MessageDestroy(&message
);
1238 // Do searchpath processing on the master A query only to keep
1239 // things simple. NXDOMAIN is authorative for the label, not
1241 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1242 assert(NULL
== message
->answer
);
1243 strcpy(q
->name
, q
->orig
);
1245 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1247 if (q
->domain
< npc
) {
1248 strcat(q
->name
, ".");
1249 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1250 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1256 rfc1035MessageDestroy(&message
);
1258 // cleanup slave AAAA query
1259 while (idns_query
*slave
= q
->slave
) {
1260 dlinkDelete(&slave
->lru
, &lru_list
);
1261 q
->slave
= slave
->slave
;
1262 rfc1035MessageDestroy(&slave
->message
);
1267 q
->query_id
= idnsQueryID();
1268 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1269 // see EDNS notes at top of file why this sends 0
1270 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1272 /* problem with query data -- query not sent */
1273 idnsCallback(q
, "Internal error");
1282 idnsSendSlaveAAAAQuery(q
);
1287 q
->message
= message
;
1291 idnsCallback(q
, NULL
);
1293 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1298 idnsRead(int fd
, void *data
)
1300 int *N
= &incoming_sockets_accepted
;
1302 int max
= INCOMING_DNS_MAX
;
1303 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1306 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1308 // Always keep reading. This stops (or at least makes harder) several
1309 // attacks on the DNS client.
1310 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1313 * two code lines after returning from comm_udprecvfrom()
1314 * something overwrites the memory behind the from parameter.
1315 * NO matter where in the stack declaration list above it is placed
1316 * The cause of this is still unknown, however copying the data appears
1317 * to allow it to be passed further without this erasure.
1319 Ip::Address bugbypass
;
1323 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1325 from
= bugbypass
; // BUG BYPASS. see notes above.
1331 if (ignoreErrno(errno
))
1335 /* Some Linux systems seem to set the FD for reading and then
1336 * return ECONNREFUSED when sendto() fails and generates an ICMP
1337 * port unreachable message. */
1338 /* or maybe an EHOSTUNREACH "No route to host" message */
1339 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1342 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1347 fd_bytes(fd
, len
, FD_READ
);
1352 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1354 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1355 int nsn
= idnsFromKnownNameserver(from
);
1358 ++ nameservers
[nsn
].nreplies
;
1361 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1362 // but after the ++ above to keep statistics right.
1364 continue; // Don't process replies if there is no pending query.
1366 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1367 static time_t last_warning
= 0;
1369 if (squid_curtime
- last_warning
> 60) {
1370 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1371 last_warning
= squid_curtime
;
1373 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1378 idnsGrokReply(rbuf
, len
, nsn
);
1383 idnsCheckQueue(void *unused
)
1386 dlink_node
*p
= NULL
;
1391 /* name servers went away; reconfiguring or shutting down */
1394 for (n
= lru_list
.tail
; n
; n
= p
) {
1397 q
= static_cast<idns_query
*>(n
->data
);
1399 /* Anything to process in the queue? */
1400 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1403 /* Query timer still running? */
1404 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1405 dlinkDelete(&q
->lru
, &lru_list
);
1406 q
->queue_t
= current_time
;
1407 dlinkAdd(q
, &q
->lru
, &lru_list
);
1411 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1412 " QID 0x" << std::hex
<< std::setfill('0') <<
1413 std::setw(4) << q
->query_id
<< ": timeout" );
1415 dlinkDelete(&q
->lru
, &lru_list
);
1418 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1421 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1422 " QID 0x" << std::hex
<< q
->query_id
<<
1423 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1424 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1427 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1429 idnsCallback(q
, "Timeout");
1437 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1439 nsvc
* vc
= (nsvc
*)data
;
1441 if (flag
== COMM_ERR_CLOSING
)
1444 if (flag
!= COMM_OK
|| len
<= 0) {
1445 if (Comm::IsConnOpen(conn
))
1450 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1452 if (vc
->msg
->contentSize() < vc
->msglen
) {
1453 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1454 CommIoCbPtrFun(idnsReadVC
, vc
));
1455 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1459 assert(vc
->ns
< nns
);
1460 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1462 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1464 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1465 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1466 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1470 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1472 nsvc
* vc
= (nsvc
*)data
;
1474 if (flag
== COMM_ERR_CLOSING
)
1477 if (flag
!= COMM_OK
|| len
<= 0) {
1478 if (Comm::IsConnOpen(conn
))
1483 vc
->read_msglen
+= len
;
1485 assert(vc
->read_msglen
<= 2);
1487 if (vc
->read_msglen
< 2) {
1488 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1489 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1490 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1494 vc
->read_msglen
= 0;
1496 vc
->msglen
= ntohs(vc
->msglen
);
1498 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1499 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1500 CommIoCbPtrFun(idnsReadVC
, vc
));
1501 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1505 * rcode < 0 indicates an error, rocde >= 0 indicates success
1508 idnsRcodeCount(int rcode
, int attempt
)
1515 if (rcode
< MAX_RCODE
)
1516 if (attempt
< MAX_ATTEMPT
)
1517 ++ RcodeMatrix
[rcode
][attempt
];
1520 /* ====================================================================== */
1523 idnsRegisterWithCacheManager(void)
1525 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1531 static int init
= 0;
1533 CBDATA_INIT_TYPE(nsvc
);
1534 CBDATA_INIT_TYPE(idns_query
);
1536 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1537 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1539 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1540 addrV6
= Config
.Addrs
.udp_outgoing
;
1542 addrV6
= Config
.Addrs
.udp_incoming
;
1544 Ip::Address addrV4
= addrV6
;
1547 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1548 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1549 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1556 if (addrV4
.isIPv4()) {
1557 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1558 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1565 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1566 fatal("Could not create a DNS socket");
1568 /* Ouch... we can't call functions using debug from a debug
1569 * statement. Doing so messes up the internal Debug::level
1571 if (DnsSocketB
>= 0) {
1572 comm_local_port(DnsSocketB
);
1573 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1574 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1576 if (DnsSocketA
>= 0) {
1577 comm_local_port(DnsSocketA
);
1578 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1579 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1584 idnsAddMDNSNameservers();
1585 bool nsFound
= idnsParseNameservers();
1586 #if !_SQUID_WINDOWS_
1589 nsFound
= idnsParseResolvConf();
1594 nsFound
= idnsParseWIN32Registry();
1598 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1600 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1602 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1605 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1606 idnsAddNameserver("127.0.0.1");
1610 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1611 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1612 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1616 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1617 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1618 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1619 max_shared_edns
= -1; // disable if we might receive random replies.
1623 idnsRegisterWithCacheManager();
1629 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1632 if (DnsSocketA
>= 0 ) {
1633 comm_close(DnsSocketA
);
1637 if (DnsSocketB
>= 0 ) {
1638 comm_close(DnsSocketB
);
1642 for (int i
= 0; i
< nns
; ++i
) {
1643 if (nsvc
*vc
= nameservers
[i
].vc
) {
1644 if (Comm::IsConnOpen(vc
->conn
))
1649 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1650 idnsFreeNameservers();
1651 idnsFreeSearchpath();
1655 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1659 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1664 q
= cbdataAlloc(idns_query
);
1665 // idns_query is POD so no constructors are called after allocation
1666 q
->xact_id
.change();
1667 // no query_id on this instance.
1669 q
->callback
= callback
;
1671 q
->callback_data
= cbdataReference(data
);
1673 q
->queue
= old
->queue
;
1681 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1683 q
->start_t
= current_time
;
1684 q
->callback
= callback
;
1685 q
->callback_data
= cbdataReference(data
);
1687 q
->hash
.key
= q
->orig
;
1688 hash_join(idns_lookup_hash
, &q
->hash
);
1694 idnsSendSlaveAAAAQuery(idns_query
*master
)
1696 idns_query
*q
= cbdataAlloc(idns_query
);
1697 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1698 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1700 q
->query_id
= idnsQueryID();
1701 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1702 q
->start_t
= master
->start_t
;
1703 q
->slave
= master
->slave
;
1705 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1706 ", id = 0x" << std::hex
<< q
->query_id
);
1717 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1719 size_t nameLength
= strlen(name
);
1721 // Prevent buffer overflow on q->name
1722 if (nameLength
> NS_MAXDNAME
) {
1723 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1724 callback(data
, NULL
, 0, "Internal error");
1728 if (idnsCachedLookup(name
, callback
, data
))
1731 idns_query
*q
= cbdataAlloc(idns_query
);
1732 // idns_query is POD so no constructors are called after allocation
1733 q
->xact_id
.change();
1734 q
->query_id
= idnsQueryID();
1737 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1741 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1742 q
->do_searchpath
= 1;
1744 q
->do_searchpath
= 0;
1747 strcpy(q
->orig
, name
);
1748 strcpy(q
->name
, q
->orig
);
1750 if (q
->do_searchpath
&& nd
< ndots
) {
1752 strcat(q
->name
, ".");
1753 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1754 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1757 // see EDNS notes at top of file why this sends 0
1758 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1761 /* problem with query data -- query not sent */
1762 callback(data
, NULL
, 0, "Internal error");
1767 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1768 ", id = 0x" << std::hex
<< q
->query_id
);
1771 idnsStartQuery(q
, callback
, data
);
1774 idnsSendSlaveAAAAQuery(q
);
1779 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1783 char ip
[MAX_IPSTRLEN
];
1785 addr
.toStr(ip
,MAX_IPSTRLEN
);
1787 q
= cbdataAlloc(idns_query
);
1789 // idns_query is POD so no constructors are called after allocation
1790 q
->xact_id
.change();
1791 q
->query_id
= idnsQueryID();
1793 if (addr
.isIPv6()) {
1794 struct in6_addr addr6
;
1795 addr
.getInAddr(addr6
);
1796 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1798 struct in_addr addr4
;
1799 addr
.getInAddr(addr4
);
1800 // see EDNS notes at top of file why this sends 0
1801 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1805 /* problem with query data -- query not sent */
1806 callback(data
, NULL
, 0, "Internal error");
1811 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1816 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1817 ", id = 0x" << std::hex
<< q
->query_id
);
1819 q
->permit_mdns
= true;
1820 idnsStartQuery(q
, callback
, data
);
1825 * The function to return the DNS via SNMP
1828 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1831 variable_list
*Answer
= NULL
;
1833 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1834 *ErrP
= SNMP_ERR_NOERROR
;
1836 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1840 for (i
= 0; i
< nns
; ++i
)
1841 n
+= nameservers
[i
].nqueries
;
1843 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1850 for (i
= 0; i
< nns
; ++i
)
1851 n
+= nameservers
[i
].nreplies
;
1853 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1860 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1867 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1875 #endif /*SQUID_SNMP */
1876 #endif /* USE_DNSHELPER */