4 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
5 * AUTHOR: Duane Wessels
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36 #include "base/InstanceId.h"
37 #include "comm/Connection.h"
38 #include "comm/ConnOpener.h"
40 #include "comm/Loops.h"
41 #include "comm/Write.h"
48 #include "mgr/Registration.h"
51 #include "SquidTime.h"
56 #if HAVE_ARPA_NAMESER_H
57 #include <arpa/nameser.h>
66 /* MS Visual Studio Projects are monolithic, so we need the following
67 #ifndef to exclude the internal DNS code from compile process when
68 using external DNS process.
72 #include "squid_windows.h"
73 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
74 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
75 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
78 #define _PATH_RESCONF "/etc/resolv.conf"
80 #ifndef NS_DEFAULTPORT
81 #define NS_DEFAULTPORT 53
85 #define NS_MAXDNAME 1025
92 /* The buffer size required to store the maximum allowed search path */
94 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
97 #define IDNS_MAX_TRIES 20
100 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
101 // NP: see http://www.iana.org/assignments/dns-parameters
102 static const char *Rcodes
[] = {
105 "Packet Format Error",
106 "DNS Server Failure",
107 "Non-Existent Domain",
111 "Name Exists when it should not",
112 "RR Set Exists when it should not",
113 "RR Set that should exist does not",
114 "Server Not Authoritative for zone",
115 "Name not contained in zone",
119 "Bad OPT Version or TSIG Signature Failure"
122 typedef struct _idns_query idns_query
;
124 typedef struct _ns ns
;
126 typedef struct _sp sp
;
128 typedef struct _nsvc nsvc
;
133 char buf
[RESOLV_BUFSZ
];
134 char name
[NS_MAXDNAME
+ 1];
135 char orig
[NS_MAXDNAME
+ 1];
137 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
138 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
144 struct timeval start_t
;
145 struct timeval sent_t
;
146 struct timeval queue_t
;
153 idns_query
*slave
; // single linked list
154 idns_query
*master
; // single pointer to a shared master
155 unsigned short domain
;
156 unsigned short do_searchpath
;
157 rfc1035_message
*message
;
161 InstanceIdDefinitions(idns_query
, "dns");
165 Comm::ConnectionPointer conn
;
166 unsigned short msglen
;
177 #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;
196 static int npc_alloc
= 0;
197 static int ndots
= 1;
198 static dlink_list lru_list
;
199 static int event_queued
= 0;
200 static hash_table
*idns_lookup_hash
= NULL
;
206 * EDNS as specified may be sent as an additional record for any request.
207 * early testing has revealed that it works on common devices, but cannot
208 * be reliably used on any A or PTR requet done for IPv4 addresses.
210 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
213 * Squid is optimized to generate one packet and re-send it to all NS
214 * due to this we cannot customize the EDNS size per NS.
216 * As such we take the configuration option value as fixed.
219 * This may not be worth doing, but if/when additional-records are parsed
220 * we will be able to recover the OPT value specific to any one NS and
221 * cache it. Effectively automating the tuning of EDNS advertised to the
222 * size our active NS are capable.
223 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
224 * Responses from the configured NS may cause this to be raised or turned off.
226 #if WHEN_EDNS_RESPONSES_ARE_PARSED
227 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
230 static OBJH idnsStats
;
231 static void idnsAddNameserver(const char *buf
);
232 static void idnsAddPathComponent(const char *buf
);
233 static void idnsFreeNameservers(void);
234 static void idnsFreeSearchpath(void);
235 static void idnsParseNameservers(void);
237 static void idnsParseResolvConf(void);
240 static void idnsParseWIN32Registry(void);
241 static void idnsParseWIN32SearchList(const char *);
243 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
244 static void idnsSendQuery(idns_query
* q
);
245 static IOCB idnsReadVCHeader
;
246 static void idnsDoSendQueryVC(nsvc
*vc
);
247 static CNCB idnsInitVCConnected
;
248 static IOCB idnsReadVC
;
249 static IOCB idnsSentQueryVC
;
251 static int idnsFromKnownNameserver(Ip::Address
const &from
);
252 static idns_query
*idnsFindQuery(unsigned short id
);
253 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
255 static EVH idnsCheckQueue
;
256 static void idnsTickleQueue(void);
257 static void idnsRcodeCount(int, int);
258 static CLCB idnsVCClosed
;
259 static unsigned short idnsQueryID(void);
260 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
263 idnsAddNameserver(const char *buf
)
268 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
273 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
275 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
278 if (!Ip::EnableIpv6
&& !A
.SetIPv4()) {
279 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
283 if (nns
== nns_alloc
) {
284 int oldalloc
= nns_alloc
;
285 ns
*oldptr
= nameservers
;
292 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
294 if (oldptr
&& oldalloc
)
295 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
301 assert(nns
< nns_alloc
);
302 A
.SetPort(NS_DEFAULTPORT
);
303 nameservers
[nns
].S
= A
;
304 #if WHEN_EDNS_RESPONSES_ARE_PARSED
305 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
306 // TODO generate a test packet to probe this NS from EDNS size and ability.
308 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
313 idnsAddPathComponent(const char *buf
)
315 if (npc
== npc_alloc
) {
316 int oldalloc
= npc_alloc
;
317 sp
*oldptr
= searchpath
;
324 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
326 if (oldptr
&& oldalloc
)
327 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
333 assert(npc
< npc_alloc
);
334 strcpy(searchpath
[npc
].domain
, buf
);
335 Tolower(searchpath
[npc
].domain
);
336 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
341 idnsFreeNameservers(void)
343 safe_free(nameservers
);
348 idnsFreeSearchpath(void)
350 safe_free(searchpath
);
355 idnsParseNameservers(void)
359 for (w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
360 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
361 idnsAddNameserver(w
->key
);
367 idnsParseResolvConf(void)
370 char buf
[RESOLV_BUFSZ
];
372 fp
= fopen(_PATH_RESCONF
, "r");
375 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
380 setmode(fileno(fp
), O_TEXT
);
383 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
384 t
= strtok(buf
, w_space
);
388 } else if (strcasecmp(t
, "nameserver") == 0) {
389 t
= strtok(NULL
, w_space
);
394 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
396 idnsAddNameserver(t
);
397 } else if (strcasecmp(t
, "domain") == 0) {
398 idnsFreeSearchpath();
399 t
= strtok(NULL
, w_space
);
404 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
406 idnsAddPathComponent(t
);
407 } else if (strcasecmp(t
, "search") == 0) {
408 idnsFreeSearchpath();
410 t
= strtok(NULL
, w_space
);
415 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
417 idnsAddPathComponent(t
);
419 } else if (strcasecmp(t
, "options") == 0) {
421 t
= strtok(NULL
, w_space
);
426 if (strncmp(t
, "ndots:", 6) == 0) {
432 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
437 if (npc
== 0 && (t
= getMyHostname())) {
440 idnsAddPathComponent(t
+1);
450 idnsParseWIN32SearchList(const char * Separator
)
456 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
460 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
462 if (Result
== ERROR_SUCCESS
&& Size
) {
463 t
= (char *) xmalloc(Size
);
464 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
465 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
466 idnsAddPathComponent(t
);
469 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
471 if (Result
== ERROR_SUCCESS
&& Size
) {
472 t
= (char *) xmalloc(Size
);
473 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
474 token
= strtok(t
, Separator
);
477 idnsAddPathComponent(token
);
478 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
479 token
= strtok(NULL
, Separator
);
486 if (npc
== 0 && (t
= (char *) getMyHostname())) {
489 idnsAddPathComponent(t
+ 1);
494 idnsParseWIN32Registry(void)
498 HKEY hndKey
, hndKey2
;
500 switch (WIN32_OS_version
) {
503 /* get nameservers from the Windows NT registry */
505 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
509 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
511 if (Result
== ERROR_SUCCESS
&& Size
) {
512 t
= (char *) xmalloc(Size
);
513 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
514 token
= strtok(t
, ", ");
517 idnsAddNameserver(token
);
518 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
519 token
= strtok(NULL
, ",");
524 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
526 if (Result
== ERROR_SUCCESS
&& Size
) {
527 t
= (char *) xmalloc(Size
);
528 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
529 token
= strtok(t
, ", ");
532 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
533 idnsAddNameserver(token
);
534 token
= strtok(NULL
, ", ");
542 idnsParseWIN32SearchList(" ");
555 /* get nameservers from the Windows 2000 registry */
556 /* search all interfaces for DNS server addresses */
558 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
560 DWORD MaxSubkeyLen
, InterfacesCount
;
562 FILETIME ftLastWriteTime
;
564 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
565 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
566 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
569 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
571 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
572 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
573 strcat(newkeyname
, "\\");
574 strcat(newkeyname
, keyname
);
575 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
579 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
580 if (Result
== ERROR_SUCCESS
&& Size
) {
581 t
= (char *) xmalloc(Size
);
582 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
583 token
= strtok(t
, ", ");
585 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
586 idnsAddNameserver(token
);
587 token
= strtok(NULL
, ", ");
592 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
593 if (Result
== ERROR_SUCCESS
&& Size
) {
594 t
= (char *) xmalloc(Size
);
595 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
596 token
= strtok(t
, ", ");
598 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
599 idnsAddNameserver(token
);
600 token
= strtok(NULL
, ", ");
606 RegCloseKey(hndKey2
);
619 idnsParseWIN32SearchList(", ");
628 /* get nameservers from the Windows 9X registry */
630 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
634 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
636 if (Result
== ERROR_SUCCESS
&& Size
) {
637 t
= (char *) xmalloc(Size
);
638 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
639 token
= strtok(t
, ", ");
642 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
643 idnsAddNameserver(token
);
644 token
= strtok(NULL
, ", ");
655 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
663 idnsStats(StoreEntry
* sentry
)
669 char buf
[MAX_IPSTRLEN
];
670 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
671 storeAppendPrintf(sentry
, "\nThe Queue:\n");
672 storeAppendPrintf(sentry
, " DELAY SINCE\n");
673 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND\n");
674 storeAppendPrintf(sentry
, "------ ---- ----- ---------- ---------\n");
676 for (n
= lru_list
.head
; n
; n
= n
->next
) {
677 q
= (idns_query
*)n
->data
;
678 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f\n",
679 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
680 tvSubDsec(q
->start_t
, current_time
),
681 tvSubDsec(q
->sent_t
, current_time
));
684 if (Config
.dns
.packet_max
> 0)
685 storeAppendPrintf(sentry
, "DNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
687 storeAppendPrintf(sentry
, "DNS jumbo-grams: not working\n");
689 storeAppendPrintf(sentry
, "\nNameservers:\n");
690 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES\n");
691 storeAppendPrintf(sentry
, "---------------------------------------------- --------- ---------\n");
693 for (i
= 0; i
< nns
; ++i
) {
694 storeAppendPrintf(sentry
, "%-45s %9d %9d\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
695 nameservers
[i
].S
.NtoA(buf
,MAX_IPSTRLEN
),
696 nameservers
[i
].nqueries
,
697 nameservers
[i
].nreplies
);
700 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
701 storeAppendPrintf(sentry
, "RCODE");
703 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
704 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
706 storeAppendPrintf(sentry
, " PROBLEM\n");
708 for (j
= 0; j
< MAX_RCODE
; ++j
) {
709 if (j
> 10 && j
< 16)
710 continue; // unassigned by IANA.
712 storeAppendPrintf(sentry
, "%5d", j
);
714 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
715 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
717 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
721 storeAppendPrintf(sentry
, "\nSearch list:\n");
723 for (i
=0; i
< npc
; ++i
)
724 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
726 storeAppendPrintf(sentry
, "\n");
731 idnsTickleQueue(void)
736 if (NULL
== lru_list
.tail
)
739 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
741 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
747 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
749 nsvc
* vc
= (nsvc
*)data
;
751 if (flag
== COMM_ERR_CLOSING
)
754 // XXX: irrelevant now that we have conn pointer?
755 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
758 if (flag
!= COMM_OK
|| size
<= 0) {
764 idnsDoSendQueryVC(vc
);
768 idnsDoSendQueryVC(nsvc
*vc
)
773 if (vc
->queue
->contentSize() == 0)
776 // if retrying after a TC UDP response, our close handler cb may be pending
777 if (fd_table
[vc
->conn
->fd
].closing())
780 MemBuf
*mb
= vc
->queue
;
782 vc
->queue
= new MemBuf
;
786 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
787 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
788 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
789 AsyncCall::Pointer nil
;
791 commSetConnTimeout(vc
->conn
, timeout
, nil
);
793 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
794 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
795 Comm::Write(vc
->conn
, mb
, call
);
801 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
803 nsvc
* vc
= (nsvc
*)data
;
805 if (status
!= COMM_OK
|| !conn
) {
806 char buf
[MAX_IPSTRLEN
] = "";
808 nameservers
[vc
->ns
].S
.NtoA(buf
,MAX_IPSTRLEN
);
809 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
815 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
816 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
817 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
818 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
820 idnsDoSendQueryVC(vc
);
824 idnsVCClosed(const CommCloseCbParams
¶ms
)
826 nsvc
* vc
= (nsvc
*)params
.data
;
830 if (vc
->ns
< nns
) // XXX: dnsShutdown may have freed nameservers[]
831 nameservers
[vc
->ns
].vc
= NULL
;
838 nsvc
*vc
= cbdataAlloc(nsvc
);
840 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
841 nameservers
[ns
].vc
= vc
;
843 vc
->queue
= new MemBuf
;
844 vc
->msg
= new MemBuf
;
847 Comm::ConnectionPointer conn
= new Comm::Connection();
849 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
850 conn
->local
= Config
.Addrs
.udp_outgoing
;
852 conn
->local
= Config
.Addrs
.udp_incoming
;
854 conn
->remote
= nameservers
[ns
].S
;
856 if (conn
->remote
.IsIPv4()) {
857 conn
->local
.SetIPv4();
860 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
862 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
863 cs
->setHost("DNS TCP Socket");
868 idnsSendQueryVC(idns_query
* q
, int ns
)
871 if (nameservers
[ns
].vc
== NULL
)
874 nsvc
*vc
= nameservers
[ns
].vc
;
877 char buf
[MAX_IPSTRLEN
];
878 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[ns
].S
.NtoA(buf
,MAX_IPSTRLEN
) << "!");
885 short head
= htons(q
->sz
);
887 vc
->queue
->append((char *)&head
, 2);
889 vc
->queue
->append(q
->buf
, q
->sz
);
891 idnsDoSendQueryVC(vc
);
895 idnsSendQuery(idns_query
* q
)
897 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
898 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
903 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
907 assert(q
->lru
.next
== NULL
);
909 assert(q
->lru
.prev
== NULL
);
915 ns
= q
->nsends
% nns
;
918 idnsSendQueryVC(q
, ns
);
921 if (DnsSocketB
>= 0 && nameservers
[ns
].S
.IsIPv6())
922 y
= comm_udp_sendto(DnsSocketB
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
923 else if (DnsSocketA
>= 0)
924 x
= comm_udp_sendto(DnsSocketA
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
929 q
->sent_t
= current_time
;
931 if (y
< 0 && nameservers
[ns
].S
.IsIPv6())
932 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
933 if (x
< 0 && nameservers
[ns
].S
.IsIPv4())
934 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
936 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
939 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
942 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
945 ++ nameservers
[ns
].nqueries
;
946 q
->queue_t
= current_time
;
947 dlinkAdd(q
, &q
->lru
, &lru_list
);
953 idnsFromKnownNameserver(Ip::Address
const &from
)
957 for (i
= 0; i
< nns
; ++i
) {
958 if (nameservers
[i
].S
!= from
)
961 if (nameservers
[i
].S
.GetPort() != from
.GetPort())
971 idnsFindQuery(unsigned short id
)
976 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
977 q
= (idns_query
*)n
->data
;
979 if (q
->query_id
== id
)
986 static unsigned short
989 unsigned short id
= squid_random() & 0xFFFF;
990 unsigned short first_id
= id
;
992 while (idnsFindQuery(id
)) {
995 if (id
== first_id
) {
996 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1005 idnsCallback(idns_query
*q
, const char *error
)
1017 // If any of our subqueries are still pending then wait for them to complete before continuing
1018 for ( q2
= q
; q2
; q2
= q2
->slave
) {
1025 rfc1035_message
*message
= q
->message
;
1030 while ( (q2
= q
->slave
) ) {
1031 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1032 q
->slave
= q2
->slave
;
1035 // two sets of RR need merging
1036 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1037 if (Config
.dns
.v4_first
) {
1038 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1039 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1041 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1042 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1045 // HACK WARNING, the answer rr:s have been copied in-place to
1046 // result, do not free them here
1047 safe_free(message
->answer
);
1048 safe_free(q2
->message
->answer
);
1049 message
->answer
= result
;
1050 message
->ancount
+= q2
->message
->ancount
;
1052 // first response empty or failed, just use the second
1053 rfc1035MessageDestroy(&message
);
1054 message
= q2
->message
;
1060 rfc1035MessageDestroy(&q2
->message
);
1064 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1066 callback
= q
->callback
;
1068 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1070 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1071 callback(cbdata
, answers
, n
, error
);
1074 idns_query
*q2
= q
->queue
;
1075 q
->queue
= q2
->queue
;
1076 callback
= q2
->callback
;
1077 q2
->callback
= NULL
;
1079 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1080 callback(cbdata
, answers
, n
, error
);
1086 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1090 rfc1035MessageDestroy(&message
);
1095 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1098 rfc1035_message
*message
= NULL
;
1101 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1103 if (message
== NULL
) {
1104 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1108 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1110 q
= idnsFindQuery(message
->id
);
1113 debugs(78, 3, "idnsGrokReply: Late response");
1114 rfc1035MessageDestroy(&message
);
1118 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1119 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1120 rfc1035MessageDestroy(&message
);
1124 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1125 // TODO: actually gr the message right here.
1126 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1127 // this is overall better than force-feeding A response with AAAA an section later anyway.
1128 // AND allows us to merge AN+AR sections from both responses (one day)
1130 if (q
->edns_seen
>= 0) {
1131 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1132 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1133 // the altered NS was limiting the whole group.
1134 max_shared_edns
= q
->edns_seen
;
1135 // may be limited by one of the others still
1136 for (int i
= 0; i
< nns
; ++i
)
1137 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1139 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1140 // maybe reduce the global limit downwards to accomodate this NS
1141 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1143 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1144 max_shared_edns
= -1;
1148 dlinkDelete(&q
->lru
, &lru_list
);
1152 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1153 rfc1035MessageDestroy(&message
);
1160 // Strange: A TCP DNS response with the truncation bit (TC) set.
1161 // Return an error and cleanup; no point in trying TCP again.
1162 debugs(78, 3, HERE
<< "TCP DNS response");
1163 idnsCallback(q
, "Truncated TCP DNS response");
1169 idnsRcodeCount(n
, q
->attempt
);
1173 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1175 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1177 * RCODE 2 is "Server failure - The name server was
1178 * unable to process this query due to a problem with
1181 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1182 rfc1035MessageDestroy(&message
);
1187 // Do searchpath processing on the master A query only to keep
1188 // things simple. NXDOMAIN is authorative for the label, not
1190 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1191 assert(NULL
== message
->answer
);
1192 strcpy(q
->name
, q
->orig
);
1194 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1196 if (q
->domain
< npc
) {
1197 strcat(q
->name
, ".");
1198 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1199 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1205 rfc1035MessageDestroy(&message
);
1207 // cleanup slave AAAA query
1208 while (idns_query
*slave
= q
->slave
) {
1209 dlinkDelete(&slave
->lru
, &lru_list
);
1210 q
->slave
= slave
->slave
;
1211 rfc1035MessageDestroy(&slave
->message
);
1216 q
->query_id
= idnsQueryID();
1217 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1218 // see EDNS notes at top of file why this sends 0
1219 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1221 /* problem with query data -- query not sent */
1222 idnsCallback(q
, "Internal error");
1230 idnsSendSlaveAAAAQuery(q
);
1235 q
->message
= message
;
1239 idnsCallback(q
, NULL
);
1241 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1246 idnsRead(int fd
, void *data
)
1248 int *N
= &incoming_sockets_accepted
;
1250 int max
= INCOMING_DNS_MAX
;
1251 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1255 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1257 // Always keep reading. This stops (or at least makes harder) several
1258 // attacks on the DNS client.
1259 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1262 * two code lines after returning from comm_udprecvfrom()
1263 * something overwrites the memory behind the from parameter.
1264 * NO matter where in the stack declaration list above it is placed
1265 * The cause of this is still unknown, however copying the data appears
1266 * to allow it to be passed further without this erasure.
1268 Ip::Address bugbypass
;
1272 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1274 from
= bugbypass
; // BUG BYPASS. see notes above.
1280 if (ignoreErrno(errno
))
1284 /* Some Linux systems seem to set the FD for reading and then
1285 * return ECONNREFUSED when sendto() fails and generates an ICMP
1286 * port unreachable message. */
1287 /* or maybe an EHOSTUNREACH "No route to host" message */
1288 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1291 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1296 fd_bytes(fd
, len
, FD_READ
);
1301 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1303 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1304 ns
= idnsFromKnownNameserver(from
);
1307 ++ nameservers
[ns
].nreplies
;
1310 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1311 // but after the ++ above to keep statistics right.
1313 continue; // Don't process replies if there is no pending query.
1315 if (ns
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1316 static time_t last_warning
= 0;
1318 if (squid_curtime
- last_warning
> 60) {
1319 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1320 last_warning
= squid_curtime
;
1322 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1327 idnsGrokReply(rbuf
, len
, ns
);
1332 idnsCheckQueue(void *unused
)
1335 dlink_node
*p
= NULL
;
1340 /* name servers went away; reconfiguring or shutting down */
1343 for (n
= lru_list
.tail
; n
; n
= p
) {
1346 q
= static_cast<idns_query
*>(n
->data
);
1348 /* Anything to process in the queue? */
1349 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1352 /* Query timer still running? */
1353 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1354 dlinkDelete(&q
->lru
, &lru_list
);
1355 q
->queue_t
= current_time
;
1356 dlinkAdd(q
, &q
->lru
, &lru_list
);
1360 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1361 " QID 0x" << std::hex
<< std::setfill('0') <<
1362 std::setw(4) << q
->query_id
<< ": timeout" );
1364 dlinkDelete(&q
->lru
, &lru_list
);
1367 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1370 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1371 " QID 0x" << std::hex
<< q
->query_id
<<
1372 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1373 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1376 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1378 idnsCallback(q
, "Timeout");
1386 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1388 nsvc
* vc
= (nsvc
*)data
;
1390 if (flag
== COMM_ERR_CLOSING
)
1393 if (flag
!= COMM_OK
|| len
<= 0) {
1394 if (Comm::IsConnOpen(conn
))
1399 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1401 if (vc
->msg
->contentSize() < vc
->msglen
) {
1402 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1403 CommIoCbPtrFun(idnsReadVC
, vc
));
1404 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1408 assert(vc
->ns
< nns
);
1409 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1411 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1413 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1414 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1415 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1419 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1421 nsvc
* vc
= (nsvc
*)data
;
1423 if (flag
== COMM_ERR_CLOSING
)
1426 if (flag
!= COMM_OK
|| len
<= 0) {
1427 if (Comm::IsConnOpen(conn
))
1432 vc
->read_msglen
+= len
;
1434 assert(vc
->read_msglen
<= 2);
1436 if (vc
->read_msglen
< 2) {
1437 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1438 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1439 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1443 vc
->read_msglen
= 0;
1445 vc
->msglen
= ntohs(vc
->msglen
);
1447 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1448 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1449 CommIoCbPtrFun(idnsReadVC
, vc
));
1450 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1454 * rcode < 0 indicates an error, rocde >= 0 indicates success
1457 idnsRcodeCount(int rcode
, int attempt
)
1464 if (rcode
< MAX_RCODE
)
1465 if (attempt
< MAX_ATTEMPT
)
1466 ++ RcodeMatrix
[rcode
][attempt
];
1469 /* ====================================================================== */
1472 idnsRegisterWithCacheManager(void)
1474 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1480 static int init
= 0;
1482 CBDATA_INIT_TYPE(nsvc
);
1483 CBDATA_INIT_TYPE(idns_query
);
1485 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1486 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1488 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
1489 addrV6
= Config
.Addrs
.udp_outgoing
;
1491 addrV6
= Config
.Addrs
.udp_incoming
;
1493 Ip::Address addrV4
= addrV6
;
1496 if (Ip::EnableIpv6
&& addrV6
.IsIPv6()) {
1497 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1498 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1505 if (addrV4
.IsIPv4()) {
1506 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1507 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1514 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1515 fatal("Could not create a DNS socket");
1517 /* Ouch... we can't call functions using debug from a debug
1518 * statement. Doing so messes up the internal Debug::level
1520 if (DnsSocketB
>= 0) {
1521 comm_local_port(DnsSocketB
);
1522 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1523 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1525 if (DnsSocketA
>= 0) {
1526 comm_local_port(DnsSocketA
);
1527 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1528 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1533 idnsParseNameservers();
1537 idnsParseResolvConf();
1542 idnsParseWIN32Registry();
1546 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1548 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1550 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1553 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1554 idnsAddNameserver("127.0.0.1");
1558 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1559 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1560 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1564 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1565 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1566 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1567 max_shared_edns
= -1; // disable if we might receive random replies.
1571 idnsRegisterWithCacheManager();
1577 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1580 if (DnsSocketA
>= 0 ) {
1581 comm_close(DnsSocketA
);
1585 if (DnsSocketB
>= 0 ) {
1586 comm_close(DnsSocketB
);
1590 for (int i
= 0; i
< nns
; ++i
) {
1591 if (nsvc
*vc
= nameservers
[i
].vc
) {
1592 if (Comm::IsConnOpen(vc
->conn
))
1597 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1598 idnsFreeNameservers();
1599 idnsFreeSearchpath();
1603 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1607 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1612 q
= cbdataAlloc(idns_query
);
1613 // idns_query is POD so no constructors are called after allocation
1614 q
->xact_id
.change();
1615 // no query_id on this instance.
1617 q
->callback
= callback
;
1619 q
->callback_data
= cbdataReference(data
);
1621 q
->queue
= old
->queue
;
1629 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1631 q
->start_t
= current_time
;
1632 q
->callback
= callback
;
1633 q
->callback_data
= cbdataReference(data
);
1635 q
->hash
.key
= q
->orig
;
1636 hash_join(idns_lookup_hash
, &q
->hash
);
1642 idnsSendSlaveAAAAQuery(idns_query
*master
)
1644 idns_query
*q
= cbdataAlloc(idns_query
);
1645 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1646 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1648 q
->query_id
= idnsQueryID();
1649 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1650 q
->start_t
= master
->start_t
;
1651 q
->slave
= master
->slave
;
1653 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1654 ", id = 0x" << std::hex
<< q
->query_id
);
1664 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1670 if (idnsCachedLookup(name
, callback
, data
))
1673 q
= cbdataAlloc(idns_query
);
1674 // idns_query is POD so no constructors are called after allocation
1675 q
->xact_id
.change();
1676 q
->query_id
= idnsQueryID();
1678 for (i
= 0; i
< strlen(name
); ++i
)
1682 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[strlen(name
)-1] != '.') {
1683 q
->do_searchpath
= 1;
1685 q
->do_searchpath
= 0;
1688 strcpy(q
->orig
, name
);
1689 strcpy(q
->name
, q
->orig
);
1691 if (q
->do_searchpath
&& nd
< ndots
) {
1693 strcat(q
->name
, ".");
1694 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1695 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1698 // see EDNS notes at top of file why this sends 0
1699 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1702 /* problem with query data -- query not sent */
1703 callback(data
, NULL
, 0, "Internal error");
1708 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1709 ", id = 0x" << std::hex
<< q
->query_id
);
1711 idnsStartQuery(q
, callback
, data
);
1714 idnsSendSlaveAAAAQuery(q
);
1719 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1723 char ip
[MAX_IPSTRLEN
];
1725 addr
.NtoA(ip
,MAX_IPSTRLEN
);
1727 q
= cbdataAlloc(idns_query
);
1729 // idns_query is POD so no constructors are called after allocation
1730 q
->xact_id
.change();
1731 q
->query_id
= idnsQueryID();
1733 if (addr
.IsIPv6()) {
1734 struct in6_addr addr6
;
1735 addr
.GetInAddr(addr6
);
1736 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1738 struct in_addr addr4
;
1739 addr
.GetInAddr(addr4
);
1740 // see EDNS notes at top of file why this sends 0
1741 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1745 /* problem with query data -- query not sent */
1746 callback(data
, NULL
, 0, "Internal error");
1751 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1756 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1757 ", id = 0x" << std::hex
<< q
->query_id
);
1759 idnsStartQuery(q
, callback
, data
);
1764 * The function to return the DNS via SNMP
1767 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1770 variable_list
*Answer
= NULL
;
1772 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1773 *ErrP
= SNMP_ERR_NOERROR
;
1775 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1779 for (i
= 0; i
< nns
; ++i
)
1780 n
+= nameservers
[i
].nqueries
;
1782 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1789 for (i
= 0; i
< nns
; ++i
)
1790 n
+= nameservers
[i
].nreplies
;
1792 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1799 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1806 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1814 #endif /*SQUID_SNMP */
1815 #endif /* USE_DNSHELPER */