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 msg_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
136 struct timeval start_t
;
137 struct timeval sent_t
;
138 struct timeval queue_t
;
145 unsigned short domain
;
146 unsigned short do_searchpath
;
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);
228 #ifndef _SQUID_MSWIN_
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 void idnsVCClosed(int fd
, void *data
);
251 static unsigned short idnsQueryID(void);
254 idnsAddNameserver(const char *buf
)
259 debugs(78, 0, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
264 debugs(78, 0, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
266 debugs(78, 0, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
269 if (!Ip::EnableIpv6
&& !A
.SetIPv4()) {
270 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
274 if (nns
== nns_alloc
) {
275 int oldalloc
= nns_alloc
;
276 ns
*oldptr
= nameservers
;
283 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
285 if (oldptr
&& oldalloc
)
286 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
292 assert(nns
< nns_alloc
);
293 A
.SetPort(NS_DEFAULTPORT
);
294 nameservers
[nns
].S
= A
;
295 #if WHEN_EDNS_RESPONSES_ARE_PARSED
296 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
297 // TODO generate a test packet to probe this NS from EDNS size and ability.
299 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
304 idnsAddPathComponent(const char *buf
)
306 if (npc
== npc_alloc
) {
307 int oldalloc
= npc_alloc
;
308 sp
*oldptr
= searchpath
;
315 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
317 if (oldptr
&& oldalloc
)
318 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
324 assert(npc
< npc_alloc
);
325 strcpy(searchpath
[npc
].domain
, buf
);
326 Tolower(searchpath
[npc
].domain
);
327 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
333 idnsFreeNameservers(void)
335 safe_free(nameservers
);
340 idnsFreeSearchpath(void)
342 safe_free(searchpath
);
349 idnsParseNameservers(void)
353 for (w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
354 debugs(78, 1, "Adding nameserver " << w
->key
<< " from squid.conf");
355 idnsAddNameserver(w
->key
);
359 #ifndef _SQUID_MSWIN_
361 idnsParseResolvConf(void)
364 char buf
[RESOLV_BUFSZ
];
366 fp
= fopen(_PATH_RESCONF
, "r");
369 debugs(78, 1, "" << _PATH_RESCONF
<< ": " << xstrerror());
374 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 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
735 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
741 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
743 nsvc
* vc
= (nsvc
*)data
;
745 if (flag
== COMM_ERR_CLOSING
)
748 // XXX: irrelevant now that we have conn pointer?
749 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
752 if (flag
!= COMM_OK
|| size
<= 0) {
758 idnsDoSendQueryVC(vc
);
762 idnsDoSendQueryVC(nsvc
*vc
)
767 if (vc
->queue
->contentSize() == 0)
770 MemBuf
*mb
= vc
->queue
;
772 vc
->queue
= new MemBuf
;
776 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
777 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
778 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
779 AsyncCall::Pointer nil
;
781 commSetConnTimeout(vc
->conn
, timeout
, nil
);
783 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
784 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
785 Comm::Write(vc
->conn
, mb
, call
);
791 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
793 nsvc
* vc
= (nsvc
*)data
;
795 if (status
!= COMM_OK
|| !conn
) {
796 char buf
[MAX_IPSTRLEN
] = "";
798 nameservers
[vc
->ns
].S
.NtoA(buf
,MAX_IPSTRLEN
);
799 debugs(78, 1, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
805 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
806 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
807 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
808 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
810 idnsDoSendQueryVC(vc
);
814 idnsVCClosed(int fd
, void *data
)
816 nsvc
* vc
= (nsvc
*)data
;
820 if (vc
->ns
< nns
) // XXX: idnsShutdown may have freed nameservers[]
821 nameservers
[vc
->ns
].vc
= NULL
;
828 nsvc
*vc
= cbdataAlloc(nsvc
);
830 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
831 nameservers
[ns
].vc
= vc
;
833 vc
->queue
= new MemBuf
;
834 vc
->msg
= new MemBuf
;
837 Comm::ConnectionPointer conn
= new Comm::Connection();
839 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
840 conn
->local
= Config
.Addrs
.udp_outgoing
;
842 conn
->local
= Config
.Addrs
.udp_incoming
;
844 conn
->remote
= nameservers
[ns
].S
;
846 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
848 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
849 cs
->setHost("DNS TCP Socket");
854 idnsSendQueryVC(idns_query
* q
, int ns
)
857 if (nameservers
[ns
].vc
== NULL
)
860 nsvc
*vc
= nameservers
[ns
].vc
;
863 char buf
[MAX_IPSTRLEN
];
864 debugs(78, 1, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[ns
].S
.NtoA(buf
,MAX_IPSTRLEN
) << "!");
871 short head
= htons(q
->sz
);
873 vc
->queue
->append((char *)&head
, 2);
875 vc
->queue
->append(q
->buf
, q
->sz
);
877 idnsDoSendQueryVC(vc
);
881 idnsSendQuery(idns_query
* q
)
883 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
884 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
889 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
893 assert(q
->lru
.next
== NULL
);
895 assert(q
->lru
.prev
== NULL
);
900 q
->start_t
= current_time
;
901 q
->msg_id
= idnsQueryID();
902 rfc1035SetQueryID(q
->buf
, q
->msg_id
);
905 ns
= q
->nsends
% nns
;
908 idnsSendQueryVC(q
, ns
);
911 if (DnsSocketB
>= 0 && nameservers
[ns
].S
.IsIPv6())
912 y
= comm_udp_sendto(DnsSocketB
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
914 x
= comm_udp_sendto(DnsSocketA
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
919 q
->queue_t
= q
->sent_t
= current_time
;
921 if (y
< 0 && nameservers
[ns
].S
.IsIPv6())
922 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
923 if (x
< 0 && nameservers
[ns
].S
.IsIPv4())
924 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
926 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
929 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
932 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
935 nameservers
[ns
].nqueries
++;
936 q
->queue_t
= current_time
;
937 dlinkAdd(q
, &q
->lru
, &lru_list
);
942 idnsFromKnownNameserver(Ip::Address
const &from
)
946 for (i
= 0; i
< nns
; i
++) {
947 if (nameservers
[i
].S
!= from
)
950 if (nameservers
[i
].S
.GetPort() != from
.GetPort())
960 idnsFindQuery(unsigned short id
)
965 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
966 q
= (idns_query
*)n
->data
;
975 static unsigned short
978 unsigned short id
= squid_random() & 0xFFFF;
979 unsigned short first_id
= id
;
981 while (idnsFindQuery(id
)) {
984 if (id
== first_id
) {
985 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
994 idnsCallback(idns_query
*q
, rfc1035_rr
*answers
, int n
, const char *error
)
999 callback
= q
->callback
;
1002 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1003 callback(cbdata
, answers
, n
, error
);
1006 idns_query
*q2
= q
->queue
;
1007 q
->queue
= q2
->queue
;
1008 callback
= q2
->callback
;
1009 q2
->callback
= NULL
;
1011 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1012 callback(cbdata
, answers
, n
, error
);
1018 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1024 idnsDropMessage(rfc1035_message
*message
, idns_query
*q
)
1026 rfc1035MessageDestroy(&message
);
1028 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1034 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1037 rfc1035_message
*message
= NULL
;
1040 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1042 if (message
== NULL
) {
1043 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
1047 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1049 q
= idnsFindQuery(message
->id
);
1052 debugs(78, 3, "idnsGrokReply: Late response");
1053 rfc1035MessageDestroy(&message
);
1057 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1058 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1059 rfc1035MessageDestroy(&message
);
1063 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1064 // TODO: actually gr the message right here.
1065 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1066 // this is overall better than force-feeding A response with AAAA an section later anyway.
1067 // AND allows us to merge AN+AR sections from both responses (one day)
1069 if (q
->edns_seen
>= 0) {
1070 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1071 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1072 // the altered NS was limiting the whole group.
1073 max_shared_edns
= q
->edns_seen
;
1074 // may be limited by one of the others still
1075 for (int i
= 0; i
< nns
; i
++)
1076 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1078 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1079 // maybe reduce the global limit downwards to accomodate this NS
1080 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1082 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1083 max_shared_edns
= -1;
1088 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1089 dlinkDelete(&q
->lru
, &lru_list
);
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 dlinkDelete(&q
->lru
, &lru_list
);
1108 idnsRcodeCount(n
, q
->attempt
);
1112 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1114 if (q
->rcode
== 2 && ++q
->attempt
< MAX_ATTEMPT
) {
1116 * RCODE 2 is "Server failure - The name server was
1117 * unable to process this query due to a problem with
1120 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1121 rfc1035MessageDestroy(&message
);
1126 if (q
->rcode
== 3 && q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1127 assert(NULL
== message
->answer
);
1128 strcpy(q
->name
, q
->orig
);
1130 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1132 if (q
->domain
< npc
) {
1133 strcat(q
->name
, ".");
1134 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1135 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1141 idnsDropMessage(message
, q
);
1143 if (Ip::EnableIpv6
&& q
->query
.qtype
== RFC1035_TYPE_AAAA
) {
1144 debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q
->name
);
1145 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1147 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1148 // see EDNS notes at top of file why this sends 0
1149 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1153 /* problem with query data -- query not sent */
1154 idnsCallback(static_cast<idns_query
*>(q
->callback_data
), NULL
, 0, "Internal error");
1165 if (q
->need_A
&& (Config
.onoff
.dns_require_A
== 1 || n
<= 0 ) ) {
1166 /* ERROR or NO AAAA exist. Failover to A records. */
1167 /* Apparently its also a good idea to lookup and store the A records
1168 * just in case the AAAA are not available when we need them.
1169 * This could occur due to number of network failings beyond our control
1170 * thus the || above allowing the user to request always both.
1174 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " has no AAAA records. Looking up A record instead.");
1175 else if (q
->need_A
&& n
<= 0)
1176 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query failed. Trying A now instead.");
1177 else // admin requested this.
1178 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query done. Configured to retrieve A now also.");
1180 // move the initial message results into the failover query for merging later.
1182 q
->initial_AAAA
.count
= message
->ancount
;
1183 q
->initial_AAAA
.answers
= message
->answer
;
1184 message
->answer
= NULL
;
1187 // remove the hashed query info
1188 idnsDropMessage(message
, q
);
1190 // reset the query as an A query
1192 // see EDNS notes at top of file why this sends 0
1193 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1197 /* problem with query data -- query not sent */
1198 idnsCallback(static_cast<idns_query
*>(q
->callback_data
), NULL
, 0, "Internal error");
1208 /** If there are two result sets from preceeding AAAA and A lookups merge them with a preference for AAAA */
1209 if (q
->initial_AAAA
.count
> 0 && n
> 0) {
1210 /* two sets of RR need merging */
1211 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q
->initial_AAAA
.count
) );
1212 rfc1035_rr
*tmp
= result
;
1214 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " AAAA has " << q
->initial_AAAA
.count
<< " RR, A has " << n
<< " RR");
1216 memcpy(tmp
, q
->initial_AAAA
.answers
, (sizeof(rfc1035_rr
)*(q
->initial_AAAA
.count
)) );
1217 tmp
+= q
->initial_AAAA
.count
;
1218 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1219 safe_free(q
->initial_AAAA
.answers
);
1221 memcpy( tmp
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1222 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1223 safe_free(message
->answer
);
1225 message
->answer
= result
;
1226 message
->ancount
+= q
->initial_AAAA
.count
;
1227 n
+= q
->initial_AAAA
.count
;
1228 q
->initial_AAAA
.count
=0;
1229 } else if (q
->initial_AAAA
.count
> 0 && n
<= 0) {
1230 /* initial of dual queries was the only result set. */
1231 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " AAAA has " << q
->initial_AAAA
.count
<< " RR, A has " << n
<< " RR");
1232 rfc1035RRDestroy(&(message
->answer
), n
);
1233 message
->answer
= q
->initial_AAAA
.answers
;
1234 n
= q
->initial_AAAA
.count
;
1236 /* else initial results were empty. just use the final set as authoritative */
1238 debugs(78, 6, HERE
<< "Sending " << n
<< " DNS results to caller.");
1239 idnsCallback(q
, message
->answer
, n
, rfc1035ErrorMessage(n
));
1240 rfc1035MessageDestroy(&message
);
1245 idnsRead(int fd
, void *data
)
1247 int *N
= &incoming_sockets_accepted
;
1249 int max
= INCOMING_DNS_MAX
;
1250 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1254 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1256 // Always keep reading. This stops (or at least makes harder) several
1257 // attacks on the DNS client.
1258 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1261 * two code lines after returning from comm_udprecvfrom()
1262 * something overwrites the memory behind the from parameter.
1263 * NO matter where in the stack declaration list above it is placed
1264 * The cause of this is still unknown, however copying the data appears
1265 * to allow it to be passed further without this erasure.
1267 Ip::Address bugbypass
;
1270 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1272 from
= bugbypass
; // BUG BYPASS. see notes above.
1278 if (ignoreErrno(errno
))
1281 #ifdef _SQUID_LINUX_
1282 /* Some Linux systems seem to set the FD for reading and then
1283 * return ECONNREFUSED when sendto() fails and generates an ICMP
1284 * port unreachable message. */
1285 /* or maybe an EHOSTUNREACH "No route to host" message */
1286 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1289 debugs(50, 1, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1294 fd_bytes(fd
, len
, FD_READ
);
1299 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1301 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1302 ns
= idnsFromKnownNameserver(from
);
1305 nameservers
[ns
].nreplies
++;
1308 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1309 // but after the ++ above to keep statistics right.
1311 continue; // Don't process replies if there is no pending query.
1313 if (ns
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1314 static time_t last_warning
= 0;
1316 if (squid_curtime
- last_warning
> 60) {
1317 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
);
1318 last_warning
= squid_curtime
;
1320 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1325 idnsGrokReply(rbuf
, len
, ns
);
1330 idnsCheckQueue(void *unused
)
1333 dlink_node
*p
= NULL
;
1338 /* name servers went away; reconfiguring or shutting down */
1341 for (n
= lru_list
.tail
; n
; n
= p
) {
1344 q
= static_cast<idns_query
*>(n
->data
);
1346 /* Anything to process in the queue? */
1347 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1350 /* Query timer expired? */
1351 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1352 dlinkDelete(&q
->lru
, &lru_list
);
1353 q
->queue_t
= current_time
;
1354 dlinkAdd(q
, &q
->lru
, &lru_list
);
1358 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1359 " QID 0x" << std::hex
<< std::setfill('0') <<
1360 std::setw(4) << q
->msg_id
<< ": timeout" );
1362 dlinkDelete(&q
->lru
, &lru_list
);
1364 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1367 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1368 " QID 0x" << std::hex
<< q
->msg_id
<<
1369 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1370 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1373 idnsCallback(q
, NULL
, -q
->rcode
, rfc1035ErrorMessage(q
->rcode
));
1375 idnsCallback(q
, NULL
, -16, "Timeout");
1385 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1387 nsvc
* vc
= (nsvc
*)data
;
1389 if (flag
== COMM_ERR_CLOSING
)
1392 if (flag
!= COMM_OK
|| len
<= 0) {
1393 if (Comm::IsConnOpen(conn
))
1398 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1400 if (vc
->msg
->contentSize() < vc
->msglen
) {
1401 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1402 CommIoCbPtrFun(idnsReadVC
, vc
));
1403 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1407 assert(vc
->ns
< nns
);
1408 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1410 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1412 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1413 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1414 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1418 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1420 nsvc
* vc
= (nsvc
*)data
;
1422 if (flag
== COMM_ERR_CLOSING
)
1425 if (flag
!= COMM_OK
|| len
<= 0) {
1426 if (Comm::IsConnOpen(conn
))
1431 vc
->read_msglen
+= len
;
1433 assert(vc
->read_msglen
<= 2);
1435 if (vc
->read_msglen
< 2) {
1436 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1437 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1438 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1442 vc
->read_msglen
= 0;
1444 vc
->msglen
= ntohs(vc
->msglen
);
1446 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1447 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1448 CommIoCbPtrFun(idnsReadVC
, vc
));
1449 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1453 * rcode < 0 indicates an error, rocde >= 0 indicates success
1456 idnsRcodeCount(int rcode
, int attempt
)
1463 if (rcode
< MAX_RCODE
)
1464 if (attempt
< MAX_ATTEMPT
)
1465 RcodeMatrix
[rcode
][attempt
]++;
1468 /* ====================================================================== */
1471 idnsRegisterWithCacheManager(void)
1473 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1479 static int init
= 0;
1481 CBDATA_INIT_TYPE(nsvc
);
1482 CBDATA_INIT_TYPE(idns_query
);
1484 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1485 Ip::Address addrA
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1487 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
1488 addrA
= Config
.Addrs
.udp_outgoing
;
1490 addrA
= Config
.Addrs
.udp_incoming
;
1492 Ip::Address addrB
= addrA
;
1495 if (Ip::EnableIpv6
&& (addrB
.IsAnyAddr() || addrB
.IsIPv6())) {
1496 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrB
);
1497 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1504 if (addrA
.IsAnyAddr() || addrA
.IsIPv4()) {
1505 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrA
);
1506 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1513 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1514 fatal("Could not create a DNS socket");
1516 /* Ouch... we can't call functions using debug from a debug
1517 * statement. Doing so messes up the internal Debug::level
1519 if (DnsSocketB
>= 0) {
1520 comm_local_port(DnsSocketB
);
1521 debugs(78, 1, "DNS Socket created at " << addrB
<< ", FD " << DnsSocketB
);
1522 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1524 if (DnsSocketA
>= 0) {
1525 comm_local_port(DnsSocketA
);
1526 debugs(78, 1, "DNS Socket created at " << addrA
<< ", FD " << DnsSocketA
);
1527 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1532 idnsParseNameservers();
1533 #ifndef _SQUID_MSWIN_
1536 idnsParseResolvConf();
1541 idnsParseWIN32Registry();
1545 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
1547 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
1549 debugs(78, 1, "Please check your /etc/resolv.conf file");
1552 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1553 idnsAddNameserver("127.0.0.1");
1557 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1558 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1559 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1563 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1564 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1565 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1566 max_shared_edns
= -1; // disable if we might receive random replies.
1570 idnsRegisterWithCacheManager();
1576 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1579 if (DnsSocketA
>= 0 ) {
1580 comm_close(DnsSocketA
);
1584 if (DnsSocketB
>= 0 ) {
1585 comm_close(DnsSocketB
);
1589 for (int i
= 0; i
< nns
; i
++) {
1590 if (nsvc
*vc
= nameservers
[i
].vc
) {
1591 if (Comm::IsConnOpen(vc
->conn
))
1596 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1597 idnsFreeNameservers();
1598 idnsFreeSearchpath();
1602 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1606 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1611 q
= cbdataAlloc(idns_query
);
1612 // idns_query is POD so no constructors are called after allocation
1613 q
->xact_id
.change();
1615 q
->callback
= callback
;
1617 q
->callback_data
= cbdataReference(data
);
1619 q
->queue
= old
->queue
;
1627 idnsCacheQuery(idns_query
*q
)
1629 q
->hash
.key
= q
->query
.name
;
1630 hash_join(idns_lookup_hash
, &q
->hash
);
1634 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1640 if (idnsCachedLookup(name
, callback
, data
))
1643 q
= cbdataAlloc(idns_query
);
1644 // idns_query is POD so no constructors are called after allocation
1645 q
->xact_id
.change();
1647 for (i
= 0; i
< strlen(name
); i
++)
1651 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[strlen(name
)-1] != '.') {
1652 q
->do_searchpath
= 1;
1654 q
->do_searchpath
= 0;
1657 strcpy(q
->orig
, name
);
1658 strcpy(q
->name
, q
->orig
);
1660 if (q
->do_searchpath
&& nd
< ndots
) {
1662 strcat(q
->name
, ".");
1663 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1664 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1667 if (Ip::EnableIpv6
) {
1668 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1671 // see EDNS notes at top of file why this sends 0
1672 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1677 /* problem with query data -- query not sent */
1678 callback(data
, NULL
, 0, "Internal error");
1683 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1684 ", id = 0x" << std::hex
<< q
->msg_id
);
1686 q
->callback
= callback
;
1687 q
->callback_data
= cbdataReference(data
);
1694 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1698 char ip
[MAX_IPSTRLEN
];
1700 addr
.NtoA(ip
,MAX_IPSTRLEN
);
1702 q
= cbdataAlloc(idns_query
);
1704 // idns_query is POD so no constructors are called after allocation
1705 q
->xact_id
.change();
1707 if (addr
.IsIPv6()) {
1708 struct in6_addr addr6
;
1709 addr
.GetInAddr(addr6
);
1710 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1712 struct in_addr addr4
;
1713 addr
.GetInAddr(addr4
);
1714 // see EDNS notes at top of file why this sends 0
1715 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1718 /* PTR does not do inbound A/AAAA */
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
->msg_id
);
1736 q
->callback
= callback
;
1737 q
->callback_data
= cbdataReference(data
);
1745 * The function to return the DNS via SNMP
1748 snmp_netIdnsFn(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_DNSSERVERS */