2 * Copyright (C) 1996-2016 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
);
128 memset(&hash
, 0, sizeof(hash
));
129 memset(&query
, 0, sizeof(query
));
133 memset(&start_t
, 0, sizeof(start_t
));
134 memset(&sent_t
, 0, sizeof(sent_t
));
135 memset(&queue_t
, 0, sizeof(queue_t
));
140 rfc1035MessageDestroy(&message
);
143 // master is just a back-reference
144 cbdataReferenceDone(callback_data
);
149 char buf
[RESOLV_BUFSZ
];
150 char name
[NS_MAXDNAME
+ 1];
151 char orig
[NS_MAXDNAME
+ 1];
153 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
154 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
161 struct timeval start_t
;
162 struct timeval sent_t
;
163 struct timeval queue_t
;
170 idns_query
*slave
; // single linked list
171 idns_query
*master
; // single pointer to a shared master
172 unsigned short domain
;
173 unsigned short do_searchpath
;
174 rfc1035_message
*message
;
179 InstanceIdDefinitions(idns_query
, "dns");
181 CBDATA_CLASS_INIT(idns_query
);
188 explicit nsvc(int nsv
) : ns(nsv
), msglen(0), read_msglen(0), msg(new MemBuf()), queue(new MemBuf()), busy(true) {}
192 Comm::ConnectionPointer conn
;
193 unsigned short msglen
;
200 CBDATA_CLASS_INIT(nsvc
);
206 #if WHEN_EDNS_RESPONSES_ARE_PARSED
216 /// manage DNS internal component
217 class ConfigRr
: public RegisteredRunner
220 /* RegisteredRunner API */
221 virtual void startReconfigure() override
;
222 virtual void endingShutdown() override
;
225 RunnerRegistrationEntry(ConfigRr
);
230 char domain
[NS_MAXDNAME
];
234 static ns
*nameservers
= NULL
;
235 static sp
*searchpath
= NULL
;
237 static int nns_alloc
= 0;
238 static int nns_mdns_count
= 0;
240 static int npc_alloc
= 0;
241 static int ndots
= 1;
242 static dlink_list lru_list
;
243 static int event_queued
= 0;
244 static hash_table
*idns_lookup_hash
= NULL
;
250 * EDNS as specified may be sent as an additional record for any request.
251 * early testing has revealed that it works on common devices, but cannot
252 * be reliably used on any A or PTR requet done for IPv4 addresses.
254 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
257 * Squid is optimized to generate one packet and re-send it to all NS
258 * due to this we cannot customize the EDNS size per NS.
260 * As such we take the configuration option value as fixed.
263 * This may not be worth doing, but if/when additional-records are parsed
264 * we will be able to recover the OPT value specific to any one NS and
265 * cache it. Effectively automating the tuning of EDNS advertised to the
266 * size our active NS are capable.
267 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
268 * Responses from the configured NS may cause this to be raised or turned off.
270 #if WHEN_EDNS_RESPONSES_ARE_PARSED
271 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
274 static OBJH idnsStats
;
275 static void idnsAddNameserver(const char *buf
);
276 static void idnsAddMDNSNameservers();
277 static void idnsAddPathComponent(const char *buf
);
278 static void idnsFreeNameservers(void);
279 static void idnsFreeSearchpath(void);
280 static bool idnsParseNameservers(void);
281 static bool idnsParseResolvConf(void);
283 static bool idnsParseWIN32Registry(void);
284 static void idnsParseWIN32SearchList(const char *);
286 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
287 static void idnsSendQuery(idns_query
* q
);
288 static IOCB idnsReadVCHeader
;
289 static void idnsDoSendQueryVC(nsvc
*vc
);
290 static CNCB idnsInitVCConnected
;
291 static IOCB idnsReadVC
;
292 static IOCB idnsSentQueryVC
;
294 static int idnsFromKnownNameserver(Ip::Address
const &from
);
295 static idns_query
*idnsFindQuery(unsigned short id
);
296 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
298 static EVH idnsCheckQueue
;
299 static void idnsTickleQueue(void);
300 static void idnsRcodeCount(int, int);
301 static CLCB idnsVCClosed
;
302 static unsigned short idnsQueryID(void);
303 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
306 idnsCheckMDNS(idns_query
*q
)
308 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
311 size_t slen
= strlen(q
->name
);
312 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
313 q
->permit_mdns
= true;
318 idnsAddMDNSNameservers()
323 if (!Config
.onoff
.dns_mdns
)
326 // mDNS resolver addresses are explicit multicast group IPs
327 if (Ip::EnableIpv6
) {
328 idnsAddNameserver("FF02::FB");
329 nameservers
[nns
-1].S
.port(5353);
330 nameservers
[nns
-1].mDNSResolver
= true;
334 idnsAddNameserver("224.0.0.251");
335 nameservers
[nns
-1].S
.port(5353);
336 nameservers
[nns
-1].mDNSResolver
= true;
342 idnsAddNameserver(const char *buf
)
347 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
352 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
354 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
357 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
358 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
362 if (nns
== nns_alloc
) {
363 int oldalloc
= nns_alloc
;
364 ns
*oldptr
= nameservers
;
371 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
373 if (oldptr
&& oldalloc
)
374 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
380 assert(nns
< nns_alloc
);
381 A
.port(NS_DEFAULTPORT
);
382 nameservers
[nns
].S
= A
;
383 #if WHEN_EDNS_RESPONSES_ARE_PARSED
384 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
385 // TODO generate a test packet to probe this NS from EDNS size and ability.
387 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
392 idnsAddPathComponent(const char *buf
)
394 if (npc
== npc_alloc
) {
395 int oldalloc
= npc_alloc
;
396 sp
*oldptr
= searchpath
;
403 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
405 if (oldptr
&& oldalloc
)
406 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
412 assert(npc
< npc_alloc
);
413 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
414 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
415 Tolower(searchpath
[npc
].domain
);
416 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
421 idnsFreeNameservers(void)
423 safe_free(nameservers
);
428 idnsFreeSearchpath(void)
430 safe_free(searchpath
);
435 idnsParseNameservers(void)
438 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
439 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
440 idnsAddNameserver(w
->key
);
447 idnsParseResolvConf(void)
451 FILE *fp
= fopen(_PATH_RESCONF
, "r");
455 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerr(xerrno
));
459 char buf
[RESOLV_BUFSZ
];
460 const char *t
= NULL
;
461 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
462 t
= strtok(buf
, w_space
);
466 } else if (strcmp(t
, "nameserver") == 0) {
467 t
= strtok(NULL
, w_space
);
472 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
474 idnsAddNameserver(t
);
476 } else if (strcmp(t
, "domain") == 0) {
477 idnsFreeSearchpath();
478 t
= strtok(NULL
, w_space
);
483 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
485 idnsAddPathComponent(t
);
486 } else if (strcmp(t
, "search") == 0) {
487 idnsFreeSearchpath();
489 t
= strtok(NULL
, w_space
);
494 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
496 idnsAddPathComponent(t
);
498 } else if (strcmp(t
, "options") == 0) {
500 t
= strtok(NULL
, w_space
);
505 if (strncmp(t
, "ndots:", 6) == 0) {
511 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
516 if (npc
== 0 && (t
= getMyHostname())) {
519 idnsAddPathComponent(t
+1);
529 idnsParseWIN32SearchList(const char * Separator
)
535 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
539 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
541 if (Result
== ERROR_SUCCESS
&& Size
) {
542 t
= (char *) xmalloc(Size
);
543 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
544 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
545 idnsAddPathComponent(t
);
548 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
550 if (Result
== ERROR_SUCCESS
&& Size
) {
551 t
= (char *) xmalloc(Size
);
552 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
553 token
= strtok(t
, Separator
);
556 idnsAddPathComponent(token
);
557 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
558 token
= strtok(NULL
, Separator
);
565 if (npc
== 0 && (t
= (char *) getMyHostname())) {
568 idnsAddPathComponent(t
+ 1);
573 idnsParseWIN32Registry(void)
577 HKEY hndKey
, hndKey2
;
580 switch (WIN32_OS_version
) {
583 /* get nameservers from the Windows NT registry */
585 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
589 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
591 if (Result
== ERROR_SUCCESS
&& Size
) {
592 t
= (char *) xmalloc(Size
);
593 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
594 token
= strtok(t
, ", ");
597 idnsAddNameserver(token
);
599 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
600 token
= strtok(NULL
, ",");
605 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
607 if (Result
== ERROR_SUCCESS
&& Size
) {
608 t
= (char *) xmalloc(Size
);
609 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
610 token
= strtok(t
, ", ");
613 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
614 idnsAddNameserver(token
);
616 token
= strtok(NULL
, ", ");
624 idnsParseWIN32SearchList(" ");
637 /* get nameservers from the Windows 2000 registry */
638 /* search all interfaces for DNS server addresses */
640 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
642 DWORD MaxSubkeyLen
, InterfacesCount
;
644 FILETIME ftLastWriteTime
;
646 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
647 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
648 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
651 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
653 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
654 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
655 strcat(newkeyname
, "\\");
656 strcat(newkeyname
, keyname
);
657 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
661 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
662 if (Result
== ERROR_SUCCESS
&& Size
) {
663 t
= (char *) xmalloc(Size
);
664 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
665 token
= strtok(t
, ", ");
667 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
668 idnsAddNameserver(token
);
670 token
= strtok(NULL
, ", ");
675 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
676 if (Result
== ERROR_SUCCESS
&& Size
) {
677 t
= (char *) xmalloc(Size
);
678 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
679 token
= strtok(t
, ", ");
681 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
682 idnsAddNameserver(token
);
684 token
= strtok(NULL
, ", ");
690 RegCloseKey(hndKey2
);
703 idnsParseWIN32SearchList(", ");
712 /* get nameservers from the Windows 9X registry */
714 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
718 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
720 if (Result
== ERROR_SUCCESS
&& Size
) {
721 t
= (char *) xmalloc(Size
);
722 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
723 token
= strtok(t
, ", ");
726 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
727 idnsAddNameserver(token
);
729 token
= strtok(NULL
, ", ");
740 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
749 idnsStats(StoreEntry
* sentry
)
755 char buf
[MAX_IPSTRLEN
];
756 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
757 storeAppendPrintf(sentry
, "\nThe Queue:\n");
758 storeAppendPrintf(sentry
, " DELAY SINCE\n");
759 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
760 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
762 for (n
= lru_list
.head
; n
; n
= n
->next
) {
763 q
= (idns_query
*)n
->data
;
764 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
765 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
766 tvSubDsec(q
->start_t
, current_time
),
767 tvSubDsec(q
->sent_t
, current_time
),
768 (q
->permit_mdns
? 'M':' '),
772 if (Config
.dns
.packet_max
> 0)
773 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
775 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
777 storeAppendPrintf(sentry
, "\nNameservers:\n");
778 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
779 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
781 for (i
= 0; i
< nns
; ++i
) {
782 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
783 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
784 nameservers
[i
].nqueries
,
785 nameservers
[i
].nreplies
,
786 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
789 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
790 storeAppendPrintf(sentry
, "RCODE");
792 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
793 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
795 storeAppendPrintf(sentry
, " PROBLEM\n");
797 for (j
= 0; j
< MAX_RCODE
; ++j
) {
798 if (j
> 10 && j
< 16)
799 continue; // unassigned by IANA.
801 storeAppendPrintf(sentry
, "%5d", j
);
803 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
804 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
806 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
810 storeAppendPrintf(sentry
, "\nSearch list:\n");
812 for (i
=0; i
< npc
; ++i
)
813 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
815 storeAppendPrintf(sentry
, "\n");
820 idnsTickleQueue(void)
825 if (NULL
== lru_list
.tail
)
828 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
830 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
836 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *, size_t size
, Comm::Flag flag
, int, void *data
)
838 nsvc
* vc
= (nsvc
*)data
;
840 if (flag
== Comm::ERR_CLOSING
)
843 // XXX: irrelevant now that we have conn pointer?
844 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
847 if (flag
!= Comm::OK
|| size
<= 0) {
853 idnsDoSendQueryVC(vc
);
857 idnsDoSendQueryVC(nsvc
*vc
)
862 if (vc
->queue
->contentSize() == 0)
865 // if retrying after a TC UDP response, our close handler cb may be pending
866 if (fd_table
[vc
->conn
->fd
].closing())
869 MemBuf
*mb
= vc
->queue
;
871 vc
->queue
= new MemBuf
;
875 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
876 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
877 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
878 AsyncCall::Pointer nil
;
880 commSetConnTimeout(vc
->conn
, timeout
, nil
);
882 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
883 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
884 Comm::Write(vc
->conn
, mb
, call
);
890 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int, void *data
)
892 nsvc
* vc
= (nsvc
*)data
;
894 if (status
!= Comm::OK
|| !conn
) {
895 char buf
[MAX_IPSTRLEN
] = "";
897 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
898 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
904 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
905 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
906 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
907 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
909 idnsDoSendQueryVC(vc
);
913 idnsVCClosed(const CommCloseCbParams
¶ms
)
915 nsvc
* vc
= (nsvc
*)params
.data
;
923 if (ns
< nns
) // XXX: idnsShutdownAndFreeState may have freed nameservers[]
924 nameservers
[ns
].vc
= NULL
;
930 nsvc
*vc
= new nsvc(nsv
);
932 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
933 nameservers
[nsv
].vc
= vc
;
935 Comm::ConnectionPointer conn
= new Comm::Connection();
937 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
938 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
940 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
942 if (conn
->remote
.isIPv4())
943 conn
->local
.setIPv4();
945 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
947 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
948 cs
->setHost("DNS TCP Socket");
953 idnsSendQueryVC(idns_query
* q
, int nsn
)
956 if (nameservers
[nsn
].vc
== NULL
)
959 nsvc
*vc
= nameservers
[nsn
].vc
;
962 char buf
[MAX_IPSTRLEN
];
963 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
970 short head
= htons(q
->sz
);
972 vc
->queue
->append((char *)&head
, 2);
974 vc
->queue
->append(q
->buf
, q
->sz
);
976 idnsDoSendQueryVC(vc
);
980 idnsSendQuery(idns_query
* q
)
982 // XXX: DNS sockets get closed during reconfigure produces a race between
983 // any already active connections (or ones received between closing DNS
984 // sockets and server listening sockets) and the reconfigure completing
985 // (Runner syncConfig() being run). Transactions which loose this race will
986 // produce DNS timeouts (or whatever the caller set) as their queries never
987 // get queued to be re-tried after the DNS socekts are re-opened.
989 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
990 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
995 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
999 assert(q
->lru
.next
== NULL
);
1001 assert(q
->lru
.prev
== NULL
);
1007 // only use mDNS resolvers for mDNS compatible queries
1008 if (!q
->permit_mdns
)
1009 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
1011 nsn
= q
->nsends
% nns
;
1014 idnsSendQueryVC(q
, nsn
);
1017 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
1018 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
1019 else if (DnsSocketA
>= 0)
1020 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
1026 q
->sent_t
= current_time
;
1028 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
1029 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketB
<< ": sendto: " << xstrerr(xerrno
));
1030 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
1031 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << DnsSocketA
<< ": sendto: " << xstrerr(xerrno
));
1033 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
1036 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
1039 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
1042 ++ nameservers
[nsn
].nqueries
;
1043 q
->queue_t
= current_time
;
1044 dlinkAdd(q
, &q
->lru
, &lru_list
);
1050 idnsFromKnownNameserver(Ip::Address
const &from
)
1054 for (i
= 0; i
< nns
; ++i
) {
1055 if (nameservers
[i
].S
!= from
)
1058 if (nameservers
[i
].S
.port() != from
.port())
1068 idnsFindQuery(unsigned short id
)
1073 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1074 q
= (idns_query
*)n
->data
;
1076 if (q
->query_id
== id
)
1083 static unsigned short
1086 // NP: apparently ranlux are faster, but not quite as "proven"
1087 static std::mt19937
mt(static_cast<uint32_t>(getCurrentTime() & 0xFFFFFFFF));
1088 unsigned short id
= mt() & 0xFFFF;
1089 unsigned short first_id
= id
;
1091 // ensure temporal uniqueness by looking for an existing use
1092 while (idnsFindQuery(id
)) {
1095 if (id
== first_id
) {
1096 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1105 idnsCallback(idns_query
*q
, const char *error
)
1116 // If any of our subqueries are still pending then wait for them to complete before continuing
1117 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1124 rfc1035_message
*message
= q
->message
;
1129 while ( idns_query
*q2
= q
->slave
) {
1130 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1131 q
->slave
= q2
->slave
;
1135 // two sets of RR need merging
1136 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1137 if (Config
.dns
.v4_first
) {
1138 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1139 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1141 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1142 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1145 // HACK WARNING, the answer rr:s have been copied in-place to
1146 // result, do not free them here
1147 safe_free(message
->answer
);
1148 safe_free(q2
->message
->answer
);
1149 message
->answer
= result
;
1150 message
->ancount
+= q2
->message
->ancount
;
1152 // first response empty or failed, just use the second
1153 rfc1035MessageDestroy(&message
);
1154 message
= q2
->message
;
1163 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1165 callback
= q
->callback
;
1167 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1169 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1170 callback(cbdata
, answers
, n
, error
);
1173 idns_query
*q2
= q
->queue
;
1174 q
->queue
= q2
->queue
;
1177 callback
= q2
->callback
;
1178 q2
->callback
= NULL
;
1180 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1181 callback(cbdata
, answers
, n
, error
);
1187 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1191 rfc1035MessageDestroy(&message
);
1196 idnsGrokReply(const char *buf
, size_t sz
, int /*from_ns*/)
1198 rfc1035_message
*message
= NULL
;
1200 int n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1202 if (message
== NULL
) {
1203 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1207 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1209 idns_query
*q
= idnsFindQuery(message
->id
);
1212 debugs(78, 3, "idnsGrokReply: Late response");
1213 rfc1035MessageDestroy(&message
);
1217 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1218 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1219 rfc1035MessageDestroy(&message
);
1223 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1224 // TODO: actually gr the message right here.
1225 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1226 // this is overall better than force-feeding A response with AAAA an section later anyway.
1227 // AND allows us to merge AN+AR sections from both responses (one day)
1229 if (q
->edns_seen
>= 0) {
1230 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1231 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1232 // the altered NS was limiting the whole group.
1233 max_shared_edns
= q
->edns_seen
;
1234 // may be limited by one of the others still
1235 for (int i
= 0; i
< nns
; ++i
)
1236 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1238 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1239 // maybe reduce the global limit downwards to accomodate this NS
1240 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1242 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1243 max_shared_edns
= -1;
1247 dlinkDelete(&q
->lru
, &lru_list
);
1251 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1252 rfc1035MessageDestroy(&message
);
1259 // Strange: A TCP DNS response with the truncation bit (TC) set.
1260 // Return an error and cleanup; no point in trying TCP again.
1261 debugs(78, 3, HERE
<< "TCP DNS response");
1262 idnsCallback(q
, "Truncated TCP DNS response");
1268 idnsRcodeCount(n
, q
->attempt
);
1272 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1274 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1276 * RCODE 2 is "Server failure - The name server was
1277 * unable to process this query due to a problem with
1280 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1281 rfc1035MessageDestroy(&message
);
1286 // Do searchpath processing on the master A query only to keep
1287 // things simple. NXDOMAIN is authorative for the label, not
1289 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1290 assert(NULL
== message
->answer
);
1291 strcpy(q
->name
, q
->orig
);
1293 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1295 if (q
->domain
< npc
) {
1296 strcat(q
->name
, ".");
1297 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1298 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1304 rfc1035MessageDestroy(&message
);
1306 // cleanup slave AAAA query
1307 while (idns_query
*slave
= q
->slave
) {
1308 dlinkDelete(&slave
->lru
, &lru_list
);
1309 q
->slave
= slave
->slave
;
1310 slave
->slave
= NULL
;
1315 q
->query_id
= idnsQueryID();
1316 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1317 // see EDNS notes at top of file why this sends 0
1318 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1320 /* problem with query data -- query not sent */
1321 idnsCallback(q
, "Internal error");
1330 idnsSendSlaveAAAAQuery(q
);
1335 q
->message
= message
;
1339 idnsCallback(q
, NULL
);
1341 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1346 idnsRead(int fd
, void *)
1348 int *N
= &incoming_sockets_accepted
;
1350 int max
= INCOMING_DNS_MAX
;
1351 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1354 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1356 // Always keep reading. This stops (or at least makes harder) several
1357 // attacks on the DNS client.
1358 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1361 * two code lines after returning from comm_udprecvfrom()
1362 * something overwrites the memory behind the from parameter.
1363 * NO matter where in the stack declaration list above it is placed
1364 * The cause of this is still unknown, however copying the data appears
1365 * to allow it to be passed further without this erasure.
1367 Ip::Address bugbypass
;
1371 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1373 from
= bugbypass
; // BUG BYPASS. see notes above.
1380 if (ignoreErrno(xerrno
))
1384 /* Some Linux systems seem to set the FD for reading and then
1385 * return ECONNREFUSED when sendto() fails and generates an ICMP
1386 * port unreachable message. */
1387 /* or maybe an EHOSTUNREACH "No route to host" message */
1388 if (xerrno
!= ECONNREFUSED
&& xerrno
!= EHOSTUNREACH
)
1390 debugs(50, DBG_IMPORTANT
, MYNAME
<< "FD " << fd
<< " recvfrom: " << xstrerr(xerrno
));
1395 fd_bytes(fd
, len
, FD_READ
);
1400 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1402 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1403 int nsn
= idnsFromKnownNameserver(from
);
1406 ++ nameservers
[nsn
].nreplies
;
1409 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1410 // but after the ++ above to keep statistics right.
1412 continue; // Don't process replies if there is no pending query.
1414 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1415 static time_t last_warning
= 0;
1417 if (squid_curtime
- last_warning
> 60) {
1418 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1419 last_warning
= squid_curtime
;
1421 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1426 idnsGrokReply(rbuf
, len
, nsn
);
1431 idnsCheckQueue(void *)
1434 dlink_node
*p
= NULL
;
1439 /* name servers went away; reconfiguring or shutting down */
1442 for (n
= lru_list
.tail
; n
; n
= p
) {
1445 q
= static_cast<idns_query
*>(n
->data
);
1447 /* Anything to process in the queue? */
1448 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1451 /* Query timer still running? */
1452 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1453 dlinkDelete(&q
->lru
, &lru_list
);
1454 q
->queue_t
= current_time
;
1455 dlinkAdd(q
, &q
->lru
, &lru_list
);
1459 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1460 " QID 0x" << std::hex
<< std::setfill('0') <<
1461 std::setw(4) << q
->query_id
<< ": timeout" );
1463 dlinkDelete(&q
->lru
, &lru_list
);
1466 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1469 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1470 " QID 0x" << std::hex
<< q
->query_id
<<
1471 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1472 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1475 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1477 idnsCallback(q
, "Timeout");
1485 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1487 nsvc
* vc
= (nsvc
*)data
;
1489 if (flag
== Comm::ERR_CLOSING
)
1492 if (flag
!= Comm::OK
|| len
<= 0) {
1493 if (Comm::IsConnOpen(conn
))
1498 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1500 if (vc
->msg
->contentSize() < vc
->msglen
) {
1501 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1502 CommIoCbPtrFun(idnsReadVC
, vc
));
1503 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1507 assert(vc
->ns
< nns
);
1508 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1510 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1512 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1513 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1514 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1518 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1520 nsvc
* vc
= (nsvc
*)data
;
1522 if (flag
== Comm::ERR_CLOSING
)
1525 if (flag
!= Comm::OK
|| len
<= 0) {
1526 if (Comm::IsConnOpen(conn
))
1531 vc
->read_msglen
+= len
;
1533 assert(vc
->read_msglen
<= 2);
1535 if (vc
->read_msglen
< 2) {
1536 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1537 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1538 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1542 vc
->read_msglen
= 0;
1544 vc
->msglen
= ntohs(vc
->msglen
);
1547 if (Comm::IsConnOpen(conn
))
1552 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1553 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1554 CommIoCbPtrFun(idnsReadVC
, vc
));
1555 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1559 * rcode < 0 indicates an error, rocde >= 0 indicates success
1562 idnsRcodeCount(int rcode
, int attempt
)
1569 if (rcode
< MAX_RCODE
)
1570 if (attempt
< MAX_ATTEMPT
)
1571 ++ RcodeMatrix
[rcode
][attempt
];
1577 static int init
= 0;
1579 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1580 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1582 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1583 addrV6
= Config
.Addrs
.udp_outgoing
;
1585 addrV6
= Config
.Addrs
.udp_incoming
;
1587 Ip::Address addrV4
= addrV6
;
1590 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1591 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1592 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1599 if (addrV4
.isIPv4()) {
1600 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1601 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1608 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1609 fatal("Could not create a DNS socket");
1611 /* Ouch... we can't call functions using debug from a debug
1612 * statement. Doing so messes up the internal Debug::level
1614 if (DnsSocketB
>= 0) {
1615 comm_local_port(DnsSocketB
);
1616 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1617 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1619 if (DnsSocketA
>= 0) {
1620 comm_local_port(DnsSocketA
);
1621 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1622 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1627 idnsAddMDNSNameservers();
1628 bool nsFound
= idnsParseNameservers();
1631 nsFound
= idnsParseResolvConf();
1635 nsFound
= idnsParseWIN32Registry();
1639 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1641 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1643 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1646 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1648 idnsAddNameserver("::1");
1649 idnsAddNameserver("127.0.0.1");
1653 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1654 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1658 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1659 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1660 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1661 max_shared_edns
= -1; // disable if we might receive random replies.
1665 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1669 idnsShutdownAndFreeState(const char *reason
)
1671 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1674 debugs(78, 2, reason
<< ": Closing DNS sockets");
1676 if (DnsSocketA
>= 0 ) {
1677 comm_close(DnsSocketA
);
1681 if (DnsSocketB
>= 0 ) {
1682 comm_close(DnsSocketB
);
1686 for (int i
= 0; i
< nns
; ++i
) {
1687 if (nsvc
*vc
= nameservers
[i
].vc
) {
1688 if (Comm::IsConnOpen(vc
->conn
))
1693 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1694 idnsFreeNameservers();
1695 idnsFreeSearchpath();
1699 Dns::ConfigRr::endingShutdown()
1701 idnsShutdownAndFreeState("Shutdown");
1705 Dns::ConfigRr::startReconfigure()
1707 idnsShutdownAndFreeState("Reconfigure");
1711 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1713 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1718 idns_query
*q
= new idns_query
;
1719 // no query_id on this instance.
1721 q
->callback
= callback
;
1722 q
->callback_data
= cbdataReference(data
);
1724 q
->queue
= old
->queue
;
1731 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1733 q
->start_t
= current_time
;
1734 q
->callback
= callback
;
1735 q
->callback_data
= cbdataReference(data
);
1737 q
->hash
.key
= q
->orig
;
1738 hash_join(idns_lookup_hash
, &q
->hash
);
1744 idnsSendSlaveAAAAQuery(idns_query
*master
)
1746 idns_query
*q
= new idns_query
;
1747 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1748 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1750 q
->query_id
= idnsQueryID();
1751 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1753 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1754 ", id = 0x" << std::hex
<< q
->query_id
);
1760 q
->start_t
= master
->start_t
;
1761 q
->slave
= master
->slave
;
1769 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1771 size_t nameLength
= strlen(name
);
1773 // Prevent buffer overflow on q->name
1774 if (nameLength
> NS_MAXDNAME
) {
1775 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1776 callback(data
, NULL
, 0, "Internal error");
1780 if (idnsCachedLookup(name
, callback
, data
))
1783 idns_query
*q
= new idns_query
;
1784 q
->query_id
= idnsQueryID();
1787 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1791 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1792 q
->do_searchpath
= 1;
1794 q
->do_searchpath
= 0;
1797 strcpy(q
->orig
, name
);
1798 strcpy(q
->name
, q
->orig
);
1800 if (q
->do_searchpath
&& nd
< ndots
) {
1802 strcat(q
->name
, ".");
1803 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1804 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1807 // see EDNS notes at top of file why this sends 0
1808 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1811 /* problem with query data -- query not sent */
1812 callback(data
, NULL
, 0, "Internal error");
1817 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1818 ", id = 0x" << std::hex
<< q
->query_id
);
1821 idnsStartQuery(q
, callback
, data
);
1824 idnsSendSlaveAAAAQuery(q
);
1828 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1830 char ip
[MAX_IPSTRLEN
];
1832 addr
.toStr(ip
,MAX_IPSTRLEN
);
1834 idns_query
*q
= new idns_query
;
1835 q
->query_id
= idnsQueryID();
1837 if (addr
.isIPv6()) {
1838 struct in6_addr addr6
;
1839 addr
.getInAddr(addr6
);
1840 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1842 struct in_addr addr4
;
1843 addr
.getInAddr(addr4
);
1844 // see EDNS notes at top of file why this sends 0
1845 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1849 /* problem with query data -- query not sent */
1850 callback(data
, NULL
, 0, "Internal error");
1855 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1860 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1861 ", id = 0x" << std::hex
<< q
->query_id
);
1863 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1864 idnsStartQuery(q
, callback
, data
);
1869 * The function to return the DNS via SNMP
1872 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1875 variable_list
*Answer
= NULL
;
1877 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1878 *ErrP
= SNMP_ERR_NOERROR
;
1880 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1884 for (i
= 0; i
< nns
; ++i
)
1885 n
+= nameservers
[i
].nqueries
;
1887 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1894 for (i
= 0; i
< nns
; ++i
)
1895 n
+= nameservers
[i
].nreplies
;
1897 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1904 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1911 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1919 #endif /*SQUID_SNMP */