2 * Copyright (C) 1996-2015 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"
14 #include "comm/Connection.h"
15 #include "comm/ConnOpener.h"
16 #include "comm/Loops.h"
17 #include "comm/Read.h"
18 #include "comm/Write.h"
20 #include "dns/forward.h"
21 #include "dns/rfc3596.h"
27 #include "mgr/Registration.h"
28 #include "SquidConfig.h"
29 #include "SquidTime.h"
36 #include "snmp_core.h"
39 #if HAVE_ARPA_NAMESER_H
40 #include <arpa/nameser.h>
49 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
50 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
51 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
54 #define _PATH_RESCONF "/etc/resolv.conf"
56 #ifndef NS_DEFAULTPORT
57 #define NS_DEFAULTPORT 53
61 #define NS_MAXDNAME 1025
68 /* The buffer size required to store the maximum allowed search path */
70 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
73 #define IDNS_MAX_TRIES 20
76 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
77 // NP: see http://www.iana.org/assignments/dns-parameters
78 static const char *Rcodes
[] = {
81 "Packet Format Error",
83 "Non-Existent Domain",
87 "Name Exists when it should not",
88 "RR Set Exists when it should not",
89 "RR Set that should exist does not",
90 "Server Not Authoritative for zone",
91 "Name not contained in zone",
95 "Bad OPT Version or TSIG Signature Failure"
98 typedef struct _ns ns
;
100 typedef struct _sp sp
;
104 CBDATA_CLASS(idns_query
);
127 memset(&hash
, 0, sizeof(hash
));
128 memset(&query
, 0, sizeof(query
));
132 memset(&start_t
, 0, sizeof(start_t
));
133 memset(&sent_t
, 0, sizeof(sent_t
));
134 memset(&queue_t
, 0, sizeof(queue_t
));
139 rfc1035MessageDestroy(&message
);
142 // master is just a back-reference
143 cbdataReferenceDone(callback_data
);
148 char buf
[RESOLV_BUFSZ
];
149 char name
[NS_MAXDNAME
+ 1];
150 char orig
[NS_MAXDNAME
+ 1];
152 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
153 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
160 struct timeval start_t
;
161 struct timeval sent_t
;
162 struct timeval queue_t
;
169 idns_query
*slave
; // single linked list
170 idns_query
*master
; // single pointer to a shared master
171 unsigned short domain
;
172 unsigned short do_searchpath
;
173 rfc1035_message
*message
;
178 InstanceIdDefinitions(idns_query
, "dns");
180 CBDATA_CLASS_INIT(idns_query
);
187 explicit nsvc(int nsv
) : ns(nsv
), msglen(0), read_msglen(0), msg(new MemBuf()), queue(new MemBuf()), busy(true) {}
191 Comm::ConnectionPointer conn
;
192 unsigned short msglen
;
199 CBDATA_CLASS_INIT(nsvc
);
205 #if WHEN_EDNS_RESPONSES_ARE_PARSED
213 char domain
[NS_MAXDNAME
];
217 static ns
*nameservers
= NULL
;
218 static sp
*searchpath
= NULL
;
220 static int nns_alloc
= 0;
221 static int nns_mdns_count
= 0;
223 static int npc_alloc
= 0;
224 static int ndots
= 1;
225 static dlink_list lru_list
;
226 static int event_queued
= 0;
227 static hash_table
*idns_lookup_hash
= NULL
;
233 * EDNS as specified may be sent as an additional record for any request.
234 * early testing has revealed that it works on common devices, but cannot
235 * be reliably used on any A or PTR requet done for IPv4 addresses.
237 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
240 * Squid is optimized to generate one packet and re-send it to all NS
241 * due to this we cannot customize the EDNS size per NS.
243 * As such we take the configuration option value as fixed.
246 * This may not be worth doing, but if/when additional-records are parsed
247 * we will be able to recover the OPT value specific to any one NS and
248 * cache it. Effectively automating the tuning of EDNS advertised to the
249 * size our active NS are capable.
250 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
251 * Responses from the configured NS may cause this to be raised or turned off.
253 #if WHEN_EDNS_RESPONSES_ARE_PARSED
254 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
257 static OBJH idnsStats
;
258 static void idnsAddNameserver(const char *buf
);
259 static void idnsAddMDNSNameservers();
260 static void idnsAddPathComponent(const char *buf
);
261 static void idnsFreeNameservers(void);
262 static void idnsFreeSearchpath(void);
263 static bool idnsParseNameservers(void);
264 static bool idnsParseResolvConf(void);
266 static bool idnsParseWIN32Registry(void);
267 static void idnsParseWIN32SearchList(const char *);
269 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
270 static void idnsSendQuery(idns_query
* q
);
271 static IOCB idnsReadVCHeader
;
272 static void idnsDoSendQueryVC(nsvc
*vc
);
273 static CNCB idnsInitVCConnected
;
274 static IOCB idnsReadVC
;
275 static IOCB idnsSentQueryVC
;
277 static int idnsFromKnownNameserver(Ip::Address
const &from
);
278 static idns_query
*idnsFindQuery(unsigned short id
);
279 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
281 static EVH idnsCheckQueue
;
282 static void idnsTickleQueue(void);
283 static void idnsRcodeCount(int, int);
284 static CLCB idnsVCClosed
;
285 static unsigned short idnsQueryID(void);
286 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
289 idnsCheckMDNS(idns_query
*q
)
291 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
294 size_t slen
= strlen(q
->name
);
295 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
296 q
->permit_mdns
= true;
301 idnsAddMDNSNameservers()
306 if (!Config
.onoff
.dns_mdns
)
309 // mDNS resolver addresses are explicit multicast group IPs
310 if (Ip::EnableIpv6
) {
311 idnsAddNameserver("FF02::FB");
312 nameservers
[nns
-1].S
.port(5353);
313 nameservers
[nns
-1].mDNSResolver
= true;
317 idnsAddNameserver("224.0.0.251");
318 nameservers
[nns
-1].S
.port(5353);
319 nameservers
[nns
-1].mDNSResolver
= true;
325 idnsAddNameserver(const char *buf
)
330 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
335 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
337 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
340 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
341 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
345 if (nns
== nns_alloc
) {
346 int oldalloc
= nns_alloc
;
347 ns
*oldptr
= nameservers
;
354 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
356 if (oldptr
&& oldalloc
)
357 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
363 assert(nns
< nns_alloc
);
364 A
.port(NS_DEFAULTPORT
);
365 nameservers
[nns
].S
= A
;
366 #if WHEN_EDNS_RESPONSES_ARE_PARSED
367 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
368 // TODO generate a test packet to probe this NS from EDNS size and ability.
370 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
375 idnsAddPathComponent(const char *buf
)
377 if (npc
== npc_alloc
) {
378 int oldalloc
= npc_alloc
;
379 sp
*oldptr
= searchpath
;
386 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
388 if (oldptr
&& oldalloc
)
389 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
395 assert(npc
< npc_alloc
);
396 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
397 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
398 Tolower(searchpath
[npc
].domain
);
399 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
404 idnsFreeNameservers(void)
406 safe_free(nameservers
);
411 idnsFreeSearchpath(void)
413 safe_free(searchpath
);
418 idnsParseNameservers(void)
421 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
422 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
423 idnsAddNameserver(w
->key
);
430 idnsParseResolvConf(void)
434 FILE *fp
= fopen(_PATH_RESCONF
, "r");
437 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
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: Dns::Shutdown 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 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
965 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
970 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
974 assert(q
->lru
.next
== NULL
);
976 assert(q
->lru
.prev
== NULL
);
982 // only use mDNS resolvers for mDNS compatible queries
984 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
986 nsn
= q
->nsends
% nns
;
989 idnsSendQueryVC(q
, nsn
);
992 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
993 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
994 else if (DnsSocketA
>= 0)
995 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
1000 q
->sent_t
= current_time
;
1002 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
1003 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
1004 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
1005 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
1007 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
1010 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
1013 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
1016 ++ nameservers
[nsn
].nqueries
;
1017 q
->queue_t
= current_time
;
1018 dlinkAdd(q
, &q
->lru
, &lru_list
);
1024 idnsFromKnownNameserver(Ip::Address
const &from
)
1028 for (i
= 0; i
< nns
; ++i
) {
1029 if (nameservers
[i
].S
!= from
)
1032 if (nameservers
[i
].S
.port() != from
.port())
1042 idnsFindQuery(unsigned short id
)
1047 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1048 q
= (idns_query
*)n
->data
;
1050 if (q
->query_id
== id
)
1057 static unsigned short
1060 // NP: apparently ranlux are faster, but not quite as "proven"
1061 static std::mt19937
mt(static_cast<uint32_t>(getCurrentTime() & 0xFFFFFFFF));
1062 unsigned short id
= mt() & 0xFFFF;
1063 unsigned short first_id
= id
;
1065 // ensure temporal uniqueness by looking for an existing use
1066 while (idnsFindQuery(id
)) {
1069 if (id
== first_id
) {
1070 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1079 idnsCallback(idns_query
*q
, const char *error
)
1090 // If any of our subqueries are still pending then wait for them to complete before continuing
1091 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1098 rfc1035_message
*message
= q
->message
;
1103 while ( idns_query
*q2
= q
->slave
) {
1104 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1105 q
->slave
= q2
->slave
;
1109 // two sets of RR need merging
1110 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1111 if (Config
.dns
.v4_first
) {
1112 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1113 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1115 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1116 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1119 // HACK WARNING, the answer rr:s have been copied in-place to
1120 // result, do not free them here
1121 safe_free(message
->answer
);
1122 safe_free(q2
->message
->answer
);
1123 message
->answer
= result
;
1124 message
->ancount
+= q2
->message
->ancount
;
1126 // first response empty or failed, just use the second
1127 rfc1035MessageDestroy(&message
);
1128 message
= q2
->message
;
1137 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1139 callback
= q
->callback
;
1141 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1143 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1144 callback(cbdata
, answers
, n
, error
);
1147 idns_query
*q2
= q
->queue
;
1148 q
->queue
= q2
->queue
;
1151 callback
= q2
->callback
;
1152 q2
->callback
= NULL
;
1154 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1155 callback(cbdata
, answers
, n
, error
);
1161 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1165 rfc1035MessageDestroy(&message
);
1170 idnsGrokReply(const char *buf
, size_t sz
, int /*from_ns*/)
1172 rfc1035_message
*message
= NULL
;
1174 int n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1176 if (message
== NULL
) {
1177 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1181 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1183 idns_query
*q
= idnsFindQuery(message
->id
);
1186 debugs(78, 3, "idnsGrokReply: Late response");
1187 rfc1035MessageDestroy(&message
);
1191 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1192 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1193 rfc1035MessageDestroy(&message
);
1197 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1198 // TODO: actually gr the message right here.
1199 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1200 // this is overall better than force-feeding A response with AAAA an section later anyway.
1201 // AND allows us to merge AN+AR sections from both responses (one day)
1203 if (q
->edns_seen
>= 0) {
1204 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1205 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1206 // the altered NS was limiting the whole group.
1207 max_shared_edns
= q
->edns_seen
;
1208 // may be limited by one of the others still
1209 for (int i
= 0; i
< nns
; ++i
)
1210 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1212 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1213 // maybe reduce the global limit downwards to accomodate this NS
1214 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1216 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1217 max_shared_edns
= -1;
1221 dlinkDelete(&q
->lru
, &lru_list
);
1225 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1226 rfc1035MessageDestroy(&message
);
1233 // Strange: A TCP DNS response with the truncation bit (TC) set.
1234 // Return an error and cleanup; no point in trying TCP again.
1235 debugs(78, 3, HERE
<< "TCP DNS response");
1236 idnsCallback(q
, "Truncated TCP DNS response");
1242 idnsRcodeCount(n
, q
->attempt
);
1246 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1248 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1250 * RCODE 2 is "Server failure - The name server was
1251 * unable to process this query due to a problem with
1254 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1255 rfc1035MessageDestroy(&message
);
1260 // Do searchpath processing on the master A query only to keep
1261 // things simple. NXDOMAIN is authorative for the label, not
1263 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1264 assert(NULL
== message
->answer
);
1265 strcpy(q
->name
, q
->orig
);
1267 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1269 if (q
->domain
< npc
) {
1270 strcat(q
->name
, ".");
1271 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1272 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1278 rfc1035MessageDestroy(&message
);
1280 // cleanup slave AAAA query
1281 while (idns_query
*slave
= q
->slave
) {
1282 dlinkDelete(&slave
->lru
, &lru_list
);
1283 q
->slave
= slave
->slave
;
1284 slave
->slave
= NULL
;
1289 q
->query_id
= idnsQueryID();
1290 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1291 // see EDNS notes at top of file why this sends 0
1292 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1294 /* problem with query data -- query not sent */
1295 idnsCallback(q
, "Internal error");
1304 idnsSendSlaveAAAAQuery(q
);
1309 q
->message
= message
;
1313 idnsCallback(q
, NULL
);
1315 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1320 idnsRead(int fd
, void *)
1322 int *N
= &incoming_sockets_accepted
;
1324 int max
= INCOMING_DNS_MAX
;
1325 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1328 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1330 // Always keep reading. This stops (or at least makes harder) several
1331 // attacks on the DNS client.
1332 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1335 * two code lines after returning from comm_udprecvfrom()
1336 * something overwrites the memory behind the from parameter.
1337 * NO matter where in the stack declaration list above it is placed
1338 * The cause of this is still unknown, however copying the data appears
1339 * to allow it to be passed further without this erasure.
1341 Ip::Address bugbypass
;
1345 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1347 from
= bugbypass
; // BUG BYPASS. see notes above.
1353 if (ignoreErrno(errno
))
1357 /* Some Linux systems seem to set the FD for reading and then
1358 * return ECONNREFUSED when sendto() fails and generates an ICMP
1359 * port unreachable message. */
1360 /* or maybe an EHOSTUNREACH "No route to host" message */
1361 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1364 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1369 fd_bytes(fd
, len
, FD_READ
);
1374 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1376 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1377 int nsn
= idnsFromKnownNameserver(from
);
1380 ++ nameservers
[nsn
].nreplies
;
1383 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1384 // but after the ++ above to keep statistics right.
1386 continue; // Don't process replies if there is no pending query.
1388 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1389 static time_t last_warning
= 0;
1391 if (squid_curtime
- last_warning
> 60) {
1392 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1393 last_warning
= squid_curtime
;
1395 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1400 idnsGrokReply(rbuf
, len
, nsn
);
1405 idnsCheckQueue(void *)
1408 dlink_node
*p
= NULL
;
1413 /* name servers went away; reconfiguring or shutting down */
1416 for (n
= lru_list
.tail
; n
; n
= p
) {
1419 q
= static_cast<idns_query
*>(n
->data
);
1421 /* Anything to process in the queue? */
1422 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1425 /* Query timer still running? */
1426 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1427 dlinkDelete(&q
->lru
, &lru_list
);
1428 q
->queue_t
= current_time
;
1429 dlinkAdd(q
, &q
->lru
, &lru_list
);
1433 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1434 " QID 0x" << std::hex
<< std::setfill('0') <<
1435 std::setw(4) << q
->query_id
<< ": timeout" );
1437 dlinkDelete(&q
->lru
, &lru_list
);
1440 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1443 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1444 " QID 0x" << std::hex
<< q
->query_id
<<
1445 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1446 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1449 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1451 idnsCallback(q
, "Timeout");
1459 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1461 nsvc
* vc
= (nsvc
*)data
;
1463 if (flag
== Comm::ERR_CLOSING
)
1466 if (flag
!= Comm::OK
|| len
<= 0) {
1467 if (Comm::IsConnOpen(conn
))
1472 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1474 if (vc
->msg
->contentSize() < vc
->msglen
) {
1475 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1476 CommIoCbPtrFun(idnsReadVC
, vc
));
1477 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1481 assert(vc
->ns
< nns
);
1482 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1484 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1486 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1487 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1488 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1492 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1494 nsvc
* vc
= (nsvc
*)data
;
1496 if (flag
== Comm::ERR_CLOSING
)
1499 if (flag
!= Comm::OK
|| len
<= 0) {
1500 if (Comm::IsConnOpen(conn
))
1505 vc
->read_msglen
+= len
;
1507 assert(vc
->read_msglen
<= 2);
1509 if (vc
->read_msglen
< 2) {
1510 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1511 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1512 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1516 vc
->read_msglen
= 0;
1518 vc
->msglen
= ntohs(vc
->msglen
);
1521 if (Comm::IsConnOpen(conn
))
1526 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1527 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1528 CommIoCbPtrFun(idnsReadVC
, vc
));
1529 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1533 * rcode < 0 indicates an error, rocde >= 0 indicates success
1536 idnsRcodeCount(int rcode
, int attempt
)
1543 if (rcode
< MAX_RCODE
)
1544 if (attempt
< MAX_ATTEMPT
)
1545 ++ RcodeMatrix
[rcode
][attempt
];
1551 static int init
= 0;
1553 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1554 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1556 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1557 addrV6
= Config
.Addrs
.udp_outgoing
;
1559 addrV6
= Config
.Addrs
.udp_incoming
;
1561 Ip::Address addrV4
= addrV6
;
1564 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1565 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1566 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1573 if (addrV4
.isIPv4()) {
1574 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1575 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1582 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1583 fatal("Could not create a DNS socket");
1585 /* Ouch... we can't call functions using debug from a debug
1586 * statement. Doing so messes up the internal Debug::level
1588 if (DnsSocketB
>= 0) {
1589 comm_local_port(DnsSocketB
);
1590 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1591 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1593 if (DnsSocketA
>= 0) {
1594 comm_local_port(DnsSocketA
);
1595 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1596 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1601 idnsAddMDNSNameservers();
1602 bool nsFound
= idnsParseNameservers();
1605 nsFound
= idnsParseResolvConf();
1609 nsFound
= idnsParseWIN32Registry();
1613 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1615 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1617 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1620 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1622 idnsAddNameserver("::1");
1623 idnsAddNameserver("127.0.0.1");
1627 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1628 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1629 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1633 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1634 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1635 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1636 max_shared_edns
= -1; // disable if we might receive random replies.
1640 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1646 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1649 if (DnsSocketA
>= 0 ) {
1650 comm_close(DnsSocketA
);
1654 if (DnsSocketB
>= 0 ) {
1655 comm_close(DnsSocketB
);
1659 for (int i
= 0; i
< nns
; ++i
) {
1660 if (nsvc
*vc
= nameservers
[i
].vc
) {
1661 if (Comm::IsConnOpen(vc
->conn
))
1666 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1667 idnsFreeNameservers();
1668 idnsFreeSearchpath();
1672 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1674 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1679 idns_query
*q
= new idns_query
;
1680 // no query_id on this instance.
1682 q
->callback
= callback
;
1683 q
->callback_data
= cbdataReference(data
);
1685 q
->queue
= old
->queue
;
1692 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1694 q
->start_t
= current_time
;
1695 q
->callback
= callback
;
1696 q
->callback_data
= cbdataReference(data
);
1698 q
->hash
.key
= q
->orig
;
1699 hash_join(idns_lookup_hash
, &q
->hash
);
1705 idnsSendSlaveAAAAQuery(idns_query
*master
)
1707 idns_query
*q
= new idns_query
;
1708 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1709 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1711 q
->query_id
= idnsQueryID();
1712 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1714 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1715 ", id = 0x" << std::hex
<< q
->query_id
);
1721 q
->start_t
= master
->start_t
;
1722 q
->slave
= master
->slave
;
1730 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1732 size_t nameLength
= strlen(name
);
1734 // Prevent buffer overflow on q->name
1735 if (nameLength
> NS_MAXDNAME
) {
1736 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1737 callback(data
, NULL
, 0, "Internal error");
1741 if (idnsCachedLookup(name
, callback
, data
))
1744 idns_query
*q
= new idns_query
;
1745 q
->query_id
= idnsQueryID();
1748 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1752 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1753 q
->do_searchpath
= 1;
1755 q
->do_searchpath
= 0;
1758 strcpy(q
->orig
, name
);
1759 strcpy(q
->name
, q
->orig
);
1761 if (q
->do_searchpath
&& nd
< ndots
) {
1763 strcat(q
->name
, ".");
1764 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1765 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1768 // see EDNS notes at top of file why this sends 0
1769 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1772 /* problem with query data -- query not sent */
1773 callback(data
, NULL
, 0, "Internal error");
1778 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1779 ", id = 0x" << std::hex
<< q
->query_id
);
1782 idnsStartQuery(q
, callback
, data
);
1785 idnsSendSlaveAAAAQuery(q
);
1789 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1791 char ip
[MAX_IPSTRLEN
];
1793 addr
.toStr(ip
,MAX_IPSTRLEN
);
1795 idns_query
*q
= new idns_query
;
1796 q
->query_id
= idnsQueryID();
1798 if (addr
.isIPv6()) {
1799 struct in6_addr addr6
;
1800 addr
.getInAddr(addr6
);
1801 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1803 struct in_addr addr4
;
1804 addr
.getInAddr(addr4
);
1805 // see EDNS notes at top of file why this sends 0
1806 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1810 /* problem with query data -- query not sent */
1811 callback(data
, NULL
, 0, "Internal error");
1816 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1821 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1822 ", id = 0x" << std::hex
<< q
->query_id
);
1824 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1825 idnsStartQuery(q
, callback
, data
);
1830 * The function to return the DNS via SNMP
1833 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1836 variable_list
*Answer
= NULL
;
1838 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1839 *ErrP
= SNMP_ERR_NOERROR
;
1841 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1845 for (i
= 0; i
< nns
; ++i
)
1846 n
+= nameservers
[i
].nqueries
;
1848 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1855 for (i
= 0; i
< nns
; ++i
)
1856 n
+= nameservers
[i
].nreplies
;
1858 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1865 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1872 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1880 #endif /*SQUID_SNMP */