2 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
3 * AUTHOR: Duane Wessels
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "base/InstanceId.h"
36 #include "comm/Connection.h"
37 #include "comm/ConnOpener.h"
38 #include "comm/Loops.h"
39 #include "comm/Write.h"
47 #include "mgr/Registration.h"
49 #include "SquidConfig.h"
50 #include "SquidTime.h"
57 #include "snmp_core.h"
60 #if HAVE_ARPA_NAMESER_H
61 #include <arpa/nameser.h>
71 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
72 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
73 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
76 #define _PATH_RESCONF "/etc/resolv.conf"
78 #ifndef NS_DEFAULTPORT
79 #define NS_DEFAULTPORT 53
83 #define NS_MAXDNAME 1025
90 /* The buffer size required to store the maximum allowed search path */
92 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
95 #define IDNS_MAX_TRIES 20
98 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
99 // NP: see http://www.iana.org/assignments/dns-parameters
100 static const char *Rcodes
[] = {
103 "Packet Format Error",
104 "DNS Server Failure",
105 "Non-Existent Domain",
109 "Name Exists when it should not",
110 "RR Set Exists when it should not",
111 "RR Set that should exist does not",
112 "Server Not Authoritative for zone",
113 "Name not contained in zone",
117 "Bad OPT Version or TSIG Signature Failure"
120 typedef struct _idns_query idns_query
;
122 typedef struct _ns ns
;
124 typedef struct _sp sp
;
126 typedef struct _nsvc nsvc
;
131 char buf
[RESOLV_BUFSZ
];
132 char name
[NS_MAXDNAME
+ 1];
133 char orig
[NS_MAXDNAME
+ 1];
135 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
136 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
143 struct timeval start_t
;
144 struct timeval sent_t
;
145 struct timeval queue_t
;
152 idns_query
*slave
; // single linked list
153 idns_query
*master
; // single pointer to a shared master
154 unsigned short domain
;
155 unsigned short do_searchpath
;
156 rfc1035_message
*message
;
160 InstanceIdDefinitions(idns_query
, "dns");
164 Comm::ConnectionPointer conn
;
165 unsigned short msglen
;
176 #if WHEN_EDNS_RESPONSES_ARE_PARSED
184 char domain
[NS_MAXDNAME
];
189 CBDATA_TYPE(idns_query
);
191 static ns
*nameservers
= NULL
;
192 static sp
*searchpath
= NULL
;
194 static int nns_alloc
= 0;
195 static int nns_mdns_count
= 0;
197 static int npc_alloc
= 0;
198 static int ndots
= 1;
199 static dlink_list lru_list
;
200 static int event_queued
= 0;
201 static hash_table
*idns_lookup_hash
= NULL
;
207 * EDNS as specified may be sent as an additional record for any request.
208 * early testing has revealed that it works on common devices, but cannot
209 * be reliably used on any A or PTR requet done for IPv4 addresses.
211 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
214 * Squid is optimized to generate one packet and re-send it to all NS
215 * due to this we cannot customize the EDNS size per NS.
217 * As such we take the configuration option value as fixed.
220 * This may not be worth doing, but if/when additional-records are parsed
221 * we will be able to recover the OPT value specific to any one NS and
222 * cache it. Effectively automating the tuning of EDNS advertised to the
223 * size our active NS are capable.
224 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
225 * Responses from the configured NS may cause this to be raised or turned off.
227 #if WHEN_EDNS_RESPONSES_ARE_PARSED
228 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
231 static OBJH idnsStats
;
232 static void idnsAddNameserver(const char *buf
);
233 static void idnsAddMDNSNameservers();
234 static void idnsAddPathComponent(const char *buf
);
235 static void idnsFreeNameservers(void);
236 static void idnsFreeSearchpath(void);
237 static bool idnsParseNameservers(void);
239 static bool idnsParseResolvConf(void);
242 static bool idnsParseWIN32Registry(void);
243 static void idnsParseWIN32SearchList(const char *);
245 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
246 static void idnsSendQuery(idns_query
* q
);
247 static IOCB idnsReadVCHeader
;
248 static void idnsDoSendQueryVC(nsvc
*vc
);
249 static CNCB idnsInitVCConnected
;
250 static IOCB idnsReadVC
;
251 static IOCB idnsSentQueryVC
;
253 static int idnsFromKnownNameserver(Ip::Address
const &from
);
254 static idns_query
*idnsFindQuery(unsigned short id
);
255 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
257 static EVH idnsCheckQueue
;
258 static void idnsTickleQueue(void);
259 static void idnsRcodeCount(int, int);
260 static CLCB idnsVCClosed
;
261 static unsigned short idnsQueryID(void);
262 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
265 idnsCheckMDNS(idns_query
*q
)
267 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
270 size_t slen
= strlen(q
->name
);
271 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
272 q
->permit_mdns
= true;
277 idnsAddMDNSNameservers()
282 if (!Config
.onoff
.dns_mdns
)
285 // mDNS resolver addresses are explicit multicast group IPs
286 if (Ip::EnableIpv6
) {
287 idnsAddNameserver("FF02::FB");
288 nameservers
[nns
-1].S
.port(5353);
289 nameservers
[nns
-1].mDNSResolver
= true;
293 idnsAddNameserver("224.0.0.251");
294 nameservers
[nns
-1].S
.port(5353);
295 nameservers
[nns
-1].mDNSResolver
= true;
301 idnsAddNameserver(const char *buf
)
306 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
311 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
313 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
316 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
317 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
321 if (nns
== nns_alloc
) {
322 int oldalloc
= nns_alloc
;
323 ns
*oldptr
= nameservers
;
330 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
332 if (oldptr
&& oldalloc
)
333 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
339 assert(nns
< nns_alloc
);
340 A
.port(NS_DEFAULTPORT
);
341 nameservers
[nns
].S
= A
;
342 #if WHEN_EDNS_RESPONSES_ARE_PARSED
343 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
344 // TODO generate a test packet to probe this NS from EDNS size and ability.
346 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
351 idnsAddPathComponent(const char *buf
)
353 if (npc
== npc_alloc
) {
354 int oldalloc
= npc_alloc
;
355 sp
*oldptr
= searchpath
;
362 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
364 if (oldptr
&& oldalloc
)
365 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
371 assert(npc
< npc_alloc
);
372 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
373 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
374 Tolower(searchpath
[npc
].domain
);
375 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
380 idnsFreeNameservers(void)
382 safe_free(nameservers
);
387 idnsFreeSearchpath(void)
389 safe_free(searchpath
);
394 idnsParseNameservers(void)
397 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
398 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
399 idnsAddNameserver(w
->key
);
407 idnsParseResolvConf(void)
410 char buf
[RESOLV_BUFSZ
];
413 fp
= fopen(_PATH_RESCONF
, "r");
416 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
421 setmode(fileno(fp
), O_TEXT
);
424 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
425 t
= strtok(buf
, w_space
);
429 } else if (strcmp(t
, "nameserver") == 0) {
430 t
= strtok(NULL
, w_space
);
435 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
437 idnsAddNameserver(t
);
439 } else if (strcmp(t
, "domain") == 0) {
440 idnsFreeSearchpath();
441 t
= strtok(NULL
, w_space
);
446 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
448 idnsAddPathComponent(t
);
449 } else if (strcmp(t
, "search") == 0) {
450 idnsFreeSearchpath();
452 t
= strtok(NULL
, w_space
);
457 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
459 idnsAddPathComponent(t
);
461 } else if (strcmp(t
, "options") == 0) {
463 t
= strtok(NULL
, w_space
);
468 if (strncmp(t
, "ndots:", 6) == 0) {
474 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
479 if (npc
== 0 && (t
= getMyHostname())) {
482 idnsAddPathComponent(t
+1);
493 idnsParseWIN32SearchList(const char * Separator
)
499 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
503 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
505 if (Result
== ERROR_SUCCESS
&& Size
) {
506 t
= (char *) xmalloc(Size
);
507 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
508 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
509 idnsAddPathComponent(t
);
512 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
514 if (Result
== ERROR_SUCCESS
&& Size
) {
515 t
= (char *) xmalloc(Size
);
516 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
517 token
= strtok(t
, Separator
);
520 idnsAddPathComponent(token
);
521 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
522 token
= strtok(NULL
, Separator
);
529 if (npc
== 0 && (t
= (char *) getMyHostname())) {
532 idnsAddPathComponent(t
+ 1);
537 idnsParseWIN32Registry(void)
541 HKEY hndKey
, hndKey2
;
544 switch (WIN32_OS_version
) {
547 /* get nameservers from the Windows NT registry */
549 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
553 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
555 if (Result
== ERROR_SUCCESS
&& Size
) {
556 t
= (char *) xmalloc(Size
);
557 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
558 token
= strtok(t
, ", ");
561 idnsAddNameserver(token
);
563 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
564 token
= strtok(NULL
, ",");
569 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
571 if (Result
== ERROR_SUCCESS
&& Size
) {
572 t
= (char *) xmalloc(Size
);
573 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
574 token
= strtok(t
, ", ");
577 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
578 idnsAddNameserver(token
);
580 token
= strtok(NULL
, ", ");
588 idnsParseWIN32SearchList(" ");
601 /* get nameservers from the Windows 2000 registry */
602 /* search all interfaces for DNS server addresses */
604 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
606 DWORD MaxSubkeyLen
, InterfacesCount
;
608 FILETIME ftLastWriteTime
;
610 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
611 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
612 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
615 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
617 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
618 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
619 strcat(newkeyname
, "\\");
620 strcat(newkeyname
, keyname
);
621 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
625 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
626 if (Result
== ERROR_SUCCESS
&& Size
) {
627 t
= (char *) xmalloc(Size
);
628 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
629 token
= strtok(t
, ", ");
631 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
632 idnsAddNameserver(token
);
634 token
= strtok(NULL
, ", ");
639 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
640 if (Result
== ERROR_SUCCESS
&& Size
) {
641 t
= (char *) xmalloc(Size
);
642 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
643 token
= strtok(t
, ", ");
645 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
646 idnsAddNameserver(token
);
648 token
= strtok(NULL
, ", ");
654 RegCloseKey(hndKey2
);
667 idnsParseWIN32SearchList(", ");
676 /* get nameservers from the Windows 9X registry */
678 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
682 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
684 if (Result
== ERROR_SUCCESS
&& Size
) {
685 t
= (char *) xmalloc(Size
);
686 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
687 token
= strtok(t
, ", ");
690 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
691 idnsAddNameserver(token
);
693 token
= strtok(NULL
, ", ");
704 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
713 idnsStats(StoreEntry
* sentry
)
719 char buf
[MAX_IPSTRLEN
];
720 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
721 storeAppendPrintf(sentry
, "\nThe Queue:\n");
722 storeAppendPrintf(sentry
, " DELAY SINCE\n");
723 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
724 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
726 for (n
= lru_list
.head
; n
; n
= n
->next
) {
727 q
= (idns_query
*)n
->data
;
728 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
729 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
730 tvSubDsec(q
->start_t
, current_time
),
731 tvSubDsec(q
->sent_t
, current_time
),
732 (q
->permit_mdns
? 'M':' '),
736 if (Config
.dns
.packet_max
> 0)
737 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
739 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
741 storeAppendPrintf(sentry
, "\nNameservers:\n");
742 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
743 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
745 for (i
= 0; i
< nns
; ++i
) {
746 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
747 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
748 nameservers
[i
].nqueries
,
749 nameservers
[i
].nreplies
,
750 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
753 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
754 storeAppendPrintf(sentry
, "RCODE");
756 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
757 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
759 storeAppendPrintf(sentry
, " PROBLEM\n");
761 for (j
= 0; j
< MAX_RCODE
; ++j
) {
762 if (j
> 10 && j
< 16)
763 continue; // unassigned by IANA.
765 storeAppendPrintf(sentry
, "%5d", j
);
767 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
768 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
770 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
774 storeAppendPrintf(sentry
, "\nSearch list:\n");
776 for (i
=0; i
< npc
; ++i
)
777 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
779 storeAppendPrintf(sentry
, "\n");
784 idnsTickleQueue(void)
789 if (NULL
== lru_list
.tail
)
792 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
794 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
800 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
802 nsvc
* vc
= (nsvc
*)data
;
804 if (flag
== COMM_ERR_CLOSING
)
807 // XXX: irrelevant now that we have conn pointer?
808 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
811 if (flag
!= COMM_OK
|| size
<= 0) {
817 idnsDoSendQueryVC(vc
);
821 idnsDoSendQueryVC(nsvc
*vc
)
826 if (vc
->queue
->contentSize() == 0)
829 // if retrying after a TC UDP response, our close handler cb may be pending
830 if (fd_table
[vc
->conn
->fd
].closing())
833 MemBuf
*mb
= vc
->queue
;
835 vc
->queue
= new MemBuf
;
839 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
840 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
841 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
842 AsyncCall::Pointer nil
;
844 commSetConnTimeout(vc
->conn
, timeout
, nil
);
846 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
847 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
848 Comm::Write(vc
->conn
, mb
, call
);
854 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
856 nsvc
* vc
= (nsvc
*)data
;
858 if (status
!= COMM_OK
|| !conn
) {
859 char buf
[MAX_IPSTRLEN
] = "";
861 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
862 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
868 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
869 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
870 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
871 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
873 idnsDoSendQueryVC(vc
);
877 idnsVCClosed(const CommCloseCbParams
¶ms
)
879 nsvc
* vc
= (nsvc
*)params
.data
;
883 if (vc
->ns
< nns
) // XXX: dnsShutdown may have freed nameservers[]
884 nameservers
[vc
->ns
].vc
= NULL
;
891 nsvc
*vc
= cbdataAlloc(nsvc
);
893 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
894 nameservers
[nsv
].vc
= vc
;
896 vc
->queue
= new MemBuf
;
897 vc
->msg
= new MemBuf
;
900 Comm::ConnectionPointer conn
= new Comm::Connection();
902 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
903 conn
->local
= Config
.Addrs
.udp_outgoing
;
905 conn
->local
= Config
.Addrs
.udp_incoming
;
907 conn
->remote
= nameservers
[nsv
].S
;
909 if (conn
->remote
.isIPv4()) {
910 conn
->local
.setIPv4();
913 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
915 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
916 cs
->setHost("DNS TCP Socket");
921 idnsSendQueryVC(idns_query
* q
, int nsn
)
924 if (nameservers
[nsn
].vc
== NULL
)
927 nsvc
*vc
= nameservers
[nsn
].vc
;
930 char buf
[MAX_IPSTRLEN
];
931 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
938 short head
= htons(q
->sz
);
940 vc
->queue
->append((char *)&head
, 2);
942 vc
->queue
->append(q
->buf
, q
->sz
);
944 idnsDoSendQueryVC(vc
);
948 idnsSendQuery(idns_query
* q
)
950 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
951 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
956 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
960 assert(q
->lru
.next
== NULL
);
962 assert(q
->lru
.prev
== NULL
);
968 // only use mDNS resolvers for mDNS compatible queries
970 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
972 nsn
= q
->nsends
% nns
;
975 idnsSendQueryVC(q
, nsn
);
978 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
979 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
980 else if (DnsSocketA
>= 0)
981 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
986 q
->sent_t
= current_time
;
988 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
989 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
990 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
991 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
993 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
996 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
999 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
1002 ++ nameservers
[nsn
].nqueries
;
1003 q
->queue_t
= current_time
;
1004 dlinkAdd(q
, &q
->lru
, &lru_list
);
1010 idnsFromKnownNameserver(Ip::Address
const &from
)
1014 for (i
= 0; i
< nns
; ++i
) {
1015 if (nameservers
[i
].S
!= from
)
1018 if (nameservers
[i
].S
.port() != from
.port())
1028 idnsFindQuery(unsigned short id
)
1033 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1034 q
= (idns_query
*)n
->data
;
1036 if (q
->query_id
== id
)
1043 static unsigned short
1046 unsigned short id
= squid_random() & 0xFFFF;
1047 unsigned short first_id
= id
;
1049 while (idnsFindQuery(id
)) {
1052 if (id
== first_id
) {
1053 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1062 idnsCallback(idns_query
*q
, const char *error
)
1073 // If any of our subqueries are still pending then wait for them to complete before continuing
1074 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1081 rfc1035_message
*message
= q
->message
;
1086 while ( idns_query
*q2
= q
->slave
) {
1087 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1088 q
->slave
= q2
->slave
;
1091 // two sets of RR need merging
1092 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1093 if (Config
.dns
.v4_first
) {
1094 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1095 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1097 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1098 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1101 // HACK WARNING, the answer rr:s have been copied in-place to
1102 // result, do not free them here
1103 safe_free(message
->answer
);
1104 safe_free(q2
->message
->answer
);
1105 message
->answer
= result
;
1106 message
->ancount
+= q2
->message
->ancount
;
1108 // first response empty or failed, just use the second
1109 rfc1035MessageDestroy(&message
);
1110 message
= q2
->message
;
1116 rfc1035MessageDestroy(&q2
->message
);
1120 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1122 callback
= q
->callback
;
1124 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1126 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1127 callback(cbdata
, answers
, n
, error
);
1130 idns_query
*q2
= q
->queue
;
1131 q
->queue
= q2
->queue
;
1132 callback
= q2
->callback
;
1133 q2
->callback
= NULL
;
1135 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1136 callback(cbdata
, answers
, n
, error
);
1142 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1146 rfc1035MessageDestroy(&message
);
1151 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1154 rfc1035_message
*message
= NULL
;
1157 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1159 if (message
== NULL
) {
1160 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1164 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1166 q
= idnsFindQuery(message
->id
);
1169 debugs(78, 3, "idnsGrokReply: Late response");
1170 rfc1035MessageDestroy(&message
);
1174 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1175 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1176 rfc1035MessageDestroy(&message
);
1180 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1181 // TODO: actually gr the message right here.
1182 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1183 // this is overall better than force-feeding A response with AAAA an section later anyway.
1184 // AND allows us to merge AN+AR sections from both responses (one day)
1186 if (q
->edns_seen
>= 0) {
1187 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1188 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1189 // the altered NS was limiting the whole group.
1190 max_shared_edns
= q
->edns_seen
;
1191 // may be limited by one of the others still
1192 for (int i
= 0; i
< nns
; ++i
)
1193 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1195 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1196 // maybe reduce the global limit downwards to accomodate this NS
1197 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1199 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1200 max_shared_edns
= -1;
1204 dlinkDelete(&q
->lru
, &lru_list
);
1208 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1209 rfc1035MessageDestroy(&message
);
1216 // Strange: A TCP DNS response with the truncation bit (TC) set.
1217 // Return an error and cleanup; no point in trying TCP again.
1218 debugs(78, 3, HERE
<< "TCP DNS response");
1219 idnsCallback(q
, "Truncated TCP DNS response");
1225 idnsRcodeCount(n
, q
->attempt
);
1229 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1231 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1233 * RCODE 2 is "Server failure - The name server was
1234 * unable to process this query due to a problem with
1237 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1238 rfc1035MessageDestroy(&message
);
1243 // Do searchpath processing on the master A query only to keep
1244 // things simple. NXDOMAIN is authorative for the label, not
1246 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1247 assert(NULL
== message
->answer
);
1248 strcpy(q
->name
, q
->orig
);
1250 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1252 if (q
->domain
< npc
) {
1253 strcat(q
->name
, ".");
1254 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1255 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1261 rfc1035MessageDestroy(&message
);
1263 // cleanup slave AAAA query
1264 while (idns_query
*slave
= q
->slave
) {
1265 dlinkDelete(&slave
->lru
, &lru_list
);
1266 q
->slave
= slave
->slave
;
1267 rfc1035MessageDestroy(&slave
->message
);
1272 q
->query_id
= idnsQueryID();
1273 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1274 // see EDNS notes at top of file why this sends 0
1275 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1277 /* problem with query data -- query not sent */
1278 idnsCallback(q
, "Internal error");
1287 idnsSendSlaveAAAAQuery(q
);
1292 q
->message
= message
;
1296 idnsCallback(q
, NULL
);
1298 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1303 idnsRead(int fd
, void *data
)
1305 int *N
= &incoming_sockets_accepted
;
1307 int max
= INCOMING_DNS_MAX
;
1308 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1311 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1313 // Always keep reading. This stops (or at least makes harder) several
1314 // attacks on the DNS client.
1315 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1318 * two code lines after returning from comm_udprecvfrom()
1319 * something overwrites the memory behind the from parameter.
1320 * NO matter where in the stack declaration list above it is placed
1321 * The cause of this is still unknown, however copying the data appears
1322 * to allow it to be passed further without this erasure.
1324 Ip::Address bugbypass
;
1328 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1330 from
= bugbypass
; // BUG BYPASS. see notes above.
1336 if (ignoreErrno(errno
))
1340 /* Some Linux systems seem to set the FD for reading and then
1341 * return ECONNREFUSED when sendto() fails and generates an ICMP
1342 * port unreachable message. */
1343 /* or maybe an EHOSTUNREACH "No route to host" message */
1344 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1347 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1352 fd_bytes(fd
, len
, FD_READ
);
1357 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1359 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1360 int nsn
= idnsFromKnownNameserver(from
);
1363 ++ nameservers
[nsn
].nreplies
;
1366 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1367 // but after the ++ above to keep statistics right.
1369 continue; // Don't process replies if there is no pending query.
1371 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1372 static time_t last_warning
= 0;
1374 if (squid_curtime
- last_warning
> 60) {
1375 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1376 last_warning
= squid_curtime
;
1378 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1383 idnsGrokReply(rbuf
, len
, nsn
);
1388 idnsCheckQueue(void *unused
)
1391 dlink_node
*p
= NULL
;
1396 /* name servers went away; reconfiguring or shutting down */
1399 for (n
= lru_list
.tail
; n
; n
= p
) {
1402 q
= static_cast<idns_query
*>(n
->data
);
1404 /* Anything to process in the queue? */
1405 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1408 /* Query timer still running? */
1409 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1410 dlinkDelete(&q
->lru
, &lru_list
);
1411 q
->queue_t
= current_time
;
1412 dlinkAdd(q
, &q
->lru
, &lru_list
);
1416 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1417 " QID 0x" << std::hex
<< std::setfill('0') <<
1418 std::setw(4) << q
->query_id
<< ": timeout" );
1420 dlinkDelete(&q
->lru
, &lru_list
);
1423 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1426 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1427 " QID 0x" << std::hex
<< q
->query_id
<<
1428 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1429 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1432 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1434 idnsCallback(q
, "Timeout");
1442 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1444 nsvc
* vc
= (nsvc
*)data
;
1446 if (flag
== COMM_ERR_CLOSING
)
1449 if (flag
!= COMM_OK
|| len
<= 0) {
1450 if (Comm::IsConnOpen(conn
))
1455 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1457 if (vc
->msg
->contentSize() < vc
->msglen
) {
1458 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1459 CommIoCbPtrFun(idnsReadVC
, vc
));
1460 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1464 assert(vc
->ns
< nns
);
1465 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1467 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1469 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1470 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1471 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1475 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1477 nsvc
* vc
= (nsvc
*)data
;
1479 if (flag
== COMM_ERR_CLOSING
)
1482 if (flag
!= COMM_OK
|| len
<= 0) {
1483 if (Comm::IsConnOpen(conn
))
1488 vc
->read_msglen
+= len
;
1490 assert(vc
->read_msglen
<= 2);
1492 if (vc
->read_msglen
< 2) {
1493 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1494 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1495 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1499 vc
->read_msglen
= 0;
1501 vc
->msglen
= ntohs(vc
->msglen
);
1503 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1504 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1505 CommIoCbPtrFun(idnsReadVC
, vc
));
1506 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1510 * rcode < 0 indicates an error, rocde >= 0 indicates success
1513 idnsRcodeCount(int rcode
, int attempt
)
1520 if (rcode
< MAX_RCODE
)
1521 if (attempt
< MAX_ATTEMPT
)
1522 ++ RcodeMatrix
[rcode
][attempt
];
1525 /* ====================================================================== */
1528 idnsRegisterWithCacheManager(void)
1530 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1536 static int init
= 0;
1538 CBDATA_INIT_TYPE(nsvc
);
1539 CBDATA_INIT_TYPE(idns_query
);
1541 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1542 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1544 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1545 addrV6
= Config
.Addrs
.udp_outgoing
;
1547 addrV6
= Config
.Addrs
.udp_incoming
;
1549 Ip::Address addrV4
= addrV6
;
1552 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1553 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1554 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1561 if (addrV4
.isIPv4()) {
1562 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1563 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1570 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1571 fatal("Could not create a DNS socket");
1573 /* Ouch... we can't call functions using debug from a debug
1574 * statement. Doing so messes up the internal Debug::level
1576 if (DnsSocketB
>= 0) {
1577 comm_local_port(DnsSocketB
);
1578 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1579 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1581 if (DnsSocketA
>= 0) {
1582 comm_local_port(DnsSocketA
);
1583 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1584 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1589 idnsAddMDNSNameservers();
1590 bool nsFound
= idnsParseNameservers();
1591 #if !_SQUID_WINDOWS_
1594 nsFound
= idnsParseResolvConf();
1599 nsFound
= idnsParseWIN32Registry();
1603 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1605 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1607 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1610 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1612 idnsAddNameserver("::1");
1613 idnsAddNameserver("127.0.0.1");
1617 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1618 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1619 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1623 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1624 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1625 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1626 max_shared_edns
= -1; // disable if we might receive random replies.
1630 idnsRegisterWithCacheManager();
1636 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1639 if (DnsSocketA
>= 0 ) {
1640 comm_close(DnsSocketA
);
1644 if (DnsSocketB
>= 0 ) {
1645 comm_close(DnsSocketB
);
1649 for (int i
= 0; i
< nns
; ++i
) {
1650 if (nsvc
*vc
= nameservers
[i
].vc
) {
1651 if (Comm::IsConnOpen(vc
->conn
))
1656 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1657 idnsFreeNameservers();
1658 idnsFreeSearchpath();
1662 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1666 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1671 q
= cbdataAlloc(idns_query
);
1672 // idns_query is POD so no constructors are called after allocation
1673 q
->xact_id
.change();
1674 // no query_id on this instance.
1676 q
->callback
= callback
;
1678 q
->callback_data
= cbdataReference(data
);
1680 q
->queue
= old
->queue
;
1688 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1690 q
->start_t
= current_time
;
1691 q
->callback
= callback
;
1692 q
->callback_data
= cbdataReference(data
);
1694 q
->hash
.key
= q
->orig
;
1695 hash_join(idns_lookup_hash
, &q
->hash
);
1701 idnsSendSlaveAAAAQuery(idns_query
*master
)
1703 idns_query
*q
= cbdataAlloc(idns_query
);
1704 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1705 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1707 q
->query_id
= idnsQueryID();
1708 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1709 q
->start_t
= master
->start_t
;
1710 q
->slave
= master
->slave
;
1712 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1713 ", id = 0x" << std::hex
<< q
->query_id
);
1724 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1726 size_t nameLength
= strlen(name
);
1728 // Prevent buffer overflow on q->name
1729 if (nameLength
> NS_MAXDNAME
) {
1730 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1731 callback(data
, NULL
, 0, "Internal error");
1735 if (idnsCachedLookup(name
, callback
, data
))
1738 idns_query
*q
= cbdataAlloc(idns_query
);
1739 // idns_query is POD so no constructors are called after allocation
1740 q
->xact_id
.change();
1741 q
->query_id
= idnsQueryID();
1744 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1748 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1749 q
->do_searchpath
= 1;
1751 q
->do_searchpath
= 0;
1754 strcpy(q
->orig
, name
);
1755 strcpy(q
->name
, q
->orig
);
1757 if (q
->do_searchpath
&& nd
< ndots
) {
1759 strcat(q
->name
, ".");
1760 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1761 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1764 // see EDNS notes at top of file why this sends 0
1765 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1768 /* problem with query data -- query not sent */
1769 callback(data
, NULL
, 0, "Internal error");
1774 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1775 ", id = 0x" << std::hex
<< q
->query_id
);
1778 idnsStartQuery(q
, callback
, data
);
1781 idnsSendSlaveAAAAQuery(q
);
1786 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1790 char ip
[MAX_IPSTRLEN
];
1792 addr
.toStr(ip
,MAX_IPSTRLEN
);
1794 q
= cbdataAlloc(idns_query
);
1796 // idns_query is POD so no constructors are called after allocation
1797 q
->xact_id
.change();
1798 q
->query_id
= idnsQueryID();
1800 if (addr
.isIPv6()) {
1801 struct in6_addr addr6
;
1802 addr
.getInAddr(addr6
);
1803 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1805 struct in_addr addr4
;
1806 addr
.getInAddr(addr4
);
1807 // see EDNS notes at top of file why this sends 0
1808 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1812 /* problem with query data -- query not sent */
1813 callback(data
, NULL
, 0, "Internal error");
1818 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1823 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1824 ", id = 0x" << std::hex
<< q
->query_id
);
1826 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1827 idnsStartQuery(q
, callback
, data
);
1832 * The function to return the DNS via SNMP
1835 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1838 variable_list
*Answer
= NULL
;
1840 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1841 *ErrP
= SNMP_ERR_NOERROR
;
1843 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1847 for (i
= 0; i
< nns
; ++i
)
1848 n
+= nameservers
[i
].nqueries
;
1850 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1857 for (i
= 0; i
< nns
; ++i
)
1858 n
+= nameservers
[i
].nreplies
;
1860 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1867 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1874 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1882 #endif /*SQUID_SNMP */