2 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
3 * AUTHOR: Duane Wessels
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "base/InstanceId.h"
35 #include "comm/Connection.h"
36 #include "comm/ConnOpener.h"
38 #include "comm/Loops.h"
39 #include "comm/Write.h"
46 #include "mgr/Registration.h"
48 #include "SquidConfig.h"
49 #include "SquidTime.h"
56 #include "snmp_core.h"
59 #if HAVE_ARPA_NAMESER_H
60 #include <arpa/nameser.h>
69 /* MS Visual Studio Projects are monolithic, so we need the following
70 #ifndef to exclude the internal DNS code from compile process when
71 using external DNS process.
75 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
76 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
77 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
80 #define _PATH_RESCONF "/etc/resolv.conf"
82 #ifndef NS_DEFAULTPORT
83 #define NS_DEFAULTPORT 53
87 #define NS_MAXDNAME 1025
94 /* The buffer size required to store the maximum allowed search path */
96 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
99 #define IDNS_MAX_TRIES 20
101 #define MAX_ATTEMPT 3
102 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
103 // NP: see http://www.iana.org/assignments/dns-parameters
104 static const char *Rcodes
[] = {
107 "Packet Format Error",
108 "DNS Server Failure",
109 "Non-Existent Domain",
113 "Name Exists when it should not",
114 "RR Set Exists when it should not",
115 "RR Set that should exist does not",
116 "Server Not Authoritative for zone",
117 "Name not contained in zone",
121 "Bad OPT Version or TSIG Signature Failure"
124 typedef struct _idns_query idns_query
;
126 typedef struct _ns ns
;
128 typedef struct _sp sp
;
130 typedef struct _nsvc nsvc
;
135 char buf
[RESOLV_BUFSZ
];
136 char name
[NS_MAXDNAME
+ 1];
137 char orig
[NS_MAXDNAME
+ 1];
139 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
140 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
146 struct timeval start_t
;
147 struct timeval sent_t
;
148 struct timeval queue_t
;
155 idns_query
*slave
; // single linked list
156 idns_query
*master
; // single pointer to a shared master
157 unsigned short domain
;
158 unsigned short do_searchpath
;
159 rfc1035_message
*message
;
163 InstanceIdDefinitions(idns_query
, "dns");
167 Comm::ConnectionPointer conn
;
168 unsigned short msglen
;
179 #if WHEN_EDNS_RESPONSES_ARE_PARSED
186 char domain
[NS_MAXDNAME
];
191 CBDATA_TYPE(idns_query
);
193 static ns
*nameservers
= NULL
;
194 static sp
*searchpath
= NULL
;
196 static int nns_alloc
= 0;
198 static int npc_alloc
= 0;
199 static int ndots
= 1;
200 static dlink_list lru_list
;
201 static int event_queued
= 0;
202 static hash_table
*idns_lookup_hash
= NULL
;
208 * EDNS as specified may be sent as an additional record for any request.
209 * early testing has revealed that it works on common devices, but cannot
210 * be reliably used on any A or PTR requet done for IPv4 addresses.
212 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
215 * Squid is optimized to generate one packet and re-send it to all NS
216 * due to this we cannot customize the EDNS size per NS.
218 * As such we take the configuration option value as fixed.
221 * This may not be worth doing, but if/when additional-records are parsed
222 * we will be able to recover the OPT value specific to any one NS and
223 * cache it. Effectively automating the tuning of EDNS advertised to the
224 * size our active NS are capable.
225 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
226 * Responses from the configured NS may cause this to be raised or turned off.
228 #if WHEN_EDNS_RESPONSES_ARE_PARSED
229 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
232 static OBJH idnsStats
;
233 static void idnsAddNameserver(const char *buf
);
234 static void idnsAddPathComponent(const char *buf
);
235 static void idnsFreeNameservers(void);
236 static void idnsFreeSearchpath(void);
237 static void idnsParseNameservers(void);
239 static void idnsParseResolvConf(void);
242 static void idnsParseWIN32Registry(void);
243 static void idnsParseWIN32SearchList(const char *);
245 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
246 static void idnsSendQuery(idns_query
* q
);
247 static IOCB idnsReadVCHeader
;
248 static void idnsDoSendQueryVC(nsvc
*vc
);
249 static CNCB idnsInitVCConnected
;
250 static IOCB idnsReadVC
;
251 static IOCB idnsSentQueryVC
;
253 static int idnsFromKnownNameserver(Ip::Address
const &from
);
254 static idns_query
*idnsFindQuery(unsigned short id
);
255 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
257 static EVH idnsCheckQueue
;
258 static void idnsTickleQueue(void);
259 static void idnsRcodeCount(int, int);
260 static CLCB idnsVCClosed
;
261 static unsigned short idnsQueryID(void);
262 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
265 idnsAddNameserver(const char *buf
)
270 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
275 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
277 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
280 if (!Ip::EnableIpv6
&& !A
.SetIPv4()) {
281 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
285 if (nns
== nns_alloc
) {
286 int oldalloc
= nns_alloc
;
287 ns
*oldptr
= nameservers
;
294 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
296 if (oldptr
&& oldalloc
)
297 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
303 assert(nns
< nns_alloc
);
304 A
.SetPort(NS_DEFAULTPORT
);
305 nameservers
[nns
].S
= A
;
306 #if WHEN_EDNS_RESPONSES_ARE_PARSED
307 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
308 // TODO generate a test packet to probe this NS from EDNS size and ability.
310 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
315 idnsAddPathComponent(const char *buf
)
317 if (npc
== npc_alloc
) {
318 int oldalloc
= npc_alloc
;
319 sp
*oldptr
= searchpath
;
326 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
328 if (oldptr
&& oldalloc
)
329 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
335 assert(npc
< npc_alloc
);
336 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
337 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
338 Tolower(searchpath
[npc
].domain
);
339 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
344 idnsFreeNameservers(void)
346 safe_free(nameservers
);
351 idnsFreeSearchpath(void)
353 safe_free(searchpath
);
358 idnsParseNameservers(void)
362 for (w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
363 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
364 idnsAddNameserver(w
->key
);
370 idnsParseResolvConf(void)
373 char buf
[RESOLV_BUFSZ
];
375 fp
= fopen(_PATH_RESCONF
, "r");
378 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
383 setmode(fileno(fp
), O_TEXT
);
386 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
387 t
= strtok(buf
, w_space
);
391 } else if (strcasecmp(t
, "nameserver") == 0) {
392 t
= strtok(NULL
, w_space
);
397 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
399 idnsAddNameserver(t
);
400 } else if (strcasecmp(t
, "domain") == 0) {
401 idnsFreeSearchpath();
402 t
= strtok(NULL
, w_space
);
407 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
409 idnsAddPathComponent(t
);
410 } else if (strcasecmp(t
, "search") == 0) {
411 idnsFreeSearchpath();
413 t
= strtok(NULL
, w_space
);
418 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
420 idnsAddPathComponent(t
);
422 } else if (strcasecmp(t
, "options") == 0) {
424 t
= strtok(NULL
, w_space
);
429 if (strncmp(t
, "ndots:", 6) == 0) {
435 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
440 if (npc
== 0 && (t
= getMyHostname())) {
443 idnsAddPathComponent(t
+1);
453 idnsParseWIN32SearchList(const char * Separator
)
459 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
463 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
465 if (Result
== ERROR_SUCCESS
&& Size
) {
466 t
= (char *) xmalloc(Size
);
467 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
468 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
469 idnsAddPathComponent(t
);
472 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
474 if (Result
== ERROR_SUCCESS
&& Size
) {
475 t
= (char *) xmalloc(Size
);
476 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
477 token
= strtok(t
, Separator
);
480 idnsAddPathComponent(token
);
481 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
482 token
= strtok(NULL
, Separator
);
489 if (npc
== 0 && (t
= (char *) getMyHostname())) {
492 idnsAddPathComponent(t
+ 1);
497 idnsParseWIN32Registry(void)
501 HKEY hndKey
, hndKey2
;
503 switch (WIN32_OS_version
) {
506 /* get nameservers from the Windows NT registry */
508 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
512 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
514 if (Result
== ERROR_SUCCESS
&& Size
) {
515 t
= (char *) xmalloc(Size
);
516 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
517 token
= strtok(t
, ", ");
520 idnsAddNameserver(token
);
521 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
522 token
= strtok(NULL
, ",");
527 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
529 if (Result
== ERROR_SUCCESS
&& Size
) {
530 t
= (char *) xmalloc(Size
);
531 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
532 token
= strtok(t
, ", ");
535 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
536 idnsAddNameserver(token
);
537 token
= strtok(NULL
, ", ");
545 idnsParseWIN32SearchList(" ");
558 /* get nameservers from the Windows 2000 registry */
559 /* search all interfaces for DNS server addresses */
561 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
563 DWORD MaxSubkeyLen
, InterfacesCount
;
565 FILETIME ftLastWriteTime
;
567 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
568 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
569 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
572 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
574 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
575 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
576 strcat(newkeyname
, "\\");
577 strcat(newkeyname
, keyname
);
578 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
582 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
583 if (Result
== ERROR_SUCCESS
&& Size
) {
584 t
= (char *) xmalloc(Size
);
585 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
586 token
= strtok(t
, ", ");
588 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
589 idnsAddNameserver(token
);
590 token
= strtok(NULL
, ", ");
595 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
596 if (Result
== ERROR_SUCCESS
&& Size
) {
597 t
= (char *) xmalloc(Size
);
598 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
599 token
= strtok(t
, ", ");
601 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
602 idnsAddNameserver(token
);
603 token
= strtok(NULL
, ", ");
609 RegCloseKey(hndKey2
);
622 idnsParseWIN32SearchList(", ");
631 /* get nameservers from the Windows 9X registry */
633 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
637 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
639 if (Result
== ERROR_SUCCESS
&& Size
) {
640 t
= (char *) xmalloc(Size
);
641 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
642 token
= strtok(t
, ", ");
645 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
646 idnsAddNameserver(token
);
647 token
= strtok(NULL
, ", ");
658 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
666 idnsStats(StoreEntry
* sentry
)
672 char buf
[MAX_IPSTRLEN
];
673 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
674 storeAppendPrintf(sentry
, "\nThe Queue:\n");
675 storeAppendPrintf(sentry
, " DELAY SINCE\n");
676 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND\n");
677 storeAppendPrintf(sentry
, "------ ---- ----- ---------- ---------\n");
679 for (n
= lru_list
.head
; n
; n
= n
->next
) {
680 q
= (idns_query
*)n
->data
;
681 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f\n",
682 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
683 tvSubDsec(q
->start_t
, current_time
),
684 tvSubDsec(q
->sent_t
, current_time
));
687 if (Config
.dns
.packet_max
> 0)
688 storeAppendPrintf(sentry
, "DNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
690 storeAppendPrintf(sentry
, "DNS jumbo-grams: not working\n");
692 storeAppendPrintf(sentry
, "\nNameservers:\n");
693 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES\n");
694 storeAppendPrintf(sentry
, "---------------------------------------------- --------- ---------\n");
696 for (i
= 0; i
< nns
; ++i
) {
697 storeAppendPrintf(sentry
, "%-45s %9d %9d\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
698 nameservers
[i
].S
.NtoA(buf
,MAX_IPSTRLEN
),
699 nameservers
[i
].nqueries
,
700 nameservers
[i
].nreplies
);
703 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
704 storeAppendPrintf(sentry
, "RCODE");
706 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
707 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
709 storeAppendPrintf(sentry
, " PROBLEM\n");
711 for (j
= 0; j
< MAX_RCODE
; ++j
) {
712 if (j
> 10 && j
< 16)
713 continue; // unassigned by IANA.
715 storeAppendPrintf(sentry
, "%5d", j
);
717 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
718 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
720 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
724 storeAppendPrintf(sentry
, "\nSearch list:\n");
726 for (i
=0; i
< npc
; ++i
)
727 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
729 storeAppendPrintf(sentry
, "\n");
734 idnsTickleQueue(void)
739 if (NULL
== lru_list
.tail
)
742 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
744 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
750 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
752 nsvc
* vc
= (nsvc
*)data
;
754 if (flag
== COMM_ERR_CLOSING
)
757 // XXX: irrelevant now that we have conn pointer?
758 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
761 if (flag
!= COMM_OK
|| size
<= 0) {
767 idnsDoSendQueryVC(vc
);
771 idnsDoSendQueryVC(nsvc
*vc
)
776 if (vc
->queue
->contentSize() == 0)
779 // if retrying after a TC UDP response, our close handler cb may be pending
780 if (fd_table
[vc
->conn
->fd
].closing())
783 MemBuf
*mb
= vc
->queue
;
785 vc
->queue
= new MemBuf
;
789 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
790 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
791 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
792 AsyncCall::Pointer nil
;
794 commSetConnTimeout(vc
->conn
, timeout
, nil
);
796 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
797 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
798 Comm::Write(vc
->conn
, mb
, call
);
804 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
806 nsvc
* vc
= (nsvc
*)data
;
808 if (status
!= COMM_OK
|| !conn
) {
809 char buf
[MAX_IPSTRLEN
] = "";
811 nameservers
[vc
->ns
].S
.NtoA(buf
,MAX_IPSTRLEN
);
812 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
818 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
819 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
820 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
821 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
823 idnsDoSendQueryVC(vc
);
827 idnsVCClosed(const CommCloseCbParams
¶ms
)
829 nsvc
* vc
= (nsvc
*)params
.data
;
833 if (vc
->ns
< nns
) // XXX: dnsShutdown may have freed nameservers[]
834 nameservers
[vc
->ns
].vc
= NULL
;
841 nsvc
*vc
= cbdataAlloc(nsvc
);
843 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
844 nameservers
[nsv
].vc
= vc
;
846 vc
->queue
= new MemBuf
;
847 vc
->msg
= new MemBuf
;
850 Comm::ConnectionPointer conn
= new Comm::Connection();
852 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
853 conn
->local
= Config
.Addrs
.udp_outgoing
;
855 conn
->local
= Config
.Addrs
.udp_incoming
;
857 conn
->remote
= nameservers
[nsv
].S
;
859 if (conn
->remote
.IsIPv4()) {
860 conn
->local
.SetIPv4();
863 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
865 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
866 cs
->setHost("DNS TCP Socket");
871 idnsSendQueryVC(idns_query
* q
, int nsn
)
874 if (nameservers
[nsn
].vc
== NULL
)
877 nsvc
*vc
= nameservers
[nsn
].vc
;
880 char buf
[MAX_IPSTRLEN
];
881 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.NtoA(buf
,MAX_IPSTRLEN
) << "!");
888 short head
= htons(q
->sz
);
890 vc
->queue
->append((char *)&head
, 2);
892 vc
->queue
->append(q
->buf
, q
->sz
);
894 idnsDoSendQueryVC(vc
);
898 idnsSendQuery(idns_query
* q
)
900 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
901 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
906 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
910 assert(q
->lru
.next
== NULL
);
912 assert(q
->lru
.prev
== NULL
);
918 nsn
= q
->nsends
% nns
;
921 idnsSendQueryVC(q
, nsn
);
924 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.IsIPv6())
925 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
926 else if (DnsSocketA
>= 0)
927 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
932 q
->sent_t
= current_time
;
934 if (y
< 0 && nameservers
[nsn
].S
.IsIPv6())
935 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
936 if (x
< 0 && nameservers
[nsn
].S
.IsIPv4())
937 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
939 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
942 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
945 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
948 ++ nameservers
[nsn
].nqueries
;
949 q
->queue_t
= current_time
;
950 dlinkAdd(q
, &q
->lru
, &lru_list
);
956 idnsFromKnownNameserver(Ip::Address
const &from
)
960 for (i
= 0; i
< nns
; ++i
) {
961 if (nameservers
[i
].S
!= from
)
964 if (nameservers
[i
].S
.GetPort() != from
.GetPort())
974 idnsFindQuery(unsigned short id
)
979 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
980 q
= (idns_query
*)n
->data
;
982 if (q
->query_id
== id
)
989 static unsigned short
992 unsigned short id
= squid_random() & 0xFFFF;
993 unsigned short first_id
= id
;
995 while (idnsFindQuery(id
)) {
998 if (id
== first_id
) {
999 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1008 idnsCallback(idns_query
*q
, const char *error
)
1019 // If any of our subqueries are still pending then wait for them to complete before continuing
1020 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1027 rfc1035_message
*message
= q
->message
;
1032 while ( idns_query
*q2
= q
->slave
) {
1033 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1034 q
->slave
= q2
->slave
;
1037 // two sets of RR need merging
1038 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1039 if (Config
.dns
.v4_first
) {
1040 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1041 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1043 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1044 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1047 // HACK WARNING, the answer rr:s have been copied in-place to
1048 // result, do not free them here
1049 safe_free(message
->answer
);
1050 safe_free(q2
->message
->answer
);
1051 message
->answer
= result
;
1052 message
->ancount
+= q2
->message
->ancount
;
1054 // first response empty or failed, just use the second
1055 rfc1035MessageDestroy(&message
);
1056 message
= q2
->message
;
1062 rfc1035MessageDestroy(&q2
->message
);
1066 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1068 callback
= q
->callback
;
1070 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1072 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1073 callback(cbdata
, answers
, n
, error
);
1076 idns_query
*q2
= q
->queue
;
1077 q
->queue
= q2
->queue
;
1078 callback
= q2
->callback
;
1079 q2
->callback
= NULL
;
1081 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1082 callback(cbdata
, answers
, n
, error
);
1088 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1092 rfc1035MessageDestroy(&message
);
1097 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1100 rfc1035_message
*message
= NULL
;
1103 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1105 if (message
== NULL
) {
1106 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1110 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1112 q
= idnsFindQuery(message
->id
);
1115 debugs(78, 3, "idnsGrokReply: Late response");
1116 rfc1035MessageDestroy(&message
);
1120 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1121 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1122 rfc1035MessageDestroy(&message
);
1126 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1127 // TODO: actually gr the message right here.
1128 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1129 // this is overall better than force-feeding A response with AAAA an section later anyway.
1130 // AND allows us to merge AN+AR sections from both responses (one day)
1132 if (q
->edns_seen
>= 0) {
1133 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1134 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1135 // the altered NS was limiting the whole group.
1136 max_shared_edns
= q
->edns_seen
;
1137 // may be limited by one of the others still
1138 for (int i
= 0; i
< nns
; ++i
)
1139 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1141 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1142 // maybe reduce the global limit downwards to accomodate this NS
1143 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1145 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1146 max_shared_edns
= -1;
1150 dlinkDelete(&q
->lru
, &lru_list
);
1154 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1155 rfc1035MessageDestroy(&message
);
1162 // Strange: A TCP DNS response with the truncation bit (TC) set.
1163 // Return an error and cleanup; no point in trying TCP again.
1164 debugs(78, 3, HERE
<< "TCP DNS response");
1165 idnsCallback(q
, "Truncated TCP DNS response");
1171 idnsRcodeCount(n
, q
->attempt
);
1175 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1177 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1179 * RCODE 2 is "Server failure - The name server was
1180 * unable to process this query due to a problem with
1183 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1184 rfc1035MessageDestroy(&message
);
1189 // Do searchpath processing on the master A query only to keep
1190 // things simple. NXDOMAIN is authorative for the label, not
1192 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1193 assert(NULL
== message
->answer
);
1194 strcpy(q
->name
, q
->orig
);
1196 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1198 if (q
->domain
< npc
) {
1199 strcat(q
->name
, ".");
1200 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1201 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1207 rfc1035MessageDestroy(&message
);
1209 // cleanup slave AAAA query
1210 while (idns_query
*slave
= q
->slave
) {
1211 dlinkDelete(&slave
->lru
, &lru_list
);
1212 q
->slave
= slave
->slave
;
1213 rfc1035MessageDestroy(&slave
->message
);
1218 q
->query_id
= idnsQueryID();
1219 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1220 // see EDNS notes at top of file why this sends 0
1221 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1223 /* problem with query data -- query not sent */
1224 idnsCallback(q
, "Internal error");
1232 idnsSendSlaveAAAAQuery(q
);
1237 q
->message
= message
;
1241 idnsCallback(q
, NULL
);
1243 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1248 idnsRead(int fd
, void *data
)
1250 int *N
= &incoming_sockets_accepted
;
1252 int max
= INCOMING_DNS_MAX
;
1253 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1256 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1258 // Always keep reading. This stops (or at least makes harder) several
1259 // attacks on the DNS client.
1260 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1263 * two code lines after returning from comm_udprecvfrom()
1264 * something overwrites the memory behind the from parameter.
1265 * NO matter where in the stack declaration list above it is placed
1266 * The cause of this is still unknown, however copying the data appears
1267 * to allow it to be passed further without this erasure.
1269 Ip::Address bugbypass
;
1273 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1275 from
= bugbypass
; // BUG BYPASS. see notes above.
1281 if (ignoreErrno(errno
))
1285 /* Some Linux systems seem to set the FD for reading and then
1286 * return ECONNREFUSED when sendto() fails and generates an ICMP
1287 * port unreachable message. */
1288 /* or maybe an EHOSTUNREACH "No route to host" message */
1289 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1292 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1297 fd_bytes(fd
, len
, FD_READ
);
1302 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1304 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1305 int nsn
= idnsFromKnownNameserver(from
);
1308 ++ nameservers
[nsn
].nreplies
;
1311 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1312 // but after the ++ above to keep statistics right.
1314 continue; // Don't process replies if there is no pending query.
1316 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1317 static time_t last_warning
= 0;
1319 if (squid_curtime
- last_warning
> 60) {
1320 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1321 last_warning
= squid_curtime
;
1323 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1328 idnsGrokReply(rbuf
, len
, nsn
);
1333 idnsCheckQueue(void *unused
)
1336 dlink_node
*p
= NULL
;
1341 /* name servers went away; reconfiguring or shutting down */
1344 for (n
= lru_list
.tail
; n
; n
= p
) {
1347 q
= static_cast<idns_query
*>(n
->data
);
1349 /* Anything to process in the queue? */
1350 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1353 /* Query timer still running? */
1354 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1355 dlinkDelete(&q
->lru
, &lru_list
);
1356 q
->queue_t
= current_time
;
1357 dlinkAdd(q
, &q
->lru
, &lru_list
);
1361 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1362 " QID 0x" << std::hex
<< std::setfill('0') <<
1363 std::setw(4) << q
->query_id
<< ": timeout" );
1365 dlinkDelete(&q
->lru
, &lru_list
);
1368 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1371 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1372 " QID 0x" << std::hex
<< q
->query_id
<<
1373 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1374 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1377 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1379 idnsCallback(q
, "Timeout");
1387 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1389 nsvc
* vc
= (nsvc
*)data
;
1391 if (flag
== COMM_ERR_CLOSING
)
1394 if (flag
!= COMM_OK
|| len
<= 0) {
1395 if (Comm::IsConnOpen(conn
))
1400 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1402 if (vc
->msg
->contentSize() < vc
->msglen
) {
1403 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1404 CommIoCbPtrFun(idnsReadVC
, vc
));
1405 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1409 assert(vc
->ns
< nns
);
1410 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1412 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1414 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1415 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1416 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1420 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1422 nsvc
* vc
= (nsvc
*)data
;
1424 if (flag
== COMM_ERR_CLOSING
)
1427 if (flag
!= COMM_OK
|| len
<= 0) {
1428 if (Comm::IsConnOpen(conn
))
1433 vc
->read_msglen
+= len
;
1435 assert(vc
->read_msglen
<= 2);
1437 if (vc
->read_msglen
< 2) {
1438 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1439 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1440 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1444 vc
->read_msglen
= 0;
1446 vc
->msglen
= ntohs(vc
->msglen
);
1448 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1449 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1450 CommIoCbPtrFun(idnsReadVC
, vc
));
1451 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1455 * rcode < 0 indicates an error, rocde >= 0 indicates success
1458 idnsRcodeCount(int rcode
, int attempt
)
1465 if (rcode
< MAX_RCODE
)
1466 if (attempt
< MAX_ATTEMPT
)
1467 ++ RcodeMatrix
[rcode
][attempt
];
1470 /* ====================================================================== */
1473 idnsRegisterWithCacheManager(void)
1475 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1481 static int init
= 0;
1483 CBDATA_INIT_TYPE(nsvc
);
1484 CBDATA_INIT_TYPE(idns_query
);
1486 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1487 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1489 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
1490 addrV6
= Config
.Addrs
.udp_outgoing
;
1492 addrV6
= Config
.Addrs
.udp_incoming
;
1494 Ip::Address addrV4
= addrV6
;
1497 if (Ip::EnableIpv6
&& addrV6
.IsIPv6()) {
1498 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1499 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1506 if (addrV4
.IsIPv4()) {
1507 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1508 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1515 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1516 fatal("Could not create a DNS socket");
1518 /* Ouch... we can't call functions using debug from a debug
1519 * statement. Doing so messes up the internal Debug::level
1521 if (DnsSocketB
>= 0) {
1522 comm_local_port(DnsSocketB
);
1523 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1524 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1526 if (DnsSocketA
>= 0) {
1527 comm_local_port(DnsSocketA
);
1528 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1529 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1534 idnsParseNameservers();
1535 #if !_SQUID_WINDOWS_
1538 idnsParseResolvConf();
1543 idnsParseWIN32Registry();
1547 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1549 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1551 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1554 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1555 idnsAddNameserver("127.0.0.1");
1559 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1560 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1561 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1565 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1566 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1567 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1568 max_shared_edns
= -1; // disable if we might receive random replies.
1572 idnsRegisterWithCacheManager();
1578 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1581 if (DnsSocketA
>= 0 ) {
1582 comm_close(DnsSocketA
);
1586 if (DnsSocketB
>= 0 ) {
1587 comm_close(DnsSocketB
);
1591 for (int i
= 0; i
< nns
; ++i
) {
1592 if (nsvc
*vc
= nameservers
[i
].vc
) {
1593 if (Comm::IsConnOpen(vc
->conn
))
1598 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1599 idnsFreeNameservers();
1600 idnsFreeSearchpath();
1604 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1608 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1613 q
= cbdataAlloc(idns_query
);
1614 // idns_query is POD so no constructors are called after allocation
1615 q
->xact_id
.change();
1616 // no query_id on this instance.
1618 q
->callback
= callback
;
1620 q
->callback_data
= cbdataReference(data
);
1622 q
->queue
= old
->queue
;
1630 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1632 q
->start_t
= current_time
;
1633 q
->callback
= callback
;
1634 q
->callback_data
= cbdataReference(data
);
1636 q
->hash
.key
= q
->orig
;
1637 hash_join(idns_lookup_hash
, &q
->hash
);
1643 idnsSendSlaveAAAAQuery(idns_query
*master
)
1645 idns_query
*q
= cbdataAlloc(idns_query
);
1646 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1647 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1649 q
->query_id
= idnsQueryID();
1650 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1651 q
->start_t
= master
->start_t
;
1652 q
->slave
= master
->slave
;
1654 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1655 ", id = 0x" << std::hex
<< q
->query_id
);
1665 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1671 if (idnsCachedLookup(name
, callback
, data
))
1674 q
= cbdataAlloc(idns_query
);
1675 // idns_query is POD so no constructors are called after allocation
1676 q
->xact_id
.change();
1677 q
->query_id
= idnsQueryID();
1679 for (i
= 0; i
< strlen(name
); ++i
)
1683 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[strlen(name
)-1] != '.') {
1684 q
->do_searchpath
= 1;
1686 q
->do_searchpath
= 0;
1689 strcpy(q
->orig
, name
);
1690 strcpy(q
->name
, q
->orig
);
1692 if (q
->do_searchpath
&& nd
< ndots
) {
1694 strcat(q
->name
, ".");
1695 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1696 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1699 // see EDNS notes at top of file why this sends 0
1700 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1703 /* problem with query data -- query not sent */
1704 callback(data
, NULL
, 0, "Internal error");
1709 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1710 ", id = 0x" << std::hex
<< q
->query_id
);
1712 idnsStartQuery(q
, callback
, data
);
1715 idnsSendSlaveAAAAQuery(q
);
1720 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1724 char ip
[MAX_IPSTRLEN
];
1726 addr
.NtoA(ip
,MAX_IPSTRLEN
);
1728 q
= cbdataAlloc(idns_query
);
1730 // idns_query is POD so no constructors are called after allocation
1731 q
->xact_id
.change();
1732 q
->query_id
= idnsQueryID();
1734 if (addr
.IsIPv6()) {
1735 struct in6_addr addr6
;
1736 addr
.GetInAddr(addr6
);
1737 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1739 struct in_addr addr4
;
1740 addr
.GetInAddr(addr4
);
1741 // see EDNS notes at top of file why this sends 0
1742 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1746 /* problem with query data -- query not sent */
1747 callback(data
, NULL
, 0, "Internal error");
1752 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1757 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1758 ", id = 0x" << std::hex
<< q
->query_id
);
1760 idnsStartQuery(q
, callback
, data
);
1765 * The function to return the DNS via SNMP
1768 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1771 variable_list
*Answer
= NULL
;
1773 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1774 *ErrP
= SNMP_ERR_NOERROR
;
1776 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1780 for (i
= 0; i
< nns
; ++i
)
1781 n
+= nameservers
[i
].nqueries
;
1783 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1790 for (i
= 0; i
< nns
; ++i
)
1791 n
+= nameservers
[i
].nreplies
;
1793 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1800 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1807 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1815 #endif /*SQUID_SNMP */
1816 #endif /* USE_DNSHELPER */