2 * Copyright (C) 1996-2023 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/IoManip.h"
15 #include "base/Random.h"
16 #include "base/RunnersRegistry.h"
18 #include "comm/Connection.h"
19 #include "comm/ConnOpener.h"
20 #include "comm/Loops.h"
21 #include "comm/Read.h"
22 #include "comm/Write.h"
23 #include "debug/Messages.h"
25 #include "dns/forward.h"
26 #include "dns/rfc3596.h"
32 #include "mgr/Registration.h"
33 #include "snmp_agent.h"
34 #include "SquidConfig.h"
41 #include "snmp_core.h"
44 #if HAVE_ARPA_NAMESER_H
45 #include <arpa/nameser.h>
53 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
54 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
55 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
58 #define _PATH_RESCONF "/etc/resolv.conf"
60 #ifndef NS_DEFAULTPORT
61 #define NS_DEFAULTPORT 53
65 #define NS_MAXDNAME 1025
72 /* The buffer size required to store the maximum allowed search path */
74 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
77 #define IDNS_MAX_TRIES 20
80 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
81 // NP: see http://www.iana.org/assignments/dns-parameters
82 static const char *Rcodes
[] = {
85 "Packet Format Error",
87 "Non-Existent Domain",
91 "Name Exists when it should not",
92 "RR Set Exists when it should not",
93 "RR Set that should exist does not",
94 "Server Not Authoritative for zone",
95 "Name not contained in zone",
99 "Bad OPT Version or TSIG Signature Failure"
102 typedef struct _sp sp
;
106 CBDATA_CLASS(idns_query
);
110 codeContext(CodeContext::Current())
113 memset(&query
, 0, sizeof(query
));
117 memset(&start_t
, 0, sizeof(start_t
));
118 memset(&sent_t
, 0, sizeof(sent_t
));
119 memset(&queue_t
, 0, sizeof(queue_t
));
124 rfc1035MessageDestroy(&message
);
127 // master is just a back-reference
128 cbdataReferenceDone(callback_data
);
133 char buf
[RESOLV_BUFSZ
];
134 char name
[NS_MAXDNAME
+ 1];
135 char orig
[NS_MAXDNAME
+ 1];
137 unsigned short query_id
= 0; ///< random query ID sent to server; changes with every query sent
138 InstanceId
<idns_query
> xact_id
; ///< identifies our "transaction", stays constant when query is retried
142 bool permit_mdns
= false;
145 struct timeval start_t
;
146 struct timeval sent_t
;
147 struct timeval queue_t
;
151 void *callback_data
= nullptr;
152 CodeContext::Pointer codeContext
; ///< requestor's context
156 idns_query
*queue
= nullptr;
157 idns_query
*slave
= nullptr; // single linked list
158 idns_query
*master
= nullptr; // single pointer to a shared master
159 unsigned short domain
= 0;
160 unsigned short do_searchpath
= 0;
161 rfc1035_message
*message
= nullptr;
163 const char *error
= nullptr;
166 InstanceIdDefinitions(idns_query
, "dns");
168 CBDATA_CLASS_INIT(idns_query
);
175 explicit nsvc(size_t nsv
) : ns(nsv
), msg(new MemBuf()), queue(new MemBuf()) {}
179 Comm::ConnectionPointer conn
;
180 unsigned short msglen
= 0;
182 MemBuf
*msg
= nullptr;
183 MemBuf
*queue
= nullptr;
187 CBDATA_CLASS_INIT(nsvc
);
195 #if WHEN_EDNS_RESPONSES_ARE_PARSED
196 int last_seen_edns
= 0;
198 bool mDNSResolver
= false;
205 /// manage DNS internal component
206 class ConfigRr
: public RegisteredRunner
209 /* RegisteredRunner API */
210 void startReconfigure() override
;
211 void endingShutdown() override
;
216 DefineRunnerRegistratorIn(Dns
, ConfigRr
);
219 char domain
[NS_MAXDNAME
];
223 static std::vector
<ns
> nameservers
;
224 static sp
*searchpath
= nullptr;
225 static int nns_mdns_count
= 0;
227 static int npc_alloc
= 0;
228 static int ndots
= 1;
229 static dlink_list lru_list
;
230 static int event_queued
= 0;
231 static hash_table
*idns_lookup_hash
= nullptr;
237 * EDNS as specified may be sent as an additional record for any request.
238 * early testing has revealed that it works on common devices, but cannot
239 * be reliably used on any A or PTR requet done for IPv4 addresses.
241 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
244 * Squid is optimized to generate one packet and re-send it to all NS
245 * due to this we cannot customize the EDNS size per NS.
247 * As such we take the configuration option value as fixed.
250 * This may not be worth doing, but if/when additional-records are parsed
251 * we will be able to recover the OPT value specific to any one NS and
252 * cache it. Effectively automating the tuning of EDNS advertised to the
253 * size our active NS are capable.
254 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
255 * Responses from the configured NS may cause this to be raised or turned off.
257 #if WHEN_EDNS_RESPONSES_ARE_PARSED
258 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
261 static OBJH idnsStats
;
262 static void idnsAddNameserver(const char *buf
);
263 static void idnsAddMDNSNameservers();
264 static void idnsAddPathComponent(const char *buf
);
265 static void idnsFreeSearchpath(void);
266 static bool idnsParseNameservers(void);
267 static bool idnsParseResolvConf(void);
269 static bool idnsParseWIN32Registry(void);
270 static void idnsParseWIN32SearchList(const char *);
272 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
273 static void idnsSendQuery(idns_query
* q
);
274 static IOCB idnsReadVCHeader
;
275 static void idnsDoSendQueryVC(nsvc
*vc
);
276 static CNCB idnsInitVCConnected
;
277 static IOCB idnsReadVC
;
278 static IOCB idnsSentQueryVC
;
280 static int idnsFromKnownNameserver(Ip::Address
const &from
);
281 static idns_query
*idnsFindQuery(unsigned short id
);
282 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
284 static EVH idnsCheckQueue
;
285 static void idnsTickleQueue(void);
286 static void idnsRcodeCount(int, int);
287 static CLCB idnsVCClosed
;
288 static unsigned short idnsQueryID(void);
289 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
290 static void idnsCallbackOnEarlyError(IDNSCB
*callback
, void *cbdata
, const char *error
);
293 idnsCheckMDNS(idns_query
*q
)
295 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
298 size_t slen
= strlen(q
->name
);
299 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
300 q
->permit_mdns
= true;
305 idnsAddMDNSNameservers()
310 if (!Config
.onoff
.dns_mdns
)
313 // mDNS resolver addresses are explicit multicast group IPs
314 if (Ip::EnableIpv6
) {
315 idnsAddNameserver("FF02::FB");
316 nameservers
.back().S
.port(5353);
317 nameservers
.back().mDNSResolver
= true;
321 idnsAddNameserver("224.0.0.251");
322 nameservers
.back().S
.port(5353);
323 nameservers
.back().mDNSResolver
= true;
329 idnsAddNameserver(const char *buf
)
334 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
339 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
341 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
344 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
345 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
349 auto &nameserver
= nameservers
.emplace_back(ns());
350 A
.port(NS_DEFAULTPORT
);
352 #if WHEN_EDNS_RESPONSES_ARE_PARSED
353 nameserver
.last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
354 // TODO generate a test packet to probe this NS from EDNS size and ability.
356 debugs(78, 3, "Added nameserver #" << nameservers
.size()-1 << " (" << A
<< ")");
360 idnsAddPathComponent(const char *buf
)
362 if (npc
== npc_alloc
) {
363 int oldalloc
= npc_alloc
;
364 sp
*oldptr
= searchpath
;
371 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
373 if (oldptr
&& oldalloc
)
374 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
380 assert(npc
< npc_alloc
);
381 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
382 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
383 Tolower(searchpath
[npc
].domain
);
384 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
389 idnsFreeSearchpath(void)
391 safe_free(searchpath
);
396 idnsParseNameservers(void)
399 for (auto &i
: Config
.dns
.nameservers
) {
400 debugs(78, Important(15), "Adding nameserver " << i
<< " from squid.conf");
401 idnsAddNameserver(i
.c_str());
408 idnsParseResolvConf(void)
412 FILE *fp
= fopen(_PATH_RESCONF
, "r");
416 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerr(xerrno
));
420 char buf
[RESOLV_BUFSZ
];
421 const char *t
= nullptr;
422 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
423 t
= strtok(buf
, w_space
);
427 } else if (strcmp(t
, "nameserver") == 0) {
428 t
= strtok(nullptr, w_space
);
433 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
435 idnsAddNameserver(t
);
437 } else if (strcmp(t
, "domain") == 0) {
438 idnsFreeSearchpath();
439 t
= strtok(nullptr, w_space
);
444 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
446 idnsAddPathComponent(t
);
447 } else if (strcmp(t
, "search") == 0) {
448 idnsFreeSearchpath();
449 while (nullptr != t
) {
450 t
= strtok(nullptr, w_space
);
455 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
457 idnsAddPathComponent(t
);
459 } else if (strcmp(t
, "options") == 0) {
460 while (nullptr != t
) {
461 t
= strtok(nullptr, w_space
);
466 if (strncmp(t
, "ndots:", 6) == 0) {
472 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
477 if (npc
== 0 && (t
= getMyHostname())) {
480 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", nullptr, &Type
, nullptr, &Size
);
502 if (Result
== ERROR_SUCCESS
&& Size
) {
503 t
= (char *) xmalloc(Size
);
504 RegQueryValueEx(hndKey
, "Domain", nullptr, &Type
, (LPBYTE
) t
, &Size
);
505 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
506 idnsAddPathComponent(t
);
509 Result
= RegQueryValueEx(hndKey
, "SearchList", nullptr, &Type
, nullptr, &Size
);
511 if (Result
== ERROR_SUCCESS
&& Size
) {
512 t
= (char *) xmalloc(Size
);
513 RegQueryValueEx(hndKey
, "SearchList", nullptr, &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(nullptr, 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", nullptr, &Type
, nullptr, &Size
);
552 if (Result
== ERROR_SUCCESS
&& Size
) {
553 t
= (char *) xmalloc(Size
);
554 RegQueryValueEx(hndKey
, "DhcpNameServer", nullptr, &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(nullptr, ",");
566 Result
= RegQueryValueEx(hndKey
, "NameServer", nullptr, &Type
, nullptr, &Size
);
568 if (Result
== ERROR_SUCCESS
&& Size
) {
569 t
= (char *) xmalloc(Size
);
570 RegQueryValueEx(hndKey
, "NameServer", nullptr, &Type
, (LPBYTE
) t
, &Size
);
571 token
= strtok(t
, ", ");
574 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
575 idnsAddNameserver(token
);
577 token
= strtok(nullptr, ", ");
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
, nullptr, nullptr, nullptr, &InterfacesCount
, &MaxSubkeyLen
, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS
) {
608 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
609 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
612 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, nullptr, nullptr, nullptr, &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", nullptr, &Type
, nullptr, &Size
);
623 if (Result
== ERROR_SUCCESS
&& Size
) {
624 t
= (char *) xmalloc(Size
);
625 RegQueryValueEx(hndKey2
, "DhcpNameServer", nullptr, &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(nullptr, ", ");
636 Result
= RegQueryValueEx(hndKey2
, "NameServer", nullptr, &Type
, nullptr, &Size
);
637 if (Result
== ERROR_SUCCESS
&& Size
) {
638 t
= (char *) xmalloc(Size
);
639 RegQueryValueEx(hndKey2
, "NameServer", nullptr, &Type
, (LPBYTE
)t
, &Size
);
640 token
= strtok(t
, ", ");
642 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
643 idnsAddNameserver(token
);
645 token
= strtok(nullptr, ", ");
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", nullptr, &Type
, nullptr, &Size
);
681 if (Result
== ERROR_SUCCESS
&& Size
) {
682 t
= (char *) xmalloc(Size
);
683 RegQueryValueEx(hndKey
, "NameServer", nullptr, &Type
, (LPBYTE
) t
, &Size
);
684 token
= strtok(t
, ", ");
687 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
688 idnsAddNameserver(token
);
690 token
= strtok(nullptr, ", ");
701 debugs(78, DBG_IMPORTANT
, "ERROR: 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 M FQDN\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 %c %s\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
),
729 (q
->permit_mdns
? 'M':' '),
733 if (Config
.dns
.packet_max
> 0)
734 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
736 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
738 storeAppendPrintf(sentry
, "\nNameservers:\n");
739 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
740 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
742 for (const auto &server
: nameservers
) {
743 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
744 server
.S
.toStr(buf
,MAX_IPSTRLEN
),
747 server
.mDNSResolver
?"multicast":"recurse");
750 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
751 storeAppendPrintf(sentry
, "RCODE");
753 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
754 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
756 storeAppendPrintf(sentry
, " PROBLEM\n");
758 for (j
= 0; j
< MAX_RCODE
; ++j
) {
759 if (j
> 10 && j
< 16)
760 continue; // unassigned by IANA.
762 storeAppendPrintf(sentry
, "%5d", j
);
764 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
765 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
767 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
771 storeAppendPrintf(sentry
, "\nSearch list:\n");
773 for (i
=0; i
< npc
; ++i
)
774 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
776 storeAppendPrintf(sentry
, "\n");
781 idnsTickleQueue(void)
786 if (nullptr == lru_list
.tail
)
789 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
791 eventAdd("idnsCheckQueue", idnsCheckQueue
, nullptr, when
, 1);
797 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *, size_t size
, Comm::Flag flag
, int, void *data
)
799 nsvc
* vc
= (nsvc
*)data
;
801 if (flag
== Comm::ERR_CLOSING
)
804 // XXX: irrelevant now that we have conn pointer?
805 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
808 if (flag
!= Comm::OK
|| size
<= 0) {
814 idnsDoSendQueryVC(vc
);
818 idnsDoSendQueryVC(nsvc
*vc
)
823 if (vc
->queue
->contentSize() == 0)
826 // if retrying after a TC UDP response, our close handler cb may be pending
827 if (fd_table
[vc
->conn
->fd
].closing())
830 MemBuf
*mb
= vc
->queue
;
832 vc
->queue
= new MemBuf
;
836 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
837 const auto timeout
= (Config
.Timeout
.idns_query
% 1000 ?
838 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
839 AsyncCall::Pointer nil
;
841 commSetConnTimeout(vc
->conn
, timeout
, nil
);
843 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
844 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
845 Comm::Write(vc
->conn
, mb
, call
);
851 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int, void *data
)
853 nsvc
* vc
= (nsvc
*)data
;
855 if (status
!= Comm::OK
|| !conn
) {
856 char buf
[MAX_IPSTRLEN
] = "";
857 if (vc
->ns
< nameservers
.size())
858 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
859 debugs(78, DBG_IMPORTANT
, "ERROR: Failed to connect to nameserver " << buf
<< " using TCP.");
865 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
866 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
867 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
868 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
870 idnsDoSendQueryVC(vc
);
874 idnsVCClosed(const CommCloseCbParams
¶ms
)
876 nsvc
* vc
= (nsvc
*)params
.data
;
878 vc
->conn
->noteClosure();
888 if (ns
< nameservers
.size()) // XXX: idnsShutdownAndFreeState may have freed nameservers[]
889 nameservers
[ns
].vc
= nullptr;
893 idnsInitVC(size_t nsv
)
895 assert(nsv
< nameservers
.size());
896 nsvc
*vc
= new nsvc(nsv
);
897 assert(vc
->conn
== nullptr); // MUST be NULL from the construction process!
898 nameservers
[nsv
].vc
= vc
;
900 Comm::ConnectionPointer conn
= new Comm::Connection();
902 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
903 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
905 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
907 if (conn
->remote
.isIPv4())
908 conn
->local
.setIPv4();
910 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
912 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
913 cs
->setHost("DNS TCP Socket");
918 idnsSendQueryVC(idns_query
* q
, size_t nsn
)
920 assert(nsn
< nameservers
.size());
921 if (nameservers
[nsn
].vc
== nullptr)
924 nsvc
*vc
= nameservers
[nsn
].vc
;
927 char buf
[MAX_IPSTRLEN
];
928 debugs(78, DBG_IMPORTANT
, "ERROR: idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
935 short head
= htons(q
->sz
);
937 vc
->queue
->append((char *)&head
, 2);
939 vc
->queue
->append(q
->buf
, q
->sz
);
941 idnsDoSendQueryVC(vc
);
945 idnsSendQuery(idns_query
* q
)
947 // XXX: DNS sockets get closed during reconfigure produces a race between
948 // any already active connections (or ones received between closing DNS
949 // sockets and server listening sockets) and the reconfigure completing
950 // (Runner syncConfig() being run). Transactions which loose this race will
951 // produce DNS timeouts (or whatever the caller set) as their queries never
952 // get queued to be re-tried after the DNS socekts are re-opened.
954 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
955 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
959 if (nameservers
.empty()) {
960 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
964 assert(q
->lru
.next
== nullptr);
966 assert(q
->lru
.prev
== nullptr);
970 const auto nsCount
= nameservers
.size();
973 // only use mDNS resolvers for mDNS compatible queries
975 nsn
= nns_mdns_count
+ q
->nsends
% (nsCount
- nns_mdns_count
);
977 nsn
= q
->nsends
% nsCount
;
980 idnsSendQueryVC(q
, nsn
);
983 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
984 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
985 else if (DnsSocketA
>= 0)
986 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
992 q
->sent_t
= current_time
;
994 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
995 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketB
<< ": sendto: " << xstrerr(xerrno
));
996 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
997 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketA
<< ": sendto: " << xstrerr(xerrno
));
999 } while ( (x
<0 && y
<0) && q
->nsends
% nsCount
!= 0);
1002 fd_bytes(DnsSocketB
, y
, IoDirection::Write
);
1005 fd_bytes(DnsSocketA
, x
, IoDirection::Write
);
1008 ++ nameservers
[nsn
].nqueries
;
1009 q
->queue_t
= current_time
;
1010 dlinkAdd(q
, &q
->lru
, &lru_list
);
1016 idnsFromKnownNameserver(Ip::Address
const &from
)
1018 for (int i
= 0; static_cast<size_t>(i
) < nameservers
.size(); ++i
) {
1019 if (nameservers
[i
].S
!= from
)
1022 if (nameservers
[i
].S
.port() != from
.port())
1032 idnsFindQuery(unsigned short id
)
1037 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1038 q
= (idns_query
*)n
->data
;
1040 if (q
->query_id
== id
)
1047 static unsigned short
1050 // NP: apparently ranlux are faster, but not quite as "proven"
1051 static std::mt19937
mt(RandomSeed32());
1052 unsigned short id
= mt() & 0xFFFF;
1053 unsigned short first_id
= id
;
1055 // ensure temporal uniqueness by looking for an existing use
1056 while (idnsFindQuery(id
)) {
1059 if (id
== first_id
) {
1060 debugs(78, DBG_IMPORTANT
, "WARNING: idnsQueryID: too many pending DNS requests");
1068 /// \returns whether master or associated queries are still waiting for replies
1070 idnsStillPending(const idns_query
*master
)
1072 assert(!master
->master
); // we were given the master transaction
1073 for (const idns_query
*qi
= master
; qi
; qi
= qi
->slave
) {
1080 static std::ostream
&
1081 operator <<(std::ostream
&os
, const idns_query
&answered
)
1084 os
<< "error \"" << answered
.error
<< "\"";
1086 os
<< answered
.ancount
<< " records";
1091 idnsCallbackOnEarlyError(IDNSCB
*callback
, void *cbdata
, const char *error
)
1093 // A cbdataReferenceValid() check asserts on unlocked cbdata: Early errors,
1094 // by definition, happen before we store/cbdataReference() cbdata.
1095 debugs(78, 6, "\"" << error
<< "\" for " << cbdata
);
1096 callback(cbdata
, nullptr, 0, "Internal error", true); // hide error details
1099 /// safely sends one set of DNS records (or an error) to the caller
1101 idnsCallbackOneWithAnswer(IDNSCB
*callback
, void *cbdata
, const idns_query
&answered
, const bool lastAnswer
)
1103 if (!cbdataReferenceValid(cbdata
))
1105 const rfc1035_rr
*records
= answered
.message
? answered
.message
->answer
: nullptr;
1106 debugs(78, 6, (lastAnswer
? "last " : "") << answered
<< " for " << cbdata
);
1107 callback(cbdata
, records
, answered
.ancount
, answered
.error
, lastAnswer
);
1112 idnsCallbackNewCallerWithOldAnswers(IDNSCB
*callback
, void *cbdata
, const idns_query
* const master
)
1114 const bool lastAnswer
= false;
1115 // iterate all queries to act on answered ones
1116 for (auto query
= master
; query
; query
= query
->slave
) {
1118 continue; // no answer yet
1119 // no CallBack(CodeContext...) -- we always run in requestor's context
1120 if (!idnsCallbackOneWithAnswer(callback
, cbdata
, *query
, lastAnswer
))
1121 break; // the caller disappeared
1126 idnsCallbackAllCallersWithNewAnswer(const idns_query
* const answered
, const bool lastAnswer
)
1128 debugs(78, 8, (lastAnswer
? "last " : "") << *answered
);
1129 const auto master
= answered
->master
? answered
->master
: answered
;
1130 // iterate all queued lookup callers
1131 for (auto looker
= master
; looker
; looker
= looker
->queue
) {
1132 CallBack(looker
->codeContext
, [&] {
1133 (void)idnsCallbackOneWithAnswer(looker
->callback
, looker
->callback_data
,
1134 *answered
, lastAnswer
);
1140 idnsCallback(idns_query
*q
, const char *error
)
1145 auto master
= q
->master
? q
->master
: q
;
1147 const bool lastAnswer
= !idnsStillPending(master
);
1148 idnsCallbackAllCallersWithNewAnswer(q
, lastAnswer
);
1151 return; // wait for more answers
1153 if (master
->hash
.key
) {
1154 hash_remove_link(idns_lookup_hash
, &master
->hash
);
1155 master
->hash
.key
= nullptr;
1162 idnsGrokReply(const char *buf
, size_t sz
, int /*from_ns*/)
1164 rfc1035_message
*message
= nullptr;
1166 int n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1168 if (message
== nullptr) {
1169 debugs(78, DBG_IMPORTANT
, "ERROR: idnsGrokReply: Malformed DNS response");
1173 debugs(78, 3, "idnsGrokReply: QID 0x" << asHex(message
->id
) << ", " << n
<< " answers");
1175 idns_query
*q
= idnsFindQuery(message
->id
);
1178 debugs(78, 3, "idnsGrokReply: Late response");
1179 rfc1035MessageDestroy(&message
);
1183 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1184 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1185 rfc1035MessageDestroy(&message
);
1189 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1190 // TODO: actually gr the message right here.
1191 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1192 // this is overall better than force-feeding A response with AAAA an section later anyway.
1193 // AND allows us to merge AN+AR sections from both responses (one day)
1195 if (q
->edns_seen
>= 0) {
1196 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1197 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1198 // the altered NS was limiting the whole group.
1199 max_shared_edns
= q
->edns_seen
;
1200 // may be limited by one of the others still
1201 for (const auto &server
: nameservers
)
1202 max_shared_edns
= min(max_shared_edns
, server
.last_seen_edns
);
1204 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1205 // maybe reduce the global limit downwards to accommodate this NS
1206 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1208 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1209 max_shared_edns
= -1;
1213 dlinkDelete(&q
->lru
, &lru_list
);
1217 debugs(78, 3, "Resolver requested TC (" << q
->query
.name
<< ")");
1218 rfc1035MessageDestroy(&message
);
1225 // Strange: A TCP DNS response with the truncation bit (TC) set.
1226 // Return an error and cleanup; no point in trying TCP again.
1227 debugs(78, 3, "TCP DNS response");
1228 idnsCallback(q
, "Truncated TCP DNS response");
1234 idnsRcodeCount(n
, q
->attempt
);
1238 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1240 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1242 * RCODE 2 is "Server failure - The name server was
1243 * unable to process this query due to a problem with
1246 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1247 rfc1035MessageDestroy(&message
);
1252 // Do searchpath processing on the master A query only to keep
1253 // things simple. NXDOMAIN is authoritative for the label, not
1255 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1256 assert(nullptr == message
->answer
);
1257 strcpy(q
->name
, q
->orig
);
1259 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1261 if (q
->domain
< npc
) {
1262 strcat(q
->name
, ".");
1263 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1264 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1270 rfc1035MessageDestroy(&message
);
1272 // cleanup slave AAAA query
1273 while (idns_query
*slave
= q
->slave
) {
1274 dlinkDelete(&slave
->lru
, &lru_list
);
1275 q
->slave
= slave
->slave
;
1276 slave
->slave
= nullptr;
1281 q
->query_id
= idnsQueryID();
1282 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1283 // see EDNS notes at top of file why this sends 0
1284 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1286 /* problem with query data -- query not sent */
1287 idnsCallback(q
, "Internal error");
1296 idnsSendSlaveAAAAQuery(q
);
1301 q
->message
= message
;
1305 idnsCallback(q
, nullptr);
1307 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1312 idnsRead(int fd
, void *)
1314 int *N
= &incoming_sockets_accepted
;
1316 int max
= INCOMING_DNS_MAX
;
1317 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1320 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1322 // Always keep reading. This stops (or at least makes harder) several
1323 // attacks on the DNS client.
1324 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, nullptr, 0);
1327 * two code lines after returning from comm_udprecvfrom()
1328 * something overwrites the memory behind the from parameter.
1329 * NO matter where in the stack declaration list above it is placed
1330 * The cause of this is still unknown, however copying the data appears
1331 * to allow it to be passed further without this erasure.
1333 Ip::Address bugbypass
;
1337 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1339 from
= bugbypass
; // BUG BYPASS. see notes above.
1346 if (ignoreErrno(xerrno
))
1350 /* Some Linux systems seem to set the FD for reading and then
1351 * return ECONNREFUSED when sendto() fails and generates an ICMP
1352 * port unreachable message. */
1353 /* or maybe an EHOSTUNREACH "No route to host" message */
1354 if (xerrno
!= ECONNREFUSED
&& xerrno
!= EHOSTUNREACH
)
1356 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << fd
<< " recvfrom: " << xstrerr(xerrno
));
1361 fd_bytes(fd
, len
, IoDirection::Read
);
1366 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1368 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1369 int nsn
= idnsFromKnownNameserver(from
);
1372 ++ nameservers
[nsn
].nreplies
;
1375 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1376 // but after the ++ above to keep statistics right.
1378 continue; // Don't process replies if there is no pending query.
1380 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1381 static time_t last_warning
= 0;
1383 if (squid_curtime
- last_warning
> 60) {
1384 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1385 last_warning
= squid_curtime
;
1387 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1392 idnsGrokReply(rbuf
, len
, nsn
);
1397 idnsCheckQueue(void *)
1400 dlink_node
*p
= nullptr;
1404 if (nameservers
.empty())
1405 /* name servers went away; reconfiguring or shutting down */
1408 const auto nsCount
= nameservers
.size();
1409 for (n
= lru_list
.tail
; n
; n
= p
) {
1412 q
= static_cast<idns_query
*>(n
->data
);
1414 /* Anything to process in the queue? */
1415 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1418 /* Query timer still running? */
1419 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nsCount
))) {
1420 dlinkDelete(&q
->lru
, &lru_list
);
1421 q
->queue_t
= current_time
;
1422 dlinkAdd(q
, &q
->lru
, &lru_list
);
1426 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1427 " QID 0x" << asHex(q
->query_id
).minDigits(4) << ": timeout");
1429 dlinkDelete(&q
->lru
, &lru_list
);
1432 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1435 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1436 " QID 0x" << asHex(q
->query_id
) <<
1437 ": giving up after " << q
->nsends
<< " tries and " <<
1438 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1441 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1443 idnsCallback(q
, "Timeout");
1451 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1453 nsvc
* vc
= (nsvc
*)data
;
1455 if (flag
== Comm::ERR_CLOSING
)
1458 if (flag
!= Comm::OK
|| len
<= 0) {
1459 if (Comm::IsConnOpen(conn
))
1464 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1466 if (vc
->msg
->contentSize() < vc
->msglen
) {
1467 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1468 CommIoCbPtrFun(idnsReadVC
, vc
));
1469 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1473 assert(vc
->ns
< nameservers
.size());
1474 debugs(78, 3, conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1476 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1478 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1479 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1480 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1484 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1486 nsvc
* vc
= (nsvc
*)data
;
1488 if (flag
== Comm::ERR_CLOSING
)
1491 if (flag
!= Comm::OK
|| len
<= 0) {
1492 if (Comm::IsConnOpen(conn
))
1497 vc
->read_msglen
+= len
;
1499 assert(vc
->read_msglen
<= 2);
1501 if (vc
->read_msglen
< 2) {
1502 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1503 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1504 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1508 vc
->read_msglen
= 0;
1510 vc
->msglen
= ntohs(vc
->msglen
);
1513 if (Comm::IsConnOpen(conn
))
1518 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1519 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1520 CommIoCbPtrFun(idnsReadVC
, vc
));
1521 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1525 * rcode < 0 indicates an error, rocde >= 0 indicates success
1528 idnsRcodeCount(int rcode
, int attempt
)
1535 if (rcode
< MAX_RCODE
)
1536 if (attempt
< MAX_ATTEMPT
)
1537 ++ RcodeMatrix
[rcode
][attempt
];
1543 static int init
= 0;
1545 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1546 Ip::Address addrV6
; // since we do not want to alter Config.Addrs.udp_* and do not have one of our own.
1548 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1549 addrV6
= Config
.Addrs
.udp_outgoing
;
1551 addrV6
= Config
.Addrs
.udp_incoming
;
1553 Ip::Address addrV4
= addrV6
;
1556 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1557 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1558 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1565 if (addrV4
.isIPv4()) {
1566 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1567 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1574 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1575 fatal("Could not create a DNS socket");
1577 /* Ouch... we can't call functions using debug from a debug
1578 * statement. Doing so messes up the internal Debug::level
1580 if (DnsSocketB
>= 0) {
1581 comm_local_port(DnsSocketB
);
1582 debugs(78, Important(16), "DNS IPv6 socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1583 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, nullptr, 0);
1585 if (DnsSocketA
>= 0) {
1586 comm_local_port(DnsSocketA
);
1587 debugs(78, Important(64), "DNS IPv4 socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1588 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, nullptr, 0);
1592 assert(nameservers
.empty());
1593 idnsAddMDNSNameservers();
1594 bool nsFound
= idnsParseNameservers();
1597 nsFound
= idnsParseResolvConf();
1601 nsFound
= idnsParseWIN32Registry();
1605 debugs(78, DBG_IMPORTANT
, "WARNING: Could not find any nameservers. Trying to use localhost");
1607 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1609 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1612 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1614 idnsAddNameserver("::1");
1615 idnsAddNameserver("127.0.0.1");
1619 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1620 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1624 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1625 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1626 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1627 max_shared_edns
= -1; // disable if we might receive random replies.
1631 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1635 idnsShutdownAndFreeState(const char *reason
)
1637 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1640 debugs(78, 2, reason
<< ": Closing DNS sockets");
1642 if (DnsSocketA
>= 0 ) {
1643 comm_close(DnsSocketA
);
1647 if (DnsSocketB
>= 0 ) {
1648 comm_close(DnsSocketB
);
1652 for (const auto &server
: nameservers
) {
1653 if (const auto vc
= server
.vc
) {
1654 if (Comm::IsConnOpen(vc
->conn
))
1659 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1660 nameservers
.clear();
1661 idnsFreeSearchpath();
1665 Dns::ConfigRr::endingShutdown()
1667 idnsShutdownAndFreeState("Shutdown");
1671 Dns::ConfigRr::startReconfigure()
1673 idnsShutdownAndFreeState("Reconfigure");
1677 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1679 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1684 // XXX: We are collapsing this DNS query (B) onto another one (A), but there
1685 // is no code to later send B if the A answer has unshareable 0 TTL records.
1687 idns_query
*q
= new idns_query
;
1688 // no query_id on this instance.
1690 q
->callback
= callback
;
1691 q
->callback_data
= cbdataReference(data
);
1693 q
->queue
= old
->queue
;
1696 // This check must follow cbdataReference() above because our callback code
1697 // needs a locked cbdata to call cbdataReferenceValid().
1698 if (idnsStillPending(old
))
1699 idnsCallbackNewCallerWithOldAnswers(callback
, data
, old
);
1700 // else: idns_lookup_hash is not a cache so no pending lookups means we are
1701 // in a reentrant lookup and will be called back when dequeued.
1707 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1709 q
->start_t
= current_time
;
1710 q
->callback
= callback
;
1711 q
->callback_data
= cbdataReference(data
);
1713 q
->hash
.key
= q
->orig
;
1714 hash_join(idns_lookup_hash
, &q
->hash
);
1720 idnsSendSlaveAAAAQuery(idns_query
*master
)
1722 idns_query
*q
= new idns_query
;
1723 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1724 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1726 q
->query_id
= idnsQueryID();
1727 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1729 debugs(78, 3, "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1730 ", id = 0x" << asHex(q
->query_id
));
1736 q
->start_t
= master
->start_t
;
1737 q
->slave
= master
->slave
;
1745 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1747 size_t nameLength
= strlen(name
);
1749 // Prevent buffer overflow on q->name
1750 if (nameLength
> NS_MAXDNAME
) {
1751 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1752 idnsCallbackOnEarlyError(callback
, data
, "huge name");
1756 if (idnsCachedLookup(name
, callback
, data
))
1759 idns_query
*q
= new idns_query
;
1760 q
->query_id
= idnsQueryID();
1763 for (size_t i
= 0; i
< nameLength
; ++i
)
1767 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1768 q
->do_searchpath
= 1;
1770 q
->do_searchpath
= 0;
1773 strcpy(q
->orig
, name
);
1774 strcpy(q
->name
, q
->orig
);
1776 if (q
->do_searchpath
&& nd
< ndots
) {
1778 strcat(q
->name
, ".");
1779 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1780 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1783 // see EDNS notes at top of file why this sends 0
1784 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1787 /* problem with query data -- query not sent */
1788 idnsCallbackOnEarlyError(callback
, data
, "rfc3596BuildAQuery error");
1793 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1794 ", id = 0x" << asHex(q
->query_id
));
1797 idnsStartQuery(q
, callback
, data
);
1800 idnsSendSlaveAAAAQuery(q
);
1804 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1806 char ip
[MAX_IPSTRLEN
];
1808 addr
.toStr(ip
,MAX_IPSTRLEN
);
1810 idns_query
*q
= new idns_query
;
1811 q
->query_id
= idnsQueryID();
1813 if (addr
.isIPv6()) {
1814 struct in6_addr addr6
;
1815 addr
.getInAddr(addr6
);
1816 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1818 struct in_addr addr4
;
1819 addr
.getInAddr(addr4
);
1820 // see EDNS notes at top of file why this sends 0
1821 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1825 /* problem with query data -- query not sent */
1826 idnsCallbackOnEarlyError(callback
, data
, "rfc3596BuildPTRQuery error");
1831 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1836 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1837 ", id = 0x" << asHex(q
->query_id
));
1839 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1840 idnsStartQuery(q
, callback
, data
);
1845 * The function to return the DNS via SNMP
1848 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1851 variable_list
*Answer
= nullptr;
1853 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1854 *ErrP
= SNMP_ERR_NOERROR
;
1856 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1860 for (const auto &server
: nameservers
)
1861 n
+= server
.nqueries
;
1863 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1870 for (const auto &server
: nameservers
)
1871 n
+= server
.nreplies
;
1873 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1880 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1887 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1895 #endif /*SQUID_SNMP */