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"
39 #include "comm/Write.h"
45 #include "SquidTime.h"
47 #include "mgr/Registration.h"
51 #if HAVE_ARPA_NAMESER_H
52 #include <arpa/nameser.h>
58 /* MS Visual Studio Projects are monolithic, so we need the following
59 #ifndef to exclude the internal DNS code from compile process when
60 using external DNS process.
64 #include "squid_windows.h"
65 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
66 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
67 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
70 #define _PATH_RESCONF "/etc/resolv.conf"
72 #ifndef NS_DEFAULTPORT
73 #define NS_DEFAULTPORT 53
77 #define NS_MAXDNAME 1025
84 /* The buffer size required to store the maximum allowed search path */
86 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
89 #define IDNS_MAX_TRIES 20
92 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
93 // NP: see http://www.iana.org/assignments/dns-parameters
94 static const char *Rcodes
[] = {
97 "Packet Format Error",
99 "Non-Existent Domain",
103 "Name Exists when it should not",
104 "RR Set Exists when it should not",
105 "RR Set that should exist does not",
106 "Server Not Authoritative for zone",
107 "Name not contained in zone",
111 "Bad OPT Version or TSIG Signature Failure"
114 typedef struct _idns_query idns_query
;
116 typedef struct _ns ns
;
118 typedef struct _sp sp
;
120 typedef struct _nsvc nsvc
;
125 char buf
[RESOLV_BUFSZ
];
126 char name
[NS_MAXDNAME
+ 1];
127 char orig
[NS_MAXDNAME
+ 1];
129 unsigned short msg_id
; /// random query ID sent to server; changes with every query sent
130 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
135 struct timeval start_t
;
136 struct timeval sent_t
;
137 struct timeval queue_t
;
144 unsigned short domain
;
145 unsigned short do_searchpath
;
152 InstanceIdDefinitions(idns_query
, "dns");
156 Comm::ConnectionPointer conn
;
157 unsigned short msglen
;
168 #if WHEN_EDNS_RESPONSES_ARE_PARSED
175 char domain
[NS_MAXDNAME
];
180 CBDATA_TYPE(idns_query
);
182 static ns
*nameservers
= NULL
;
183 static sp
*searchpath
= NULL
;
185 static int nns_alloc
= 0;
187 static int npc_alloc
= 0;
188 static int ndots
= 1;
189 static dlink_list lru_list
;
190 static int event_queued
= 0;
191 static hash_table
*idns_lookup_hash
= NULL
;
197 * EDNS as specified may be sent as an additional record for any request.
198 * early testing has revealed that it works on common devices, but cannot
199 * be reliably used on any A or PTR requet done for IPv4 addresses.
201 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
204 * Squid is optimized to generate one packet and re-send it to all NS
205 * due to this we cannot customize the EDNS size per NS.
207 * As such we take the configuration option value as fixed.
210 * This may not be worth doing, but if/when additional-records are parsed
211 * we will be able to recover the OPT value specific to any one NS and
212 * cache it. Effectively automating the tuning of EDNS advertised to the
213 * size our active NS are capable.
214 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
215 * Responses from the configured NS may cause this to be raised or turned off.
217 #if WHEN_EDNS_RESPONSES_ARE_PARSED
218 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
221 static OBJH idnsStats
;
222 static void idnsAddNameserver(const char *buf
);
223 static void idnsAddPathComponent(const char *buf
);
224 static void idnsFreeNameservers(void);
225 static void idnsFreeSearchpath(void);
226 static void idnsParseNameservers(void);
227 #ifndef _SQUID_MSWIN_
228 static void idnsParseResolvConf(void);
231 static void idnsParseWIN32Registry(void);
232 static void idnsParseWIN32SearchList(const char *);
234 static void idnsCacheQuery(idns_query
* q
);
235 static void idnsSendQuery(idns_query
* q
);
236 static void idnsDoSendQueryVC(nsvc
*vc
);
237 static CNCB idnsInitVCConnected
;
238 static IOCB idnsReadVCHeader
;
239 static IOCB idnsReadVC
;
240 static IOCB idnsSentQueryVC
;
242 static int idnsFromKnownNameserver(Ip::Address
const &from
);
243 static idns_query
*idnsFindQuery(unsigned short id
);
244 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
246 static EVH idnsCheckQueue
;
247 static void idnsTickleQueue(void);
248 static void idnsRcodeCount(int, int);
249 static void idnsVCClosed(int fd
, void *data
);
250 static unsigned short idnsQueryID(void);
253 idnsAddNameserver(const char *buf
)
258 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
263 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
265 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
268 if (!Ip::EnableIpv6
&& !A
.SetIPv4()) {
269 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
273 if (nns
== nns_alloc
) {
274 int oldalloc
= nns_alloc
;
275 ns
*oldptr
= nameservers
;
282 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
284 if (oldptr
&& oldalloc
)
285 xmemcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
291 assert(nns
< nns_alloc
);
292 A
.SetPort(NS_DEFAULTPORT
);
293 nameservers
[nns
].S
= A
;
294 #if WHEN_EDNS_RESPONSES_ARE_PARSED
295 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
296 // TODO generate a test packet to probe this NS from EDNS size and ability.
298 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
303 idnsAddPathComponent(const char *buf
)
305 if (npc
== npc_alloc
) {
306 int oldalloc
= npc_alloc
;
307 sp
*oldptr
= searchpath
;
314 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
316 if (oldptr
&& oldalloc
)
317 xmemcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
323 assert(npc
< npc_alloc
);
324 strcpy(searchpath
[npc
].domain
, buf
);
325 Tolower(searchpath
[npc
].domain
);
326 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
332 idnsFreeNameservers(void)
334 safe_free(nameservers
);
339 idnsFreeSearchpath(void)
341 safe_free(searchpath
);
348 idnsParseNameservers(void)
352 for (w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
353 debugs(78, 1, "Adding nameserver " << w
->key
<< " from squid.conf");
354 idnsAddNameserver(w
->key
);
358 #ifndef _SQUID_MSWIN_
360 idnsParseResolvConf(void)
363 char buf
[RESOLV_BUFSZ
];
365 fp
= fopen(_PATH_RESCONF
, "r");
368 debugs(78, 1, "" << _PATH_RESCONF
<< ": " << xstrerror());
372 #if defined(_SQUID_CYGWIN_)
373 setmode(fileno(fp
), O_TEXT
);
377 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
378 t
= strtok(buf
, w_space
);
382 } else if (strcasecmp(t
, "nameserver") == 0) {
383 t
= strtok(NULL
, w_space
);
388 debugs(78, 1, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
390 idnsAddNameserver(t
);
391 } else if (strcasecmp(t
, "domain") == 0) {
392 idnsFreeSearchpath();
393 t
= strtok(NULL
, w_space
);
398 debugs(78, 1, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
400 idnsAddPathComponent(t
);
401 } else if (strcasecmp(t
, "search") == 0) {
402 idnsFreeSearchpath();
404 t
= strtok(NULL
, w_space
);
409 debugs(78, 1, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
411 idnsAddPathComponent(t
);
413 } else if (strcasecmp(t
, "options") == 0) {
415 t
= strtok(NULL
, w_space
);
420 if (strncmp(t
, "ndots:", 6) == 0) {
426 debugs(78, 1, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
431 if (npc
== 0 && (t
= getMyHostname())) {
434 idnsAddPathComponent(t
+1);
444 idnsParseWIN32SearchList(const char * Separator
)
450 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
454 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
456 if (Result
== ERROR_SUCCESS
&& Size
) {
457 t
= (char *) xmalloc(Size
);
458 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
459 debugs(78, 1, "Adding domain " << t
<< " from Registry");
460 idnsAddPathComponent(t
);
463 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
465 if (Result
== ERROR_SUCCESS
&& Size
) {
466 t
= (char *) xmalloc(Size
);
467 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
468 token
= strtok(t
, Separator
);
471 idnsAddPathComponent(token
);
472 debugs(78, 1, "Adding domain " << token
<< " from Registry");
473 token
= strtok(NULL
, Separator
);
480 if (npc
== 0 && (t
= (char *) getMyHostname())) {
483 idnsAddPathComponent(t
+ 1);
488 idnsParseWIN32Registry(void)
492 HKEY hndKey
, hndKey2
;
494 switch (WIN32_OS_version
) {
497 /* get nameservers from the Windows NT registry */
499 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
503 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
505 if (Result
== ERROR_SUCCESS
&& Size
) {
506 t
= (char *) xmalloc(Size
);
507 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
508 token
= strtok(t
, ", ");
511 idnsAddNameserver(token
);
512 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
513 token
= strtok(NULL
, ",");
518 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
520 if (Result
== ERROR_SUCCESS
&& Size
) {
521 t
= (char *) xmalloc(Size
);
522 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
523 token
= strtok(t
, ", ");
526 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
527 idnsAddNameserver(token
);
528 token
= strtok(NULL
, ", ");
536 idnsParseWIN32SearchList(" ");
549 /* get nameservers from the Windows 2000 registry */
550 /* search all interfaces for DNS server addresses */
552 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
554 DWORD MaxSubkeyLen
, InterfacesCount
;
556 FILETIME ftLastWriteTime
;
558 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
559 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
560 for (i
= 0; i
< (int) InterfacesCount
; i
++) {
563 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
565 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
566 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
567 strcat(newkeyname
, "\\");
568 strcat(newkeyname
, keyname
);
569 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
573 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
574 if (Result
== ERROR_SUCCESS
&& Size
) {
575 t
= (char *) xmalloc(Size
);
576 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
577 token
= strtok(t
, ", ");
579 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
580 idnsAddNameserver(token
);
581 token
= strtok(NULL
, ", ");
586 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
587 if (Result
== ERROR_SUCCESS
&& Size
) {
588 t
= (char *) xmalloc(Size
);
589 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
590 token
= strtok(t
, ", ");
592 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
593 idnsAddNameserver(token
);
594 token
= strtok(NULL
, ", ");
600 RegCloseKey(hndKey2
);
613 idnsParseWIN32SearchList(", ");
622 /* get nameservers from the Windows 9X registry */
624 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
628 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
630 if (Result
== ERROR_SUCCESS
&& Size
) {
631 t
= (char *) xmalloc(Size
);
632 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
633 token
= strtok(t
, ", ");
636 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
637 idnsAddNameserver(token
);
638 token
= strtok(NULL
, ", ");
649 debugs(78, 1, "Failed to read nameserver from Registry: Unknown System Type.");
657 idnsStats(StoreEntry
* sentry
)
663 char buf
[MAX_IPSTRLEN
];
664 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
665 storeAppendPrintf(sentry
, "\nThe Queue:\n");
666 storeAppendPrintf(sentry
, " DELAY SINCE\n");
667 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND\n");
668 storeAppendPrintf(sentry
, "------ ---- ----- ---------- ---------\n");
670 for (n
= lru_list
.head
; n
; n
= n
->next
) {
671 q
= (idns_query
*)n
->data
;
672 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f\n",
673 (int) q
->msg_id
, (int) q
->sz
, q
->nsends
,
674 tvSubDsec(q
->start_t
, current_time
),
675 tvSubDsec(q
->sent_t
, current_time
));
678 if (Config
.dns
.packet_max
> 0)
679 storeAppendPrintf(sentry
, "DNS jumbo-grams: %Zd Bytes\n", Config
.dns
.packet_max
);
681 storeAppendPrintf(sentry
, "DNS jumbo-grams: not working\n");
683 storeAppendPrintf(sentry
, "\nNameservers:\n");
684 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES\n");
685 storeAppendPrintf(sentry
, "---------------------------------------------- --------- ---------\n");
687 for (i
= 0; i
< nns
; i
++) {
688 storeAppendPrintf(sentry
, "%-45s %9d %9d\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
689 nameservers
[i
].S
.NtoA(buf
,MAX_IPSTRLEN
),
690 nameservers
[i
].nqueries
,
691 nameservers
[i
].nreplies
);
694 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
695 storeAppendPrintf(sentry
, "RCODE");
697 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
698 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
700 storeAppendPrintf(sentry
, " PROBLEM\n");
702 for (j
= 0; j
< MAX_RCODE
; j
++) {
703 if (j
> 10 && j
< 16)
704 continue; // unassigned by IANA.
706 storeAppendPrintf(sentry
, "%5d", j
);
708 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
709 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
711 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
715 storeAppendPrintf(sentry
, "\nSearch list:\n");
717 for (i
=0; i
< npc
; i
++)
718 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
720 storeAppendPrintf(sentry
, "\n");
725 idnsTickleQueue(void)
730 if (NULL
== lru_list
.tail
)
733 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, 1.0, 1);
739 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
741 nsvc
* vc
= (nsvc
*)data
;
743 if (flag
== COMM_ERR_CLOSING
)
746 // XXX: irrelevant now that we have conn pointer?
747 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
750 if (flag
!= COMM_OK
|| size
<= 0) {
756 idnsDoSendQueryVC(vc
);
760 idnsDoSendQueryVC(nsvc
*vc
)
765 if (vc
->queue
->contentSize() == 0)
768 MemBuf
*mb
= vc
->queue
;
770 vc
->queue
= new MemBuf
;
774 commSetTimeout(vc
->conn
->fd
, Config
.Timeout
.idns_query
, NULL
, NULL
);
776 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
777 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
778 Comm::Write(vc
->conn
, mb
, call
);
784 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
786 nsvc
* vc
= (nsvc
*)data
;
788 if (status
!= COMM_OK
|| !conn
) {
789 char buf
[MAX_IPSTRLEN
] = "";
791 nameservers
[vc
->ns
].S
.NtoA(buf
,MAX_IPSTRLEN
);
792 debugs(78, 1, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
798 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
799 comm_read(conn
, (char *)&vc
->msglen
, 2 , idnsReadVCHeader
, vc
);
801 idnsDoSendQueryVC(vc
);
805 idnsVCClosed(int fd
, void *data
)
807 nsvc
* vc
= (nsvc
*)data
;
811 if (vc
->ns
< nns
) // XXX: idnsShutdown may have freed nameservers[]
812 nameservers
[vc
->ns
].vc
= NULL
;
819 nsvc
*vc
= cbdataAlloc(nsvc
);
821 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
822 nameservers
[ns
].vc
= vc
;
824 vc
->queue
= new MemBuf
;
825 vc
->msg
= new MemBuf
;
828 Comm::ConnectionPointer conn
= new Comm::Connection();
830 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
831 conn
->local
= Config
.Addrs
.udp_outgoing
;
833 conn
->local
= Config
.Addrs
.udp_incoming
;
835 conn
->remote
= nameservers
[ns
].S
;
837 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
839 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
840 cs
->setHost("DNS TCP Socket");
845 idnsSendQueryVC(idns_query
* q
, int ns
)
848 if (nameservers
[ns
].vc
== NULL
)
851 nsvc
*vc
= nameservers
[ns
].vc
;
854 char buf
[MAX_IPSTRLEN
];
855 debugs(78, 1, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[ns
].S
.NtoA(buf
,MAX_IPSTRLEN
) << "!");
862 short head
= htons(q
->sz
);
864 vc
->queue
->append((char *)&head
, 2);
866 vc
->queue
->append(q
->buf
, q
->sz
);
868 idnsDoSendQueryVC(vc
);
872 idnsSendQuery(idns_query
* q
)
874 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
875 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
880 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
884 assert(q
->lru
.next
== NULL
);
886 assert(q
->lru
.prev
== NULL
);
891 q
->start_t
= current_time
;
892 q
->msg_id
= idnsQueryID();
893 rfc1035SetQueryID(q
->buf
, q
->msg_id
);
896 ns
= q
->nsends
% nns
;
899 idnsSendQueryVC(q
, ns
);
902 if (DnsSocketB
>= 0 && nameservers
[ns
].S
.IsIPv6())
903 y
= comm_udp_sendto(DnsSocketB
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
905 x
= comm_udp_sendto(DnsSocketA
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
910 q
->queue_t
= q
->sent_t
= current_time
;
912 if (y
< 0 && nameservers
[ns
].S
.IsIPv6())
913 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
914 if (x
< 0 && nameservers
[ns
].S
.IsIPv4())
915 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
917 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
920 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
923 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
926 nameservers
[ns
].nqueries
++;
927 q
->queue_t
= current_time
;
928 dlinkAdd(q
, &q
->lru
, &lru_list
);
933 idnsFromKnownNameserver(Ip::Address
const &from
)
937 for (i
= 0; i
< nns
; i
++) {
938 if (nameservers
[i
].S
!= from
)
941 if (nameservers
[i
].S
.GetPort() != from
.GetPort())
951 idnsFindQuery(unsigned short id
)
956 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
957 q
= (idns_query
*)n
->data
;
966 static unsigned short
969 unsigned short id
= squid_random() & 0xFFFF;
970 unsigned short first_id
= id
;
972 while (idnsFindQuery(id
)) {
975 if (id
== first_id
) {
976 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
985 idnsCallback(idns_query
*q
, rfc1035_rr
*answers
, int n
, const char *error
)
990 callback
= q
->callback
;
993 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
994 callback(cbdata
, answers
, n
, error
);
997 idns_query
*q2
= q
->queue
;
998 q
->queue
= q2
->queue
;
999 callback
= q2
->callback
;
1000 q2
->callback
= NULL
;
1002 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1003 callback(cbdata
, answers
, n
, error
);
1009 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1015 idnsDropMessage(rfc1035_message
*message
, idns_query
*q
)
1017 rfc1035MessageDestroy(&message
);
1019 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1025 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1028 rfc1035_message
*message
= NULL
;
1031 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1033 if (message
== NULL
) {
1034 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
1038 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1040 q
= idnsFindQuery(message
->id
);
1043 debugs(78, 3, "idnsGrokReply: Late response");
1044 rfc1035MessageDestroy(&message
);
1048 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1049 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1050 rfc1035MessageDestroy(&message
);
1054 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1055 // TODO: actually gr the message right here.
1056 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1057 // this is overall better than force-feeding A response with AAAA an section later anyway.
1058 // AND allows us to merge AN+AR sections from both responses (one day)
1060 if (q
->edns_seen
>= 0) {
1061 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1062 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1063 // the altered NS was limiting the whole group.
1064 max_shared_edns
= q
->edns_seen
;
1065 // may be limited by one of the others still
1066 for (int i
= 0; i
< nns
; i
++)
1067 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1069 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1070 // maybe reduce the global limit downwards to accomodate this NS
1071 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1073 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1074 max_shared_edns
= -1;
1079 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1080 dlinkDelete(&q
->lru
, &lru_list
);
1081 rfc1035MessageDestroy(&message
);
1088 // Strange: A TCP DNS response with the truncation bit (TC) set.
1089 // Return an error and cleanup; no point in trying TCP again.
1090 debugs(78, 3, HERE
<< "TCP DNS response");
1091 idnsCallback(q
, NULL
, 0, "Truncated TCP DNS response");
1098 dlinkDelete(&q
->lru
, &lru_list
);
1099 idnsRcodeCount(n
, q
->attempt
);
1103 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1105 if (q
->rcode
== 2 && ++q
->attempt
< MAX_ATTEMPT
) {
1107 * RCODE 2 is "Server failure - The name server was
1108 * unable to process this query due to a problem with
1111 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1112 rfc1035MessageDestroy(&message
);
1117 if (q
->rcode
== 3 && q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1118 assert(NULL
== message
->answer
);
1119 strcpy(q
->name
, q
->orig
);
1121 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1123 if (q
->domain
< npc
) {
1124 strcat(q
->name
, ".");
1125 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1126 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1132 idnsDropMessage(message
, q
);
1134 if (Ip::EnableIpv6
&& q
->query
.qtype
== RFC1035_TYPE_AAAA
) {
1135 debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q
->name
);
1136 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1138 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1139 // see EDNS notes at top of file why this sends 0
1140 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1148 if (q
->need_A
&& (Config
.onoff
.dns_require_A
== 1 || n
<= 0 ) ) {
1149 /* ERROR or NO AAAA exist. Failover to A records. */
1150 /* Apparently its also a good idea to lookup and store the A records
1151 * just in case the AAAA are not available when we need them.
1152 * This could occur due to number of network failings beyond our control
1153 * thus the || above allowing the user to request always both.
1157 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " has no AAAA records. Looking up A record instead.");
1158 else if (q
->need_A
&& n
<= 0)
1159 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query failed. Trying A now instead.");
1160 else // admin requested this.
1161 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query done. Configured to retrieve A now also.");
1163 // move the initial message results into the failover query for merging later.
1165 q
->initial_AAAA
.count
= message
->ancount
;
1166 q
->initial_AAAA
.answers
= message
->answer
;
1167 message
->answer
= NULL
;
1170 // remove the hashed query info
1171 idnsDropMessage(message
, q
);
1173 // reset the query as an A query
1175 // see EDNS notes at top of file why this sends 0
1176 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1183 /** If there are two result sets from preceeding AAAA and A lookups merge them with a preference for AAAA */
1184 if (q
->initial_AAAA
.count
> 0 && n
> 0) {
1185 /* two sets of RR need merging */
1186 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q
->initial_AAAA
.count
) );
1187 rfc1035_rr
*tmp
= result
;
1189 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " AAAA has " << q
->initial_AAAA
.count
<< " RR, A has " << n
<< " RR");
1191 memcpy(tmp
, q
->initial_AAAA
.answers
, (sizeof(rfc1035_rr
)*(q
->initial_AAAA
.count
)) );
1192 tmp
+= q
->initial_AAAA
.count
;
1193 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1194 safe_free(q
->initial_AAAA
.answers
);
1196 memcpy( tmp
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1197 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1198 safe_free(message
->answer
);
1200 message
->answer
= result
;
1201 message
->ancount
+= q
->initial_AAAA
.count
;
1202 n
+= q
->initial_AAAA
.count
;
1203 q
->initial_AAAA
.count
=0;
1204 } else if (q
->initial_AAAA
.count
> 0 && n
<= 0) {
1205 /* initial of dual queries was the only result set. */
1206 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " AAAA has " << q
->initial_AAAA
.count
<< " RR, A has " << n
<< " RR");
1207 rfc1035RRDestroy(&(message
->answer
), n
);
1208 message
->answer
= q
->initial_AAAA
.answers
;
1209 n
= q
->initial_AAAA
.count
;
1211 /* else initial results were empty. just use the final set as authoritative */
1213 debugs(78, 6, HERE
<< "Sending " << n
<< " DNS results to caller.");
1214 idnsCallback(q
, message
->answer
, n
, rfc1035ErrorMessage(n
));
1215 rfc1035MessageDestroy(&message
);
1220 idnsRead(int fd
, void *data
)
1222 int *N
= &incoming_sockets_accepted
;
1224 int max
= INCOMING_DNS_MAX
;
1225 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1229 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1231 // Always keep reading. This stops (or at least makes harder) several
1232 // attacks on the DNS client.
1233 commSetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1236 * two code lines after returning from comm_udprecvfrom()
1237 * something overwrites the memory behind the from parameter.
1238 * NO matter where in the stack declaration list above it is placed
1239 * The cause of this is still unknown, however copying the data appears
1240 * to allow it to be passed further without this erasure.
1242 Ip::Address bugbypass
;
1245 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1247 from
= bugbypass
; // BUG BYPASS. see notes above.
1253 if (ignoreErrno(errno
))
1256 #ifdef _SQUID_LINUX_
1257 /* Some Linux systems seem to set the FD for reading and then
1258 * return ECONNREFUSED when sendto() fails and generates an ICMP
1259 * port unreachable message. */
1260 /* or maybe an EHOSTUNREACH "No route to host" message */
1261 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1264 debugs(50, 1, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1269 fd_bytes(fd
, len
, FD_READ
);
1274 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1276 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1277 ns
= idnsFromKnownNameserver(from
);
1280 nameservers
[ns
].nreplies
++;
1283 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1284 // but after the ++ above to keep statistics right.
1286 continue; // Don't process replies if there is no pending query.
1288 if (ns
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1289 static time_t last_warning
= 0;
1291 if (squid_curtime
- last_warning
> 60) {
1292 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
);
1293 last_warning
= squid_curtime
;
1295 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1300 idnsGrokReply(rbuf
, len
, ns
);
1305 idnsCheckQueue(void *unused
)
1308 dlink_node
*p
= NULL
;
1313 /* name servers went away; reconfiguring or shutting down */
1316 for (n
= lru_list
.tail
; n
; n
= p
) {
1319 q
= static_cast<idns_query
*>(n
->data
);
1321 /* Anything to process in the queue? */
1322 if (tvSubDsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1325 /* Query timer expired? */
1326 if (tvSubDsec(q
->sent_t
, current_time
) < Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
)) {
1327 dlinkDelete(&q
->lru
, &lru_list
);
1328 q
->queue_t
= current_time
;
1329 dlinkAdd(q
, &q
->lru
, &lru_list
);
1333 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1334 " QID 0x" << std::hex
<< std::setfill('0') <<
1335 std::setw(4) << q
->msg_id
<< ": timeout" );
1337 dlinkDelete(&q
->lru
, &lru_list
);
1339 if (tvSubDsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1342 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1343 " QID 0x" << std::hex
<< q
->msg_id
<<
1344 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1345 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1348 idnsCallback(q
, NULL
, -q
->rcode
, rfc1035ErrorMessage(q
->rcode
));
1350 idnsCallback(q
, NULL
, -16, "Timeout");
1360 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1362 nsvc
* vc
= (nsvc
*)data
;
1364 if (flag
== COMM_ERR_CLOSING
)
1367 if (flag
!= COMM_OK
|| len
<= 0) {
1368 if (Comm::IsConnOpen(conn
))
1373 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1375 if (vc
->msg
->contentSize() < vc
->msglen
) {
1376 comm_read(conn
, buf
+ len
, vc
->msglen
- vc
->msg
->contentSize(), idnsReadVC
, vc
);
1380 assert(vc
->ns
< nns
);
1381 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1383 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1385 comm_read(conn
, (char *)&vc
->msglen
, 2 , idnsReadVCHeader
, vc
);
1389 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1391 nsvc
* vc
= (nsvc
*)data
;
1393 if (flag
== COMM_ERR_CLOSING
)
1396 if (flag
!= COMM_OK
|| len
<= 0) {
1397 if (Comm::IsConnOpen(conn
))
1402 vc
->read_msglen
+= len
;
1404 assert(vc
->read_msglen
<= 2);
1406 if (vc
->read_msglen
< 2) {
1407 comm_read(conn
, buf
+ len
, 2 - vc
->read_msglen
, idnsReadVCHeader
, vc
);
1411 vc
->read_msglen
= 0;
1413 vc
->msglen
= ntohs(vc
->msglen
);
1415 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1416 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, idnsReadVC
, vc
);
1420 * rcode < 0 indicates an error, rocde >= 0 indicates success
1423 idnsRcodeCount(int rcode
, int attempt
)
1430 if (rcode
< MAX_RCODE
)
1431 if (attempt
< MAX_ATTEMPT
)
1432 RcodeMatrix
[rcode
][attempt
]++;
1435 /* ====================================================================== */
1438 idnsRegisterWithCacheManager(void)
1440 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1446 static int init
= 0;
1448 CBDATA_INIT_TYPE(nsvc
);
1449 CBDATA_INIT_TYPE(idns_query
);
1451 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1454 Ip::Address addrA
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1456 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
1457 addrA
= Config
.Addrs
.udp_outgoing
;
1459 addrA
= Config
.Addrs
.udp_incoming
;
1461 Ip::Address addrB
= addrA
;
1464 if (Ip::EnableIpv6
&& (addrB
.IsAnyAddr() || addrB
.IsIPv6())) {
1465 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrB
);
1466 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1473 if (addrA
.IsAnyAddr() || addrA
.IsIPv4()) {
1474 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrA
);
1475 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1482 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1483 fatal("Could not create a DNS socket");
1485 /* Ouch... we can't call functions using debug from a debug
1486 * statement. Doing so messes up the internal Debug::level
1488 if (DnsSocketB
>= 0) {
1489 port
= comm_local_port(DnsSocketB
);
1490 debugs(78, 1, "DNS Socket created at " << addrB
<< ", FD " << DnsSocketB
);
1491 commSetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1493 if (DnsSocketA
>= 0) {
1494 port
= comm_local_port(DnsSocketA
);
1495 debugs(78, 1, "DNS Socket created at " << addrA
<< ", FD " << DnsSocketA
);
1496 commSetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1501 idnsParseNameservers();
1502 #ifndef _SQUID_MSWIN_
1505 idnsParseResolvConf();
1508 #ifdef _SQUID_WIN32_
1511 idnsParseWIN32Registry();
1516 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
1517 #ifdef _SQUID_WIN32_
1519 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
1522 debugs(78, 1, "Please check your /etc/resolv.conf file");
1525 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1526 idnsAddNameserver("127.0.0.1");
1530 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1531 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1532 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1536 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1537 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1538 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1539 max_shared_edns
= -1; // disable if we might receive random replies.
1543 idnsRegisterWithCacheManager();
1549 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1552 if (DnsSocketA
>= 0 ) {
1553 comm_close(DnsSocketA
);
1557 if (DnsSocketB
>= 0 ) {
1558 comm_close(DnsSocketB
);
1562 for (int i
= 0; i
< nns
; i
++) {
1563 if (nsvc
*vc
= nameservers
[i
].vc
) {
1564 if (Comm::IsConnOpen(vc
->conn
))
1569 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1570 idnsFreeNameservers();
1571 idnsFreeSearchpath();
1575 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1579 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1584 q
= cbdataAlloc(idns_query
);
1585 // idns_query is POD so no constructors are called after allocation
1586 q
->xact_id
.change();
1588 q
->callback
= callback
;
1590 q
->callback_data
= cbdataReference(data
);
1592 q
->queue
= old
->queue
;
1600 idnsCacheQuery(idns_query
*q
)
1602 q
->hash
.key
= q
->query
.name
;
1603 hash_join(idns_lookup_hash
, &q
->hash
);
1607 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1613 if (idnsCachedLookup(name
, callback
, data
))
1616 q
= cbdataAlloc(idns_query
);
1617 // idns_query is POD so no constructors are called after allocation
1618 q
->xact_id
.change();
1620 for (i
= 0; i
< strlen(name
); i
++)
1624 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[strlen(name
)-1] != '.') {
1625 q
->do_searchpath
= 1;
1627 q
->do_searchpath
= 0;
1630 strcpy(q
->orig
, name
);
1631 strcpy(q
->name
, q
->orig
);
1633 if (q
->do_searchpath
&& nd
< ndots
) {
1635 strcat(q
->name
, ".");
1636 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1637 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1640 if (Ip::EnableIpv6
) {
1641 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1644 // see EDNS notes at top of file why this sends 0
1645 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1650 /* problem with query data -- query not sent */
1651 callback(data
, NULL
, 0, "Internal error");
1656 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1657 ", id = 0x" << std::hex
<< q
->msg_id
);
1659 q
->callback
= callback
;
1661 q
->callback_data
= cbdataReference(data
);
1669 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1673 char ip
[MAX_IPSTRLEN
];
1675 addr
.NtoA(ip
,MAX_IPSTRLEN
);
1677 q
= cbdataAlloc(idns_query
);
1679 // idns_query is POD so no constructors are called after allocation
1680 q
->xact_id
.change();
1682 if (Ip::EnableIpv6
&& addr
.IsIPv6()) {
1683 struct in6_addr addr6
;
1684 addr
.GetInAddr(addr6
);
1685 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1687 struct in_addr addr4
;
1688 addr
.GetInAddr(addr4
);
1689 // see EDNS notes at top of file why this sends 0
1690 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1693 /* PTR does not do inbound A/AAAA */
1697 /* problem with query data -- query not sent */
1698 callback(data
, NULL
, 0, "Internal error");
1703 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1708 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1709 ", id = 0x" << std::hex
<< q
->msg_id
);
1711 q
->callback
= callback
;
1713 q
->callback_data
= cbdataReference(data
);
1722 * The function to return the DNS via SNMP
1725 snmp_netIdnsFn(variable_list
* Var
, snint
* ErrP
)
1728 variable_list
*Answer
= NULL
;
1730 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1731 *ErrP
= SNMP_ERR_NOERROR
;
1733 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1737 for (i
= 0; i
< nns
; i
++)
1738 n
+= nameservers
[i
].nqueries
;
1740 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1747 for (i
= 0; i
< nns
; i
++)
1748 n
+= nameservers
[i
].nreplies
;
1750 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1757 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1764 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1772 #endif /*SQUID_SNMP */
1773 #endif /* USE_DNSSERVERS */