2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 78 DNS lookups; interacts with dns/rfc1035.cc */
12 #include "base/InstanceId.h"
13 #include "base/RunnersRegistry.h"
15 #include "comm/Connection.h"
16 #include "comm/ConnOpener.h"
17 #include "comm/Loops.h"
18 #include "comm/Read.h"
19 #include "comm/Write.h"
21 #include "dns/forward.h"
22 #include "dns/rfc3596.h"
28 #include "mgr/Registration.h"
29 #include "SquidConfig.h"
30 #include "SquidTime.h"
37 #include "snmp_core.h"
40 #if HAVE_ARPA_NAMESER_H
41 #include <arpa/nameser.h>
50 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
51 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
52 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
55 #define _PATH_RESCONF "/etc/resolv.conf"
57 #ifndef NS_DEFAULTPORT
58 #define NS_DEFAULTPORT 53
62 #define NS_MAXDNAME 1025
69 /* The buffer size required to store the maximum allowed search path */
71 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
74 #define IDNS_MAX_TRIES 20
77 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
78 // NP: see http://www.iana.org/assignments/dns-parameters
79 static const char *Rcodes
[] = {
82 "Packet Format Error",
84 "Non-Existent Domain",
88 "Name Exists when it should not",
89 "RR Set Exists when it should not",
90 "RR Set that should exist does not",
91 "Server Not Authoritative for zone",
92 "Name not contained in zone",
96 "Bad OPT Version or TSIG Signature Failure"
99 typedef struct _ns ns
;
101 typedef struct _sp sp
;
105 CBDATA_CLASS(idns_query
);
110 memset(&query
, 0, sizeof(query
));
114 memset(&start_t
, 0, sizeof(start_t
));
115 memset(&sent_t
, 0, sizeof(sent_t
));
116 memset(&queue_t
, 0, sizeof(queue_t
));
121 rfc1035MessageDestroy(&message
);
124 // master is just a back-reference
125 cbdataReferenceDone(callback_data
);
130 char buf
[RESOLV_BUFSZ
];
131 char name
[NS_MAXDNAME
+ 1];
132 char orig
[NS_MAXDNAME
+ 1];
134 unsigned short query_id
= 0; ///< random query ID sent to server; changes with every query sent
135 InstanceId
<idns_query
> xact_id
; ///< identifies our "transaction", stays constant when query is retried
139 bool permit_mdns
= false;
142 struct timeval start_t
;
143 struct timeval sent_t
;
144 struct timeval queue_t
;
147 void *callback_data
= nullptr;
150 idns_query
*queue
= nullptr;
151 idns_query
*slave
= nullptr; // single linked list
152 idns_query
*master
= nullptr; // single pointer to a shared master
153 unsigned short domain
= 0;
154 unsigned short do_searchpath
= 0;
155 rfc1035_message
*message
= nullptr;
157 const char *error
= nullptr;
160 InstanceIdDefinitions(idns_query
, "dns");
162 CBDATA_CLASS_INIT(idns_query
);
169 explicit nsvc(int nsv
) : ns(nsv
), msg(new MemBuf()), queue(new MemBuf()) {}
173 Comm::ConnectionPointer conn
;
174 unsigned short msglen
= 0;
176 MemBuf
*msg
= nullptr;
177 MemBuf
*queue
= nullptr;
181 CBDATA_CLASS_INIT(nsvc
);
187 #if WHEN_EDNS_RESPONSES_ARE_PARSED
197 /// manage DNS internal component
198 class ConfigRr
: public RegisteredRunner
201 /* RegisteredRunner API */
202 virtual void startReconfigure() override
;
203 virtual void endingShutdown() override
;
206 RunnerRegistrationEntry(ConfigRr
);
211 char domain
[NS_MAXDNAME
];
215 static ns
*nameservers
= NULL
;
216 static sp
*searchpath
= NULL
;
218 static int nns_alloc
= 0;
219 static int nns_mdns_count
= 0;
221 static int npc_alloc
= 0;
222 static int ndots
= 1;
223 static dlink_list lru_list
;
224 static int event_queued
= 0;
225 static hash_table
*idns_lookup_hash
= NULL
;
231 * EDNS as specified may be sent as an additional record for any request.
232 * early testing has revealed that it works on common devices, but cannot
233 * be reliably used on any A or PTR requet done for IPv4 addresses.
235 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
238 * Squid is optimized to generate one packet and re-send it to all NS
239 * due to this we cannot customize the EDNS size per NS.
241 * As such we take the configuration option value as fixed.
244 * This may not be worth doing, but if/when additional-records are parsed
245 * we will be able to recover the OPT value specific to any one NS and
246 * cache it. Effectively automating the tuning of EDNS advertised to the
247 * size our active NS are capable.
248 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
249 * Responses from the configured NS may cause this to be raised or turned off.
251 #if WHEN_EDNS_RESPONSES_ARE_PARSED
252 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
255 static OBJH idnsStats
;
256 static void idnsAddNameserver(const char *buf
);
257 static void idnsAddMDNSNameservers();
258 static void idnsAddPathComponent(const char *buf
);
259 static void idnsFreeNameservers(void);
260 static void idnsFreeSearchpath(void);
261 static bool idnsParseNameservers(void);
262 static bool idnsParseResolvConf(void);
264 static bool idnsParseWIN32Registry(void);
265 static void idnsParseWIN32SearchList(const char *);
267 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
268 static void idnsSendQuery(idns_query
* q
);
269 static IOCB idnsReadVCHeader
;
270 static void idnsDoSendQueryVC(nsvc
*vc
);
271 static CNCB idnsInitVCConnected
;
272 static IOCB idnsReadVC
;
273 static IOCB idnsSentQueryVC
;
275 static int idnsFromKnownNameserver(Ip::Address
const &from
);
276 static idns_query
*idnsFindQuery(unsigned short id
);
277 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
279 static EVH idnsCheckQueue
;
280 static void idnsTickleQueue(void);
281 static void idnsRcodeCount(int, int);
282 static CLCB idnsVCClosed
;
283 static unsigned short idnsQueryID(void);
284 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
285 static void idnsCallbackOnEarlyError(IDNSCB
*callback
, void *cbdata
, const char *error
);
288 idnsCheckMDNS(idns_query
*q
)
290 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
293 size_t slen
= strlen(q
->name
);
294 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
295 q
->permit_mdns
= true;
300 idnsAddMDNSNameservers()
305 if (!Config
.onoff
.dns_mdns
)
308 // mDNS resolver addresses are explicit multicast group IPs
309 if (Ip::EnableIpv6
) {
310 idnsAddNameserver("FF02::FB");
311 nameservers
[nns
-1].S
.port(5353);
312 nameservers
[nns
-1].mDNSResolver
= true;
316 idnsAddNameserver("224.0.0.251");
317 nameservers
[nns
-1].S
.port(5353);
318 nameservers
[nns
-1].mDNSResolver
= true;
324 idnsAddNameserver(const char *buf
)
329 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
334 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
336 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
339 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
340 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
344 if (nns
== nns_alloc
) {
345 int oldalloc
= nns_alloc
;
346 ns
*oldptr
= nameservers
;
353 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
355 if (oldptr
&& oldalloc
)
356 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
362 assert(nns
< nns_alloc
);
363 A
.port(NS_DEFAULTPORT
);
364 nameservers
[nns
].S
= A
;
365 #if WHEN_EDNS_RESPONSES_ARE_PARSED
366 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
367 // TODO generate a test packet to probe this NS from EDNS size and ability.
369 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
374 idnsAddPathComponent(const char *buf
)
376 if (npc
== npc_alloc
) {
377 int oldalloc
= npc_alloc
;
378 sp
*oldptr
= searchpath
;
385 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
387 if (oldptr
&& oldalloc
)
388 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
394 assert(npc
< npc_alloc
);
395 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
396 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
397 Tolower(searchpath
[npc
].domain
);
398 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
403 idnsFreeNameservers(void)
405 safe_free(nameservers
);
410 idnsFreeSearchpath(void)
412 safe_free(searchpath
);
417 idnsParseNameservers(void)
420 for (auto &i
: Config
.dns
.nameservers
) {
421 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << i
<< " from squid.conf");
422 idnsAddNameserver(i
.c_str());
429 idnsParseResolvConf(void)
433 FILE *fp
= fopen(_PATH_RESCONF
, "r");
437 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerr(xerrno
));
441 char buf
[RESOLV_BUFSZ
];
442 const char *t
= NULL
;
443 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
444 t
= strtok(buf
, w_space
);
448 } else if (strcmp(t
, "nameserver") == 0) {
449 t
= strtok(NULL
, w_space
);
454 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
456 idnsAddNameserver(t
);
458 } else if (strcmp(t
, "domain") == 0) {
459 idnsFreeSearchpath();
460 t
= strtok(NULL
, w_space
);
465 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
467 idnsAddPathComponent(t
);
468 } else if (strcmp(t
, "search") == 0) {
469 idnsFreeSearchpath();
471 t
= strtok(NULL
, w_space
);
476 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
478 idnsAddPathComponent(t
);
480 } else if (strcmp(t
, "options") == 0) {
482 t
= strtok(NULL
, w_space
);
487 if (strncmp(t
, "ndots:", 6) == 0) {
493 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
498 if (npc
== 0 && (t
= getMyHostname())) {
501 idnsAddPathComponent(t
+1);
511 idnsParseWIN32SearchList(const char * Separator
)
517 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
521 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
523 if (Result
== ERROR_SUCCESS
&& Size
) {
524 t
= (char *) xmalloc(Size
);
525 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
526 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
527 idnsAddPathComponent(t
);
530 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
532 if (Result
== ERROR_SUCCESS
&& Size
) {
533 t
= (char *) xmalloc(Size
);
534 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
535 token
= strtok(t
, Separator
);
538 idnsAddPathComponent(token
);
539 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
540 token
= strtok(NULL
, Separator
);
547 if (npc
== 0 && (t
= (char *) getMyHostname())) {
550 idnsAddPathComponent(t
+ 1);
555 idnsParseWIN32Registry(void)
559 HKEY hndKey
, hndKey2
;
562 switch (WIN32_OS_version
) {
565 /* get nameservers from the Windows NT registry */
567 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
571 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
573 if (Result
== ERROR_SUCCESS
&& Size
) {
574 t
= (char *) xmalloc(Size
);
575 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
576 token
= strtok(t
, ", ");
579 idnsAddNameserver(token
);
581 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
582 token
= strtok(NULL
, ",");
587 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
589 if (Result
== ERROR_SUCCESS
&& Size
) {
590 t
= (char *) xmalloc(Size
);
591 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
592 token
= strtok(t
, ", ");
595 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
596 idnsAddNameserver(token
);
598 token
= strtok(NULL
, ", ");
606 idnsParseWIN32SearchList(" ");
619 /* get nameservers from the Windows 2000 registry */
620 /* search all interfaces for DNS server addresses */
622 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
624 DWORD MaxSubkeyLen
, InterfacesCount
;
626 FILETIME ftLastWriteTime
;
628 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
629 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
630 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
633 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
635 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
636 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
637 strcat(newkeyname
, "\\");
638 strcat(newkeyname
, keyname
);
639 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
643 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
644 if (Result
== ERROR_SUCCESS
&& Size
) {
645 t
= (char *) xmalloc(Size
);
646 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
647 token
= strtok(t
, ", ");
649 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
650 idnsAddNameserver(token
);
652 token
= strtok(NULL
, ", ");
657 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
658 if (Result
== ERROR_SUCCESS
&& Size
) {
659 t
= (char *) xmalloc(Size
);
660 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
661 token
= strtok(t
, ", ");
663 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
664 idnsAddNameserver(token
);
666 token
= strtok(NULL
, ", ");
672 RegCloseKey(hndKey2
);
685 idnsParseWIN32SearchList(", ");
694 /* get nameservers from the Windows 9X registry */
696 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
700 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
702 if (Result
== ERROR_SUCCESS
&& Size
) {
703 t
= (char *) xmalloc(Size
);
704 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
705 token
= strtok(t
, ", ");
708 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
709 idnsAddNameserver(token
);
711 token
= strtok(NULL
, ", ");
722 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
731 idnsStats(StoreEntry
* sentry
)
737 char buf
[MAX_IPSTRLEN
];
738 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
739 storeAppendPrintf(sentry
, "\nThe Queue:\n");
740 storeAppendPrintf(sentry
, " DELAY SINCE\n");
741 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
742 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
744 for (n
= lru_list
.head
; n
; n
= n
->next
) {
745 q
= (idns_query
*)n
->data
;
746 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
747 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
748 tvSubDsec(q
->start_t
, current_time
),
749 tvSubDsec(q
->sent_t
, current_time
),
750 (q
->permit_mdns
? 'M':' '),
754 if (Config
.dns
.packet_max
> 0)
755 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
757 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
759 storeAppendPrintf(sentry
, "\nNameservers:\n");
760 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
761 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
763 for (i
= 0; i
< nns
; ++i
) {
764 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
765 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
766 nameservers
[i
].nqueries
,
767 nameservers
[i
].nreplies
,
768 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
771 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
772 storeAppendPrintf(sentry
, "RCODE");
774 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
775 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
777 storeAppendPrintf(sentry
, " PROBLEM\n");
779 for (j
= 0; j
< MAX_RCODE
; ++j
) {
780 if (j
> 10 && j
< 16)
781 continue; // unassigned by IANA.
783 storeAppendPrintf(sentry
, "%5d", j
);
785 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
786 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
788 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
792 storeAppendPrintf(sentry
, "\nSearch list:\n");
794 for (i
=0; i
< npc
; ++i
)
795 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
797 storeAppendPrintf(sentry
, "\n");
802 idnsTickleQueue(void)
807 if (NULL
== lru_list
.tail
)
810 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
812 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
818 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *, size_t size
, Comm::Flag flag
, int, void *data
)
820 nsvc
* vc
= (nsvc
*)data
;
822 if (flag
== Comm::ERR_CLOSING
)
825 // XXX: irrelevant now that we have conn pointer?
826 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
829 if (flag
!= Comm::OK
|| size
<= 0) {
835 idnsDoSendQueryVC(vc
);
839 idnsDoSendQueryVC(nsvc
*vc
)
844 if (vc
->queue
->contentSize() == 0)
847 // if retrying after a TC UDP response, our close handler cb may be pending
848 if (fd_table
[vc
->conn
->fd
].closing())
851 MemBuf
*mb
= vc
->queue
;
853 vc
->queue
= new MemBuf
;
857 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
858 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
859 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
860 AsyncCall::Pointer nil
;
862 commSetConnTimeout(vc
->conn
, timeout
, nil
);
864 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
865 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
866 Comm::Write(vc
->conn
, mb
, call
);
872 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int, void *data
)
874 nsvc
* vc
= (nsvc
*)data
;
876 if (status
!= Comm::OK
|| !conn
) {
877 char buf
[MAX_IPSTRLEN
] = "";
879 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
880 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
886 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
887 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
888 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
889 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
891 idnsDoSendQueryVC(vc
);
895 idnsVCClosed(const CommCloseCbParams
¶ms
)
897 nsvc
* vc
= (nsvc
*)params
.data
;
905 if (ns
< nns
) // XXX: idnsShutdownAndFreeState may have freed nameservers[]
906 nameservers
[ns
].vc
= NULL
;
912 nsvc
*vc
= new nsvc(nsv
);
914 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
915 nameservers
[nsv
].vc
= vc
;
917 Comm::ConnectionPointer conn
= new Comm::Connection();
919 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
920 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
922 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
924 if (conn
->remote
.isIPv4())
925 conn
->local
.setIPv4();
927 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
929 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
930 cs
->setHost("DNS TCP Socket");
935 idnsSendQueryVC(idns_query
* q
, int nsn
)
938 if (nameservers
[nsn
].vc
== NULL
)
941 nsvc
*vc
= nameservers
[nsn
].vc
;
944 char buf
[MAX_IPSTRLEN
];
945 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
952 short head
= htons(q
->sz
);
954 vc
->queue
->append((char *)&head
, 2);
956 vc
->queue
->append(q
->buf
, q
->sz
);
958 idnsDoSendQueryVC(vc
);
962 idnsSendQuery(idns_query
* q
)
964 // XXX: DNS sockets get closed during reconfigure produces a race between
965 // any already active connections (or ones received between closing DNS
966 // sockets and server listening sockets) and the reconfigure completing
967 // (Runner syncConfig() being run). Transactions which loose this race will
968 // produce DNS timeouts (or whatever the caller set) as their queries never
969 // get queued to be re-tried after the DNS socekts are re-opened.
971 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
972 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
977 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
981 assert(q
->lru
.next
== NULL
);
983 assert(q
->lru
.prev
== NULL
);
989 // only use mDNS resolvers for mDNS compatible queries
991 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
993 nsn
= q
->nsends
% nns
;
996 idnsSendQueryVC(q
, nsn
);
999 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
1000 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
1001 else if (DnsSocketA
>= 0)
1002 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
1008 q
->sent_t
= current_time
;
1010 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
1011 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketB
<< ": sendto: " << xstrerr(xerrno
));
1012 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
1013 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketA
<< ": sendto: " << xstrerr(xerrno
));
1015 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
1018 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
1021 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
1024 ++ nameservers
[nsn
].nqueries
;
1025 q
->queue_t
= current_time
;
1026 dlinkAdd(q
, &q
->lru
, &lru_list
);
1032 idnsFromKnownNameserver(Ip::Address
const &from
)
1036 for (i
= 0; i
< nns
; ++i
) {
1037 if (nameservers
[i
].S
!= from
)
1040 if (nameservers
[i
].S
.port() != from
.port())
1050 idnsFindQuery(unsigned short id
)
1055 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1056 q
= (idns_query
*)n
->data
;
1058 if (q
->query_id
== id
)
1065 static unsigned short
1068 // NP: apparently ranlux are faster, but not quite as "proven"
1069 static std::mt19937
mt(static_cast<uint32_t>(getCurrentTime() & 0xFFFFFFFF));
1070 unsigned short id
= mt() & 0xFFFF;
1071 unsigned short first_id
= id
;
1073 // ensure temporal uniqueness by looking for an existing use
1074 while (idnsFindQuery(id
)) {
1077 if (id
== first_id
) {
1078 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1086 /// \returns whether master or associated queries are still waiting for replies
1088 idnsStillPending(const idns_query
*master
)
1090 assert(!master
->master
); // we were given the master transaction
1091 for (const idns_query
*qi
= master
; qi
; qi
= qi
->slave
) {
1098 static std::ostream
&
1099 operator <<(std::ostream
&os
, const idns_query
&answered
)
1102 os
<< "error \"" << answered
.error
<< "\"";
1104 os
<< answered
.ancount
<< " records";
1109 idnsCallbackOnEarlyError(IDNSCB
*callback
, void *cbdata
, const char *error
)
1111 // A cbdataReferenceValid() check asserts on unlocked cbdata: Early errors,
1112 // by definition, happen before we store/cbdataReference() cbdata.
1113 debugs(78, 6, "\"" << error
<< "\" for " << cbdata
);
1114 callback(cbdata
, nullptr, 0, "Internal error", true); // hide error details
1117 /// safely sends one set of DNS records (or an error) to the caller
1119 idnsCallbackOneWithAnswer(IDNSCB
*callback
, void *cbdata
, const idns_query
&answered
, const bool lastAnswer
)
1121 if (!cbdataReferenceValid(cbdata
))
1123 const rfc1035_rr
*records
= answered
.message
? answered
.message
->answer
: nullptr;
1124 debugs(78, 6, (lastAnswer
? "last " : "") << answered
<< " for " << cbdata
);
1125 callback(cbdata
, records
, answered
.ancount
, answered
.error
, lastAnswer
);
1130 idnsCallbackNewCallerWithOldAnswers(IDNSCB
*callback
, void *cbdata
, const idns_query
* const master
)
1132 const bool lastAnswer
= false;
1133 // iterate all queries to act on answered ones
1134 for (auto query
= master
; query
; query
= query
->slave
) {
1136 continue; // no answer yet
1137 if (!idnsCallbackOneWithAnswer(callback
, cbdata
, *query
, lastAnswer
))
1138 break; // the caller disappeared
1143 idnsCallbackAllCallersWithNewAnswer(const idns_query
* const answered
, const bool lastAnswer
)
1145 debugs(78, 8, (lastAnswer
? "last " : "") << *answered
);
1146 const auto master
= answered
->master
? answered
->master
: answered
;
1147 // iterate all queued lookup callers
1148 for (auto looker
= master
; looker
; looker
= looker
->queue
) {
1149 (void)idnsCallbackOneWithAnswer(looker
->callback
, looker
->callback_data
,
1150 *answered
, lastAnswer
);
1155 idnsCallback(idns_query
*q
, const char *error
)
1160 auto master
= q
->master
? q
->master
: q
;
1162 const bool lastAnswer
= !idnsStillPending(master
);
1163 idnsCallbackAllCallersWithNewAnswer(q
, lastAnswer
);
1166 return; // wait for more answers
1168 if (master
->hash
.key
) {
1169 hash_remove_link(idns_lookup_hash
, &master
->hash
);
1170 master
->hash
.key
= nullptr;
1177 idnsGrokReply(const char *buf
, size_t sz
, int /*from_ns*/)
1179 rfc1035_message
*message
= NULL
;
1181 int n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1183 if (message
== NULL
) {
1184 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1188 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1190 idns_query
*q
= idnsFindQuery(message
->id
);
1193 debugs(78, 3, "idnsGrokReply: Late response");
1194 rfc1035MessageDestroy(&message
);
1198 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1199 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1200 rfc1035MessageDestroy(&message
);
1204 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1205 // TODO: actually gr the message right here.
1206 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1207 // this is overall better than force-feeding A response with AAAA an section later anyway.
1208 // AND allows us to merge AN+AR sections from both responses (one day)
1210 if (q
->edns_seen
>= 0) {
1211 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1212 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1213 // the altered NS was limiting the whole group.
1214 max_shared_edns
= q
->edns_seen
;
1215 // may be limited by one of the others still
1216 for (int i
= 0; i
< nns
; ++i
)
1217 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1219 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1220 // maybe reduce the global limit downwards to accomodate this NS
1221 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1223 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1224 max_shared_edns
= -1;
1228 dlinkDelete(&q
->lru
, &lru_list
);
1232 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1233 rfc1035MessageDestroy(&message
);
1240 // Strange: A TCP DNS response with the truncation bit (TC) set.
1241 // Return an error and cleanup; no point in trying TCP again.
1242 debugs(78, 3, HERE
<< "TCP DNS response");
1243 idnsCallback(q
, "Truncated TCP DNS response");
1249 idnsRcodeCount(n
, q
->attempt
);
1253 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1255 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1257 * RCODE 2 is "Server failure - The name server was
1258 * unable to process this query due to a problem with
1261 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1262 rfc1035MessageDestroy(&message
);
1267 // Do searchpath processing on the master A query only to keep
1268 // things simple. NXDOMAIN is authorative for the label, not
1270 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1271 assert(NULL
== message
->answer
);
1272 strcpy(q
->name
, q
->orig
);
1274 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1276 if (q
->domain
< npc
) {
1277 strcat(q
->name
, ".");
1278 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1279 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1285 rfc1035MessageDestroy(&message
);
1287 // cleanup slave AAAA query
1288 while (idns_query
*slave
= q
->slave
) {
1289 dlinkDelete(&slave
->lru
, &lru_list
);
1290 q
->slave
= slave
->slave
;
1291 slave
->slave
= NULL
;
1296 q
->query_id
= idnsQueryID();
1297 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1298 // see EDNS notes at top of file why this sends 0
1299 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1301 /* problem with query data -- query not sent */
1302 idnsCallback(q
, "Internal error");
1311 idnsSendSlaveAAAAQuery(q
);
1316 q
->message
= message
;
1320 idnsCallback(q
, NULL
);
1322 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1327 idnsRead(int fd
, void *)
1329 int *N
= &incoming_sockets_accepted
;
1331 int max
= INCOMING_DNS_MAX
;
1332 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1335 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1337 // Always keep reading. This stops (or at least makes harder) several
1338 // attacks on the DNS client.
1339 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1342 * two code lines after returning from comm_udprecvfrom()
1343 * something overwrites the memory behind the from parameter.
1344 * NO matter where in the stack declaration list above it is placed
1345 * The cause of this is still unknown, however copying the data appears
1346 * to allow it to be passed further without this erasure.
1348 Ip::Address bugbypass
;
1352 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1354 from
= bugbypass
; // BUG BYPASS. see notes above.
1361 if (ignoreErrno(xerrno
))
1365 /* Some Linux systems seem to set the FD for reading and then
1366 * return ECONNREFUSED when sendto() fails and generates an ICMP
1367 * port unreachable message. */
1368 /* or maybe an EHOSTUNREACH "No route to host" message */
1369 if (xerrno
!= ECONNREFUSED
&& xerrno
!= EHOSTUNREACH
)
1371 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << fd
<< " recvfrom: " << xstrerr(xerrno
));
1376 fd_bytes(fd
, len
, FD_READ
);
1381 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1383 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1384 int nsn
= idnsFromKnownNameserver(from
);
1387 ++ nameservers
[nsn
].nreplies
;
1390 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1391 // but after the ++ above to keep statistics right.
1393 continue; // Don't process replies if there is no pending query.
1395 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1396 static time_t last_warning
= 0;
1398 if (squid_curtime
- last_warning
> 60) {
1399 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1400 last_warning
= squid_curtime
;
1402 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1407 idnsGrokReply(rbuf
, len
, nsn
);
1412 idnsCheckQueue(void *)
1415 dlink_node
*p
= NULL
;
1420 /* name servers went away; reconfiguring or shutting down */
1423 for (n
= lru_list
.tail
; n
; n
= p
) {
1426 q
= static_cast<idns_query
*>(n
->data
);
1428 /* Anything to process in the queue? */
1429 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1432 /* Query timer still running? */
1433 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1434 dlinkDelete(&q
->lru
, &lru_list
);
1435 q
->queue_t
= current_time
;
1436 dlinkAdd(q
, &q
->lru
, &lru_list
);
1440 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1441 " QID 0x" << std::hex
<< std::setfill('0') <<
1442 std::setw(4) << q
->query_id
<< ": timeout" );
1444 dlinkDelete(&q
->lru
, &lru_list
);
1447 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1450 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1451 " QID 0x" << std::hex
<< q
->query_id
<<
1452 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1453 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1456 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1458 idnsCallback(q
, "Timeout");
1466 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1468 nsvc
* vc
= (nsvc
*)data
;
1470 if (flag
== Comm::ERR_CLOSING
)
1473 if (flag
!= Comm::OK
|| len
<= 0) {
1474 if (Comm::IsConnOpen(conn
))
1479 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1481 if (vc
->msg
->contentSize() < vc
->msglen
) {
1482 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1483 CommIoCbPtrFun(idnsReadVC
, vc
));
1484 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1488 assert(vc
->ns
< nns
);
1489 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1491 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1493 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1494 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1495 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1499 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1501 nsvc
* vc
= (nsvc
*)data
;
1503 if (flag
== Comm::ERR_CLOSING
)
1506 if (flag
!= Comm::OK
|| len
<= 0) {
1507 if (Comm::IsConnOpen(conn
))
1512 vc
->read_msglen
+= len
;
1514 assert(vc
->read_msglen
<= 2);
1516 if (vc
->read_msglen
< 2) {
1517 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1518 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1519 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1523 vc
->read_msglen
= 0;
1525 vc
->msglen
= ntohs(vc
->msglen
);
1528 if (Comm::IsConnOpen(conn
))
1533 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1534 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1535 CommIoCbPtrFun(idnsReadVC
, vc
));
1536 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1540 * rcode < 0 indicates an error, rocde >= 0 indicates success
1543 idnsRcodeCount(int rcode
, int attempt
)
1550 if (rcode
< MAX_RCODE
)
1551 if (attempt
< MAX_ATTEMPT
)
1552 ++ RcodeMatrix
[rcode
][attempt
];
1558 static int init
= 0;
1560 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1561 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1563 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1564 addrV6
= Config
.Addrs
.udp_outgoing
;
1566 addrV6
= Config
.Addrs
.udp_incoming
;
1568 Ip::Address addrV4
= addrV6
;
1571 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1572 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1573 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1580 if (addrV4
.isIPv4()) {
1581 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1582 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1589 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1590 fatal("Could not create a DNS socket");
1592 /* Ouch... we can't call functions using debug from a debug
1593 * statement. Doing so messes up the internal Debug::level
1595 if (DnsSocketB
>= 0) {
1596 comm_local_port(DnsSocketB
);
1597 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1598 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1600 if (DnsSocketA
>= 0) {
1601 comm_local_port(DnsSocketA
);
1602 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1603 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1608 idnsAddMDNSNameservers();
1609 bool nsFound
= idnsParseNameservers();
1612 nsFound
= idnsParseResolvConf();
1616 nsFound
= idnsParseWIN32Registry();
1620 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1622 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1624 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1627 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1629 idnsAddNameserver("::1");
1630 idnsAddNameserver("127.0.0.1");
1634 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1635 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1639 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1640 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1641 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1642 max_shared_edns
= -1; // disable if we might receive random replies.
1646 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1650 idnsShutdownAndFreeState(const char *reason
)
1652 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1655 debugs(78, 2, reason
<< ": Closing DNS sockets");
1657 if (DnsSocketA
>= 0 ) {
1658 comm_close(DnsSocketA
);
1662 if (DnsSocketB
>= 0 ) {
1663 comm_close(DnsSocketB
);
1667 for (int i
= 0; i
< nns
; ++i
) {
1668 if (nsvc
*vc
= nameservers
[i
].vc
) {
1669 if (Comm::IsConnOpen(vc
->conn
))
1674 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1675 idnsFreeNameservers();
1676 idnsFreeSearchpath();
1680 Dns::ConfigRr::endingShutdown()
1682 idnsShutdownAndFreeState("Shutdown");
1686 Dns::ConfigRr::startReconfigure()
1688 idnsShutdownAndFreeState("Reconfigure");
1692 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1694 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1699 idns_query
*q
= new idns_query
;
1700 // no query_id on this instance.
1702 q
->callback
= callback
;
1703 q
->callback_data
= cbdataReference(data
);
1705 q
->queue
= old
->queue
;
1708 // This check must follow cbdataReference() above because our callback code
1709 // needs a locked cbdata to call cbdataReferenceValid().
1710 if (idnsStillPending(old
))
1711 idnsCallbackNewCallerWithOldAnswers(callback
, data
, old
);
1712 // else: idns_lookup_hash is not a cache so no pending lookups means we are
1713 // in a reentrant lookup and will be called back when dequeued.
1719 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1721 q
->start_t
= current_time
;
1722 q
->callback
= callback
;
1723 q
->callback_data
= cbdataReference(data
);
1725 q
->hash
.key
= q
->orig
;
1726 hash_join(idns_lookup_hash
, &q
->hash
);
1732 idnsSendSlaveAAAAQuery(idns_query
*master
)
1734 idns_query
*q
= new idns_query
;
1735 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1736 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1738 q
->query_id
= idnsQueryID();
1739 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1741 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1742 ", id = 0x" << std::hex
<< q
->query_id
);
1748 q
->start_t
= master
->start_t
;
1749 q
->slave
= master
->slave
;
1757 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1759 size_t nameLength
= strlen(name
);
1761 // Prevent buffer overflow on q->name
1762 if (nameLength
> NS_MAXDNAME
) {
1763 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1764 idnsCallbackOnEarlyError(callback
, data
, "huge name");
1768 if (idnsCachedLookup(name
, callback
, data
))
1771 idns_query
*q
= new idns_query
;
1772 q
->query_id
= idnsQueryID();
1775 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1779 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1780 q
->do_searchpath
= 1;
1782 q
->do_searchpath
= 0;
1785 strcpy(q
->orig
, name
);
1786 strcpy(q
->name
, q
->orig
);
1788 if (q
->do_searchpath
&& nd
< ndots
) {
1790 strcat(q
->name
, ".");
1791 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1792 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1795 // see EDNS notes at top of file why this sends 0
1796 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1799 /* problem with query data -- query not sent */
1800 idnsCallbackOnEarlyError(callback
, data
, "rfc3596BuildAQuery error");
1805 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1806 ", id = 0x" << std::hex
<< q
->query_id
);
1809 idnsStartQuery(q
, callback
, data
);
1812 idnsSendSlaveAAAAQuery(q
);
1816 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1818 char ip
[MAX_IPSTRLEN
];
1820 addr
.toStr(ip
,MAX_IPSTRLEN
);
1822 idns_query
*q
= new idns_query
;
1823 q
->query_id
= idnsQueryID();
1825 if (addr
.isIPv6()) {
1826 struct in6_addr addr6
;
1827 addr
.getInAddr(addr6
);
1828 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1830 struct in_addr addr4
;
1831 addr
.getInAddr(addr4
);
1832 // see EDNS notes at top of file why this sends 0
1833 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1837 /* problem with query data -- query not sent */
1838 idnsCallbackOnEarlyError(callback
, data
, "rfc3596BuildPTRQuery error");
1843 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1848 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1849 ", id = 0x" << std::hex
<< q
->query_id
);
1851 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1852 idnsStartQuery(q
, callback
, data
);
1857 * The function to return the DNS via SNMP
1860 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1863 variable_list
*Answer
= NULL
;
1865 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1866 *ErrP
= SNMP_ERR_NOERROR
;
1868 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1872 for (i
= 0; i
< nns
; ++i
)
1873 n
+= nameservers
[i
].nqueries
;
1875 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1882 for (i
= 0; i
< nns
; ++i
)
1883 n
+= nameservers
[i
].nreplies
;
1885 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1892 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1899 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1907 #endif /*SQUID_SNMP */