2 * Copyright (C) 1996-2017 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
);
287 idnsCheckMDNS(idns_query
*q
)
289 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
292 size_t slen
= strlen(q
->name
);
293 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
294 q
->permit_mdns
= true;
299 idnsAddMDNSNameservers()
304 if (!Config
.onoff
.dns_mdns
)
307 // mDNS resolver addresses are explicit multicast group IPs
308 if (Ip::EnableIpv6
) {
309 idnsAddNameserver("FF02::FB");
310 nameservers
[nns
-1].S
.port(5353);
311 nameservers
[nns
-1].mDNSResolver
= true;
315 idnsAddNameserver("224.0.0.251");
316 nameservers
[nns
-1].S
.port(5353);
317 nameservers
[nns
-1].mDNSResolver
= true;
323 idnsAddNameserver(const char *buf
)
328 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
333 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
335 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
338 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
339 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
343 if (nns
== nns_alloc
) {
344 int oldalloc
= nns_alloc
;
345 ns
*oldptr
= nameservers
;
352 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
354 if (oldptr
&& oldalloc
)
355 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
361 assert(nns
< nns_alloc
);
362 A
.port(NS_DEFAULTPORT
);
363 nameservers
[nns
].S
= A
;
364 #if WHEN_EDNS_RESPONSES_ARE_PARSED
365 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
366 // TODO generate a test packet to probe this NS from EDNS size and ability.
368 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
373 idnsAddPathComponent(const char *buf
)
375 if (npc
== npc_alloc
) {
376 int oldalloc
= npc_alloc
;
377 sp
*oldptr
= searchpath
;
384 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
386 if (oldptr
&& oldalloc
)
387 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
393 assert(npc
< npc_alloc
);
394 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
395 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
396 Tolower(searchpath
[npc
].domain
);
397 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
402 idnsFreeNameservers(void)
404 safe_free(nameservers
);
409 idnsFreeSearchpath(void)
411 safe_free(searchpath
);
416 idnsParseNameservers(void)
419 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
420 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
421 idnsAddNameserver(w
->key
);
428 idnsParseResolvConf(void)
432 FILE *fp
= fopen(_PATH_RESCONF
, "r");
436 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerr(xerrno
));
440 char buf
[RESOLV_BUFSZ
];
441 const char *t
= NULL
;
442 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
443 t
= strtok(buf
, w_space
);
447 } else if (strcmp(t
, "nameserver") == 0) {
448 t
= strtok(NULL
, w_space
);
453 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
455 idnsAddNameserver(t
);
457 } else if (strcmp(t
, "domain") == 0) {
458 idnsFreeSearchpath();
459 t
= strtok(NULL
, w_space
);
464 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
466 idnsAddPathComponent(t
);
467 } else if (strcmp(t
, "search") == 0) {
468 idnsFreeSearchpath();
470 t
= strtok(NULL
, w_space
);
475 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
477 idnsAddPathComponent(t
);
479 } else if (strcmp(t
, "options") == 0) {
481 t
= strtok(NULL
, w_space
);
486 if (strncmp(t
, "ndots:", 6) == 0) {
492 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
497 if (npc
== 0 && (t
= getMyHostname())) {
500 idnsAddPathComponent(t
+1);
510 idnsParseWIN32SearchList(const char * Separator
)
516 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
520 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
522 if (Result
== ERROR_SUCCESS
&& Size
) {
523 t
= (char *) xmalloc(Size
);
524 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
525 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
526 idnsAddPathComponent(t
);
529 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
531 if (Result
== ERROR_SUCCESS
&& Size
) {
532 t
= (char *) xmalloc(Size
);
533 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
534 token
= strtok(t
, Separator
);
537 idnsAddPathComponent(token
);
538 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
539 token
= strtok(NULL
, Separator
);
546 if (npc
== 0 && (t
= (char *) getMyHostname())) {
549 idnsAddPathComponent(t
+ 1);
554 idnsParseWIN32Registry(void)
558 HKEY hndKey
, hndKey2
;
561 switch (WIN32_OS_version
) {
564 /* get nameservers from the Windows NT registry */
566 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
570 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
572 if (Result
== ERROR_SUCCESS
&& Size
) {
573 t
= (char *) xmalloc(Size
);
574 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
575 token
= strtok(t
, ", ");
578 idnsAddNameserver(token
);
580 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
581 token
= strtok(NULL
, ",");
586 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
588 if (Result
== ERROR_SUCCESS
&& Size
) {
589 t
= (char *) xmalloc(Size
);
590 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
591 token
= strtok(t
, ", ");
594 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
595 idnsAddNameserver(token
);
597 token
= strtok(NULL
, ", ");
605 idnsParseWIN32SearchList(" ");
618 /* get nameservers from the Windows 2000 registry */
619 /* search all interfaces for DNS server addresses */
621 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
623 DWORD MaxSubkeyLen
, InterfacesCount
;
625 FILETIME ftLastWriteTime
;
627 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
628 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
629 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
632 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
634 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
635 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
636 strcat(newkeyname
, "\\");
637 strcat(newkeyname
, keyname
);
638 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
642 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
643 if (Result
== ERROR_SUCCESS
&& Size
) {
644 t
= (char *) xmalloc(Size
);
645 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
646 token
= strtok(t
, ", ");
648 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
649 idnsAddNameserver(token
);
651 token
= strtok(NULL
, ", ");
656 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
657 if (Result
== ERROR_SUCCESS
&& Size
) {
658 t
= (char *) xmalloc(Size
);
659 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
660 token
= strtok(t
, ", ");
662 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
663 idnsAddNameserver(token
);
665 token
= strtok(NULL
, ", ");
671 RegCloseKey(hndKey2
);
684 idnsParseWIN32SearchList(", ");
693 /* get nameservers from the Windows 9X registry */
695 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
699 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
701 if (Result
== ERROR_SUCCESS
&& Size
) {
702 t
= (char *) xmalloc(Size
);
703 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
704 token
= strtok(t
, ", ");
707 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
708 idnsAddNameserver(token
);
710 token
= strtok(NULL
, ", ");
721 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
730 idnsStats(StoreEntry
* sentry
)
736 char buf
[MAX_IPSTRLEN
];
737 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
738 storeAppendPrintf(sentry
, "\nThe Queue:\n");
739 storeAppendPrintf(sentry
, " DELAY SINCE\n");
740 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
741 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
743 for (n
= lru_list
.head
; n
; n
= n
->next
) {
744 q
= (idns_query
*)n
->data
;
745 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
746 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
747 tvSubDsec(q
->start_t
, current_time
),
748 tvSubDsec(q
->sent_t
, current_time
),
749 (q
->permit_mdns
? 'M':' '),
753 if (Config
.dns
.packet_max
> 0)
754 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
756 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
758 storeAppendPrintf(sentry
, "\nNameservers:\n");
759 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
760 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
762 for (i
= 0; i
< nns
; ++i
) {
763 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
764 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
765 nameservers
[i
].nqueries
,
766 nameservers
[i
].nreplies
,
767 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
770 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
771 storeAppendPrintf(sentry
, "RCODE");
773 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
774 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
776 storeAppendPrintf(sentry
, " PROBLEM\n");
778 for (j
= 0; j
< MAX_RCODE
; ++j
) {
779 if (j
> 10 && j
< 16)
780 continue; // unassigned by IANA.
782 storeAppendPrintf(sentry
, "%5d", j
);
784 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
785 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
787 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
791 storeAppendPrintf(sentry
, "\nSearch list:\n");
793 for (i
=0; i
< npc
; ++i
)
794 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
796 storeAppendPrintf(sentry
, "\n");
801 idnsTickleQueue(void)
806 if (NULL
== lru_list
.tail
)
809 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
811 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
817 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *, size_t size
, Comm::Flag flag
, int, void *data
)
819 nsvc
* vc
= (nsvc
*)data
;
821 if (flag
== Comm::ERR_CLOSING
)
824 // XXX: irrelevant now that we have conn pointer?
825 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
828 if (flag
!= Comm::OK
|| size
<= 0) {
834 idnsDoSendQueryVC(vc
);
838 idnsDoSendQueryVC(nsvc
*vc
)
843 if (vc
->queue
->contentSize() == 0)
846 // if retrying after a TC UDP response, our close handler cb may be pending
847 if (fd_table
[vc
->conn
->fd
].closing())
850 MemBuf
*mb
= vc
->queue
;
852 vc
->queue
= new MemBuf
;
856 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
857 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
858 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
859 AsyncCall::Pointer nil
;
861 commSetConnTimeout(vc
->conn
, timeout
, nil
);
863 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
864 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
865 Comm::Write(vc
->conn
, mb
, call
);
871 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int, void *data
)
873 nsvc
* vc
= (nsvc
*)data
;
875 if (status
!= Comm::OK
|| !conn
) {
876 char buf
[MAX_IPSTRLEN
] = "";
878 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
879 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
885 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
886 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
887 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
888 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
890 idnsDoSendQueryVC(vc
);
894 idnsVCClosed(const CommCloseCbParams
¶ms
)
896 nsvc
* vc
= (nsvc
*)params
.data
;
904 if (ns
< nns
) // XXX: idnsShutdownAndFreeState may have freed nameservers[]
905 nameservers
[ns
].vc
= NULL
;
911 nsvc
*vc
= new nsvc(nsv
);
913 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
914 nameservers
[nsv
].vc
= vc
;
916 Comm::ConnectionPointer conn
= new Comm::Connection();
918 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
919 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
921 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
923 if (conn
->remote
.isIPv4())
924 conn
->local
.setIPv4();
926 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
928 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
929 cs
->setHost("DNS TCP Socket");
934 idnsSendQueryVC(idns_query
* q
, int nsn
)
937 if (nameservers
[nsn
].vc
== NULL
)
940 nsvc
*vc
= nameservers
[nsn
].vc
;
943 char buf
[MAX_IPSTRLEN
];
944 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
951 short head
= htons(q
->sz
);
953 vc
->queue
->append((char *)&head
, 2);
955 vc
->queue
->append(q
->buf
, q
->sz
);
957 idnsDoSendQueryVC(vc
);
961 idnsSendQuery(idns_query
* q
)
963 // XXX: DNS sockets get closed during reconfigure produces a race between
964 // any already active connections (or ones received between closing DNS
965 // sockets and server listening sockets) and the reconfigure completing
966 // (Runner syncConfig() being run). Transactions which loose this race will
967 // produce DNS timeouts (or whatever the caller set) as their queries never
968 // get queued to be re-tried after the DNS socekts are re-opened.
970 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
971 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
976 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
980 assert(q
->lru
.next
== NULL
);
982 assert(q
->lru
.prev
== NULL
);
988 // only use mDNS resolvers for mDNS compatible queries
990 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
992 nsn
= q
->nsends
% nns
;
995 idnsSendQueryVC(q
, nsn
);
998 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
999 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
1000 else if (DnsSocketA
>= 0)
1001 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
1007 q
->sent_t
= current_time
;
1009 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
1010 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketB
<< ": sendto: " << xstrerr(xerrno
));
1011 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
1012 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketA
<< ": sendto: " << xstrerr(xerrno
));
1014 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
1017 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
1020 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
1023 ++ nameservers
[nsn
].nqueries
;
1024 q
->queue_t
= current_time
;
1025 dlinkAdd(q
, &q
->lru
, &lru_list
);
1031 idnsFromKnownNameserver(Ip::Address
const &from
)
1035 for (i
= 0; i
< nns
; ++i
) {
1036 if (nameservers
[i
].S
!= from
)
1039 if (nameservers
[i
].S
.port() != from
.port())
1049 idnsFindQuery(unsigned short id
)
1054 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1055 q
= (idns_query
*)n
->data
;
1057 if (q
->query_id
== id
)
1064 static unsigned short
1067 // NP: apparently ranlux are faster, but not quite as "proven"
1068 static std::mt19937
mt(static_cast<uint32_t>(getCurrentTime() & 0xFFFFFFFF));
1069 unsigned short id
= mt() & 0xFFFF;
1070 unsigned short first_id
= id
;
1072 // ensure temporal uniqueness by looking for an existing use
1073 while (idnsFindQuery(id
)) {
1076 if (id
== first_id
) {
1077 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1086 idnsCallback(idns_query
*q
, const char *error
)
1097 // If any of our subqueries are still pending then wait for them to complete before continuing
1098 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1105 rfc1035_message
*message
= q
->message
;
1110 while ( idns_query
*q2
= q
->slave
) {
1111 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1112 q
->slave
= q2
->slave
;
1116 // two sets of RR need merging
1117 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1118 if (Config
.dns
.v4_first
) {
1119 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1120 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1122 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1123 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1126 // HACK WARNING, the answer rr:s have been copied in-place to
1127 // result, do not free them here
1128 safe_free(message
->answer
);
1129 safe_free(q2
->message
->answer
);
1130 message
->answer
= result
;
1131 message
->ancount
+= q2
->message
->ancount
;
1133 // first response empty or failed, just use the second
1134 rfc1035MessageDestroy(&message
);
1135 message
= q2
->message
;
1144 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1146 callback
= q
->callback
;
1148 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1150 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1151 callback(cbdata
, answers
, n
, error
);
1154 idns_query
*q2
= q
->queue
;
1155 q
->queue
= q2
->queue
;
1158 callback
= q2
->callback
;
1159 q2
->callback
= NULL
;
1161 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1162 callback(cbdata
, answers
, n
, error
);
1168 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1172 rfc1035MessageDestroy(&message
);
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
;
1712 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1714 q
->start_t
= current_time
;
1715 q
->callback
= callback
;
1716 q
->callback_data
= cbdataReference(data
);
1718 q
->hash
.key
= q
->orig
;
1719 hash_join(idns_lookup_hash
, &q
->hash
);
1725 idnsSendSlaveAAAAQuery(idns_query
*master
)
1727 idns_query
*q
= new idns_query
;
1728 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1729 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1731 q
->query_id
= idnsQueryID();
1732 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1734 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1735 ", id = 0x" << std::hex
<< q
->query_id
);
1741 q
->start_t
= master
->start_t
;
1742 q
->slave
= master
->slave
;
1750 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1752 size_t nameLength
= strlen(name
);
1754 // Prevent buffer overflow on q->name
1755 if (nameLength
> NS_MAXDNAME
) {
1756 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1757 callback(data
, NULL
, 0, "Internal error");
1761 if (idnsCachedLookup(name
, callback
, data
))
1764 idns_query
*q
= new idns_query
;
1765 q
->query_id
= idnsQueryID();
1768 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1772 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1773 q
->do_searchpath
= 1;
1775 q
->do_searchpath
= 0;
1778 strcpy(q
->orig
, name
);
1779 strcpy(q
->name
, q
->orig
);
1781 if (q
->do_searchpath
&& nd
< ndots
) {
1783 strcat(q
->name
, ".");
1784 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1785 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1788 // see EDNS notes at top of file why this sends 0
1789 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1792 /* problem with query data -- query not sent */
1793 callback(data
, NULL
, 0, "Internal error");
1798 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1799 ", id = 0x" << std::hex
<< q
->query_id
);
1802 idnsStartQuery(q
, callback
, data
);
1805 idnsSendSlaveAAAAQuery(q
);
1809 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1811 char ip
[MAX_IPSTRLEN
];
1813 addr
.toStr(ip
,MAX_IPSTRLEN
);
1815 idns_query
*q
= new idns_query
;
1816 q
->query_id
= idnsQueryID();
1818 if (addr
.isIPv6()) {
1819 struct in6_addr addr6
;
1820 addr
.getInAddr(addr6
);
1821 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1823 struct in_addr addr4
;
1824 addr
.getInAddr(addr4
);
1825 // see EDNS notes at top of file why this sends 0
1826 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1830 /* problem with query data -- query not sent */
1831 callback(data
, NULL
, 0, "Internal error");
1836 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1841 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1842 ", id = 0x" << std::hex
<< q
->query_id
);
1844 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1845 idnsStartQuery(q
, callback
, data
);
1850 * The function to return the DNS via SNMP
1853 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1856 variable_list
*Answer
= NULL
;
1858 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1859 *ErrP
= SNMP_ERR_NOERROR
;
1861 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1865 for (i
= 0; i
< nns
; ++i
)
1866 n
+= nameservers
[i
].nqueries
;
1868 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1875 for (i
= 0; i
< nns
; ++i
)
1876 n
+= nameservers
[i
].nreplies
;
1878 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1885 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1892 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1900 #endif /*SQUID_SNMP */