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 "comm/Connection.h"
37 #include "comm/ConnOpener.h"
39 #include "comm/Loops.h"
40 #include "comm/Write.h"
42 #include "SquidTime.h"
47 #include "mgr/Registration.h"
50 #include "base/InstanceId.h"
52 #if HAVE_ARPA_NAMESER_H
53 #include <arpa/nameser.h>
59 /* MS Visual Studio Projects are monolithic, so we need the following
60 #ifndef to exclude the internal DNS code from compile process when
61 using external DNS process.
65 #include "squid_windows.h"
66 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
67 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
68 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
71 #define _PATH_RESCONF "/etc/resolv.conf"
73 #ifndef NS_DEFAULTPORT
74 #define NS_DEFAULTPORT 53
78 #define NS_MAXDNAME 1025
85 /* The buffer size required to store the maximum allowed search path */
87 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
90 #define IDNS_MAX_TRIES 20
93 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
94 // NP: see http://www.iana.org/assignments/dns-parameters
95 static const char *Rcodes
[] = {
98 "Packet Format Error",
100 "Non-Existent Domain",
104 "Name Exists when it should not",
105 "RR Set Exists when it should not",
106 "RR Set that should exist does not",
107 "Server Not Authoritative for zone",
108 "Name not contained in zone",
112 "Bad OPT Version or TSIG Signature Failure"
115 typedef struct _idns_query idns_query
;
117 typedef struct _ns ns
;
119 typedef struct _sp sp
;
121 typedef struct _nsvc nsvc
;
126 char buf
[RESOLV_BUFSZ
];
127 char name
[NS_MAXDNAME
+ 1];
128 char orig
[NS_MAXDNAME
+ 1];
130 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
131 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
137 struct timeval start_t
;
138 struct timeval sent_t
;
139 struct timeval queue_t
;
146 idns_query
*slave
; // AAAA
147 idns_query
*master
; // A
148 unsigned short domain
;
149 unsigned short do_searchpath
;
150 rfc1035_message
*message
;
153 InstanceIdDefinitions(idns_query
, "dns");
157 Comm::ConnectionPointer conn
;
158 unsigned short msglen
;
169 #if WHEN_EDNS_RESPONSES_ARE_PARSED
176 char domain
[NS_MAXDNAME
];
181 CBDATA_TYPE(idns_query
);
183 static ns
*nameservers
= NULL
;
184 static sp
*searchpath
= NULL
;
186 static int nns_alloc
= 0;
188 static int npc_alloc
= 0;
189 static int ndots
= 1;
190 static dlink_list lru_list
;
191 static int event_queued
= 0;
192 static hash_table
*idns_lookup_hash
= NULL
;
198 * EDNS as specified may be sent as an additional record for any request.
199 * early testing has revealed that it works on common devices, but cannot
200 * be reliably used on any A or PTR requet done for IPv4 addresses.
202 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
205 * Squid is optimized to generate one packet and re-send it to all NS
206 * due to this we cannot customize the EDNS size per NS.
208 * As such we take the configuration option value as fixed.
211 * This may not be worth doing, but if/when additional-records are parsed
212 * we will be able to recover the OPT value specific to any one NS and
213 * cache it. Effectively automating the tuning of EDNS advertised to the
214 * size our active NS are capable.
215 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
216 * Responses from the configured NS may cause this to be raised or turned off.
218 #if WHEN_EDNS_RESPONSES_ARE_PARSED
219 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
222 static OBJH idnsStats
;
223 static void idnsAddNameserver(const char *buf
);
224 static void idnsAddPathComponent(const char *buf
);
225 static void idnsFreeNameservers(void);
226 static void idnsFreeSearchpath(void);
227 static void idnsParseNameservers(void);
229 static void idnsParseResolvConf(void);
232 static void idnsParseWIN32Registry(void);
233 static void idnsParseWIN32SearchList(const char *);
235 static void idnsCacheQuery(idns_query
* q
);
236 static void idnsSendQuery(idns_query
* q
);
237 static IOCB idnsReadVCHeader
;
238 static void idnsDoSendQueryVC(nsvc
*vc
);
239 static CNCB idnsInitVCConnected
;
240 static IOCB idnsReadVC
;
241 static IOCB idnsSentQueryVC
;
243 static int idnsFromKnownNameserver(Ip::Address
const &from
);
244 static idns_query
*idnsFindQuery(unsigned short id
);
245 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
247 static EVH idnsCheckQueue
;
248 static void idnsTickleQueue(void);
249 static void idnsRcodeCount(int, int);
250 static CLCB idnsVCClosed
;
251 static unsigned short idnsQueryID(void);
252 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
255 idnsAddNameserver(const char *buf
)
260 debugs(78, 0, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
265 debugs(78, 0, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
267 debugs(78, 0, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
270 if (!Ip::EnableIpv6
&& !A
.SetIPv4()) {
271 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
275 if (nns
== nns_alloc
) {
276 int oldalloc
= nns_alloc
;
277 ns
*oldptr
= nameservers
;
284 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
286 if (oldptr
&& oldalloc
)
287 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
293 assert(nns
< nns_alloc
);
294 A
.SetPort(NS_DEFAULTPORT
);
295 nameservers
[nns
].S
= A
;
296 #if WHEN_EDNS_RESPONSES_ARE_PARSED
297 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
298 // TODO generate a test packet to probe this NS from EDNS size and ability.
300 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
305 idnsAddPathComponent(const char *buf
)
307 if (npc
== npc_alloc
) {
308 int oldalloc
= npc_alloc
;
309 sp
*oldptr
= searchpath
;
316 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
318 if (oldptr
&& oldalloc
)
319 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
325 assert(npc
< npc_alloc
);
326 strcpy(searchpath
[npc
].domain
, buf
);
327 Tolower(searchpath
[npc
].domain
);
328 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
334 idnsFreeNameservers(void)
336 safe_free(nameservers
);
341 idnsFreeSearchpath(void)
343 safe_free(searchpath
);
350 idnsParseNameservers(void)
354 for (w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
355 debugs(78, 1, "Adding nameserver " << w
->key
<< " from squid.conf");
356 idnsAddNameserver(w
->key
);
362 idnsParseResolvConf(void)
365 char buf
[RESOLV_BUFSZ
];
367 fp
= fopen(_PATH_RESCONF
, "r");
370 debugs(78, 1, "" << _PATH_RESCONF
<< ": " << xstrerror());
375 setmode(fileno(fp
), O_TEXT
);
378 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
379 t
= strtok(buf
, w_space
);
383 } else if (strcasecmp(t
, "nameserver") == 0) {
384 t
= strtok(NULL
, w_space
);
389 debugs(78, 1, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
391 idnsAddNameserver(t
);
392 } else if (strcasecmp(t
, "domain") == 0) {
393 idnsFreeSearchpath();
394 t
= strtok(NULL
, w_space
);
399 debugs(78, 1, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
401 idnsAddPathComponent(t
);
402 } else if (strcasecmp(t
, "search") == 0) {
403 idnsFreeSearchpath();
405 t
= strtok(NULL
, w_space
);
410 debugs(78, 1, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
412 idnsAddPathComponent(t
);
414 } else if (strcasecmp(t
, "options") == 0) {
416 t
= strtok(NULL
, w_space
);
421 if (strncmp(t
, "ndots:", 6) == 0) {
427 debugs(78, 1, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
432 if (npc
== 0 && (t
= getMyHostname())) {
435 idnsAddPathComponent(t
+1);
445 idnsParseWIN32SearchList(const char * Separator
)
451 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
455 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
457 if (Result
== ERROR_SUCCESS
&& Size
) {
458 t
= (char *) xmalloc(Size
);
459 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
460 debugs(78, 1, "Adding domain " << t
<< " from Registry");
461 idnsAddPathComponent(t
);
464 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
466 if (Result
== ERROR_SUCCESS
&& Size
) {
467 t
= (char *) xmalloc(Size
);
468 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
469 token
= strtok(t
, Separator
);
472 idnsAddPathComponent(token
);
473 debugs(78, 1, "Adding domain " << token
<< " from Registry");
474 token
= strtok(NULL
, Separator
);
481 if (npc
== 0 && (t
= (char *) getMyHostname())) {
484 idnsAddPathComponent(t
+ 1);
489 idnsParseWIN32Registry(void)
493 HKEY hndKey
, hndKey2
;
495 switch (WIN32_OS_version
) {
498 /* get nameservers from the Windows NT registry */
500 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
504 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
506 if (Result
== ERROR_SUCCESS
&& Size
) {
507 t
= (char *) xmalloc(Size
);
508 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
509 token
= strtok(t
, ", ");
512 idnsAddNameserver(token
);
513 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
514 token
= strtok(NULL
, ",");
519 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
521 if (Result
== ERROR_SUCCESS
&& Size
) {
522 t
= (char *) xmalloc(Size
);
523 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
524 token
= strtok(t
, ", ");
527 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
528 idnsAddNameserver(token
);
529 token
= strtok(NULL
, ", ");
537 idnsParseWIN32SearchList(" ");
550 /* get nameservers from the Windows 2000 registry */
551 /* search all interfaces for DNS server addresses */
553 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
555 DWORD MaxSubkeyLen
, InterfacesCount
;
557 FILETIME ftLastWriteTime
;
559 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
560 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
561 for (i
= 0; i
< (int) InterfacesCount
; i
++) {
564 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
566 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
567 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
568 strcat(newkeyname
, "\\");
569 strcat(newkeyname
, keyname
);
570 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
574 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
575 if (Result
== ERROR_SUCCESS
&& Size
) {
576 t
= (char *) xmalloc(Size
);
577 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
578 token
= strtok(t
, ", ");
580 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
581 idnsAddNameserver(token
);
582 token
= strtok(NULL
, ", ");
587 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
588 if (Result
== ERROR_SUCCESS
&& Size
) {
589 t
= (char *) xmalloc(Size
);
590 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
591 token
= strtok(t
, ", ");
593 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
594 idnsAddNameserver(token
);
595 token
= strtok(NULL
, ", ");
601 RegCloseKey(hndKey2
);
614 idnsParseWIN32SearchList(", ");
623 /* get nameservers from the Windows 9X registry */
625 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
629 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
631 if (Result
== ERROR_SUCCESS
&& Size
) {
632 t
= (char *) xmalloc(Size
);
633 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
634 token
= strtok(t
, ", ");
637 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
638 idnsAddNameserver(token
);
639 token
= strtok(NULL
, ", ");
650 debugs(78, 1, "Failed to read nameserver from Registry: Unknown System Type.");
658 idnsStats(StoreEntry
* sentry
)
664 char buf
[MAX_IPSTRLEN
];
665 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
666 storeAppendPrintf(sentry
, "\nThe Queue:\n");
667 storeAppendPrintf(sentry
, " DELAY SINCE\n");
668 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND\n");
669 storeAppendPrintf(sentry
, "------ ---- ----- ---------- ---------\n");
671 for (n
= lru_list
.head
; n
; n
= n
->next
) {
672 q
= (idns_query
*)n
->data
;
673 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f\n",
674 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
675 tvSubDsec(q
->start_t
, current_time
),
676 tvSubDsec(q
->sent_t
, current_time
));
679 if (Config
.dns
.packet_max
> 0)
680 storeAppendPrintf(sentry
, "DNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
682 storeAppendPrintf(sentry
, "DNS jumbo-grams: not working\n");
684 storeAppendPrintf(sentry
, "\nNameservers:\n");
685 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES\n");
686 storeAppendPrintf(sentry
, "---------------------------------------------- --------- ---------\n");
688 for (i
= 0; i
< nns
; i
++) {
689 storeAppendPrintf(sentry
, "%-45s %9d %9d\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
690 nameservers
[i
].S
.NtoA(buf
,MAX_IPSTRLEN
),
691 nameservers
[i
].nqueries
,
692 nameservers
[i
].nreplies
);
695 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
696 storeAppendPrintf(sentry
, "RCODE");
698 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
699 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
701 storeAppendPrintf(sentry
, " PROBLEM\n");
703 for (j
= 0; j
< MAX_RCODE
; j
++) {
704 if (j
> 10 && j
< 16)
705 continue; // unassigned by IANA.
707 storeAppendPrintf(sentry
, "%5d", j
);
709 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
710 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
712 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
716 storeAppendPrintf(sentry
, "\nSearch list:\n");
718 for (i
=0; i
< npc
; i
++)
719 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
721 storeAppendPrintf(sentry
, "\n");
726 idnsTickleQueue(void)
731 if (NULL
== lru_list
.tail
)
734 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
736 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
742 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
744 nsvc
* vc
= (nsvc
*)data
;
746 if (flag
== COMM_ERR_CLOSING
)
749 // XXX: irrelevant now that we have conn pointer?
750 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
753 if (flag
!= COMM_OK
|| size
<= 0) {
759 idnsDoSendQueryVC(vc
);
763 idnsDoSendQueryVC(nsvc
*vc
)
768 if (vc
->queue
->contentSize() == 0)
771 // if retrying after a TC UDP response, our close handler cb may be pending
772 if (fd_table
[vc
->conn
->fd
].closing())
775 MemBuf
*mb
= vc
->queue
;
777 vc
->queue
= new MemBuf
;
781 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
782 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
783 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
784 AsyncCall::Pointer nil
;
786 commSetConnTimeout(vc
->conn
, timeout
, nil
);
788 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
789 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
790 Comm::Write(vc
->conn
, mb
, call
);
796 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
798 nsvc
* vc
= (nsvc
*)data
;
800 if (status
!= COMM_OK
|| !conn
) {
801 char buf
[MAX_IPSTRLEN
] = "";
803 nameservers
[vc
->ns
].S
.NtoA(buf
,MAX_IPSTRLEN
);
804 debugs(78, 1, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
810 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
811 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
812 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
813 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
815 idnsDoSendQueryVC(vc
);
819 idnsVCClosed(const CommCloseCbParams
¶ms
)
821 nsvc
* vc
= (nsvc
*)params
.data
;
825 if (vc
->ns
< nns
) // XXX: dnsShutdown may have freed nameservers[]
826 nameservers
[vc
->ns
].vc
= NULL
;
833 nsvc
*vc
= cbdataAlloc(nsvc
);
835 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
836 nameservers
[ns
].vc
= vc
;
838 vc
->queue
= new MemBuf
;
839 vc
->msg
= new MemBuf
;
842 Comm::ConnectionPointer conn
= new Comm::Connection();
844 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
845 conn
->local
= Config
.Addrs
.udp_outgoing
;
847 conn
->local
= Config
.Addrs
.udp_incoming
;
849 conn
->remote
= nameservers
[ns
].S
;
851 if (conn
->remote
.IsIPv4()) {
852 conn
->local
.SetIPv4();
855 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
857 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
858 cs
->setHost("DNS TCP Socket");
863 idnsSendQueryVC(idns_query
* q
, int ns
)
866 if (nameservers
[ns
].vc
== NULL
)
869 nsvc
*vc
= nameservers
[ns
].vc
;
872 char buf
[MAX_IPSTRLEN
];
873 debugs(78, 1, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[ns
].S
.NtoA(buf
,MAX_IPSTRLEN
) << "!");
880 short head
= htons(q
->sz
);
882 vc
->queue
->append((char *)&head
, 2);
884 vc
->queue
->append(q
->buf
, q
->sz
);
886 idnsDoSendQueryVC(vc
);
890 idnsSendQuery(idns_query
* q
)
892 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
893 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
898 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
902 assert(q
->lru
.next
== NULL
);
904 assert(q
->lru
.prev
== NULL
);
909 q
->start_t
= current_time
;
912 ns
= q
->nsends
% nns
;
915 idnsSendQueryVC(q
, ns
);
918 if (DnsSocketB
>= 0 && nameservers
[ns
].S
.IsIPv6())
919 y
= comm_udp_sendto(DnsSocketB
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
920 else if (DnsSocketA
>= 0)
921 x
= comm_udp_sendto(DnsSocketA
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
926 q
->queue_t
= q
->sent_t
= current_time
;
928 if (y
< 0 && nameservers
[ns
].S
.IsIPv6())
929 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
930 if (x
< 0 && nameservers
[ns
].S
.IsIPv4())
931 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
933 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
936 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
939 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
942 nameservers
[ns
].nqueries
++;
943 q
->queue_t
= current_time
;
944 dlinkAdd(q
, &q
->lru
, &lru_list
);
950 idnsFromKnownNameserver(Ip::Address
const &from
)
954 for (i
= 0; i
< nns
; i
++) {
955 if (nameservers
[i
].S
!= from
)
958 if (nameservers
[i
].S
.GetPort() != from
.GetPort())
968 idnsFindQuery(unsigned short id
)
973 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
974 q
= (idns_query
*)n
->data
;
976 if (q
->query_id
== id
)
983 static unsigned short
986 unsigned short id
= squid_random() & 0xFFFF;
987 unsigned short first_id
= id
;
989 while (idnsFindQuery(id
)) {
992 if (id
== first_id
) {
993 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
1002 idnsCallback(idns_query
*q
, rfc1035_rr
*answers
, int n
, const char *error
)
1007 callback
= q
->callback
;
1010 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1011 callback(cbdata
, answers
, n
, error
);
1014 idns_query
*q2
= q
->queue
;
1015 q
->queue
= q2
->queue
;
1016 callback
= q2
->callback
;
1017 q2
->callback
= NULL
;
1019 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1020 callback(cbdata
, answers
, n
, error
);
1026 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1032 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1035 rfc1035_message
*message
= NULL
;
1038 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1040 if (message
== NULL
) {
1041 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
1045 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1047 q
= idnsFindQuery(message
->id
);
1050 debugs(78, 3, "idnsGrokReply: Late response");
1051 rfc1035MessageDestroy(&message
);
1055 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1056 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1057 rfc1035MessageDestroy(&message
);
1061 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1062 // TODO: actually gr the message right here.
1063 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1064 // this is overall better than force-feeding A response with AAAA an section later anyway.
1065 // AND allows us to merge AN+AR sections from both responses (one day)
1067 if (q
->edns_seen
>= 0) {
1068 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1069 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1070 // the altered NS was limiting the whole group.
1071 max_shared_edns
= q
->edns_seen
;
1072 // may be limited by one of the others still
1073 for (int i
= 0; i
< nns
; i
++)
1074 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1076 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1077 // maybe reduce the global limit downwards to accomodate this NS
1078 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1080 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1081 max_shared_edns
= -1;
1085 dlinkDelete(&q
->lru
, &lru_list
);
1089 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1090 rfc1035MessageDestroy(&message
);
1097 // Strange: A TCP DNS response with the truncation bit (TC) set.
1098 // Return an error and cleanup; no point in trying TCP again.
1099 debugs(78, 3, HERE
<< "TCP DNS response");
1100 idnsCallback(q
, NULL
, 0, "Truncated TCP DNS response");
1107 idnsRcodeCount(n
, q
->attempt
);
1111 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1113 if (q
->rcode
== 2 && ++q
->attempt
< MAX_ATTEMPT
) {
1115 * RCODE 2 is "Server failure - The name server was
1116 * unable to process this query due to a problem with
1119 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1120 rfc1035MessageDestroy(&message
);
1125 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1126 assert(NULL
== message
->answer
);
1127 strcpy(q
->name
, q
->orig
);
1129 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1131 if (q
->domain
< npc
) {
1132 strcat(q
->name
, ".");
1133 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1134 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1140 rfc1035MessageDestroy(&message
);
1142 // cleanup stale AAAA query
1143 while (idns_query
*slave
= q
->slave
) {
1144 dlinkDelete(&slave
->lru
, &lru_list
);
1145 q
->slave
= slave
->slave
;
1146 rfc1035MessageDestroy(&slave
->message
);
1151 q
->query_id
= idnsQueryID();
1152 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1153 // see EDNS notes at top of file why this sends 0
1154 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1156 /* problem with query data -- query not sent */
1157 idnsCallback(static_cast<idns_query
*>(q
->callback_data
), NULL
, 0, "Internal error");
1164 idnsSendSlaveAAAAQuery(q
);
1169 q
->message
= message
;
1176 // If any of our subqueries are still pending then wait for them to complete before continuing
1177 for ( q2
= q
; q2
; q2
= q2
->slave
) {
1184 message
= q
->message
;
1187 while ( (q2
= q
->slave
) ) {
1188 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1189 q
->slave
= q2
->slave
;
1190 if ( q2
->ancount
>= 0 ) {
1192 // two sets of RR need merging
1193 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1194 if (Config
.dns
.v4_first
) {
1195 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1196 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1198 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1199 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1202 safe_free(message
->answer
);
1203 message
->answer
= result
;
1204 message
->ancount
+= q2
->message
->ancount
;
1205 safe_free(q2
->message
->answer
);
1206 q2
->message
->answer
= NULL
;
1207 } else if (n
< 0 || q2
->ancount
> 0) {
1208 // first set empty / failed
1209 rfc1035MessageDestroy(&message
);
1210 message
= q
->message
= q2
->message
;
1215 rfc1035MessageDestroy(&q2
->message
);
1219 debugs(78, 6, HERE
<< "Sending " << n
<< " DNS results to caller.");
1220 idnsCallback(q
, message
->answer
, n
, rfc1035ErrorMessage(n
));
1221 rfc1035MessageDestroy(&message
);
1226 idnsRead(int fd
, void *data
)
1228 int *N
= &incoming_sockets_accepted
;
1230 int max
= INCOMING_DNS_MAX
;
1231 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1235 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1237 // Always keep reading. This stops (or at least makes harder) several
1238 // attacks on the DNS client.
1239 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1242 * two code lines after returning from comm_udprecvfrom()
1243 * something overwrites the memory behind the from parameter.
1244 * NO matter where in the stack declaration list above it is placed
1245 * The cause of this is still unknown, however copying the data appears
1246 * to allow it to be passed further without this erasure.
1248 Ip::Address bugbypass
;
1251 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1253 from
= bugbypass
; // BUG BYPASS. see notes above.
1259 if (ignoreErrno(errno
))
1263 /* Some Linux systems seem to set the FD for reading and then
1264 * return ECONNREFUSED when sendto() fails and generates an ICMP
1265 * port unreachable message. */
1266 /* or maybe an EHOSTUNREACH "No route to host" message */
1267 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1270 debugs(50, 1, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1275 fd_bytes(fd
, len
, FD_READ
);
1280 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1282 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1283 ns
= idnsFromKnownNameserver(from
);
1286 nameservers
[ns
].nreplies
++;
1289 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1290 // but after the ++ above to keep statistics right.
1292 continue; // Don't process replies if there is no pending query.
1294 if (ns
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1295 static time_t last_warning
= 0;
1297 if (squid_curtime
- last_warning
> 60) {
1298 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
);
1299 last_warning
= squid_curtime
;
1301 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1306 idnsGrokReply(rbuf
, len
, ns
);
1311 idnsCheckQueue(void *unused
)
1314 dlink_node
*p
= NULL
;
1319 /* name servers went away; reconfiguring or shutting down */
1322 for (n
= lru_list
.tail
; n
; n
= p
) {
1325 q
= static_cast<idns_query
*>(n
->data
);
1327 /* Anything to process in the queue? */
1328 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1331 /* Query timer expired? */
1332 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1333 dlinkDelete(&q
->lru
, &lru_list
);
1334 q
->queue_t
= current_time
;
1335 dlinkAdd(q
, &q
->lru
, &lru_list
);
1339 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1340 " QID 0x" << std::hex
<< std::setfill('0') <<
1341 std::setw(4) << q
->query_id
<< ": timeout" );
1343 dlinkDelete(&q
->lru
, &lru_list
);
1345 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1348 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1349 " QID 0x" << std::hex
<< q
->query_id
<<
1350 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1351 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1354 idnsCallback(q
, NULL
, -q
->rcode
, rfc1035ErrorMessage(q
->rcode
));
1356 idnsCallback(q
, NULL
, -16, "Timeout");
1366 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1368 nsvc
* vc
= (nsvc
*)data
;
1370 if (flag
== COMM_ERR_CLOSING
)
1373 if (flag
!= COMM_OK
|| len
<= 0) {
1374 if (Comm::IsConnOpen(conn
))
1379 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1381 if (vc
->msg
->contentSize() < vc
->msglen
) {
1382 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1383 CommIoCbPtrFun(idnsReadVC
, vc
));
1384 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1388 assert(vc
->ns
< nns
);
1389 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1391 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1393 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1394 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1395 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1399 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1401 nsvc
* vc
= (nsvc
*)data
;
1403 if (flag
== COMM_ERR_CLOSING
)
1406 if (flag
!= COMM_OK
|| len
<= 0) {
1407 if (Comm::IsConnOpen(conn
))
1412 vc
->read_msglen
+= len
;
1414 assert(vc
->read_msglen
<= 2);
1416 if (vc
->read_msglen
< 2) {
1417 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1418 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1419 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1423 vc
->read_msglen
= 0;
1425 vc
->msglen
= ntohs(vc
->msglen
);
1427 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1428 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1429 CommIoCbPtrFun(idnsReadVC
, vc
));
1430 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1434 * rcode < 0 indicates an error, rocde >= 0 indicates success
1437 idnsRcodeCount(int rcode
, int attempt
)
1444 if (rcode
< MAX_RCODE
)
1445 if (attempt
< MAX_ATTEMPT
)
1446 RcodeMatrix
[rcode
][attempt
]++;
1449 /* ====================================================================== */
1452 idnsRegisterWithCacheManager(void)
1454 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1460 static int init
= 0;
1462 CBDATA_INIT_TYPE(nsvc
);
1463 CBDATA_INIT_TYPE(idns_query
);
1465 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1466 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1468 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
1469 addrV6
= Config
.Addrs
.udp_outgoing
;
1471 addrV6
= Config
.Addrs
.udp_incoming
;
1473 Ip::Address addrV4
= addrV6
;
1476 if (Ip::EnableIpv6
&& addrV6
.IsIPv6()) {
1477 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1478 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1485 if (addrV4
.IsIPv4()) {
1486 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1487 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1494 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1495 fatal("Could not create a DNS socket");
1497 /* Ouch... we can't call functions using debug from a debug
1498 * statement. Doing so messes up the internal Debug::level
1500 if (DnsSocketB
>= 0) {
1501 comm_local_port(DnsSocketB
);
1502 debugs(78, 1, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1503 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1505 if (DnsSocketA
>= 0) {
1506 comm_local_port(DnsSocketA
);
1507 debugs(78, 1, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1508 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1513 idnsParseNameservers();
1517 idnsParseResolvConf();
1522 idnsParseWIN32Registry();
1526 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
1528 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
1530 debugs(78, 1, "Please check your /etc/resolv.conf file");
1533 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1534 idnsAddNameserver("127.0.0.1");
1538 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1539 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1540 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1544 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1545 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1546 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1547 max_shared_edns
= -1; // disable if we might receive random replies.
1551 idnsRegisterWithCacheManager();
1557 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1560 if (DnsSocketA
>= 0 ) {
1561 comm_close(DnsSocketA
);
1565 if (DnsSocketB
>= 0 ) {
1566 comm_close(DnsSocketB
);
1570 for (int i
= 0; i
< nns
; i
++) {
1571 if (nsvc
*vc
= nameservers
[i
].vc
) {
1572 if (Comm::IsConnOpen(vc
->conn
))
1577 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1578 idnsFreeNameservers();
1579 idnsFreeSearchpath();
1583 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1587 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1592 q
= cbdataAlloc(idns_query
);
1593 // idns_query is POD so no constructors are called after allocation
1594 q
->xact_id
.change();
1595 // no query_id on this instance.
1597 q
->callback
= callback
;
1599 q
->callback_data
= cbdataReference(data
);
1601 q
->queue
= old
->queue
;
1609 idnsCacheQuery(idns_query
*q
)
1611 q
->hash
.key
= q
->orig
;
1612 hash_join(idns_lookup_hash
, &q
->hash
);
1616 idnsSendSlaveAAAAQuery(idns_query
*master
)
1618 idns_query
*q
= cbdataAlloc(idns_query
);
1619 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1620 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1622 q
->query_id
= idnsQueryID();
1623 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1624 q
->slave
= master
->slave
;
1626 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1627 ", id = 0x" << std::hex
<< q
->query_id
);
1637 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1643 if (idnsCachedLookup(name
, callback
, data
))
1646 q
= cbdataAlloc(idns_query
);
1647 // idns_query is POD so no constructors are called after allocation
1648 q
->xact_id
.change();
1649 q
->query_id
= idnsQueryID();
1651 for (i
= 0; i
< strlen(name
); i
++)
1655 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[strlen(name
)-1] != '.') {
1656 q
->do_searchpath
= 1;
1658 q
->do_searchpath
= 0;
1661 strcpy(q
->orig
, name
);
1662 strcpy(q
->name
, q
->orig
);
1664 if (q
->do_searchpath
&& nd
< ndots
) {
1666 strcat(q
->name
, ".");
1667 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1668 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1671 // see EDNS notes at top of file why this sends 0
1672 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1675 /* problem with query data -- query not sent */
1676 callback(data
, NULL
, 0, "Internal error");
1681 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1682 ", id = 0x" << std::hex
<< q
->query_id
);
1684 q
->callback
= callback
;
1685 q
->callback_data
= cbdataReference(data
);
1691 idnsSendSlaveAAAAQuery(q
);
1696 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1700 char ip
[MAX_IPSTRLEN
];
1702 addr
.NtoA(ip
,MAX_IPSTRLEN
);
1704 q
= cbdataAlloc(idns_query
);
1706 // idns_query is POD so no constructors are called after allocation
1707 q
->xact_id
.change();
1708 q
->query_id
= idnsQueryID();
1710 if (addr
.IsIPv6()) {
1711 struct in6_addr addr6
;
1712 addr
.GetInAddr(addr6
);
1713 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1715 struct in_addr addr4
;
1716 addr
.GetInAddr(addr4
);
1717 // see EDNS notes at top of file why this sends 0
1718 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1722 /* problem with query data -- query not sent */
1723 callback(data
, NULL
, 0, "Internal error");
1728 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1733 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1734 ", id = 0x" << std::hex
<< q
->query_id
);
1736 q
->callback
= callback
;
1737 q
->callback_data
= cbdataReference(data
);
1745 * The function to return the DNS via SNMP
1748 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1751 variable_list
*Answer
= NULL
;
1753 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1754 *ErrP
= SNMP_ERR_NOERROR
;
1756 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1760 for (i
= 0; i
< nns
; i
++)
1761 n
+= nameservers
[i
].nqueries
;
1763 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1770 for (i
= 0; i
< nns
; i
++)
1771 n
+= nameservers
[i
].nreplies
;
1773 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1780 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1787 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1795 #endif /*SQUID_SNMP */
1796 #endif /* USE_DNSHELPER */