2 * Copyright (C) 1996-2014 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 lib/rfc1035.c */
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"
26 #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>
48 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
49 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
50 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
53 #define _PATH_RESCONF "/etc/resolv.conf"
55 #ifndef NS_DEFAULTPORT
56 #define NS_DEFAULTPORT 53
60 #define NS_MAXDNAME 1025
67 /* The buffer size required to store the maximum allowed search path */
69 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
72 #define IDNS_MAX_TRIES 20
75 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
76 // NP: see http://www.iana.org/assignments/dns-parameters
77 static const char *Rcodes
[] = {
80 "Packet Format Error",
82 "Non-Existent Domain",
86 "Name Exists when it should not",
87 "RR Set Exists when it should not",
88 "RR Set that should exist does not",
89 "Server Not Authoritative for zone",
90 "Name not contained in zone",
94 "Bad OPT Version or TSIG Signature Failure"
97 typedef struct _idns_query idns_query
;
99 typedef struct _ns ns
;
101 typedef struct _sp sp
;
103 typedef struct _nsvc nsvc
;
108 char buf
[RESOLV_BUFSZ
];
109 char name
[NS_MAXDNAME
+ 1];
110 char orig
[NS_MAXDNAME
+ 1];
112 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
113 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
120 struct timeval start_t
;
121 struct timeval sent_t
;
122 struct timeval queue_t
;
129 idns_query
*slave
; // single linked list
130 idns_query
*master
; // single pointer to a shared master
131 unsigned short domain
;
132 unsigned short do_searchpath
;
133 rfc1035_message
*message
;
137 InstanceIdDefinitions(idns_query
, "dns");
141 Comm::ConnectionPointer conn
;
142 unsigned short msglen
;
153 #if WHEN_EDNS_RESPONSES_ARE_PARSED
161 char domain
[NS_MAXDNAME
];
166 CBDATA_TYPE(idns_query
);
168 static ns
*nameservers
= NULL
;
169 static sp
*searchpath
= NULL
;
171 static int nns_alloc
= 0;
172 static int nns_mdns_count
= 0;
174 static int npc_alloc
= 0;
175 static int ndots
= 1;
176 static dlink_list lru_list
;
177 static int event_queued
= 0;
178 static hash_table
*idns_lookup_hash
= NULL
;
184 * EDNS as specified may be sent as an additional record for any request.
185 * early testing has revealed that it works on common devices, but cannot
186 * be reliably used on any A or PTR requet done for IPv4 addresses.
188 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
191 * Squid is optimized to generate one packet and re-send it to all NS
192 * due to this we cannot customize the EDNS size per NS.
194 * As such we take the configuration option value as fixed.
197 * This may not be worth doing, but if/when additional-records are parsed
198 * we will be able to recover the OPT value specific to any one NS and
199 * cache it. Effectively automating the tuning of EDNS advertised to the
200 * size our active NS are capable.
201 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
202 * Responses from the configured NS may cause this to be raised or turned off.
204 #if WHEN_EDNS_RESPONSES_ARE_PARSED
205 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
208 static OBJH idnsStats
;
209 static void idnsAddNameserver(const char *buf
);
210 static void idnsAddMDNSNameservers();
211 static void idnsAddPathComponent(const char *buf
);
212 static void idnsFreeNameservers(void);
213 static void idnsFreeSearchpath(void);
214 static bool idnsParseNameservers(void);
216 static bool idnsParseResolvConf(void);
219 static bool idnsParseWIN32Registry(void);
220 static void idnsParseWIN32SearchList(const char *);
222 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
223 static void idnsSendQuery(idns_query
* q
);
224 static IOCB idnsReadVCHeader
;
225 static void idnsDoSendQueryVC(nsvc
*vc
);
226 static CNCB idnsInitVCConnected
;
227 static IOCB idnsReadVC
;
228 static IOCB idnsSentQueryVC
;
230 static int idnsFromKnownNameserver(Ip::Address
const &from
);
231 static idns_query
*idnsFindQuery(unsigned short id
);
232 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
234 static EVH idnsCheckQueue
;
235 static void idnsTickleQueue(void);
236 static void idnsRcodeCount(int, int);
237 static CLCB idnsVCClosed
;
238 static unsigned short idnsQueryID(void);
239 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
242 idnsCheckMDNS(idns_query
*q
)
244 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
247 size_t slen
= strlen(q
->name
);
248 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
249 q
->permit_mdns
= true;
254 idnsAddMDNSNameservers()
259 if (!Config
.onoff
.dns_mdns
)
262 // mDNS resolver addresses are explicit multicast group IPs
263 if (Ip::EnableIpv6
) {
264 idnsAddNameserver("FF02::FB");
265 nameservers
[nns
-1].S
.port(5353);
266 nameservers
[nns
-1].mDNSResolver
= true;
270 idnsAddNameserver("224.0.0.251");
271 nameservers
[nns
-1].S
.port(5353);
272 nameservers
[nns
-1].mDNSResolver
= true;
278 idnsAddNameserver(const char *buf
)
283 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
288 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
290 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
293 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
294 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
298 if (nns
== nns_alloc
) {
299 int oldalloc
= nns_alloc
;
300 ns
*oldptr
= nameservers
;
307 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
309 if (oldptr
&& oldalloc
)
310 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
316 assert(nns
< nns_alloc
);
317 A
.port(NS_DEFAULTPORT
);
318 nameservers
[nns
].S
= A
;
319 #if WHEN_EDNS_RESPONSES_ARE_PARSED
320 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
321 // TODO generate a test packet to probe this NS from EDNS size and ability.
323 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
328 idnsAddPathComponent(const char *buf
)
330 if (npc
== npc_alloc
) {
331 int oldalloc
= npc_alloc
;
332 sp
*oldptr
= searchpath
;
339 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
341 if (oldptr
&& oldalloc
)
342 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
348 assert(npc
< npc_alloc
);
349 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
350 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
351 Tolower(searchpath
[npc
].domain
);
352 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
357 idnsFreeNameservers(void)
359 safe_free(nameservers
);
364 idnsFreeSearchpath(void)
366 safe_free(searchpath
);
371 idnsParseNameservers(void)
374 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
375 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
376 idnsAddNameserver(w
->key
);
384 idnsParseResolvConf(void)
387 char buf
[RESOLV_BUFSZ
];
390 fp
= fopen(_PATH_RESCONF
, "r");
393 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
398 setmode(fileno(fp
), O_TEXT
);
401 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
402 t
= strtok(buf
, w_space
);
406 } else if (strcmp(t
, "nameserver") == 0) {
407 t
= strtok(NULL
, w_space
);
412 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
414 idnsAddNameserver(t
);
416 } else if (strcmp(t
, "domain") == 0) {
417 idnsFreeSearchpath();
418 t
= strtok(NULL
, w_space
);
423 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
425 idnsAddPathComponent(t
);
426 } else if (strcmp(t
, "search") == 0) {
427 idnsFreeSearchpath();
429 t
= strtok(NULL
, w_space
);
434 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
436 idnsAddPathComponent(t
);
438 } else if (strcmp(t
, "options") == 0) {
440 t
= strtok(NULL
, w_space
);
445 if (strncmp(t
, "ndots:", 6) == 0) {
451 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
456 if (npc
== 0 && (t
= getMyHostname())) {
459 idnsAddPathComponent(t
+1);
470 idnsParseWIN32SearchList(const char * Separator
)
476 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
480 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
482 if (Result
== ERROR_SUCCESS
&& Size
) {
483 t
= (char *) xmalloc(Size
);
484 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
485 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
486 idnsAddPathComponent(t
);
489 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
491 if (Result
== ERROR_SUCCESS
&& Size
) {
492 t
= (char *) xmalloc(Size
);
493 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
494 token
= strtok(t
, Separator
);
497 idnsAddPathComponent(token
);
498 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
499 token
= strtok(NULL
, Separator
);
506 if (npc
== 0 && (t
= (char *) getMyHostname())) {
509 idnsAddPathComponent(t
+ 1);
514 idnsParseWIN32Registry(void)
518 HKEY hndKey
, hndKey2
;
521 switch (WIN32_OS_version
) {
524 /* get nameservers from the Windows NT registry */
526 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
530 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
532 if (Result
== ERROR_SUCCESS
&& Size
) {
533 t
= (char *) xmalloc(Size
);
534 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
535 token
= strtok(t
, ", ");
538 idnsAddNameserver(token
);
540 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
541 token
= strtok(NULL
, ",");
546 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
548 if (Result
== ERROR_SUCCESS
&& Size
) {
549 t
= (char *) xmalloc(Size
);
550 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
551 token
= strtok(t
, ", ");
554 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
555 idnsAddNameserver(token
);
557 token
= strtok(NULL
, ", ");
565 idnsParseWIN32SearchList(" ");
578 /* get nameservers from the Windows 2000 registry */
579 /* search all interfaces for DNS server addresses */
581 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
583 DWORD MaxSubkeyLen
, InterfacesCount
;
585 FILETIME ftLastWriteTime
;
587 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
588 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
589 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
592 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
594 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
595 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
596 strcat(newkeyname
, "\\");
597 strcat(newkeyname
, keyname
);
598 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
602 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
603 if (Result
== ERROR_SUCCESS
&& Size
) {
604 t
= (char *) xmalloc(Size
);
605 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
606 token
= strtok(t
, ", ");
608 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
609 idnsAddNameserver(token
);
611 token
= strtok(NULL
, ", ");
616 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
617 if (Result
== ERROR_SUCCESS
&& Size
) {
618 t
= (char *) xmalloc(Size
);
619 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
620 token
= strtok(t
, ", ");
622 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
623 idnsAddNameserver(token
);
625 token
= strtok(NULL
, ", ");
631 RegCloseKey(hndKey2
);
644 idnsParseWIN32SearchList(", ");
653 /* get nameservers from the Windows 9X registry */
655 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
659 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
661 if (Result
== ERROR_SUCCESS
&& Size
) {
662 t
= (char *) xmalloc(Size
);
663 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
664 token
= strtok(t
, ", ");
667 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
668 idnsAddNameserver(token
);
670 token
= strtok(NULL
, ", ");
681 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
690 idnsStats(StoreEntry
* sentry
)
696 char buf
[MAX_IPSTRLEN
];
697 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
698 storeAppendPrintf(sentry
, "\nThe Queue:\n");
699 storeAppendPrintf(sentry
, " DELAY SINCE\n");
700 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
701 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
703 for (n
= lru_list
.head
; n
; n
= n
->next
) {
704 q
= (idns_query
*)n
->data
;
705 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
706 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
707 tvSubDsec(q
->start_t
, current_time
),
708 tvSubDsec(q
->sent_t
, current_time
),
709 (q
->permit_mdns
? 'M':' '),
713 if (Config
.dns
.packet_max
> 0)
714 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
716 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
718 storeAppendPrintf(sentry
, "\nNameservers:\n");
719 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
720 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
722 for (i
= 0; i
< nns
; ++i
) {
723 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
724 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
725 nameservers
[i
].nqueries
,
726 nameservers
[i
].nreplies
,
727 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
730 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
731 storeAppendPrintf(sentry
, "RCODE");
733 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
734 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
736 storeAppendPrintf(sentry
, " PROBLEM\n");
738 for (j
= 0; j
< MAX_RCODE
; ++j
) {
739 if (j
> 10 && j
< 16)
740 continue; // unassigned by IANA.
742 storeAppendPrintf(sentry
, "%5d", j
);
744 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
745 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
747 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
751 storeAppendPrintf(sentry
, "\nSearch list:\n");
753 for (i
=0; i
< npc
; ++i
)
754 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
756 storeAppendPrintf(sentry
, "\n");
761 idnsTickleQueue(void)
766 if (NULL
== lru_list
.tail
)
769 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
771 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
777 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, Comm::Flag flag
, int xerrno
, void *data
)
779 nsvc
* vc
= (nsvc
*)data
;
781 if (flag
== Comm::ERR_CLOSING
)
784 // XXX: irrelevant now that we have conn pointer?
785 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
788 if (flag
!= Comm::OK
|| size
<= 0) {
794 idnsDoSendQueryVC(vc
);
798 idnsDoSendQueryVC(nsvc
*vc
)
803 if (vc
->queue
->contentSize() == 0)
806 // if retrying after a TC UDP response, our close handler cb may be pending
807 if (fd_table
[vc
->conn
->fd
].closing())
810 MemBuf
*mb
= vc
->queue
;
812 vc
->queue
= new MemBuf
;
816 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
817 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
818 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
819 AsyncCall::Pointer nil
;
821 commSetConnTimeout(vc
->conn
, timeout
, nil
);
823 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
824 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
825 Comm::Write(vc
->conn
, mb
, call
);
831 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int xerrno
, void *data
)
833 nsvc
* vc
= (nsvc
*)data
;
835 if (status
!= Comm::OK
|| !conn
) {
836 char buf
[MAX_IPSTRLEN
] = "";
838 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
839 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
845 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
846 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
847 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
848 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
850 idnsDoSendQueryVC(vc
);
854 idnsVCClosed(const CommCloseCbParams
¶ms
)
856 nsvc
* vc
= (nsvc
*)params
.data
;
860 if (vc
->ns
< nns
) // XXX: dnsShutdown may have freed nameservers[]
861 nameservers
[vc
->ns
].vc
= NULL
;
868 nsvc
*vc
= cbdataAlloc(nsvc
);
870 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
871 nameservers
[nsv
].vc
= vc
;
873 vc
->queue
= new MemBuf
;
874 vc
->msg
= new MemBuf
;
877 Comm::ConnectionPointer conn
= new Comm::Connection();
879 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
880 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
882 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
884 if (conn
->remote
.isIPv4())
885 conn
->local
.setIPv4();
887 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
889 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
890 cs
->setHost("DNS TCP Socket");
895 idnsSendQueryVC(idns_query
* q
, int nsn
)
898 if (nameservers
[nsn
].vc
== NULL
)
901 nsvc
*vc
= nameservers
[nsn
].vc
;
904 char buf
[MAX_IPSTRLEN
];
905 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
912 short head
= htons(q
->sz
);
914 vc
->queue
->append((char *)&head
, 2);
916 vc
->queue
->append(q
->buf
, q
->sz
);
918 idnsDoSendQueryVC(vc
);
922 idnsSendQuery(idns_query
* q
)
924 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
925 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
930 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
934 assert(q
->lru
.next
== NULL
);
936 assert(q
->lru
.prev
== NULL
);
942 // only use mDNS resolvers for mDNS compatible queries
944 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
946 nsn
= q
->nsends
% nns
;
949 idnsSendQueryVC(q
, nsn
);
952 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
953 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
954 else if (DnsSocketA
>= 0)
955 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
960 q
->sent_t
= current_time
;
962 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
963 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
964 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
965 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
967 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
970 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
973 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
976 ++ nameservers
[nsn
].nqueries
;
977 q
->queue_t
= current_time
;
978 dlinkAdd(q
, &q
->lru
, &lru_list
);
984 idnsFromKnownNameserver(Ip::Address
const &from
)
988 for (i
= 0; i
< nns
; ++i
) {
989 if (nameservers
[i
].S
!= from
)
992 if (nameservers
[i
].S
.port() != from
.port())
1002 idnsFindQuery(unsigned short id
)
1007 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1008 q
= (idns_query
*)n
->data
;
1010 if (q
->query_id
== id
)
1017 static unsigned short
1020 unsigned short id
= squid_random() & 0xFFFF;
1021 unsigned short first_id
= id
;
1023 while (idnsFindQuery(id
)) {
1026 if (id
== first_id
) {
1027 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1036 idnsCallback(idns_query
*q
, const char *error
)
1047 // If any of our subqueries are still pending then wait for them to complete before continuing
1048 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1055 rfc1035_message
*message
= q
->message
;
1060 while ( idns_query
*q2
= q
->slave
) {
1061 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1062 q
->slave
= q2
->slave
;
1065 // two sets of RR need merging
1066 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1067 if (Config
.dns
.v4_first
) {
1068 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1069 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1071 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1072 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1075 // HACK WARNING, the answer rr:s have been copied in-place to
1076 // result, do not free them here
1077 safe_free(message
->answer
);
1078 safe_free(q2
->message
->answer
);
1079 message
->answer
= result
;
1080 message
->ancount
+= q2
->message
->ancount
;
1082 // first response empty or failed, just use the second
1083 rfc1035MessageDestroy(&message
);
1084 message
= q2
->message
;
1090 rfc1035MessageDestroy(&q2
->message
);
1094 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1096 callback
= q
->callback
;
1098 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1100 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1101 callback(cbdata
, answers
, n
, error
);
1104 idns_query
*q2
= q
->queue
;
1105 q
->queue
= q2
->queue
;
1106 callback
= q2
->callback
;
1107 q2
->callback
= NULL
;
1109 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1110 callback(cbdata
, answers
, n
, error
);
1116 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1120 rfc1035MessageDestroy(&message
);
1125 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1128 rfc1035_message
*message
= NULL
;
1131 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1133 if (message
== NULL
) {
1134 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1138 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1140 q
= idnsFindQuery(message
->id
);
1143 debugs(78, 3, "idnsGrokReply: Late response");
1144 rfc1035MessageDestroy(&message
);
1148 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1149 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1150 rfc1035MessageDestroy(&message
);
1154 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1155 // TODO: actually gr the message right here.
1156 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1157 // this is overall better than force-feeding A response with AAAA an section later anyway.
1158 // AND allows us to merge AN+AR sections from both responses (one day)
1160 if (q
->edns_seen
>= 0) {
1161 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1162 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1163 // the altered NS was limiting the whole group.
1164 max_shared_edns
= q
->edns_seen
;
1165 // may be limited by one of the others still
1166 for (int i
= 0; i
< nns
; ++i
)
1167 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1169 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1170 // maybe reduce the global limit downwards to accomodate this NS
1171 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1173 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1174 max_shared_edns
= -1;
1178 dlinkDelete(&q
->lru
, &lru_list
);
1182 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1183 rfc1035MessageDestroy(&message
);
1190 // Strange: A TCP DNS response with the truncation bit (TC) set.
1191 // Return an error and cleanup; no point in trying TCP again.
1192 debugs(78, 3, HERE
<< "TCP DNS response");
1193 idnsCallback(q
, "Truncated TCP DNS response");
1199 idnsRcodeCount(n
, q
->attempt
);
1203 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1205 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1207 * RCODE 2 is "Server failure - The name server was
1208 * unable to process this query due to a problem with
1211 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1212 rfc1035MessageDestroy(&message
);
1217 // Do searchpath processing on the master A query only to keep
1218 // things simple. NXDOMAIN is authorative for the label, not
1220 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1221 assert(NULL
== message
->answer
);
1222 strcpy(q
->name
, q
->orig
);
1224 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1226 if (q
->domain
< npc
) {
1227 strcat(q
->name
, ".");
1228 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1229 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1235 rfc1035MessageDestroy(&message
);
1237 // cleanup slave AAAA query
1238 while (idns_query
*slave
= q
->slave
) {
1239 dlinkDelete(&slave
->lru
, &lru_list
);
1240 q
->slave
= slave
->slave
;
1241 rfc1035MessageDestroy(&slave
->message
);
1246 q
->query_id
= idnsQueryID();
1247 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1248 // see EDNS notes at top of file why this sends 0
1249 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1251 /* problem with query data -- query not sent */
1252 idnsCallback(q
, "Internal error");
1261 idnsSendSlaveAAAAQuery(q
);
1266 q
->message
= message
;
1270 idnsCallback(q
, NULL
);
1272 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1277 idnsRead(int fd
, void *data
)
1279 int *N
= &incoming_sockets_accepted
;
1281 int max
= INCOMING_DNS_MAX
;
1282 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1285 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1287 // Always keep reading. This stops (or at least makes harder) several
1288 // attacks on the DNS client.
1289 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1292 * two code lines after returning from comm_udprecvfrom()
1293 * something overwrites the memory behind the from parameter.
1294 * NO matter where in the stack declaration list above it is placed
1295 * The cause of this is still unknown, however copying the data appears
1296 * to allow it to be passed further without this erasure.
1298 Ip::Address bugbypass
;
1302 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1304 from
= bugbypass
; // BUG BYPASS. see notes above.
1310 if (ignoreErrno(errno
))
1314 /* Some Linux systems seem to set the FD for reading and then
1315 * return ECONNREFUSED when sendto() fails and generates an ICMP
1316 * port unreachable message. */
1317 /* or maybe an EHOSTUNREACH "No route to host" message */
1318 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1321 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1326 fd_bytes(fd
, len
, FD_READ
);
1331 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1333 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1334 int nsn
= idnsFromKnownNameserver(from
);
1337 ++ nameservers
[nsn
].nreplies
;
1340 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1341 // but after the ++ above to keep statistics right.
1343 continue; // Don't process replies if there is no pending query.
1345 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1346 static time_t last_warning
= 0;
1348 if (squid_curtime
- last_warning
> 60) {
1349 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1350 last_warning
= squid_curtime
;
1352 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1357 idnsGrokReply(rbuf
, len
, nsn
);
1362 idnsCheckQueue(void *unused
)
1365 dlink_node
*p
= NULL
;
1370 /* name servers went away; reconfiguring or shutting down */
1373 for (n
= lru_list
.tail
; n
; n
= p
) {
1376 q
= static_cast<idns_query
*>(n
->data
);
1378 /* Anything to process in the queue? */
1379 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1382 /* Query timer still running? */
1383 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1384 dlinkDelete(&q
->lru
, &lru_list
);
1385 q
->queue_t
= current_time
;
1386 dlinkAdd(q
, &q
->lru
, &lru_list
);
1390 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1391 " QID 0x" << std::hex
<< std::setfill('0') <<
1392 std::setw(4) << q
->query_id
<< ": timeout" );
1394 dlinkDelete(&q
->lru
, &lru_list
);
1397 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1400 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1401 " QID 0x" << std::hex
<< q
->query_id
<<
1402 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1403 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1406 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1408 idnsCallback(q
, "Timeout");
1416 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
1418 nsvc
* vc
= (nsvc
*)data
;
1420 if (flag
== Comm::ERR_CLOSING
)
1423 if (flag
!= Comm::OK
|| len
<= 0) {
1424 if (Comm::IsConnOpen(conn
))
1429 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1431 if (vc
->msg
->contentSize() < vc
->msglen
) {
1432 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1433 CommIoCbPtrFun(idnsReadVC
, vc
));
1434 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1438 assert(vc
->ns
< nns
);
1439 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1441 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1443 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1444 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1445 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1449 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
1451 nsvc
* vc
= (nsvc
*)data
;
1453 if (flag
== Comm::ERR_CLOSING
)
1456 if (flag
!= Comm::OK
|| len
<= 0) {
1457 if (Comm::IsConnOpen(conn
))
1462 vc
->read_msglen
+= len
;
1464 assert(vc
->read_msglen
<= 2);
1466 if (vc
->read_msglen
< 2) {
1467 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1468 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1469 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1473 vc
->read_msglen
= 0;
1475 vc
->msglen
= ntohs(vc
->msglen
);
1478 if (Comm::IsConnOpen(conn
))
1483 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1484 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1485 CommIoCbPtrFun(idnsReadVC
, vc
));
1486 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1490 * rcode < 0 indicates an error, rocde >= 0 indicates success
1493 idnsRcodeCount(int rcode
, int attempt
)
1500 if (rcode
< MAX_RCODE
)
1501 if (attempt
< MAX_ATTEMPT
)
1502 ++ RcodeMatrix
[rcode
][attempt
];
1505 /* ====================================================================== */
1508 idnsRegisterWithCacheManager(void)
1510 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1516 static int init
= 0;
1518 CBDATA_INIT_TYPE(nsvc
);
1519 CBDATA_INIT_TYPE(idns_query
);
1521 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1522 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1524 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1525 addrV6
= Config
.Addrs
.udp_outgoing
;
1527 addrV6
= Config
.Addrs
.udp_incoming
;
1529 Ip::Address addrV4
= addrV6
;
1532 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1533 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1534 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1541 if (addrV4
.isIPv4()) {
1542 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1543 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1550 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1551 fatal("Could not create a DNS socket");
1553 /* Ouch... we can't call functions using debug from a debug
1554 * statement. Doing so messes up the internal Debug::level
1556 if (DnsSocketB
>= 0) {
1557 comm_local_port(DnsSocketB
);
1558 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1559 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1561 if (DnsSocketA
>= 0) {
1562 comm_local_port(DnsSocketA
);
1563 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1564 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1569 idnsAddMDNSNameservers();
1570 bool nsFound
= idnsParseNameservers();
1571 #if !_SQUID_WINDOWS_
1574 nsFound
= idnsParseResolvConf();
1579 nsFound
= idnsParseWIN32Registry();
1583 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1585 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1587 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1590 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1592 idnsAddNameserver("::1");
1593 idnsAddNameserver("127.0.0.1");
1597 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1598 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1599 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1603 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1604 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1605 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1606 max_shared_edns
= -1; // disable if we might receive random replies.
1610 idnsRegisterWithCacheManager();
1616 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1619 if (DnsSocketA
>= 0 ) {
1620 comm_close(DnsSocketA
);
1624 if (DnsSocketB
>= 0 ) {
1625 comm_close(DnsSocketB
);
1629 for (int i
= 0; i
< nns
; ++i
) {
1630 if (nsvc
*vc
= nameservers
[i
].vc
) {
1631 if (Comm::IsConnOpen(vc
->conn
))
1636 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1637 idnsFreeNameservers();
1638 idnsFreeSearchpath();
1642 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1646 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1651 q
= cbdataAlloc(idns_query
);
1652 // idns_query is POD so no constructors are called after allocation
1653 q
->xact_id
.change();
1654 // no query_id on this instance.
1656 q
->callback
= callback
;
1658 q
->callback_data
= cbdataReference(data
);
1660 q
->queue
= old
->queue
;
1668 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1670 q
->start_t
= current_time
;
1671 q
->callback
= callback
;
1672 q
->callback_data
= cbdataReference(data
);
1674 q
->hash
.key
= q
->orig
;
1675 hash_join(idns_lookup_hash
, &q
->hash
);
1681 idnsSendSlaveAAAAQuery(idns_query
*master
)
1683 idns_query
*q
= cbdataAlloc(idns_query
);
1684 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1685 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1687 q
->query_id
= idnsQueryID();
1688 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1689 q
->start_t
= master
->start_t
;
1690 q
->slave
= master
->slave
;
1692 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1693 ", id = 0x" << std::hex
<< q
->query_id
);
1704 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1706 size_t nameLength
= strlen(name
);
1708 // Prevent buffer overflow on q->name
1709 if (nameLength
> NS_MAXDNAME
) {
1710 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1711 callback(data
, NULL
, 0, "Internal error");
1715 if (idnsCachedLookup(name
, callback
, data
))
1718 idns_query
*q
= cbdataAlloc(idns_query
);
1719 // idns_query is POD so no constructors are called after allocation
1720 q
->xact_id
.change();
1721 q
->query_id
= idnsQueryID();
1724 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1728 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1729 q
->do_searchpath
= 1;
1731 q
->do_searchpath
= 0;
1734 strcpy(q
->orig
, name
);
1735 strcpy(q
->name
, q
->orig
);
1737 if (q
->do_searchpath
&& nd
< ndots
) {
1739 strcat(q
->name
, ".");
1740 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1741 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1744 // see EDNS notes at top of file why this sends 0
1745 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1748 /* problem with query data -- query not sent */
1749 callback(data
, NULL
, 0, "Internal error");
1754 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1755 ", id = 0x" << std::hex
<< q
->query_id
);
1758 idnsStartQuery(q
, callback
, data
);
1761 idnsSendSlaveAAAAQuery(q
);
1766 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1770 char ip
[MAX_IPSTRLEN
];
1772 addr
.toStr(ip
,MAX_IPSTRLEN
);
1774 q
= cbdataAlloc(idns_query
);
1776 // idns_query is POD so no constructors are called after allocation
1777 q
->xact_id
.change();
1778 q
->query_id
= idnsQueryID();
1780 if (addr
.isIPv6()) {
1781 struct in6_addr addr6
;
1782 addr
.getInAddr(addr6
);
1783 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1785 struct in_addr addr4
;
1786 addr
.getInAddr(addr4
);
1787 // see EDNS notes at top of file why this sends 0
1788 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1792 /* problem with query data -- query not sent */
1793 callback(data
, NULL
, 0, "Internal error");
1798 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1803 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1804 ", id = 0x" << std::hex
<< q
->query_id
);
1806 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1807 idnsStartQuery(q
, callback
, data
);
1812 * The function to return the DNS via SNMP
1815 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1818 variable_list
*Answer
= NULL
;
1820 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1821 *ErrP
= SNMP_ERR_NOERROR
;
1823 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1827 for (i
= 0; i
< nns
; ++i
)
1828 n
+= nameservers
[i
].nqueries
;
1830 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1837 for (i
= 0; i
< nns
; ++i
)
1838 n
+= nameservers
[i
].nreplies
;
1840 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1847 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1854 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1862 #endif /*SQUID_SNMP */