2 * Copyright (C) 1996-2025 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 * Squid is optimized to generate one packet and re-send it to all NS
238 * due to this we cannot customize the EDNS size per NS.
240 * As such we take the configuration option value as fixed.
243 * This may not be worth doing, but if/when additional-records are parsed
244 * we will be able to recover the OPT value specific to any one NS and
245 * cache it. Effectively automating the tuning of EDNS advertised to the
246 * size our active NS are capable.
247 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
248 * Responses from the configured NS may cause this to be raised or turned off.
250 #if WHEN_EDNS_RESPONSES_ARE_PARSED
251 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
254 static OBJH idnsStats
;
255 static void idnsAddNameserver(const char *buf
);
256 static void idnsAddMDNSNameservers();
257 static void idnsAddPathComponent(const char *buf
);
258 static void idnsFreeSearchpath(void);
259 static bool idnsParseNameservers(void);
260 static bool idnsParseResolvConf(void);
262 static bool idnsParseWIN32Registry(void);
263 static void idnsParseWIN32SearchList(const char *);
265 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
266 static void idnsSendQuery(idns_query
* q
);
267 static IOCB idnsReadVCHeader
;
268 static void idnsDoSendQueryVC(nsvc
*vc
);
269 static CNCB idnsInitVCConnected
;
270 static IOCB idnsReadVC
;
271 static IOCB idnsSentQueryVC
;
273 static int idnsFromKnownNameserver(Ip::Address
const &from
);
274 static idns_query
*idnsFindQuery(unsigned short id
);
275 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
277 static EVH idnsCheckQueue
;
278 static void idnsTickleQueue(void);
279 static void idnsRcodeCount(int, int);
280 static CLCB idnsVCClosed
;
281 static unsigned short idnsQueryID(void);
282 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
283 static void idnsCallbackOnEarlyError(IDNSCB
*callback
, void *cbdata
, const char *error
);
286 idnsCheckMDNS(idns_query
*q
)
288 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
291 size_t slen
= strlen(q
->name
);
292 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
293 q
->permit_mdns
= true;
298 idnsAddMDNSNameservers()
303 if (!Config
.onoff
.dns_mdns
)
306 // mDNS resolver addresses are explicit multicast group IPs
307 if (Ip::EnableIpv6
) {
308 idnsAddNameserver("FF02::FB");
309 nameservers
.back().S
.port(5353);
310 nameservers
.back().mDNSResolver
= true;
314 idnsAddNameserver("224.0.0.251");
315 nameservers
.back().S
.port(5353);
316 nameservers
.back().mDNSResolver
= true;
322 idnsAddNameserver(const char *buf
)
327 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
332 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
334 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
337 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
338 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
342 auto &nameserver
= nameservers
.emplace_back(ns());
343 A
.port(NS_DEFAULTPORT
);
345 #if WHEN_EDNS_RESPONSES_ARE_PARSED
346 nameserver
.last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
347 // TODO generate a test packet to probe this NS from EDNS size and ability.
349 debugs(78, 3, "Added nameserver #" << nameservers
.size()-1 << " (" << A
<< ")");
353 idnsAddPathComponent(const char *buf
)
355 if (npc
== npc_alloc
) {
356 int oldalloc
= npc_alloc
;
357 sp
*oldptr
= searchpath
;
364 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
366 if (oldptr
&& oldalloc
)
367 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
373 assert(npc
< npc_alloc
);
374 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
375 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
376 Tolower(searchpath
[npc
].domain
);
377 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
382 idnsFreeSearchpath(void)
384 safe_free(searchpath
);
389 idnsParseNameservers(void)
392 for (auto &i
: Config
.dns
.nameservers
) {
393 debugs(78, Important(15), "Adding nameserver " << i
<< " from squid.conf");
394 idnsAddNameserver(i
.c_str());
401 idnsParseResolvConf(void)
405 FILE *fp
= fopen(_PATH_RESCONF
, "r");
409 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerr(xerrno
));
413 char buf
[RESOLV_BUFSZ
];
414 const char *t
= nullptr;
415 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
416 t
= strtok(buf
, w_space
);
420 } else if (strcmp(t
, "nameserver") == 0) {
421 t
= strtok(nullptr, w_space
);
426 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
428 idnsAddNameserver(t
);
430 } else if (strcmp(t
, "domain") == 0) {
431 idnsFreeSearchpath();
432 t
= strtok(nullptr, w_space
);
437 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
439 idnsAddPathComponent(t
);
440 } else if (strcmp(t
, "search") == 0) {
441 idnsFreeSearchpath();
442 while (nullptr != t
) {
443 t
= strtok(nullptr, w_space
);
448 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
450 idnsAddPathComponent(t
);
452 } else if (strcmp(t
, "options") == 0) {
453 while (nullptr != t
) {
454 t
= strtok(nullptr, w_space
);
459 if (strncmp(t
, "ndots:", 6) == 0) {
465 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
470 if (npc
== 0 && (t
= getMyHostname())) {
473 idnsAddPathComponent(t
+1);
483 idnsParseWIN32SearchList(const char * Separator
)
489 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
493 Result
= RegQueryValueEx(hndKey
, "Domain", nullptr, &Type
, nullptr, &Size
);
495 if (Result
== ERROR_SUCCESS
&& Size
) {
496 t
= (char *) xmalloc(Size
);
497 RegQueryValueEx(hndKey
, "Domain", nullptr, &Type
, (LPBYTE
) t
, &Size
);
498 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
499 idnsAddPathComponent(t
);
502 Result
= RegQueryValueEx(hndKey
, "SearchList", nullptr, &Type
, nullptr, &Size
);
504 if (Result
== ERROR_SUCCESS
&& Size
) {
505 t
= (char *) xmalloc(Size
);
506 RegQueryValueEx(hndKey
, "SearchList", nullptr, &Type
, (LPBYTE
) t
, &Size
);
507 token
= strtok(t
, Separator
);
510 idnsAddPathComponent(token
);
511 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
512 token
= strtok(nullptr, Separator
);
519 if (npc
== 0 && (t
= (char *) getMyHostname())) {
522 idnsAddPathComponent(t
+ 1);
527 idnsParseWIN32Registry(void)
531 HKEY hndKey
, hndKey2
;
534 switch (WIN32_OS_version
) {
537 /* get nameservers from the Windows NT registry */
539 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
543 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", nullptr, &Type
, nullptr, &Size
);
545 if (Result
== ERROR_SUCCESS
&& Size
) {
546 t
= (char *) xmalloc(Size
);
547 RegQueryValueEx(hndKey
, "DhcpNameServer", nullptr, &Type
, (LPBYTE
) t
, &Size
);
548 token
= strtok(t
, ", ");
551 idnsAddNameserver(token
);
553 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
554 token
= strtok(nullptr, ",");
559 Result
= RegQueryValueEx(hndKey
, "NameServer", nullptr, &Type
, nullptr, &Size
);
561 if (Result
== ERROR_SUCCESS
&& Size
) {
562 t
= (char *) xmalloc(Size
);
563 RegQueryValueEx(hndKey
, "NameServer", nullptr, &Type
, (LPBYTE
) t
, &Size
);
564 token
= strtok(t
, ", ");
567 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
568 idnsAddNameserver(token
);
570 token
= strtok(nullptr, ", ");
578 idnsParseWIN32SearchList(" ");
591 /* get nameservers from the Windows 2000 registry */
592 /* search all interfaces for DNS server addresses */
594 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
596 DWORD MaxSubkeyLen
, InterfacesCount
;
598 FILETIME ftLastWriteTime
;
600 if (RegQueryInfoKey(hndKey
, nullptr, nullptr, nullptr, &InterfacesCount
, &MaxSubkeyLen
, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS
) {
601 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
602 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
605 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, nullptr, nullptr, nullptr, &ftLastWriteTime
) == ERROR_SUCCESS
) {
607 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
608 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
609 strcat(newkeyname
, "\\");
610 strcat(newkeyname
, keyname
);
611 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
615 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", nullptr, &Type
, nullptr, &Size
);
616 if (Result
== ERROR_SUCCESS
&& Size
) {
617 t
= (char *) xmalloc(Size
);
618 RegQueryValueEx(hndKey2
, "DhcpNameServer", nullptr, &Type
, (LPBYTE
)t
, &Size
);
619 token
= strtok(t
, ", ");
621 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
622 idnsAddNameserver(token
);
624 token
= strtok(nullptr, ", ");
629 Result
= RegQueryValueEx(hndKey2
, "NameServer", nullptr, &Type
, nullptr, &Size
);
630 if (Result
== ERROR_SUCCESS
&& Size
) {
631 t
= (char *) xmalloc(Size
);
632 RegQueryValueEx(hndKey2
, "NameServer", nullptr, &Type
, (LPBYTE
)t
, &Size
);
633 token
= strtok(t
, ", ");
635 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
636 idnsAddNameserver(token
);
638 token
= strtok(nullptr, ", ");
644 RegCloseKey(hndKey2
);
657 idnsParseWIN32SearchList(", ");
666 /* get nameservers from the Windows 9X registry */
668 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
672 Result
= RegQueryValueEx(hndKey
, "NameServer", nullptr, &Type
, nullptr, &Size
);
674 if (Result
== ERROR_SUCCESS
&& Size
) {
675 t
= (char *) xmalloc(Size
);
676 RegQueryValueEx(hndKey
, "NameServer", nullptr, &Type
, (LPBYTE
) t
, &Size
);
677 token
= strtok(t
, ", ");
680 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
681 idnsAddNameserver(token
);
683 token
= strtok(nullptr, ", ");
694 debugs(78, DBG_IMPORTANT
, "ERROR: Failed to read nameserver from Registry: Unknown System Type.");
703 idnsStats(StoreEntry
* sentry
)
709 char buf
[MAX_IPSTRLEN
];
710 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
711 storeAppendPrintf(sentry
, "\nThe Queue:\n");
712 storeAppendPrintf(sentry
, " DELAY SINCE\n");
713 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
714 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
716 for (n
= lru_list
.head
; n
; n
= n
->next
) {
717 q
= (idns_query
*)n
->data
;
718 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
719 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
720 tvSubDsec(q
->start_t
, current_time
),
721 tvSubDsec(q
->sent_t
, current_time
),
722 (q
->permit_mdns
? 'M':' '),
726 if (Config
.dns
.packet_max
> 0)
727 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
729 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
731 storeAppendPrintf(sentry
, "\nNameservers:\n");
732 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
733 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
735 for (const auto &server
: nameservers
) {
736 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
737 server
.S
.toStr(buf
,MAX_IPSTRLEN
),
740 server
.mDNSResolver
?"multicast":"recurse");
743 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
744 storeAppendPrintf(sentry
, "RCODE");
746 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
747 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
749 storeAppendPrintf(sentry
, " PROBLEM\n");
751 for (j
= 0; j
< MAX_RCODE
; ++j
) {
752 if (j
> 10 && j
< 16)
753 continue; // unassigned by IANA.
755 storeAppendPrintf(sentry
, "%5d", j
);
757 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
758 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
760 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
764 storeAppendPrintf(sentry
, "\nSearch list:\n");
766 for (i
=0; i
< npc
; ++i
)
767 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
769 storeAppendPrintf(sentry
, "\n");
774 idnsTickleQueue(void)
779 if (nullptr == lru_list
.tail
)
782 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
784 eventAdd("idnsCheckQueue", idnsCheckQueue
, nullptr, when
, 1);
790 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *, size_t size
, Comm::Flag flag
, int, void *data
)
792 nsvc
* vc
= (nsvc
*)data
;
794 if (flag
== Comm::ERR_CLOSING
)
797 // XXX: irrelevant now that we have conn pointer?
798 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
801 if (flag
!= Comm::OK
|| size
<= 0) {
807 idnsDoSendQueryVC(vc
);
811 idnsDoSendQueryVC(nsvc
*vc
)
816 if (vc
->queue
->contentSize() == 0)
819 // if retrying after a TC UDP response, our close handler cb may be pending
820 if (fd_table
[vc
->conn
->fd
].closing())
823 MemBuf
*mb
= vc
->queue
;
825 vc
->queue
= new MemBuf
;
829 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
830 const auto timeout
= (Config
.Timeout
.idns_query
% 1000 ?
831 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
832 AsyncCall::Pointer nil
;
834 commSetConnTimeout(vc
->conn
, timeout
, nil
);
836 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
837 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
838 Comm::Write(vc
->conn
, mb
, call
);
844 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int, void *data
)
846 nsvc
* vc
= (nsvc
*)data
;
848 if (status
!= Comm::OK
|| !conn
) {
849 char buf
[MAX_IPSTRLEN
] = "";
850 if (vc
->ns
< nameservers
.size())
851 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
852 debugs(78, DBG_IMPORTANT
, "ERROR: Failed to connect to nameserver " << buf
<< " using TCP.");
859 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
860 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
861 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
862 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
864 idnsDoSendQueryVC(vc
);
868 idnsVCClosed(const CommCloseCbParams
¶ms
)
870 nsvc
* vc
= (nsvc
*)params
.data
;
872 vc
->conn
->noteClosure();
882 // we may outlive nameservers version that was pointing to us because
883 // reconfigurations repopulate nameservers
884 if (ns
< nameservers
.size() && nameservers
[ns
].vc
== this)
885 nameservers
[ns
].vc
= nullptr;
889 idnsInitVC(size_t nsv
)
891 assert(nsv
< nameservers
.size());
892 nsvc
*vc
= new nsvc(nsv
);
893 assert(vc
->conn
== nullptr); // MUST be NULL from the construction process!
894 nameservers
[nsv
].vc
= vc
;
896 Comm::ConnectionPointer conn
= new Comm::Connection();
898 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
899 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
901 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
903 if (conn
->remote
.isIPv4())
904 conn
->local
.setIPv4();
906 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
908 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
909 cs
->setHost("DNS TCP Socket");
914 idnsSendQueryVC(idns_query
* q
, size_t nsn
)
916 assert(nsn
< nameservers
.size());
917 if (nameservers
[nsn
].vc
== nullptr)
920 nsvc
*vc
= nameservers
[nsn
].vc
;
923 char buf
[MAX_IPSTRLEN
];
924 debugs(78, DBG_IMPORTANT
, "ERROR: idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
929 if (vc
->queue
->isNull())
932 const auto serialiedQuerySize
= 2 + q
->sz
+ 1; // payload_length + payload + terminate()
933 if (vc
->queue
->potentialSpaceSize() < serialiedQuerySize
) {
934 // header + payload + MemBuf terminator exceed maximum space size
935 debugs(78, DBG_IMPORTANT
, "ERROR: Dropping DNS query due to insufficient buffer space for DNS over TCP query queue" <<
936 Debug::Extra
<< "query: " << q
->name
<<
937 Debug::Extra
<< "nameserver: " << nameservers
[nsn
].S
<<
938 Debug::Extra
<< "used space: " << vc
->queue
->contentSize() <<
939 Debug::Extra
<< "remaining space: " << vc
->queue
->potentialSpaceSize() <<
940 Debug::Extra
<< "required space: " << serialiedQuerySize
);
941 return; // the query will timeout and either fail or be retried
944 short head
= htons(q
->sz
);
946 vc
->queue
->append((char *)&head
, 2);
948 vc
->queue
->append(q
->buf
, q
->sz
);
950 idnsDoSendQueryVC(vc
);
954 idnsSendQuery(idns_query
* q
)
956 // XXX: DNS sockets get closed during reconfigure produces a race between
957 // any already active connections (or ones received between closing DNS
958 // sockets and server listening sockets) and the reconfigure completing
959 // (Runner syncConfig() being run). Transactions which loose this race will
960 // produce DNS timeouts (or whatever the caller set) as their queries never
961 // get queued to be re-tried after the DNS socekts are re-opened.
963 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
964 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
968 if (nameservers
.empty()) {
969 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
973 assert(q
->lru
.next
== nullptr);
975 assert(q
->lru
.prev
== nullptr);
979 const auto nsCount
= nameservers
.size();
982 // only use mDNS resolvers for mDNS compatible queries
984 nsn
= nns_mdns_count
+ q
->nsends
% (nsCount
- nns_mdns_count
);
986 nsn
= q
->nsends
% nsCount
;
989 idnsSendQueryVC(q
, nsn
);
992 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
993 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
994 else if (DnsSocketA
>= 0)
995 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
1001 q
->sent_t
= current_time
;
1003 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
1004 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketB
<< ": sendto: " << xstrerr(xerrno
));
1005 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
1006 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketA
<< ": sendto: " << xstrerr(xerrno
));
1008 } while ( (x
<0 && y
<0) && q
->nsends
% nsCount
!= 0);
1011 fd_bytes(DnsSocketB
, y
, IoDirection::Write
);
1014 fd_bytes(DnsSocketA
, x
, IoDirection::Write
);
1017 ++ nameservers
[nsn
].nqueries
;
1018 q
->queue_t
= current_time
;
1019 dlinkAdd(q
, &q
->lru
, &lru_list
);
1025 idnsFromKnownNameserver(Ip::Address
const &from
)
1027 for (int i
= 0; static_cast<size_t>(i
) < nameservers
.size(); ++i
) {
1028 if (nameservers
[i
].S
!= from
)
1031 if (nameservers
[i
].S
.port() != from
.port())
1041 idnsFindQuery(unsigned short id
)
1046 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1047 q
= (idns_query
*)n
->data
;
1049 if (q
->query_id
== id
)
1056 static unsigned short
1059 // NP: apparently ranlux are faster, but not quite as "proven"
1060 static std::mt19937
mt(RandomSeed32());
1061 unsigned short id
= mt() & 0xFFFF;
1062 unsigned short first_id
= id
;
1064 // ensure temporal uniqueness by looking for an existing use
1065 while (idnsFindQuery(id
)) {
1068 if (id
== first_id
) {
1069 debugs(78, DBG_IMPORTANT
, "WARNING: idnsQueryID: too many pending DNS requests");
1077 /// \returns whether master or associated queries are still waiting for replies
1079 idnsStillPending(const idns_query
*master
)
1081 assert(!master
->master
); // we were given the master transaction
1082 for (const idns_query
*qi
= master
; qi
; qi
= qi
->slave
) {
1089 static std::ostream
&
1090 operator <<(std::ostream
&os
, const idns_query
&answered
)
1093 os
<< "error \"" << answered
.error
<< "\"";
1095 os
<< answered
.ancount
<< " records";
1100 idnsCallbackOnEarlyError(IDNSCB
*callback
, void *cbdata
, const char *error
)
1102 // A cbdataReferenceValid() check asserts on unlocked cbdata: Early errors,
1103 // by definition, happen before we store/cbdataReference() cbdata.
1104 debugs(78, 6, "\"" << error
<< "\" for " << cbdata
);
1105 callback(cbdata
, nullptr, 0, "Internal error", true); // hide error details
1108 /// safely sends one set of DNS records (or an error) to the caller
1110 idnsCallbackOneWithAnswer(IDNSCB
*callback
, void *cbdata
, const idns_query
&answered
, const bool lastAnswer
)
1112 if (!cbdataReferenceValid(cbdata
))
1114 const rfc1035_rr
*records
= answered
.message
? answered
.message
->answer
: nullptr;
1115 debugs(78, 6, (lastAnswer
? "last " : "") << answered
<< " for " << cbdata
);
1116 callback(cbdata
, records
, answered
.ancount
, answered
.error
, lastAnswer
);
1121 idnsCallbackNewCallerWithOldAnswers(IDNSCB
*callback
, void *cbdata
, const idns_query
* const master
)
1123 const bool lastAnswer
= false;
1124 // iterate all queries to act on answered ones
1125 for (auto query
= master
; query
; query
= query
->slave
) {
1127 continue; // no answer yet
1128 // no CallBack(CodeContext...) -- we always run in requestor's context
1129 if (!idnsCallbackOneWithAnswer(callback
, cbdata
, *query
, lastAnswer
))
1130 break; // the caller disappeared
1135 idnsCallbackAllCallersWithNewAnswer(const idns_query
* const answered
, const bool lastAnswer
)
1137 debugs(78, 8, (lastAnswer
? "last " : "") << *answered
);
1138 const auto master
= answered
->master
? answered
->master
: answered
;
1139 // iterate all queued lookup callers
1140 for (auto looker
= master
; looker
; looker
= looker
->queue
) {
1141 CallBack(looker
->codeContext
, [&] {
1142 (void)idnsCallbackOneWithAnswer(looker
->callback
, looker
->callback_data
,
1143 *answered
, lastAnswer
);
1149 idnsCallback(idns_query
*q
, const char *error
)
1154 auto master
= q
->master
? q
->master
: q
;
1156 const bool lastAnswer
= !idnsStillPending(master
);
1157 idnsCallbackAllCallersWithNewAnswer(q
, lastAnswer
);
1160 return; // wait for more answers
1162 if (master
->hash
.key
) {
1163 hash_remove_link(idns_lookup_hash
, &master
->hash
);
1164 master
->hash
.key
= nullptr;
1171 idnsGrokReply(const char *buf
, size_t sz
, int /*from_ns*/)
1173 rfc1035_message
*message
= nullptr;
1175 int n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1177 if (message
== nullptr) {
1178 debugs(78, DBG_IMPORTANT
, "ERROR: idnsGrokReply: Malformed DNS response");
1182 debugs(78, 3, "idnsGrokReply: QID 0x" << asHex(message
->id
) << ", " << n
<< " answers");
1184 idns_query
*q
= idnsFindQuery(message
->id
);
1187 debugs(78, 3, "idnsGrokReply: Late response");
1188 rfc1035MessageDestroy(&message
);
1192 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1193 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1194 rfc1035MessageDestroy(&message
);
1198 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1199 // TODO: actually gr the message right here.
1200 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1201 // this is overall better than force-feeding A response with AAAA an section later anyway.
1202 // AND allows us to merge AN+AR sections from both responses (one day)
1204 if (q
->edns_seen
>= 0) {
1205 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1206 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1207 // the altered NS was limiting the whole group.
1208 max_shared_edns
= q
->edns_seen
;
1209 // may be limited by one of the others still
1210 for (const auto &server
: nameservers
)
1211 max_shared_edns
= min(max_shared_edns
, server
.last_seen_edns
);
1213 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1214 // maybe reduce the global limit downwards to accommodate this NS
1215 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1217 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1218 max_shared_edns
= -1;
1222 dlinkDelete(&q
->lru
, &lru_list
);
1226 debugs(78, 3, "Resolver requested TC (" << q
->query
.name
<< ")");
1227 rfc1035MessageDestroy(&message
);
1234 // Strange: A TCP DNS response with the truncation bit (TC) set.
1235 // Return an error and cleanup; no point in trying TCP again.
1236 debugs(78, 3, "TCP DNS response");
1237 idnsCallback(q
, "Truncated TCP DNS response");
1243 idnsRcodeCount(n
, q
->attempt
);
1247 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1249 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1251 * RCODE 2 is "Server failure - The name server was
1252 * unable to process this query due to a problem with
1255 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1256 rfc1035MessageDestroy(&message
);
1261 // Do searchpath processing on the master A query only to keep
1262 // things simple. NXDOMAIN is authoritative for the label, not
1264 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1265 assert(nullptr == message
->answer
);
1266 strcpy(q
->name
, q
->orig
);
1268 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1270 if (q
->domain
< npc
) {
1271 strcat(q
->name
, ".");
1272 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1273 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1279 rfc1035MessageDestroy(&message
);
1281 // cleanup slave AAAA query
1282 while (idns_query
*slave
= q
->slave
) {
1283 dlinkDelete(&slave
->lru
, &lru_list
);
1284 q
->slave
= slave
->slave
;
1285 slave
->slave
= nullptr;
1290 q
->query_id
= idnsQueryID();
1291 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1292 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
);
1294 /* problem with query data -- query not sent */
1295 idnsCallback(q
, "Internal error");
1304 idnsSendSlaveAAAAQuery(q
);
1309 q
->message
= message
;
1313 idnsCallback(q
, nullptr);
1315 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1320 idnsRead(int fd
, void *)
1322 int *N
= &incoming_sockets_accepted
;
1324 int max
= INCOMING_DNS_MAX
;
1325 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1328 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1330 // Always keep reading. This stops (or at least makes harder) several
1331 // attacks on the DNS client.
1332 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, nullptr, 0);
1335 * two code lines after returning from comm_udprecvfrom()
1336 * something overwrites the memory behind the from parameter.
1337 * NO matter where in the stack declaration list above it is placed
1338 * The cause of this is still unknown, however copying the data appears
1339 * to allow it to be passed further without this erasure.
1341 Ip::Address bugbypass
;
1345 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1347 from
= bugbypass
; // BUG BYPASS. see notes above.
1354 if (ignoreErrno(xerrno
))
1358 /* Some Linux systems seem to set the FD for reading and then
1359 * return ECONNREFUSED when sendto() fails and generates an ICMP
1360 * port unreachable message. */
1361 /* or maybe an EHOSTUNREACH "No route to host" message */
1362 if (xerrno
!= ECONNREFUSED
&& xerrno
!= EHOSTUNREACH
)
1364 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << fd
<< " recvfrom: " << xstrerr(xerrno
));
1369 fd_bytes(fd
, len
, IoDirection::Read
);
1374 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1376 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1377 int nsn
= idnsFromKnownNameserver(from
);
1380 ++ nameservers
[nsn
].nreplies
;
1383 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1384 // but after the ++ above to keep statistics right.
1386 continue; // Don't process replies if there is no pending query.
1388 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1389 static time_t last_warning
= 0;
1391 if (squid_curtime
- last_warning
> 60) {
1392 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1393 last_warning
= squid_curtime
;
1395 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1400 idnsGrokReply(rbuf
, len
, nsn
);
1405 idnsCheckQueue(void *)
1408 dlink_node
*p
= nullptr;
1412 if (nameservers
.empty())
1413 /* name servers went away; reconfiguring or shutting down */
1416 const auto nsCount
= nameservers
.size();
1417 for (n
= lru_list
.tail
; n
; n
= p
) {
1420 q
= static_cast<idns_query
*>(n
->data
);
1422 /* Anything to process in the queue? */
1423 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1426 /* Query timer still running? */
1427 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nsCount
))) {
1428 dlinkDelete(&q
->lru
, &lru_list
);
1429 q
->queue_t
= current_time
;
1430 dlinkAdd(q
, &q
->lru
, &lru_list
);
1434 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1435 " QID 0x" << asHex(q
->query_id
).minDigits(4) << ": timeout");
1437 dlinkDelete(&q
->lru
, &lru_list
);
1440 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1443 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1444 " QID 0x" << asHex(q
->query_id
) <<
1445 ": giving up after " << q
->nsends
<< " tries and " <<
1446 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1449 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1451 idnsCallback(q
, "Timeout");
1459 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1461 nsvc
* vc
= (nsvc
*)data
;
1463 if (flag
== Comm::ERR_CLOSING
)
1466 if (flag
!= Comm::OK
|| len
<= 0) {
1467 if (Comm::IsConnOpen(conn
))
1472 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1474 if (vc
->msg
->contentSize() < vc
->msglen
) {
1475 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1476 CommIoCbPtrFun(idnsReadVC
, vc
));
1477 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1481 assert(vc
->ns
< nameservers
.size());
1482 debugs(78, 3, conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1484 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1486 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1487 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1488 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1492 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1494 nsvc
* vc
= (nsvc
*)data
;
1496 if (flag
== Comm::ERR_CLOSING
)
1499 if (flag
!= Comm::OK
|| len
<= 0) {
1500 if (Comm::IsConnOpen(conn
))
1505 vc
->read_msglen
+= len
;
1507 assert(vc
->read_msglen
<= 2);
1509 if (vc
->read_msglen
< 2) {
1510 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1511 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1512 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1516 vc
->read_msglen
= 0;
1518 vc
->msglen
= ntohs(vc
->msglen
);
1521 if (Comm::IsConnOpen(conn
))
1526 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1527 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1528 CommIoCbPtrFun(idnsReadVC
, vc
));
1529 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1533 * rcode < 0 indicates an error, rocde >= 0 indicates success
1536 idnsRcodeCount(int rcode
, int attempt
)
1543 if (rcode
< MAX_RCODE
)
1544 if (attempt
< MAX_ATTEMPT
)
1545 ++ RcodeMatrix
[rcode
][attempt
];
1551 static int init
= 0;
1553 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1554 Ip::Address addrV6
; // since we do not want to alter Config.Addrs.udp_* and do not have one of our own.
1556 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1557 addrV6
= Config
.Addrs
.udp_outgoing
;
1559 addrV6
= Config
.Addrs
.udp_incoming
;
1561 Ip::Address addrV4
= addrV6
;
1564 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1565 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1566 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1573 if (addrV4
.isIPv4()) {
1574 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1575 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1582 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1583 fatal("Could not create a DNS socket");
1585 /* Ouch... we can't call functions using debug from a debug
1586 * statement. Doing so messes up the internal Debug::level
1588 if (DnsSocketB
>= 0) {
1589 comm_local_port(DnsSocketB
);
1590 debugs(78, Important(16), "DNS IPv6 socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1591 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, nullptr, 0);
1593 if (DnsSocketA
>= 0) {
1594 comm_local_port(DnsSocketA
);
1595 debugs(78, Important(64), "DNS IPv4 socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1596 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, nullptr, 0);
1600 assert(nameservers
.empty());
1601 idnsAddMDNSNameservers();
1602 bool nsFound
= idnsParseNameservers();
1605 nsFound
= idnsParseResolvConf();
1609 nsFound
= idnsParseWIN32Registry();
1613 debugs(78, DBG_IMPORTANT
, "WARNING: Could not find any nameservers. Trying to use localhost");
1615 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1617 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1620 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1622 idnsAddNameserver("::1");
1623 idnsAddNameserver("127.0.0.1");
1627 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1628 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1632 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1633 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1634 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1635 max_shared_edns
= -1; // disable if we might receive random replies.
1639 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1643 idnsShutdownAndFreeState(const char *reason
)
1645 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1648 debugs(78, 2, reason
<< ": Closing DNS sockets");
1650 if (DnsSocketA
>= 0 ) {
1651 comm_close(DnsSocketA
);
1655 if (DnsSocketB
>= 0 ) {
1656 comm_close(DnsSocketB
);
1660 for (const auto &server
: nameservers
) {
1661 if (const auto vc
= server
.vc
) {
1662 if (Comm::IsConnOpen(vc
->conn
))
1667 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1668 nameservers
.clear();
1669 idnsFreeSearchpath();
1673 Dns::ConfigRr::endingShutdown()
1675 idnsShutdownAndFreeState("Shutdown");
1679 Dns::ConfigRr::startReconfigure()
1681 idnsShutdownAndFreeState("Reconfigure");
1685 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1687 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1692 // XXX: We are collapsing this DNS query (B) onto another one (A), but there
1693 // is no code to later send B if the A answer has unshareable 0 TTL records.
1695 idns_query
*q
= new idns_query
;
1696 // no query_id on this instance.
1698 q
->callback
= callback
;
1699 q
->callback_data
= cbdataReference(data
);
1701 q
->queue
= old
->queue
;
1704 // This check must follow cbdataReference() above because our callback code
1705 // needs a locked cbdata to call cbdataReferenceValid().
1706 if (idnsStillPending(old
))
1707 idnsCallbackNewCallerWithOldAnswers(callback
, data
, old
);
1708 // else: idns_lookup_hash is not a cache so no pending lookups means we are
1709 // in a reentrant lookup and will be called back when dequeued.
1715 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1717 q
->start_t
= current_time
;
1718 q
->callback
= callback
;
1719 q
->callback_data
= cbdataReference(data
);
1721 q
->hash
.key
= q
->orig
;
1722 hash_join(idns_lookup_hash
, &q
->hash
);
1728 idnsSendSlaveAAAAQuery(idns_query
*master
)
1730 idns_query
*q
= new idns_query
;
1731 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1732 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1734 q
->query_id
= idnsQueryID();
1735 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
);
1737 debugs(78, 3, "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1738 ", id = 0x" << asHex(q
->query_id
));
1744 q
->start_t
= master
->start_t
;
1745 q
->slave
= master
->slave
;
1753 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1755 size_t nameLength
= strlen(name
);
1757 // Prevent buffer overflow on q->name
1758 if (nameLength
> NS_MAXDNAME
) {
1759 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1760 idnsCallbackOnEarlyError(callback
, data
, "huge name");
1764 if (idnsCachedLookup(name
, callback
, data
))
1767 idns_query
*q
= new idns_query
;
1768 q
->query_id
= idnsQueryID();
1771 for (size_t i
= 0; i
< nameLength
; ++i
)
1775 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1776 q
->do_searchpath
= 1;
1778 q
->do_searchpath
= 0;
1781 strcpy(q
->orig
, name
);
1782 strcpy(q
->name
, q
->orig
);
1784 if (q
->do_searchpath
&& nd
< ndots
) {
1786 strcat(q
->name
, ".");
1787 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1788 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1791 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
);
1794 /* problem with query data -- query not sent */
1795 idnsCallbackOnEarlyError(callback
, data
, "rfc3596BuildAQuery error");
1800 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1801 ", id = 0x" << asHex(q
->query_id
));
1804 idnsStartQuery(q
, callback
, data
);
1807 idnsSendSlaveAAAAQuery(q
);
1811 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1813 char ip
[MAX_IPSTRLEN
];
1815 addr
.toStr(ip
,MAX_IPSTRLEN
);
1817 idns_query
*q
= new idns_query
;
1818 q
->query_id
= idnsQueryID();
1820 if (addr
.isIPv6()) {
1821 struct in6_addr addr6
;
1822 addr
.getInAddr(addr6
);
1823 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
);
1825 struct in_addr addr4
;
1826 addr
.getInAddr(addr4
);
1827 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
);
1831 /* problem with query data -- query not sent */
1832 idnsCallbackOnEarlyError(callback
, data
, "rfc3596BuildPTRQuery error");
1837 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1842 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1843 ", id = 0x" << asHex(q
->query_id
));
1845 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1846 idnsStartQuery(q
, callback
, data
);
1851 * The function to return the DNS via SNMP
1854 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1857 variable_list
*Answer
= nullptr;
1859 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1860 *ErrP
= SNMP_ERR_NOERROR
;
1862 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1866 for (const auto &server
: nameservers
)
1867 n
+= server
.nqueries
;
1869 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1876 for (const auto &server
: nameservers
)
1877 n
+= server
.nreplies
;
1879 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1886 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1893 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1901 #endif /*SQUID_SNMP */