2 * Copyright (C) 1996-2019 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/CodeContext.h"
13 #include "base/InstanceId.h"
14 #include "base/RunnersRegistry.h"
16 #include "comm/Connection.h"
17 #include "comm/ConnOpener.h"
18 #include "comm/Loops.h"
19 #include "comm/Read.h"
20 #include "comm/Write.h"
22 #include "dns/forward.h"
23 #include "dns/rfc3596.h"
29 #include "mgr/Registration.h"
30 #include "SquidConfig.h"
31 #include "SquidTime.h"
38 #include "snmp_core.h"
41 #if HAVE_ARPA_NAMESER_H
42 #include <arpa/nameser.h>
51 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
52 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
53 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
56 #define _PATH_RESCONF "/etc/resolv.conf"
58 #ifndef NS_DEFAULTPORT
59 #define NS_DEFAULTPORT 53
63 #define NS_MAXDNAME 1025
70 /* The buffer size required to store the maximum allowed search path */
72 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
75 #define IDNS_MAX_TRIES 20
78 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
79 // NP: see http://www.iana.org/assignments/dns-parameters
80 static const char *Rcodes
[] = {
83 "Packet Format Error",
85 "Non-Existent Domain",
89 "Name Exists when it should not",
90 "RR Set Exists when it should not",
91 "RR Set that should exist does not",
92 "Server Not Authoritative for zone",
93 "Name not contained in zone",
97 "Bad OPT Version or TSIG Signature Failure"
100 typedef struct _sp sp
;
104 CBDATA_CLASS(idns_query
);
108 codeContext(CodeContext::Current())
111 memset(&query
, 0, sizeof(query
));
115 memset(&start_t
, 0, sizeof(start_t
));
116 memset(&sent_t
, 0, sizeof(sent_t
));
117 memset(&queue_t
, 0, sizeof(queue_t
));
122 rfc1035MessageDestroy(&message
);
125 // master is just a back-reference
126 cbdataReferenceDone(callback_data
);
131 char buf
[RESOLV_BUFSZ
];
132 char name
[NS_MAXDNAME
+ 1];
133 char orig
[NS_MAXDNAME
+ 1];
135 unsigned short query_id
= 0; ///< random query ID sent to server; changes with every query sent
136 InstanceId
<idns_query
> xact_id
; ///< identifies our "transaction", stays constant when query is retried
140 bool permit_mdns
= false;
143 struct timeval start_t
;
144 struct timeval sent_t
;
145 struct timeval queue_t
;
149 void *callback_data
= nullptr;
150 CodeContext::Pointer codeContext
; ///< requestor's context
154 idns_query
*queue
= nullptr;
155 idns_query
*slave
= nullptr; // single linked list
156 idns_query
*master
= nullptr; // single pointer to a shared master
157 unsigned short domain
= 0;
158 unsigned short do_searchpath
= 0;
159 rfc1035_message
*message
= nullptr;
161 const char *error
= nullptr;
164 InstanceIdDefinitions(idns_query
, "dns");
166 CBDATA_CLASS_INIT(idns_query
);
173 explicit nsvc(size_t nsv
) : ns(nsv
), msg(new MemBuf()), queue(new MemBuf()) {}
177 Comm::ConnectionPointer conn
;
178 unsigned short msglen
= 0;
180 MemBuf
*msg
= nullptr;
181 MemBuf
*queue
= nullptr;
185 CBDATA_CLASS_INIT(nsvc
);
193 #if WHEN_EDNS_RESPONSES_ARE_PARSED
194 int last_seen_edns
= 0;
196 bool mDNSResolver
= false;
203 /// manage DNS internal component
204 class ConfigRr
: public RegisteredRunner
207 /* RegisteredRunner API */
208 virtual void startReconfigure() override
;
209 virtual void endingShutdown() override
;
212 RunnerRegistrationEntry(ConfigRr
);
217 char domain
[NS_MAXDNAME
];
221 static std::vector
<ns
> nameservers
;
222 static sp
*searchpath
= NULL
;
223 static int nns_mdns_count
= 0;
225 static int npc_alloc
= 0;
226 static int ndots
= 1;
227 static dlink_list lru_list
;
228 static int event_queued
= 0;
229 static hash_table
*idns_lookup_hash
= NULL
;
235 * EDNS as specified may be sent as an additional record for any request.
236 * early testing has revealed that it works on common devices, but cannot
237 * be reliably used on any A or PTR requet done for IPv4 addresses.
239 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
242 * Squid is optimized to generate one packet and re-send it to all NS
243 * due to this we cannot customize the EDNS size per NS.
245 * As such we take the configuration option value as fixed.
248 * This may not be worth doing, but if/when additional-records are parsed
249 * we will be able to recover the OPT value specific to any one NS and
250 * cache it. Effectively automating the tuning of EDNS advertised to the
251 * size our active NS are capable.
252 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
253 * Responses from the configured NS may cause this to be raised or turned off.
255 #if WHEN_EDNS_RESPONSES_ARE_PARSED
256 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
259 static OBJH idnsStats
;
260 static void idnsAddNameserver(const char *buf
);
261 static void idnsAddMDNSNameservers();
262 static void idnsAddPathComponent(const char *buf
);
263 static void idnsFreeSearchpath(void);
264 static bool idnsParseNameservers(void);
265 static bool idnsParseResolvConf(void);
267 static bool idnsParseWIN32Registry(void);
268 static void idnsParseWIN32SearchList(const char *);
270 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
271 static void idnsSendQuery(idns_query
* q
);
272 static IOCB idnsReadVCHeader
;
273 static void idnsDoSendQueryVC(nsvc
*vc
);
274 static CNCB idnsInitVCConnected
;
275 static IOCB idnsReadVC
;
276 static IOCB idnsSentQueryVC
;
278 static int idnsFromKnownNameserver(Ip::Address
const &from
);
279 static idns_query
*idnsFindQuery(unsigned short id
);
280 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
282 static EVH idnsCheckQueue
;
283 static void idnsTickleQueue(void);
284 static void idnsRcodeCount(int, int);
285 static CLCB idnsVCClosed
;
286 static unsigned short idnsQueryID(void);
287 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
288 static void idnsCallbackOnEarlyError(IDNSCB
*callback
, void *cbdata
, const char *error
);
291 idnsCheckMDNS(idns_query
*q
)
293 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
296 size_t slen
= strlen(q
->name
);
297 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
298 q
->permit_mdns
= true;
303 idnsAddMDNSNameservers()
308 if (!Config
.onoff
.dns_mdns
)
311 // mDNS resolver addresses are explicit multicast group IPs
312 if (Ip::EnableIpv6
) {
313 idnsAddNameserver("FF02::FB");
314 nameservers
.back().S
.port(5353);
315 nameservers
.back().mDNSResolver
= true;
319 idnsAddNameserver("224.0.0.251");
320 nameservers
.back().S
.port(5353);
321 nameservers
.back().mDNSResolver
= true;
327 idnsAddNameserver(const char *buf
)
332 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
337 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
339 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
342 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
343 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
347 nameservers
.emplace_back(ns());
348 A
.port(NS_DEFAULTPORT
);
349 nameservers
.back().S
= A
;
350 #if WHEN_EDNS_RESPONSES_ARE_PARSED
351 nameservers
.back().last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
352 // TODO generate a test packet to probe this NS from EDNS size and ability.
354 debugs(78, 3, "Added nameserver #" << nameservers
.size()-1 << " (" << A
<< ")");
358 idnsAddPathComponent(const char *buf
)
360 if (npc
== npc_alloc
) {
361 int oldalloc
= npc_alloc
;
362 sp
*oldptr
= searchpath
;
369 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
371 if (oldptr
&& oldalloc
)
372 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
378 assert(npc
< npc_alloc
);
379 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
380 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
381 Tolower(searchpath
[npc
].domain
);
382 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
387 idnsFreeSearchpath(void)
389 safe_free(searchpath
);
394 idnsParseNameservers(void)
397 for (auto &i
: Config
.dns
.nameservers
) {
398 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << i
<< " from squid.conf");
399 idnsAddNameserver(i
.c_str());
406 idnsParseResolvConf(void)
410 FILE *fp
= fopen(_PATH_RESCONF
, "r");
414 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerr(xerrno
));
418 char buf
[RESOLV_BUFSZ
];
419 const char *t
= NULL
;
420 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
421 t
= strtok(buf
, w_space
);
425 } else if (strcmp(t
, "nameserver") == 0) {
426 t
= strtok(NULL
, w_space
);
431 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
433 idnsAddNameserver(t
);
435 } else if (strcmp(t
, "domain") == 0) {
436 idnsFreeSearchpath();
437 t
= strtok(NULL
, w_space
);
442 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
444 idnsAddPathComponent(t
);
445 } else if (strcmp(t
, "search") == 0) {
446 idnsFreeSearchpath();
448 t
= strtok(NULL
, w_space
);
453 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
455 idnsAddPathComponent(t
);
457 } else if (strcmp(t
, "options") == 0) {
459 t
= strtok(NULL
, w_space
);
464 if (strncmp(t
, "ndots:", 6) == 0) {
470 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
475 if (npc
== 0 && (t
= getMyHostname())) {
478 idnsAddPathComponent(t
+1);
488 idnsParseWIN32SearchList(const char * Separator
)
494 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
498 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
500 if (Result
== ERROR_SUCCESS
&& Size
) {
501 t
= (char *) xmalloc(Size
);
502 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
503 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
504 idnsAddPathComponent(t
);
507 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
509 if (Result
== ERROR_SUCCESS
&& Size
) {
510 t
= (char *) xmalloc(Size
);
511 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
512 token
= strtok(t
, Separator
);
515 idnsAddPathComponent(token
);
516 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
517 token
= strtok(NULL
, Separator
);
524 if (npc
== 0 && (t
= (char *) getMyHostname())) {
527 idnsAddPathComponent(t
+ 1);
532 idnsParseWIN32Registry(void)
536 HKEY hndKey
, hndKey2
;
539 switch (WIN32_OS_version
) {
542 /* get nameservers from the Windows NT registry */
544 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
548 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
550 if (Result
== ERROR_SUCCESS
&& Size
) {
551 t
= (char *) xmalloc(Size
);
552 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
553 token
= strtok(t
, ", ");
556 idnsAddNameserver(token
);
558 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
559 token
= strtok(NULL
, ",");
564 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
566 if (Result
== ERROR_SUCCESS
&& Size
) {
567 t
= (char *) xmalloc(Size
);
568 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
569 token
= strtok(t
, ", ");
572 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
573 idnsAddNameserver(token
);
575 token
= strtok(NULL
, ", ");
583 idnsParseWIN32SearchList(" ");
596 /* get nameservers from the Windows 2000 registry */
597 /* search all interfaces for DNS server addresses */
599 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
601 DWORD MaxSubkeyLen
, InterfacesCount
;
603 FILETIME ftLastWriteTime
;
605 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
606 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
607 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
610 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
612 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
613 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
614 strcat(newkeyname
, "\\");
615 strcat(newkeyname
, keyname
);
616 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
620 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
621 if (Result
== ERROR_SUCCESS
&& Size
) {
622 t
= (char *) xmalloc(Size
);
623 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
624 token
= strtok(t
, ", ");
626 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
627 idnsAddNameserver(token
);
629 token
= strtok(NULL
, ", ");
634 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
635 if (Result
== ERROR_SUCCESS
&& Size
) {
636 t
= (char *) xmalloc(Size
);
637 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
638 token
= strtok(t
, ", ");
640 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
641 idnsAddNameserver(token
);
643 token
= strtok(NULL
, ", ");
649 RegCloseKey(hndKey2
);
662 idnsParseWIN32SearchList(", ");
671 /* get nameservers from the Windows 9X registry */
673 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
677 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
679 if (Result
== ERROR_SUCCESS
&& Size
) {
680 t
= (char *) xmalloc(Size
);
681 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
682 token
= strtok(t
, ", ");
685 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
686 idnsAddNameserver(token
);
688 token
= strtok(NULL
, ", ");
699 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
708 idnsStats(StoreEntry
* sentry
)
714 char buf
[MAX_IPSTRLEN
];
715 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
716 storeAppendPrintf(sentry
, "\nThe Queue:\n");
717 storeAppendPrintf(sentry
, " DELAY SINCE\n");
718 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
719 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
721 for (n
= lru_list
.head
; n
; n
= n
->next
) {
722 q
= (idns_query
*)n
->data
;
723 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
724 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
725 tvSubDsec(q
->start_t
, current_time
),
726 tvSubDsec(q
->sent_t
, current_time
),
727 (q
->permit_mdns
? 'M':' '),
731 if (Config
.dns
.packet_max
> 0)
732 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
734 storeAppendPrintf(sentry
, "\nDNS 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 (const auto &server
: nameservers
) {
741 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
742 server
.S
.toStr(buf
,MAX_IPSTRLEN
),
745 server
.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 *, size_t size
, Comm::Flag flag
, int, 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::Flag status
, int, void *data
)
851 nsvc
* vc
= (nsvc
*)data
;
853 if (status
!= Comm::OK
|| !conn
) {
854 char buf
[MAX_IPSTRLEN
] = "";
855 if (vc
->ns
< nameservers
.size())
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
;
882 if (ns
< nameservers
.size()) // XXX: idnsShutdownAndFreeState may have freed nameservers[]
883 nameservers
[ns
].vc
= NULL
;
887 idnsInitVC(size_t nsv
)
889 assert(nsv
< nameservers
.size());
890 nsvc
*vc
= new nsvc(nsv
);
891 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
892 nameservers
[nsv
].vc
= vc
;
894 Comm::ConnectionPointer conn
= new Comm::Connection();
896 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
897 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
899 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
901 if (conn
->remote
.isIPv4())
902 conn
->local
.setIPv4();
904 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
906 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
907 cs
->setHost("DNS TCP Socket");
912 idnsSendQueryVC(idns_query
* q
, size_t nsn
)
914 assert(nsn
< nameservers
.size());
915 if (nameservers
[nsn
].vc
== NULL
)
918 nsvc
*vc
= nameservers
[nsn
].vc
;
921 char buf
[MAX_IPSTRLEN
];
922 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
929 short head
= htons(q
->sz
);
931 vc
->queue
->append((char *)&head
, 2);
933 vc
->queue
->append(q
->buf
, q
->sz
);
935 idnsDoSendQueryVC(vc
);
939 idnsSendQuery(idns_query
* q
)
941 // XXX: DNS sockets get closed during reconfigure produces a race between
942 // any already active connections (or ones received between closing DNS
943 // sockets and server listening sockets) and the reconfigure completing
944 // (Runner syncConfig() being run). Transactions which loose this race will
945 // produce DNS timeouts (or whatever the caller set) as their queries never
946 // get queued to be re-tried after the DNS socekts are re-opened.
948 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
949 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
953 if (nameservers
.empty()) {
954 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
958 assert(q
->lru
.next
== NULL
);
960 assert(q
->lru
.prev
== NULL
);
964 const auto nsCount
= nameservers
.size();
967 // only use mDNS resolvers for mDNS compatible queries
969 nsn
= nns_mdns_count
+ q
->nsends
% (nsCount
- nns_mdns_count
);
971 nsn
= q
->nsends
% nsCount
;
974 idnsSendQueryVC(q
, nsn
);
977 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
978 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
979 else if (DnsSocketA
>= 0)
980 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
986 q
->sent_t
= current_time
;
988 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
989 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketB
<< ": sendto: " << xstrerr(xerrno
));
990 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
991 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketA
<< ": sendto: " << xstrerr(xerrno
));
993 } while ( (x
<0 && y
<0) && q
->nsends
% nsCount
!= 0);
996 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
999 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
1002 ++ nameservers
[nsn
].nqueries
;
1003 q
->queue_t
= current_time
;
1004 dlinkAdd(q
, &q
->lru
, &lru_list
);
1010 idnsFromKnownNameserver(Ip::Address
const &from
)
1012 for (int i
= 0; static_cast<size_t>(i
) < nameservers
.size(); ++i
) {
1013 if (nameservers
[i
].S
!= from
)
1016 if (nameservers
[i
].S
.port() != from
.port())
1026 idnsFindQuery(unsigned short id
)
1031 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1032 q
= (idns_query
*)n
->data
;
1034 if (q
->query_id
== id
)
1041 static unsigned short
1044 // NP: apparently ranlux are faster, but not quite as "proven"
1045 static std::mt19937
mt(static_cast<uint32_t>(getCurrentTime() & 0xFFFFFFFF));
1046 unsigned short id
= mt() & 0xFFFF;
1047 unsigned short first_id
= id
;
1049 // ensure temporal uniqueness by looking for an existing use
1050 while (idnsFindQuery(id
)) {
1053 if (id
== first_id
) {
1054 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1062 /// \returns whether master or associated queries are still waiting for replies
1064 idnsStillPending(const idns_query
*master
)
1066 assert(!master
->master
); // we were given the master transaction
1067 for (const idns_query
*qi
= master
; qi
; qi
= qi
->slave
) {
1074 static std::ostream
&
1075 operator <<(std::ostream
&os
, const idns_query
&answered
)
1078 os
<< "error \"" << answered
.error
<< "\"";
1080 os
<< answered
.ancount
<< " records";
1085 idnsCallbackOnEarlyError(IDNSCB
*callback
, void *cbdata
, const char *error
)
1087 // A cbdataReferenceValid() check asserts on unlocked cbdata: Early errors,
1088 // by definition, happen before we store/cbdataReference() cbdata.
1089 debugs(78, 6, "\"" << error
<< "\" for " << cbdata
);
1090 callback(cbdata
, nullptr, 0, "Internal error", true); // hide error details
1093 /// safely sends one set of DNS records (or an error) to the caller
1095 idnsCallbackOneWithAnswer(IDNSCB
*callback
, void *cbdata
, const idns_query
&answered
, const bool lastAnswer
)
1097 if (!cbdataReferenceValid(cbdata
))
1099 const rfc1035_rr
*records
= answered
.message
? answered
.message
->answer
: nullptr;
1100 debugs(78, 6, (lastAnswer
? "last " : "") << answered
<< " for " << cbdata
);
1101 callback(cbdata
, records
, answered
.ancount
, answered
.error
, lastAnswer
);
1106 idnsCallbackNewCallerWithOldAnswers(IDNSCB
*callback
, void *cbdata
, const idns_query
* const master
)
1108 const bool lastAnswer
= false;
1109 // iterate all queries to act on answered ones
1110 for (auto query
= master
; query
; query
= query
->slave
) {
1112 continue; // no answer yet
1113 // no CallBack(CodeContext...) -- we always run in requestor's context
1114 if (!idnsCallbackOneWithAnswer(callback
, cbdata
, *query
, lastAnswer
))
1115 break; // the caller disappeared
1120 idnsCallbackAllCallersWithNewAnswer(const idns_query
* const answered
, const bool lastAnswer
)
1122 debugs(78, 8, (lastAnswer
? "last " : "") << *answered
);
1123 const auto master
= answered
->master
? answered
->master
: answered
;
1124 // iterate all queued lookup callers
1125 for (auto looker
= master
; looker
; looker
= looker
->queue
) {
1126 CallBack(looker
->codeContext
, [&] {
1127 (void)idnsCallbackOneWithAnswer(looker
->callback
, looker
->callback_data
,
1128 *answered
, lastAnswer
);
1134 idnsCallback(idns_query
*q
, const char *error
)
1139 auto master
= q
->master
? q
->master
: q
;
1141 const bool lastAnswer
= !idnsStillPending(master
);
1142 idnsCallbackAllCallersWithNewAnswer(q
, lastAnswer
);
1145 return; // wait for more answers
1147 if (master
->hash
.key
) {
1148 hash_remove_link(idns_lookup_hash
, &master
->hash
);
1149 master
->hash
.key
= nullptr;
1156 idnsGrokReply(const char *buf
, size_t sz
, int /*from_ns*/)
1158 rfc1035_message
*message
= NULL
;
1160 int n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1162 if (message
== NULL
) {
1163 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1167 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1169 idns_query
*q
= idnsFindQuery(message
->id
);
1172 debugs(78, 3, "idnsGrokReply: Late response");
1173 rfc1035MessageDestroy(&message
);
1177 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1178 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1179 rfc1035MessageDestroy(&message
);
1183 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1184 // TODO: actually gr the message right here.
1185 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1186 // this is overall better than force-feeding A response with AAAA an section later anyway.
1187 // AND allows us to merge AN+AR sections from both responses (one day)
1189 if (q
->edns_seen
>= 0) {
1190 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1191 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1192 // the altered NS was limiting the whole group.
1193 max_shared_edns
= q
->edns_seen
;
1194 // may be limited by one of the others still
1195 for (const auto &server
: nameservers
)
1196 max_shared_edns
= min(max_shared_edns
, server
.last_seen_edns
);
1198 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1199 // maybe reduce the global limit downwards to accomodate this NS
1200 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1202 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1203 max_shared_edns
= -1;
1207 dlinkDelete(&q
->lru
, &lru_list
);
1211 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1212 rfc1035MessageDestroy(&message
);
1219 // Strange: A TCP DNS response with the truncation bit (TC) set.
1220 // Return an error and cleanup; no point in trying TCP again.
1221 debugs(78, 3, HERE
<< "TCP DNS response");
1222 idnsCallback(q
, "Truncated TCP DNS response");
1228 idnsRcodeCount(n
, q
->attempt
);
1232 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1234 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1236 * RCODE 2 is "Server failure - The name server was
1237 * unable to process this query due to a problem with
1240 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1241 rfc1035MessageDestroy(&message
);
1246 // Do searchpath processing on the master A query only to keep
1247 // things simple. NXDOMAIN is authorative for the label, not
1249 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1250 assert(NULL
== message
->answer
);
1251 strcpy(q
->name
, q
->orig
);
1253 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1255 if (q
->domain
< npc
) {
1256 strcat(q
->name
, ".");
1257 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1258 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1264 rfc1035MessageDestroy(&message
);
1266 // cleanup slave AAAA query
1267 while (idns_query
*slave
= q
->slave
) {
1268 dlinkDelete(&slave
->lru
, &lru_list
);
1269 q
->slave
= slave
->slave
;
1270 slave
->slave
= NULL
;
1275 q
->query_id
= idnsQueryID();
1276 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1277 // see EDNS notes at top of file why this sends 0
1278 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1280 /* problem with query data -- query not sent */
1281 idnsCallback(q
, "Internal error");
1290 idnsSendSlaveAAAAQuery(q
);
1295 q
->message
= message
;
1299 idnsCallback(q
, NULL
);
1301 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1306 idnsRead(int fd
, void *)
1308 int *N
= &incoming_sockets_accepted
;
1310 int max
= INCOMING_DNS_MAX
;
1311 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1314 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1316 // Always keep reading. This stops (or at least makes harder) several
1317 // attacks on the DNS client.
1318 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1321 * two code lines after returning from comm_udprecvfrom()
1322 * something overwrites the memory behind the from parameter.
1323 * NO matter where in the stack declaration list above it is placed
1324 * The cause of this is still unknown, however copying the data appears
1325 * to allow it to be passed further without this erasure.
1327 Ip::Address bugbypass
;
1331 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1333 from
= bugbypass
; // BUG BYPASS. see notes above.
1340 if (ignoreErrno(xerrno
))
1344 /* Some Linux systems seem to set the FD for reading and then
1345 * return ECONNREFUSED when sendto() fails and generates an ICMP
1346 * port unreachable message. */
1347 /* or maybe an EHOSTUNREACH "No route to host" message */
1348 if (xerrno
!= ECONNREFUSED
&& xerrno
!= EHOSTUNREACH
)
1350 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << fd
<< " recvfrom: " << xstrerr(xerrno
));
1355 fd_bytes(fd
, len
, FD_READ
);
1360 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1362 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1363 int nsn
= idnsFromKnownNameserver(from
);
1366 ++ nameservers
[nsn
].nreplies
;
1369 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1370 // but after the ++ above to keep statistics right.
1372 continue; // Don't process replies if there is no pending query.
1374 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1375 static time_t last_warning
= 0;
1377 if (squid_curtime
- last_warning
> 60) {
1378 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1379 last_warning
= squid_curtime
;
1381 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1386 idnsGrokReply(rbuf
, len
, nsn
);
1391 idnsCheckQueue(void *)
1394 dlink_node
*p
= NULL
;
1398 if (nameservers
.empty())
1399 /* name servers went away; reconfiguring or shutting down */
1402 const auto nsCount
= nameservers
.size();
1403 for (n
= lru_list
.tail
; n
; n
= p
) {
1406 q
= static_cast<idns_query
*>(n
->data
);
1408 /* Anything to process in the queue? */
1409 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1412 /* Query timer still running? */
1413 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nsCount
))) {
1414 dlinkDelete(&q
->lru
, &lru_list
);
1415 q
->queue_t
= current_time
;
1416 dlinkAdd(q
, &q
->lru
, &lru_list
);
1420 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1421 " QID 0x" << std::hex
<< std::setfill('0') <<
1422 std::setw(4) << q
->query_id
<< ": timeout" );
1424 dlinkDelete(&q
->lru
, &lru_list
);
1427 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1430 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1431 " QID 0x" << std::hex
<< q
->query_id
<<
1432 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1433 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1436 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1438 idnsCallback(q
, "Timeout");
1446 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1448 nsvc
* vc
= (nsvc
*)data
;
1450 if (flag
== Comm::ERR_CLOSING
)
1453 if (flag
!= Comm::OK
|| len
<= 0) {
1454 if (Comm::IsConnOpen(conn
))
1459 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1461 if (vc
->msg
->contentSize() < vc
->msglen
) {
1462 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1463 CommIoCbPtrFun(idnsReadVC
, vc
));
1464 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1468 assert(vc
->ns
< nameservers
.size());
1469 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1471 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1473 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1474 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1475 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1479 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1481 nsvc
* vc
= (nsvc
*)data
;
1483 if (flag
== Comm::ERR_CLOSING
)
1486 if (flag
!= Comm::OK
|| len
<= 0) {
1487 if (Comm::IsConnOpen(conn
))
1492 vc
->read_msglen
+= len
;
1494 assert(vc
->read_msglen
<= 2);
1496 if (vc
->read_msglen
< 2) {
1497 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1498 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1499 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1503 vc
->read_msglen
= 0;
1505 vc
->msglen
= ntohs(vc
->msglen
);
1508 if (Comm::IsConnOpen(conn
))
1513 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1514 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1515 CommIoCbPtrFun(idnsReadVC
, vc
));
1516 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1520 * rcode < 0 indicates an error, rocde >= 0 indicates success
1523 idnsRcodeCount(int rcode
, int attempt
)
1530 if (rcode
< MAX_RCODE
)
1531 if (attempt
< MAX_ATTEMPT
)
1532 ++ RcodeMatrix
[rcode
][attempt
];
1538 static int init
= 0;
1540 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1541 Ip::Address addrV6
; // since we do not want to alter Config.Addrs.udp_* and do not have one of our own.
1543 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1544 addrV6
= Config
.Addrs
.udp_outgoing
;
1546 addrV6
= Config
.Addrs
.udp_incoming
;
1548 Ip::Address addrV4
= addrV6
;
1551 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1552 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1553 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1560 if (addrV4
.isIPv4()) {
1561 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1562 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1569 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1570 fatal("Could not create a DNS socket");
1572 /* Ouch... we can't call functions using debug from a debug
1573 * statement. Doing so messes up the internal Debug::level
1575 if (DnsSocketB
>= 0) {
1576 comm_local_port(DnsSocketB
);
1577 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1578 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1580 if (DnsSocketA
>= 0) {
1581 comm_local_port(DnsSocketA
);
1582 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1583 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1587 assert(nameservers
.empty());
1588 idnsAddMDNSNameservers();
1589 bool nsFound
= idnsParseNameservers();
1592 nsFound
= idnsParseResolvConf();
1596 nsFound
= idnsParseWIN32Registry();
1600 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1602 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1604 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1607 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1609 idnsAddNameserver("::1");
1610 idnsAddNameserver("127.0.0.1");
1614 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1615 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1619 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1620 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1621 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1622 max_shared_edns
= -1; // disable if we might receive random replies.
1626 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1630 idnsShutdownAndFreeState(const char *reason
)
1632 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1635 debugs(78, 2, reason
<< ": Closing DNS sockets");
1637 if (DnsSocketA
>= 0 ) {
1638 comm_close(DnsSocketA
);
1642 if (DnsSocketB
>= 0 ) {
1643 comm_close(DnsSocketB
);
1647 for (const auto &server
: nameservers
) {
1648 if (const auto vc
= server
.vc
) {
1649 if (Comm::IsConnOpen(vc
->conn
))
1654 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1655 nameservers
.clear();
1656 idnsFreeSearchpath();
1660 Dns::ConfigRr::endingShutdown()
1662 idnsShutdownAndFreeState("Shutdown");
1666 Dns::ConfigRr::startReconfigure()
1668 idnsShutdownAndFreeState("Reconfigure");
1672 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1674 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1679 // XXX: We are collapsing this DNS query (B) onto another one (A), but there
1680 // is no code to later send B if the A answer has unshareable 0 TTL records.
1682 idns_query
*q
= new idns_query
;
1683 // no query_id on this instance.
1685 q
->callback
= callback
;
1686 q
->callback_data
= cbdataReference(data
);
1688 q
->queue
= old
->queue
;
1691 // This check must follow cbdataReference() above because our callback code
1692 // needs a locked cbdata to call cbdataReferenceValid().
1693 if (idnsStillPending(old
))
1694 idnsCallbackNewCallerWithOldAnswers(callback
, data
, old
);
1695 // else: idns_lookup_hash is not a cache so no pending lookups means we are
1696 // in a reentrant lookup and will be called back when dequeued.
1702 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1704 q
->start_t
= current_time
;
1705 q
->callback
= callback
;
1706 q
->callback_data
= cbdataReference(data
);
1708 q
->hash
.key
= q
->orig
;
1709 hash_join(idns_lookup_hash
, &q
->hash
);
1715 idnsSendSlaveAAAAQuery(idns_query
*master
)
1717 idns_query
*q
= new idns_query
;
1718 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1719 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1721 q
->query_id
= idnsQueryID();
1722 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1724 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1725 ", id = 0x" << std::hex
<< q
->query_id
);
1731 q
->start_t
= master
->start_t
;
1732 q
->slave
= master
->slave
;
1740 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1742 size_t nameLength
= strlen(name
);
1744 // Prevent buffer overflow on q->name
1745 if (nameLength
> NS_MAXDNAME
) {
1746 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1747 idnsCallbackOnEarlyError(callback
, data
, "huge name");
1751 if (idnsCachedLookup(name
, callback
, data
))
1754 idns_query
*q
= new idns_query
;
1755 q
->query_id
= idnsQueryID();
1758 for (size_t i
= 0; i
< nameLength
; ++i
)
1762 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1763 q
->do_searchpath
= 1;
1765 q
->do_searchpath
= 0;
1768 strcpy(q
->orig
, name
);
1769 strcpy(q
->name
, q
->orig
);
1771 if (q
->do_searchpath
&& nd
< ndots
) {
1773 strcat(q
->name
, ".");
1774 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1775 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1778 // see EDNS notes at top of file why this sends 0
1779 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1782 /* problem with query data -- query not sent */
1783 idnsCallbackOnEarlyError(callback
, data
, "rfc3596BuildAQuery error");
1788 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1789 ", id = 0x" << std::hex
<< q
->query_id
);
1792 idnsStartQuery(q
, callback
, data
);
1795 idnsSendSlaveAAAAQuery(q
);
1799 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1801 char ip
[MAX_IPSTRLEN
];
1803 addr
.toStr(ip
,MAX_IPSTRLEN
);
1805 idns_query
*q
= new idns_query
;
1806 q
->query_id
= idnsQueryID();
1808 if (addr
.isIPv6()) {
1809 struct in6_addr addr6
;
1810 addr
.getInAddr(addr6
);
1811 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1813 struct in_addr addr4
;
1814 addr
.getInAddr(addr4
);
1815 // see EDNS notes at top of file why this sends 0
1816 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1820 /* problem with query data -- query not sent */
1821 idnsCallbackOnEarlyError(callback
, data
, "rfc3596BuildPTRQuery error");
1826 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1831 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1832 ", id = 0x" << std::hex
<< q
->query_id
);
1834 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1835 idnsStartQuery(q
, callback
, data
);
1840 * The function to return the DNS via SNMP
1843 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1846 variable_list
*Answer
= NULL
;
1848 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1849 *ErrP
= SNMP_ERR_NOERROR
;
1851 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1855 for (const auto &server
: nameservers
)
1856 n
+= server
.nqueries
;
1858 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1865 for (const auto &server
: nameservers
)
1866 n
+= server
.nreplies
;
1868 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1875 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1882 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1890 #endif /*SQUID_SNMP */