2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 78 DNS lookups; interacts with dns/rfc1035.cc */
12 #include "base/InstanceId.h"
14 #include "comm/Connection.h"
15 #include "comm/ConnOpener.h"
16 #include "comm/Loops.h"
17 #include "comm/Read.h"
18 #include "comm/Write.h"
20 #include "dns/forward.h"
21 #include "dns/rfc3596.h"
27 #include "mgr/Registration.h"
28 #include "SquidConfig.h"
29 #include "SquidTime.h"
36 #include "snmp_core.h"
39 #if HAVE_ARPA_NAMESER_H
40 #include <arpa/nameser.h>
49 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
50 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
51 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
54 #define _PATH_RESCONF "/etc/resolv.conf"
56 #ifndef NS_DEFAULTPORT
57 #define NS_DEFAULTPORT 53
61 #define NS_MAXDNAME 1025
68 /* The buffer size required to store the maximum allowed search path */
70 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
73 #define IDNS_MAX_TRIES 20
76 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
77 // NP: see http://www.iana.org/assignments/dns-parameters
78 static const char *Rcodes
[] = {
81 "Packet Format Error",
83 "Non-Existent Domain",
87 "Name Exists when it should not",
88 "RR Set Exists when it should not",
89 "RR Set that should exist does not",
90 "Server Not Authoritative for zone",
91 "Name not contained in zone",
95 "Bad OPT Version or TSIG Signature Failure"
98 typedef struct _ns ns
;
100 typedef struct _sp sp
;
104 CBDATA_CLASS(idns_query
);
127 memset(&hash
, 0, sizeof(hash
));
128 memset(&query
, 0, sizeof(query
));
132 memset(&start_t
, 0, sizeof(start_t
));
133 memset(&sent_t
, 0, sizeof(sent_t
));
134 memset(&queue_t
, 0, sizeof(queue_t
));
139 rfc1035MessageDestroy(&message
);
142 // master is just a back-reference
143 cbdataReferenceDone(callback_data
);
148 char buf
[RESOLV_BUFSZ
];
149 char name
[NS_MAXDNAME
+ 1];
150 char orig
[NS_MAXDNAME
+ 1];
152 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
153 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
160 struct timeval start_t
;
161 struct timeval sent_t
;
162 struct timeval queue_t
;
169 idns_query
*slave
; // single linked list
170 idns_query
*master
; // single pointer to a shared master
171 unsigned short domain
;
172 unsigned short do_searchpath
;
173 rfc1035_message
*message
;
178 InstanceIdDefinitions(idns_query
, "dns");
180 CBDATA_CLASS_INIT(idns_query
);
187 explicit nsvc(int nsv
) : ns(nsv
), msglen(0), read_msglen(0), msg(new MemBuf()), queue(new MemBuf()), busy(true) {}
191 Comm::ConnectionPointer conn
;
192 unsigned short msglen
;
199 CBDATA_CLASS_INIT(nsvc
);
205 #if WHEN_EDNS_RESPONSES_ARE_PARSED
213 char domain
[NS_MAXDNAME
];
217 static ns
*nameservers
= NULL
;
218 static sp
*searchpath
= NULL
;
220 static int nns_alloc
= 0;
221 static int nns_mdns_count
= 0;
223 static int npc_alloc
= 0;
224 static int ndots
= 1;
225 static dlink_list lru_list
;
226 static int event_queued
= 0;
227 static hash_table
*idns_lookup_hash
= NULL
;
233 * EDNS as specified may be sent as an additional record for any request.
234 * early testing has revealed that it works on common devices, but cannot
235 * be reliably used on any A or PTR requet done for IPv4 addresses.
237 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
240 * Squid is optimized to generate one packet and re-send it to all NS
241 * due to this we cannot customize the EDNS size per NS.
243 * As such we take the configuration option value as fixed.
246 * This may not be worth doing, but if/when additional-records are parsed
247 * we will be able to recover the OPT value specific to any one NS and
248 * cache it. Effectively automating the tuning of EDNS advertised to the
249 * size our active NS are capable.
250 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
251 * Responses from the configured NS may cause this to be raised or turned off.
253 #if WHEN_EDNS_RESPONSES_ARE_PARSED
254 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
257 static OBJH idnsStats
;
258 static void idnsAddNameserver(const char *buf
);
259 static void idnsAddMDNSNameservers();
260 static void idnsAddPathComponent(const char *buf
);
261 static void idnsFreeNameservers(void);
262 static void idnsFreeSearchpath(void);
263 static bool idnsParseNameservers(void);
264 static bool idnsParseResolvConf(void);
266 static bool idnsParseWIN32Registry(void);
267 static void idnsParseWIN32SearchList(const char *);
269 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
270 static void idnsSendQuery(idns_query
* q
);
271 static IOCB idnsReadVCHeader
;
272 static void idnsDoSendQueryVC(nsvc
*vc
);
273 static CNCB idnsInitVCConnected
;
274 static IOCB idnsReadVC
;
275 static IOCB idnsSentQueryVC
;
277 static int idnsFromKnownNameserver(Ip::Address
const &from
);
278 static idns_query
*idnsFindQuery(unsigned short id
);
279 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
281 static EVH idnsCheckQueue
;
282 static void idnsTickleQueue(void);
283 static void idnsRcodeCount(int, int);
284 static CLCB idnsVCClosed
;
285 static unsigned short idnsQueryID(void);
286 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
289 idnsCheckMDNS(idns_query
*q
)
291 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
294 size_t slen
= strlen(q
->name
);
295 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
296 q
->permit_mdns
= true;
301 idnsAddMDNSNameservers()
306 if (!Config
.onoff
.dns_mdns
)
309 // mDNS resolver addresses are explicit multicast group IPs
310 if (Ip::EnableIpv6
) {
311 idnsAddNameserver("FF02::FB");
312 nameservers
[nns
-1].S
.port(5353);
313 nameservers
[nns
-1].mDNSResolver
= true;
317 idnsAddNameserver("224.0.0.251");
318 nameservers
[nns
-1].S
.port(5353);
319 nameservers
[nns
-1].mDNSResolver
= true;
325 idnsAddNameserver(const char *buf
)
330 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
335 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
337 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
340 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
341 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
345 if (nns
== nns_alloc
) {
346 int oldalloc
= nns_alloc
;
347 ns
*oldptr
= nameservers
;
354 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
356 if (oldptr
&& oldalloc
)
357 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
363 assert(nns
< nns_alloc
);
364 A
.port(NS_DEFAULTPORT
);
365 nameservers
[nns
].S
= A
;
366 #if WHEN_EDNS_RESPONSES_ARE_PARSED
367 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
368 // TODO generate a test packet to probe this NS from EDNS size and ability.
370 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
375 idnsAddPathComponent(const char *buf
)
377 if (npc
== npc_alloc
) {
378 int oldalloc
= npc_alloc
;
379 sp
*oldptr
= searchpath
;
386 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
388 if (oldptr
&& oldalloc
)
389 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
395 assert(npc
< npc_alloc
);
396 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
397 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
398 Tolower(searchpath
[npc
].domain
);
399 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
404 idnsFreeNameservers(void)
406 safe_free(nameservers
);
411 idnsFreeSearchpath(void)
413 safe_free(searchpath
);
418 idnsParseNameservers(void)
421 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
422 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
423 idnsAddNameserver(w
->key
);
430 idnsParseResolvConf(void)
434 FILE *fp
= fopen(_PATH_RESCONF
, "r");
438 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerr(xerrno
));
442 char buf
[RESOLV_BUFSZ
];
443 const char *t
= NULL
;
444 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
445 t
= strtok(buf
, w_space
);
449 } else if (strcmp(t
, "nameserver") == 0) {
450 t
= strtok(NULL
, w_space
);
455 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
457 idnsAddNameserver(t
);
459 } else if (strcmp(t
, "domain") == 0) {
460 idnsFreeSearchpath();
461 t
= strtok(NULL
, w_space
);
466 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
468 idnsAddPathComponent(t
);
469 } else if (strcmp(t
, "search") == 0) {
470 idnsFreeSearchpath();
472 t
= strtok(NULL
, w_space
);
477 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
479 idnsAddPathComponent(t
);
481 } else if (strcmp(t
, "options") == 0) {
483 t
= strtok(NULL
, w_space
);
488 if (strncmp(t
, "ndots:", 6) == 0) {
494 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
499 if (npc
== 0 && (t
= getMyHostname())) {
502 idnsAddPathComponent(t
+1);
512 idnsParseWIN32SearchList(const char * Separator
)
518 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
522 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
524 if (Result
== ERROR_SUCCESS
&& Size
) {
525 t
= (char *) xmalloc(Size
);
526 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
527 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
528 idnsAddPathComponent(t
);
531 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
533 if (Result
== ERROR_SUCCESS
&& Size
) {
534 t
= (char *) xmalloc(Size
);
535 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
536 token
= strtok(t
, Separator
);
539 idnsAddPathComponent(token
);
540 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
541 token
= strtok(NULL
, Separator
);
548 if (npc
== 0 && (t
= (char *) getMyHostname())) {
551 idnsAddPathComponent(t
+ 1);
556 idnsParseWIN32Registry(void)
560 HKEY hndKey
, hndKey2
;
563 switch (WIN32_OS_version
) {
566 /* get nameservers from the Windows NT registry */
568 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
572 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
574 if (Result
== ERROR_SUCCESS
&& Size
) {
575 t
= (char *) xmalloc(Size
);
576 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
577 token
= strtok(t
, ", ");
580 idnsAddNameserver(token
);
582 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
583 token
= strtok(NULL
, ",");
588 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
590 if (Result
== ERROR_SUCCESS
&& Size
) {
591 t
= (char *) xmalloc(Size
);
592 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
593 token
= strtok(t
, ", ");
596 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
597 idnsAddNameserver(token
);
599 token
= strtok(NULL
, ", ");
607 idnsParseWIN32SearchList(" ");
620 /* get nameservers from the Windows 2000 registry */
621 /* search all interfaces for DNS server addresses */
623 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
625 DWORD MaxSubkeyLen
, InterfacesCount
;
627 FILETIME ftLastWriteTime
;
629 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
630 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
631 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
634 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
636 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
637 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
638 strcat(newkeyname
, "\\");
639 strcat(newkeyname
, keyname
);
640 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
644 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
645 if (Result
== ERROR_SUCCESS
&& Size
) {
646 t
= (char *) xmalloc(Size
);
647 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
648 token
= strtok(t
, ", ");
650 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
651 idnsAddNameserver(token
);
653 token
= strtok(NULL
, ", ");
658 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
659 if (Result
== ERROR_SUCCESS
&& Size
) {
660 t
= (char *) xmalloc(Size
);
661 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
662 token
= strtok(t
, ", ");
664 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
665 idnsAddNameserver(token
);
667 token
= strtok(NULL
, ", ");
673 RegCloseKey(hndKey2
);
686 idnsParseWIN32SearchList(", ");
695 /* get nameservers from the Windows 9X registry */
697 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
701 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
703 if (Result
== ERROR_SUCCESS
&& Size
) {
704 t
= (char *) xmalloc(Size
);
705 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
706 token
= strtok(t
, ", ");
709 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
710 idnsAddNameserver(token
);
712 token
= strtok(NULL
, ", ");
723 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
732 idnsStats(StoreEntry
* sentry
)
738 char buf
[MAX_IPSTRLEN
];
739 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
740 storeAppendPrintf(sentry
, "\nThe Queue:\n");
741 storeAppendPrintf(sentry
, " DELAY SINCE\n");
742 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
743 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
745 for (n
= lru_list
.head
; n
; n
= n
->next
) {
746 q
= (idns_query
*)n
->data
;
747 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
748 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
749 tvSubDsec(q
->start_t
, current_time
),
750 tvSubDsec(q
->sent_t
, current_time
),
751 (q
->permit_mdns
? 'M':' '),
755 if (Config
.dns
.packet_max
> 0)
756 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
758 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
760 storeAppendPrintf(sentry
, "\nNameservers:\n");
761 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
762 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
764 for (i
= 0; i
< nns
; ++i
) {
765 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
766 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
767 nameservers
[i
].nqueries
,
768 nameservers
[i
].nreplies
,
769 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
772 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
773 storeAppendPrintf(sentry
, "RCODE");
775 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
776 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
778 storeAppendPrintf(sentry
, " PROBLEM\n");
780 for (j
= 0; j
< MAX_RCODE
; ++j
) {
781 if (j
> 10 && j
< 16)
782 continue; // unassigned by IANA.
784 storeAppendPrintf(sentry
, "%5d", j
);
786 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
787 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
789 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
793 storeAppendPrintf(sentry
, "\nSearch list:\n");
795 for (i
=0; i
< npc
; ++i
)
796 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
798 storeAppendPrintf(sentry
, "\n");
803 idnsTickleQueue(void)
808 if (NULL
== lru_list
.tail
)
811 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
813 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
819 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *, size_t size
, Comm::Flag flag
, int, void *data
)
821 nsvc
* vc
= (nsvc
*)data
;
823 if (flag
== Comm::ERR_CLOSING
)
826 // XXX: irrelevant now that we have conn pointer?
827 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
830 if (flag
!= Comm::OK
|| size
<= 0) {
836 idnsDoSendQueryVC(vc
);
840 idnsDoSendQueryVC(nsvc
*vc
)
845 if (vc
->queue
->contentSize() == 0)
848 // if retrying after a TC UDP response, our close handler cb may be pending
849 if (fd_table
[vc
->conn
->fd
].closing())
852 MemBuf
*mb
= vc
->queue
;
854 vc
->queue
= new MemBuf
;
858 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
859 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
860 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
861 AsyncCall::Pointer nil
;
863 commSetConnTimeout(vc
->conn
, timeout
, nil
);
865 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
866 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
867 Comm::Write(vc
->conn
, mb
, call
);
873 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int, void *data
)
875 nsvc
* vc
= (nsvc
*)data
;
877 if (status
!= Comm::OK
|| !conn
) {
878 char buf
[MAX_IPSTRLEN
] = "";
880 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
881 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
887 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
888 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
889 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
890 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
892 idnsDoSendQueryVC(vc
);
896 idnsVCClosed(const CommCloseCbParams
¶ms
)
898 nsvc
* vc
= (nsvc
*)params
.data
;
906 if (ns
< nns
) // XXX: Dns::Shutdown may have freed nameservers[]
907 nameservers
[ns
].vc
= NULL
;
913 nsvc
*vc
= new nsvc(nsv
);
915 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
916 nameservers
[nsv
].vc
= vc
;
918 Comm::ConnectionPointer conn
= new Comm::Connection();
920 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
921 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
923 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
925 if (conn
->remote
.isIPv4())
926 conn
->local
.setIPv4();
928 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
930 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
931 cs
->setHost("DNS TCP Socket");
936 idnsSendQueryVC(idns_query
* q
, int nsn
)
939 if (nameservers
[nsn
].vc
== NULL
)
942 nsvc
*vc
= nameservers
[nsn
].vc
;
945 char buf
[MAX_IPSTRLEN
];
946 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
953 short head
= htons(q
->sz
);
955 vc
->queue
->append((char *)&head
, 2);
957 vc
->queue
->append(q
->buf
, q
->sz
);
959 idnsDoSendQueryVC(vc
);
963 idnsSendQuery(idns_query
* q
)
965 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
966 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
971 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
975 assert(q
->lru
.next
== NULL
);
977 assert(q
->lru
.prev
== NULL
);
983 // only use mDNS resolvers for mDNS compatible queries
985 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
987 nsn
= q
->nsends
% nns
;
990 idnsSendQueryVC(q
, nsn
);
993 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
994 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
995 else if (DnsSocketA
>= 0)
996 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
1002 q
->sent_t
= current_time
;
1004 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
1005 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketB
<< ": sendto: " << xstrerr(xerrno
));
1006 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
1007 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketA
<< ": sendto: " << xstrerr(xerrno
));
1009 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
1012 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
1015 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
1018 ++ nameservers
[nsn
].nqueries
;
1019 q
->queue_t
= current_time
;
1020 dlinkAdd(q
, &q
->lru
, &lru_list
);
1026 idnsFromKnownNameserver(Ip::Address
const &from
)
1030 for (i
= 0; i
< nns
; ++i
) {
1031 if (nameservers
[i
].S
!= from
)
1034 if (nameservers
[i
].S
.port() != from
.port())
1044 idnsFindQuery(unsigned short id
)
1049 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1050 q
= (idns_query
*)n
->data
;
1052 if (q
->query_id
== id
)
1059 static unsigned short
1062 // NP: apparently ranlux are faster, but not quite as "proven"
1063 static std::mt19937
mt(static_cast<uint32_t>(getCurrentTime() & 0xFFFFFFFF));
1064 unsigned short id
= mt() & 0xFFFF;
1065 unsigned short first_id
= id
;
1067 // ensure temporal uniqueness by looking for an existing use
1068 while (idnsFindQuery(id
)) {
1071 if (id
== first_id
) {
1072 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1081 idnsCallback(idns_query
*q
, const char *error
)
1092 // If any of our subqueries are still pending then wait for them to complete before continuing
1093 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1100 rfc1035_message
*message
= q
->message
;
1105 while ( idns_query
*q2
= q
->slave
) {
1106 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1107 q
->slave
= q2
->slave
;
1111 // two sets of RR need merging
1112 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1113 if (Config
.dns
.v4_first
) {
1114 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1115 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1117 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1118 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1121 // HACK WARNING, the answer rr:s have been copied in-place to
1122 // result, do not free them here
1123 safe_free(message
->answer
);
1124 safe_free(q2
->message
->answer
);
1125 message
->answer
= result
;
1126 message
->ancount
+= q2
->message
->ancount
;
1128 // first response empty or failed, just use the second
1129 rfc1035MessageDestroy(&message
);
1130 message
= q2
->message
;
1139 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1141 callback
= q
->callback
;
1143 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1145 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1146 callback(cbdata
, answers
, n
, error
);
1149 idns_query
*q2
= q
->queue
;
1150 q
->queue
= q2
->queue
;
1153 callback
= q2
->callback
;
1154 q2
->callback
= NULL
;
1156 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1157 callback(cbdata
, answers
, n
, error
);
1163 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1167 rfc1035MessageDestroy(&message
);
1172 idnsGrokReply(const char *buf
, size_t sz
, int /*from_ns*/)
1174 rfc1035_message
*message
= NULL
;
1176 int n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1178 if (message
== NULL
) {
1179 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1183 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1185 idns_query
*q
= idnsFindQuery(message
->id
);
1188 debugs(78, 3, "idnsGrokReply: Late response");
1189 rfc1035MessageDestroy(&message
);
1193 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1194 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1195 rfc1035MessageDestroy(&message
);
1199 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1200 // TODO: actually gr the message right here.
1201 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1202 // this is overall better than force-feeding A response with AAAA an section later anyway.
1203 // AND allows us to merge AN+AR sections from both responses (one day)
1205 if (q
->edns_seen
>= 0) {
1206 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1207 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1208 // the altered NS was limiting the whole group.
1209 max_shared_edns
= q
->edns_seen
;
1210 // may be limited by one of the others still
1211 for (int i
= 0; i
< nns
; ++i
)
1212 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1214 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1215 // maybe reduce the global limit downwards to accomodate this NS
1216 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1218 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1219 max_shared_edns
= -1;
1223 dlinkDelete(&q
->lru
, &lru_list
);
1227 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1228 rfc1035MessageDestroy(&message
);
1235 // Strange: A TCP DNS response with the truncation bit (TC) set.
1236 // Return an error and cleanup; no point in trying TCP again.
1237 debugs(78, 3, HERE
<< "TCP DNS response");
1238 idnsCallback(q
, "Truncated TCP DNS response");
1244 idnsRcodeCount(n
, q
->attempt
);
1248 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1250 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1252 * RCODE 2 is "Server failure - The name server was
1253 * unable to process this query due to a problem with
1256 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1257 rfc1035MessageDestroy(&message
);
1262 // Do searchpath processing on the master A query only to keep
1263 // things simple. NXDOMAIN is authorative for the label, not
1265 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1266 assert(NULL
== message
->answer
);
1267 strcpy(q
->name
, q
->orig
);
1269 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1271 if (q
->domain
< npc
) {
1272 strcat(q
->name
, ".");
1273 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1274 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1280 rfc1035MessageDestroy(&message
);
1282 // cleanup slave AAAA query
1283 while (idns_query
*slave
= q
->slave
) {
1284 dlinkDelete(&slave
->lru
, &lru_list
);
1285 q
->slave
= slave
->slave
;
1286 slave
->slave
= NULL
;
1291 q
->query_id
= idnsQueryID();
1292 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1293 // see EDNS notes at top of file why this sends 0
1294 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1296 /* problem with query data -- query not sent */
1297 idnsCallback(q
, "Internal error");
1306 idnsSendSlaveAAAAQuery(q
);
1311 q
->message
= message
;
1315 idnsCallback(q
, NULL
);
1317 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1322 idnsRead(int fd
, void *)
1324 int *N
= &incoming_sockets_accepted
;
1326 int max
= INCOMING_DNS_MAX
;
1327 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1330 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1332 // Always keep reading. This stops (or at least makes harder) several
1333 // attacks on the DNS client.
1334 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1337 * two code lines after returning from comm_udprecvfrom()
1338 * something overwrites the memory behind the from parameter.
1339 * NO matter where in the stack declaration list above it is placed
1340 * The cause of this is still unknown, however copying the data appears
1341 * to allow it to be passed further without this erasure.
1343 Ip::Address bugbypass
;
1347 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1349 from
= bugbypass
; // BUG BYPASS. see notes above.
1356 if (ignoreErrno(xerrno
))
1360 /* Some Linux systems seem to set the FD for reading and then
1361 * return ECONNREFUSED when sendto() fails and generates an ICMP
1362 * port unreachable message. */
1363 /* or maybe an EHOSTUNREACH "No route to host" message */
1364 if (xerrno
!= ECONNREFUSED
&& xerrno
!= EHOSTUNREACH
)
1366 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << fd
<< " recvfrom: " << xstrerr(xerrno
));
1371 fd_bytes(fd
, len
, FD_READ
);
1376 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1378 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1379 int nsn
= idnsFromKnownNameserver(from
);
1382 ++ nameservers
[nsn
].nreplies
;
1385 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1386 // but after the ++ above to keep statistics right.
1388 continue; // Don't process replies if there is no pending query.
1390 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1391 static time_t last_warning
= 0;
1393 if (squid_curtime
- last_warning
> 60) {
1394 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1395 last_warning
= squid_curtime
;
1397 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1402 idnsGrokReply(rbuf
, len
, nsn
);
1407 idnsCheckQueue(void *)
1410 dlink_node
*p
= NULL
;
1415 /* name servers went away; reconfiguring or shutting down */
1418 for (n
= lru_list
.tail
; n
; n
= p
) {
1421 q
= static_cast<idns_query
*>(n
->data
);
1423 /* Anything to process in the queue? */
1424 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1427 /* Query timer still running? */
1428 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1429 dlinkDelete(&q
->lru
, &lru_list
);
1430 q
->queue_t
= current_time
;
1431 dlinkAdd(q
, &q
->lru
, &lru_list
);
1435 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1436 " QID 0x" << std::hex
<< std::setfill('0') <<
1437 std::setw(4) << q
->query_id
<< ": timeout" );
1439 dlinkDelete(&q
->lru
, &lru_list
);
1442 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1445 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1446 " QID 0x" << std::hex
<< q
->query_id
<<
1447 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1448 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1451 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1453 idnsCallback(q
, "Timeout");
1461 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1463 nsvc
* vc
= (nsvc
*)data
;
1465 if (flag
== Comm::ERR_CLOSING
)
1468 if (flag
!= Comm::OK
|| len
<= 0) {
1469 if (Comm::IsConnOpen(conn
))
1474 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1476 if (vc
->msg
->contentSize() < vc
->msglen
) {
1477 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1478 CommIoCbPtrFun(idnsReadVC
, vc
));
1479 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1483 assert(vc
->ns
< nns
);
1484 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1486 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1488 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1489 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1490 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1494 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1496 nsvc
* vc
= (nsvc
*)data
;
1498 if (flag
== Comm::ERR_CLOSING
)
1501 if (flag
!= Comm::OK
|| len
<= 0) {
1502 if (Comm::IsConnOpen(conn
))
1507 vc
->read_msglen
+= len
;
1509 assert(vc
->read_msglen
<= 2);
1511 if (vc
->read_msglen
< 2) {
1512 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1513 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1514 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1518 vc
->read_msglen
= 0;
1520 vc
->msglen
= ntohs(vc
->msglen
);
1523 if (Comm::IsConnOpen(conn
))
1528 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1529 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1530 CommIoCbPtrFun(idnsReadVC
, vc
));
1531 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1535 * rcode < 0 indicates an error, rocde >= 0 indicates success
1538 idnsRcodeCount(int rcode
, int attempt
)
1545 if (rcode
< MAX_RCODE
)
1546 if (attempt
< MAX_ATTEMPT
)
1547 ++ RcodeMatrix
[rcode
][attempt
];
1553 static int init
= 0;
1555 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1556 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1558 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1559 addrV6
= Config
.Addrs
.udp_outgoing
;
1561 addrV6
= Config
.Addrs
.udp_incoming
;
1563 Ip::Address addrV4
= addrV6
;
1566 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1567 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1568 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1575 if (addrV4
.isIPv4()) {
1576 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1577 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1584 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1585 fatal("Could not create a DNS socket");
1587 /* Ouch... we can't call functions using debug from a debug
1588 * statement. Doing so messes up the internal Debug::level
1590 if (DnsSocketB
>= 0) {
1591 comm_local_port(DnsSocketB
);
1592 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1593 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1595 if (DnsSocketA
>= 0) {
1596 comm_local_port(DnsSocketA
);
1597 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1598 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1603 idnsAddMDNSNameservers();
1604 bool nsFound
= idnsParseNameservers();
1607 nsFound
= idnsParseResolvConf();
1611 nsFound
= idnsParseWIN32Registry();
1615 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1617 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1619 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1622 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1624 idnsAddNameserver("::1");
1625 idnsAddNameserver("127.0.0.1");
1629 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1630 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1634 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1635 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1636 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1637 max_shared_edns
= -1; // disable if we might receive random replies.
1641 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1647 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1650 if (DnsSocketA
>= 0 ) {
1651 comm_close(DnsSocketA
);
1655 if (DnsSocketB
>= 0 ) {
1656 comm_close(DnsSocketB
);
1660 for (int i
= 0; i
< nns
; ++i
) {
1661 if (nsvc
*vc
= nameservers
[i
].vc
) {
1662 if (Comm::IsConnOpen(vc
->conn
))
1667 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1668 idnsFreeNameservers();
1669 idnsFreeSearchpath();
1673 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1675 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1680 idns_query
*q
= new idns_query
;
1681 // no query_id on this instance.
1683 q
->callback
= callback
;
1684 q
->callback_data
= cbdataReference(data
);
1686 q
->queue
= old
->queue
;
1693 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1695 q
->start_t
= current_time
;
1696 q
->callback
= callback
;
1697 q
->callback_data
= cbdataReference(data
);
1699 q
->hash
.key
= q
->orig
;
1700 hash_join(idns_lookup_hash
, &q
->hash
);
1706 idnsSendSlaveAAAAQuery(idns_query
*master
)
1708 idns_query
*q
= new idns_query
;
1709 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1710 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1712 q
->query_id
= idnsQueryID();
1713 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1715 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1716 ", id = 0x" << std::hex
<< q
->query_id
);
1722 q
->start_t
= master
->start_t
;
1723 q
->slave
= master
->slave
;
1731 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1733 size_t nameLength
= strlen(name
);
1735 // Prevent buffer overflow on q->name
1736 if (nameLength
> NS_MAXDNAME
) {
1737 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1738 callback(data
, NULL
, 0, "Internal error");
1742 if (idnsCachedLookup(name
, callback
, data
))
1745 idns_query
*q
= new idns_query
;
1746 q
->query_id
= idnsQueryID();
1749 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1753 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1754 q
->do_searchpath
= 1;
1756 q
->do_searchpath
= 0;
1759 strcpy(q
->orig
, name
);
1760 strcpy(q
->name
, q
->orig
);
1762 if (q
->do_searchpath
&& nd
< ndots
) {
1764 strcat(q
->name
, ".");
1765 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1766 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1769 // see EDNS notes at top of file why this sends 0
1770 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1773 /* problem with query data -- query not sent */
1774 callback(data
, NULL
, 0, "Internal error");
1779 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1780 ", id = 0x" << std::hex
<< q
->query_id
);
1783 idnsStartQuery(q
, callback
, data
);
1786 idnsSendSlaveAAAAQuery(q
);
1790 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1792 char ip
[MAX_IPSTRLEN
];
1794 addr
.toStr(ip
,MAX_IPSTRLEN
);
1796 idns_query
*q
= new idns_query
;
1797 q
->query_id
= idnsQueryID();
1799 if (addr
.isIPv6()) {
1800 struct in6_addr addr6
;
1801 addr
.getInAddr(addr6
);
1802 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1804 struct in_addr addr4
;
1805 addr
.getInAddr(addr4
);
1806 // see EDNS notes at top of file why this sends 0
1807 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1811 /* problem with query data -- query not sent */
1812 callback(data
, NULL
, 0, "Internal error");
1817 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1822 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1823 ", id = 0x" << std::hex
<< q
->query_id
);
1825 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1826 idnsStartQuery(q
, callback
, data
);
1831 * The function to return the DNS via SNMP
1834 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1837 variable_list
*Answer
= NULL
;
1839 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1840 *ErrP
= SNMP_ERR_NOERROR
;
1842 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1846 for (i
= 0; i
< nns
; ++i
)
1847 n
+= nameservers
[i
].nqueries
;
1849 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1856 for (i
= 0; i
< nns
; ++i
)
1857 n
+= nameservers
[i
].nreplies
;
1859 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1866 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1873 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1881 #endif /*SQUID_SNMP */