5 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
6 * AUTHOR: Duane Wessels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
39 #include "SquidTime.h"
45 #include "mgr/Registration.h"
48 #include "base/InstanceId.h"
50 #if HAVE_ARPA_NAMESER_H
51 #include <arpa/nameser.h>
57 /* MS Visual Studio Projects are monolithic, so we need the following
58 #ifndef to exclude the internal DNS code from compile process when
59 using external DNS process.
63 #include "squid_windows.h"
64 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
65 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
66 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
69 #define _PATH_RESCONF "/etc/resolv.conf"
71 #ifndef NS_DEFAULTPORT
72 #define NS_DEFAULTPORT 53
76 #define NS_MAXDNAME 1025
83 /* The buffer size required to store the maximum allowed search path */
85 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
88 #define IDNS_MAX_TRIES 20
91 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
92 // NP: see http://www.iana.org/assignments/dns-parameters
93 static const char *Rcodes
[] = {
96 "Packet Format Error",
98 "Non-Existent Domain",
102 "Name Exists when it should not",
103 "RR Set Exists when it should not",
104 "RR Set that should exist does not",
105 "Server Not Authoritative for zone",
106 "Name not contained in zone",
110 "Bad OPT Version or TSIG Signature Failure"
113 typedef struct _idns_query idns_query
;
115 typedef struct _ns ns
;
117 typedef struct _sp sp
;
119 typedef struct _nsvc nsvc
;
124 char buf
[RESOLV_BUFSZ
];
125 char name
[NS_MAXDNAME
+ 1];
126 char orig
[NS_MAXDNAME
+ 1];
128 unsigned short msg_id
; /// random query ID sent to server; changes with every query sent
129 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
134 struct timeval start_t
;
135 struct timeval sent_t
;
136 struct timeval queue_t
;
143 unsigned short domain
;
144 unsigned short do_searchpath
;
151 InstanceIdDefinitions(idns_query
, "dns");
156 unsigned short msglen
;
167 #if WHEN_EDNS_RESPONSES_ARE_PARSED
174 char domain
[NS_MAXDNAME
];
179 CBDATA_TYPE(idns_query
);
181 static ns
*nameservers
= NULL
;
182 static sp
*searchpath
= NULL
;
184 static int nns_alloc
= 0;
186 static int npc_alloc
= 0;
187 static int ndots
= 1;
188 static dlink_list lru_list
;
189 static int event_queued
= 0;
190 static hash_table
*idns_lookup_hash
= NULL
;
196 * EDNS as specified may be sent as an additional record for any request.
197 * early testing has revealed that it works on common devices, but cannot
198 * be reliably used on any A or PTR requet done for IPv4 addresses.
200 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
203 * Squid is optimized to generate one packet and re-send it to all NS
204 * due to this we cannot customize the EDNS size per NS.
206 * As such we take the configuration option value as fixed.
209 * This may not be worth doing, but if/when additional-records are parsed
210 * we will be able to recover the OPT value specific to any one NS and
211 * cache it. Effectively automating the tuning of EDNS advertised to the
212 * size our active NS are capable.
213 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
214 * Responses from the configured NS may cause this to be raised or turned off.
216 #if WHEN_EDNS_RESPONSES_ARE_PARSED
217 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
220 static OBJH idnsStats
;
221 static void idnsAddNameserver(const char *buf
);
222 static void idnsAddPathComponent(const char *buf
);
223 static void idnsFreeNameservers(void);
224 static void idnsFreeSearchpath(void);
225 static void idnsParseNameservers(void);
226 #ifndef _SQUID_MSWIN_
227 static void idnsParseResolvConf(void);
230 static void idnsParseWIN32Registry(void);
231 static void idnsParseWIN32SearchList(const char *);
233 static void idnsCacheQuery(idns_query
* q
);
234 static void idnsSendQuery(idns_query
* q
);
235 static IOCB idnsReadVCHeader
;
236 static void idnsDoSendQueryVC(nsvc
*vc
);
238 static int idnsFromKnownNameserver(Ip::Address
const &from
);
239 static idns_query
*idnsFindQuery(unsigned short id
);
240 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
242 static EVH idnsCheckQueue
;
243 static void idnsTickleQueue(void);
244 static void idnsRcodeCount(int, int);
245 static unsigned short idnsQueryID(void);
248 idnsAddNameserver(const char *buf
)
253 debugs(78, 0, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
258 debugs(78, 0, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
260 debugs(78, 0, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
263 if (!Ip::EnableIpv6
&& !A
.SetIPv4()) {
264 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
268 if (nns
== nns_alloc
) {
269 int oldalloc
= nns_alloc
;
270 ns
*oldptr
= nameservers
;
277 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
279 if (oldptr
&& oldalloc
)
280 xmemcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
286 assert(nns
< nns_alloc
);
287 A
.SetPort(NS_DEFAULTPORT
);
288 nameservers
[nns
].S
= A
;
289 #if WHEN_EDNS_RESPONSES_ARE_PARSED
290 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
291 // TODO generate a test packet to probe this NS from EDNS size and ability.
293 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
298 idnsAddPathComponent(const char *buf
)
300 if (npc
== npc_alloc
) {
301 int oldalloc
= npc_alloc
;
302 sp
*oldptr
= searchpath
;
309 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
311 if (oldptr
&& oldalloc
)
312 xmemcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
318 assert(npc
< npc_alloc
);
319 strcpy(searchpath
[npc
].domain
, buf
);
320 Tolower(searchpath
[npc
].domain
);
321 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
327 idnsFreeNameservers(void)
329 safe_free(nameservers
);
334 idnsFreeSearchpath(void)
336 safe_free(searchpath
);
343 idnsParseNameservers(void)
347 for (w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
348 debugs(78, 1, "Adding nameserver " << w
->key
<< " from squid.conf");
349 idnsAddNameserver(w
->key
);
353 #ifndef _SQUID_MSWIN_
355 idnsParseResolvConf(void)
358 char buf
[RESOLV_BUFSZ
];
360 fp
= fopen(_PATH_RESCONF
, "r");
363 debugs(78, 1, "" << _PATH_RESCONF
<< ": " << xstrerror());
367 #if defined(_SQUID_CYGWIN_)
368 setmode(fileno(fp
), O_TEXT
);
372 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
373 t
= strtok(buf
, w_space
);
377 } else if (strcasecmp(t
, "nameserver") == 0) {
378 t
= strtok(NULL
, w_space
);
383 debugs(78, 1, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
385 idnsAddNameserver(t
);
386 } else if (strcasecmp(t
, "domain") == 0) {
387 idnsFreeSearchpath();
388 t
= strtok(NULL
, w_space
);
393 debugs(78, 1, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
395 idnsAddPathComponent(t
);
396 } else if (strcasecmp(t
, "search") == 0) {
397 idnsFreeSearchpath();
399 t
= strtok(NULL
, w_space
);
404 debugs(78, 1, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
406 idnsAddPathComponent(t
);
408 } else if (strcasecmp(t
, "options") == 0) {
410 t
= strtok(NULL
, w_space
);
415 if (strncmp(t
, "ndots:", 6) == 0) {
421 debugs(78, 1, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
426 if (npc
== 0 && (t
= getMyHostname())) {
429 idnsAddPathComponent(t
+1);
439 idnsParseWIN32SearchList(const char * Separator
)
445 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
449 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
451 if (Result
== ERROR_SUCCESS
&& Size
) {
452 t
= (char *) xmalloc(Size
);
453 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
454 debugs(78, 1, "Adding domain " << t
<< " from Registry");
455 idnsAddPathComponent(t
);
458 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
460 if (Result
== ERROR_SUCCESS
&& Size
) {
461 t
= (char *) xmalloc(Size
);
462 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
463 token
= strtok(t
, Separator
);
466 idnsAddPathComponent(token
);
467 debugs(78, 1, "Adding domain " << token
<< " from Registry");
468 token
= strtok(NULL
, Separator
);
475 if (npc
== 0 && (t
= (char *) getMyHostname())) {
478 idnsAddPathComponent(t
+ 1);
483 idnsParseWIN32Registry(void)
487 HKEY hndKey
, hndKey2
;
489 switch (WIN32_OS_version
) {
492 /* get nameservers from the Windows NT registry */
494 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
498 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
500 if (Result
== ERROR_SUCCESS
&& Size
) {
501 t
= (char *) xmalloc(Size
);
502 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
503 token
= strtok(t
, ", ");
506 idnsAddNameserver(token
);
507 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
508 token
= strtok(NULL
, ",");
513 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
515 if (Result
== ERROR_SUCCESS
&& Size
) {
516 t
= (char *) xmalloc(Size
);
517 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
518 token
= strtok(t
, ", ");
521 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
522 idnsAddNameserver(token
);
523 token
= strtok(NULL
, ", ");
531 idnsParseWIN32SearchList(" ");
544 /* get nameservers from the Windows 2000 registry */
545 /* search all interfaces for DNS server addresses */
547 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
549 DWORD MaxSubkeyLen
, InterfacesCount
;
551 FILETIME ftLastWriteTime
;
553 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
554 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
555 for (i
= 0; i
< (int) InterfacesCount
; i
++) {
558 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
560 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
561 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
562 strcat(newkeyname
, "\\");
563 strcat(newkeyname
, keyname
);
564 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
568 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
569 if (Result
== ERROR_SUCCESS
&& Size
) {
570 t
= (char *) xmalloc(Size
);
571 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
572 token
= strtok(t
, ", ");
574 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
575 idnsAddNameserver(token
);
576 token
= strtok(NULL
, ", ");
581 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
582 if (Result
== ERROR_SUCCESS
&& Size
) {
583 t
= (char *) xmalloc(Size
);
584 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
585 token
= strtok(t
, ", ");
587 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
588 idnsAddNameserver(token
);
589 token
= strtok(NULL
, ", ");
595 RegCloseKey(hndKey2
);
608 idnsParseWIN32SearchList(", ");
617 /* get nameservers from the Windows 9X registry */
619 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
623 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
625 if (Result
== ERROR_SUCCESS
&& Size
) {
626 t
= (char *) xmalloc(Size
);
627 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
628 token
= strtok(t
, ", ");
631 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
632 idnsAddNameserver(token
);
633 token
= strtok(NULL
, ", ");
644 debugs(78, 1, "Failed to read nameserver from Registry: Unknown System Type.");
652 idnsStats(StoreEntry
* sentry
)
658 char buf
[MAX_IPSTRLEN
];
659 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
660 storeAppendPrintf(sentry
, "\nThe Queue:\n");
661 storeAppendPrintf(sentry
, " DELAY SINCE\n");
662 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND\n");
663 storeAppendPrintf(sentry
, "------ ---- ----- ---------- ---------\n");
665 for (n
= lru_list
.head
; n
; n
= n
->next
) {
666 q
= (idns_query
*)n
->data
;
667 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f\n",
668 (int) q
->msg_id
, (int) q
->sz
, q
->nsends
,
669 tvSubDsec(q
->start_t
, current_time
),
670 tvSubDsec(q
->sent_t
, current_time
));
673 if (Config
.dns
.packet_max
> 0)
674 storeAppendPrintf(sentry
, "DNS jumbo-grams: %Zd Bytes\n", Config
.dns
.packet_max
);
676 storeAppendPrintf(sentry
, "DNS jumbo-grams: not working\n");
678 storeAppendPrintf(sentry
, "\nNameservers:\n");
679 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES\n");
680 storeAppendPrintf(sentry
, "---------------------------------------------- --------- ---------\n");
682 for (i
= 0; i
< nns
; i
++) {
683 storeAppendPrintf(sentry
, "%-45s %9d %9d\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
684 nameservers
[i
].S
.NtoA(buf
,MAX_IPSTRLEN
),
685 nameservers
[i
].nqueries
,
686 nameservers
[i
].nreplies
);
689 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
690 storeAppendPrintf(sentry
, "RCODE");
692 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
693 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
695 storeAppendPrintf(sentry
, " PROBLEM\n");
697 for (j
= 0; j
< MAX_RCODE
; j
++) {
698 if (j
> 10 && j
< 16)
699 continue; // unassigned by IANA.
701 storeAppendPrintf(sentry
, "%5d", j
);
703 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
704 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
706 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
710 storeAppendPrintf(sentry
, "\nSearch list:\n");
712 for (i
=0; i
< npc
; i
++)
713 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
715 storeAppendPrintf(sentry
, "\n");
720 idnsTickleQueue(void)
725 if (NULL
== lru_list
.tail
)
728 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, 1.0, 1);
734 idnsSentQueryVC(int fd
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
736 nsvc
* vc
= (nsvc
*)data
;
738 if (flag
== COMM_ERR_CLOSING
)
741 if (fd_table
[fd
].closing())
744 if (flag
!= COMM_OK
|| size
<= 0) {
750 idnsDoSendQueryVC(vc
);
754 idnsDoSendQueryVC(nsvc
*vc
)
759 if (vc
->queue
->contentSize() == 0)
762 MemBuf
*mb
= vc
->queue
;
764 vc
->queue
= new MemBuf
;
768 commSetTimeout(vc
->fd
, Config
.Timeout
.idns_query
, NULL
, NULL
);
770 comm_write_mbuf(vc
->fd
, mb
, idnsSentQueryVC
, vc
);
776 idnsInitVCConnected(int fd
, const DnsLookupDetails
&details
, comm_err_t status
, int xerrno
, void *data
)
778 nsvc
* vc
= (nsvc
*)data
;
780 if (status
!= COMM_OK
) {
781 char buf
[MAX_IPSTRLEN
] = "";
783 nameservers
[vc
->ns
].S
.NtoA(buf
,MAX_IPSTRLEN
);
784 debugs(78, 1, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP: " << details
);
789 comm_read(fd
, (char *)&vc
->msglen
, 2 , idnsReadVCHeader
, vc
);
791 idnsDoSendQueryVC(vc
);
795 idnsVCClosed(int fd
, void *data
)
797 nsvc
* vc
= (nsvc
*)data
;
800 if (vc
->ns
< nns
) // XXX: idnsShutdown may have freed nameservers[]
801 nameservers
[vc
->ns
].vc
= NULL
;
808 char buf
[MAX_IPSTRLEN
];
810 nsvc
*vc
= cbdataAlloc(nsvc
);
812 nameservers
[ns
].vc
= vc
;
817 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
818 addr
= Config
.Addrs
.udp_outgoing
;
820 addr
= Config
.Addrs
.udp_incoming
;
822 if (nameservers
[ns
].S
.IsIPv4() && !addr
.SetIPv4()) {
823 debugs(31, DBG_CRITICAL
, "ERROR: Cannot contact DNS nameserver " << nameservers
[ns
].S
<< " from " << addr
);
828 vc
->queue
= new MemBuf
;
830 vc
->msg
= new MemBuf
;
832 vc
->fd
= comm_open(SOCK_STREAM
,
839 fatal("Could not create a DNS socket");
841 comm_add_close_handler(vc
->fd
, idnsVCClosed
, vc
);
845 commConnectStart(vc
->fd
, nameservers
[ns
].S
.NtoA(buf
,MAX_IPSTRLEN
), nameservers
[ns
].S
.GetPort(), idnsInitVCConnected
, vc
);
849 idnsSendQueryVC(idns_query
* q
, int ns
)
852 if (nameservers
[ns
].vc
== NULL
)
855 nsvc
*vc
= nameservers
[ns
].vc
;
858 char buf
[MAX_IPSTRLEN
];
859 debugs(78, 1, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[ns
].S
.NtoA(buf
,MAX_IPSTRLEN
) << "!");
866 short head
= htons(q
->sz
);
868 vc
->queue
->append((char *)&head
, 2);
870 vc
->queue
->append(q
->buf
, q
->sz
);
872 idnsDoSendQueryVC(vc
);
876 idnsSendQuery(idns_query
* q
)
878 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
879 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
884 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
888 assert(q
->lru
.next
== NULL
);
890 assert(q
->lru
.prev
== NULL
);
895 q
->start_t
= current_time
;
896 q
->msg_id
= idnsQueryID();
897 rfc1035SetQueryID(q
->buf
, q
->msg_id
);
900 ns
= q
->nsends
% nns
;
903 idnsSendQueryVC(q
, ns
);
906 if (DnsSocketB
>= 0 && nameservers
[ns
].S
.IsIPv6())
907 y
= comm_udp_sendto(DnsSocketB
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
909 x
= comm_udp_sendto(DnsSocketA
, nameservers
[ns
].S
, q
->buf
, q
->sz
);
914 q
->queue_t
= q
->sent_t
= current_time
;
916 if (y
< 0 && nameservers
[ns
].S
.IsIPv6())
917 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
918 if (x
< 0 && nameservers
[ns
].S
.IsIPv4())
919 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
921 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
924 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
927 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
930 nameservers
[ns
].nqueries
++;
931 q
->queue_t
= current_time
;
932 dlinkAdd(q
, &q
->lru
, &lru_list
);
937 idnsFromKnownNameserver(Ip::Address
const &from
)
941 for (i
= 0; i
< nns
; i
++) {
942 if (nameservers
[i
].S
!= from
)
945 if (nameservers
[i
].S
.GetPort() != from
.GetPort())
955 idnsFindQuery(unsigned short id
)
960 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
961 q
= (idns_query
*)n
->data
;
970 static unsigned short
973 unsigned short id
= squid_random() & 0xFFFF;
974 unsigned short first_id
= id
;
976 while (idnsFindQuery(id
)) {
979 if (id
== first_id
) {
980 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
989 idnsCallback(idns_query
*q
, rfc1035_rr
*answers
, int n
, const char *error
)
994 callback
= q
->callback
;
997 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
998 callback(cbdata
, answers
, n
, error
);
1001 idns_query
*q2
= q
->queue
;
1002 q
->queue
= q2
->queue
;
1003 callback
= q2
->callback
;
1004 q2
->callback
= NULL
;
1006 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1007 callback(cbdata
, answers
, n
, error
);
1013 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1019 idnsDropMessage(rfc1035_message
*message
, idns_query
*q
)
1021 rfc1035MessageDestroy(&message
);
1023 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1029 idnsGrokReply(const char *buf
, size_t sz
, int from_ns
)
1032 rfc1035_message
*message
= NULL
;
1035 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1037 if (message
== NULL
) {
1038 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
1042 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1044 q
= idnsFindQuery(message
->id
);
1047 debugs(78, 3, "idnsGrokReply: Late response");
1048 rfc1035MessageDestroy(&message
);
1052 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1053 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1054 rfc1035MessageDestroy(&message
);
1058 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1059 // TODO: actually gr the message right here.
1060 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1061 // this is overall better than force-feeding A response with AAAA an section later anyway.
1062 // AND allows us to merge AN+AR sections from both responses (one day)
1064 if (q
->edns_seen
>= 0) {
1065 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1066 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1067 // the altered NS was limiting the whole group.
1068 max_shared_edns
= q
->edns_seen
;
1069 // may be limited by one of the others still
1070 for (int i
= 0; i
< nns
; i
++)
1071 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1073 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1074 // maybe reduce the global limit downwards to accomodate this NS
1075 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1077 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1078 max_shared_edns
= -1;
1083 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1084 dlinkDelete(&q
->lru
, &lru_list
);
1085 rfc1035MessageDestroy(&message
);
1092 // Strange: A TCP DNS response with the truncation bit (TC) set.
1093 // Return an error and cleanup; no point in trying TCP again.
1094 debugs(78, 3, HERE
<< "TCP DNS response");
1095 idnsCallback(q
, NULL
, 0, "Truncated TCP DNS response");
1102 dlinkDelete(&q
->lru
, &lru_list
);
1103 idnsRcodeCount(n
, q
->attempt
);
1107 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1109 if (q
->rcode
== 2 && ++q
->attempt
< MAX_ATTEMPT
) {
1111 * RCODE 2 is "Server failure - The name server was
1112 * unable to process this query due to a problem with
1115 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1116 rfc1035MessageDestroy(&message
);
1121 if (q
->rcode
== 3 && q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1122 assert(NULL
== message
->answer
);
1123 strcpy(q
->name
, q
->orig
);
1125 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1127 if (q
->domain
< npc
) {
1128 strcat(q
->name
, ".");
1129 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1130 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1136 idnsDropMessage(message
, q
);
1138 if (Ip::EnableIpv6
&& q
->query
.qtype
== RFC1035_TYPE_AAAA
) {
1139 debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q
->name
);
1140 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1142 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1143 // see EDNS notes at top of file why this sends 0
1144 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1152 if (q
->need_A
&& (Config
.onoff
.dns_require_A
== 1 || n
<= 0 ) ) {
1153 /* ERROR or NO AAAA exist. Failover to A records. */
1154 /* Apparently its also a good idea to lookup and store the A records
1155 * just in case the AAAA are not available when we need them.
1156 * This could occur due to number of network failings beyond our control
1157 * thus the || above allowing the user to request always both.
1161 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " has no AAAA records. Looking up A record instead.");
1162 else if (q
->need_A
&& n
<= 0)
1163 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query failed. Trying A now instead.");
1164 else // admin requested this.
1165 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query done. Configured to retrieve A now also.");
1167 // move the initial message results into the failover query for merging later.
1169 q
->initial_AAAA
.count
= message
->ancount
;
1170 q
->initial_AAAA
.answers
= message
->answer
;
1171 message
->answer
= NULL
;
1174 // remove the hashed query info
1175 idnsDropMessage(message
, q
);
1177 // reset the query as an A query
1179 // see EDNS notes at top of file why this sends 0
1180 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1187 /** If there are two result sets from preceeding AAAA and A lookups merge them with a preference for AAAA */
1188 if (q
->initial_AAAA
.count
> 0 && n
> 0) {
1189 /* two sets of RR need merging */
1190 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q
->initial_AAAA
.count
) );
1191 rfc1035_rr
*tmp
= result
;
1193 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " AAAA has " << q
->initial_AAAA
.count
<< " RR, A has " << n
<< " RR");
1195 memcpy(tmp
, q
->initial_AAAA
.answers
, (sizeof(rfc1035_rr
)*(q
->initial_AAAA
.count
)) );
1196 tmp
+= q
->initial_AAAA
.count
;
1197 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1198 safe_free(q
->initial_AAAA
.answers
);
1200 memcpy( tmp
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1201 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1202 safe_free(message
->answer
);
1204 message
->answer
= result
;
1205 message
->ancount
+= q
->initial_AAAA
.count
;
1206 n
+= q
->initial_AAAA
.count
;
1207 q
->initial_AAAA
.count
=0;
1208 } else if (q
->initial_AAAA
.count
> 0 && n
<= 0) {
1209 /* initial of dual queries was the only result set. */
1210 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " AAAA has " << q
->initial_AAAA
.count
<< " RR, A has " << n
<< " RR");
1211 rfc1035RRDestroy(&(message
->answer
), n
);
1212 message
->answer
= q
->initial_AAAA
.answers
;
1213 n
= q
->initial_AAAA
.count
;
1215 /* else initial results were empty. just use the final set as authoritative */
1217 debugs(78, 6, HERE
<< "Sending " << n
<< " DNS results to caller.");
1218 idnsCallback(q
, message
->answer
, n
, rfc1035ErrorMessage(n
));
1219 rfc1035MessageDestroy(&message
);
1224 idnsRead(int fd
, void *data
)
1226 int *N
= &incoming_sockets_accepted
;
1228 int max
= INCOMING_DNS_MAX
;
1229 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1233 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1235 // Always keep reading. This stops (or at least makes harder) several
1236 // attacks on the DNS client.
1237 commSetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1240 * two code lines after returning from comm_udprecvfrom()
1241 * something overwrites the memory behind the from parameter.
1242 * NO matter where in the stack declaration list above it is placed
1243 * The cause of this is still unknown, however copying the data appears
1244 * to allow it to be passed further without this erasure.
1246 Ip::Address bugbypass
;
1249 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1251 from
= bugbypass
; // BUG BYPASS. see notes above.
1257 if (ignoreErrno(errno
))
1260 #ifdef _SQUID_LINUX_
1261 /* Some Linux systems seem to set the FD for reading and then
1262 * return ECONNREFUSED when sendto() fails and generates an ICMP
1263 * port unreachable message. */
1264 /* or maybe an EHOSTUNREACH "No route to host" message */
1265 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1268 debugs(50, 1, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1273 fd_bytes(fd
, len
, FD_READ
);
1278 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1280 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1281 ns
= idnsFromKnownNameserver(from
);
1284 nameservers
[ns
].nreplies
++;
1287 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1288 // but after the ++ above to keep statistics right.
1290 continue; // Don't process replies if there is no pending query.
1292 if (ns
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1293 static time_t last_warning
= 0;
1295 if (squid_curtime
- last_warning
> 60) {
1296 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
);
1297 last_warning
= squid_curtime
;
1299 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1304 idnsGrokReply(rbuf
, len
, ns
);
1309 idnsCheckQueue(void *unused
)
1312 dlink_node
*p
= NULL
;
1317 /* name servers went away; reconfiguring or shutting down */
1320 for (n
= lru_list
.tail
; n
; n
= p
) {
1323 q
= static_cast<idns_query
*>(n
->data
);
1325 /* Anything to process in the queue? */
1326 if (tvSubDsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1329 /* Query timer expired? */
1330 if (tvSubDsec(q
->sent_t
, current_time
) < Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
)) {
1331 dlinkDelete(&q
->lru
, &lru_list
);
1332 q
->queue_t
= current_time
;
1333 dlinkAdd(q
, &q
->lru
, &lru_list
);
1337 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1338 " QID 0x" << std::hex
<< std::setfill('0') <<
1339 std::setw(4) << q
->msg_id
<< ": timeout" );
1341 dlinkDelete(&q
->lru
, &lru_list
);
1343 if (tvSubDsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1346 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1347 " QID 0x" << std::hex
<< q
->msg_id
<<
1348 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1349 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1352 idnsCallback(q
, NULL
, -q
->rcode
, rfc1035ErrorMessage(q
->rcode
));
1354 idnsCallback(q
, NULL
, -16, "Timeout");
1364 idnsReadVC(int fd
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1366 nsvc
* vc
= (nsvc
*)data
;
1368 if (flag
== COMM_ERR_CLOSING
)
1371 if (flag
!= COMM_OK
|| len
<= 0) {
1376 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1378 if (vc
->msg
->contentSize() < vc
->msglen
) {
1379 comm_read(fd
, buf
+ len
, vc
->msglen
- vc
->msg
->contentSize(), idnsReadVC
, vc
);
1383 assert(vc
->ns
< nns
);
1384 debugs(78, 3, "idnsReadVC: FD " << fd
<< ": received " <<
1385 (int) vc
->msg
->contentSize() << " bytes via tcp from " <<
1386 nameservers
[vc
->ns
].S
<< ".");
1388 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1390 comm_read(fd
, (char *)&vc
->msglen
, 2 , idnsReadVCHeader
, vc
);
1394 idnsReadVCHeader(int fd
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1396 nsvc
* vc
= (nsvc
*)data
;
1398 if (flag
== COMM_ERR_CLOSING
)
1401 if (flag
!= COMM_OK
|| len
<= 0) {
1406 vc
->read_msglen
+= len
;
1408 assert(vc
->read_msglen
<= 2);
1410 if (vc
->read_msglen
< 2) {
1411 comm_read(fd
, buf
+ len
, 2 - vc
->read_msglen
, idnsReadVCHeader
, vc
);
1415 vc
->read_msglen
= 0;
1417 vc
->msglen
= ntohs(vc
->msglen
);
1419 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1420 comm_read(fd
, vc
->msg
->buf
, vc
->msglen
, idnsReadVC
, vc
);
1424 * rcode < 0 indicates an error, rocde >= 0 indicates success
1427 idnsRcodeCount(int rcode
, int attempt
)
1434 if (rcode
< MAX_RCODE
)
1435 if (attempt
< MAX_ATTEMPT
)
1436 RcodeMatrix
[rcode
][attempt
]++;
1439 /* ====================================================================== */
1442 idnsRegisterWithCacheManager(void)
1444 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1450 static int init
= 0;
1452 CBDATA_INIT_TYPE(nsvc
);
1453 CBDATA_INIT_TYPE(idns_query
);
1455 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1458 Ip::Address addrA
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1460 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
1461 addrA
= Config
.Addrs
.udp_outgoing
;
1463 addrA
= Config
.Addrs
.udp_incoming
;
1465 Ip::Address addrB
= addrA
;
1468 if (Ip::EnableIpv6
&& (addrB
.IsAnyAddr() || addrB
.IsIPv6())) {
1469 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrB
);
1470 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1477 if (addrA
.IsAnyAddr() || addrA
.IsIPv4()) {
1478 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrA
);
1479 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1486 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1487 fatal("Could not create a DNS socket");
1489 /* Ouch... we can't call functions using debug from a debug
1490 * statement. Doing so messes up the internal Debug::level
1492 if (DnsSocketB
>= 0) {
1493 port
= comm_local_port(DnsSocketB
);
1494 debugs(78, 1, "DNS Socket created at " << addrB
<< ", FD " << DnsSocketB
);
1495 commSetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1497 if (DnsSocketA
>= 0) {
1498 port
= comm_local_port(DnsSocketA
);
1499 debugs(78, 1, "DNS Socket created at " << addrA
<< ", FD " << DnsSocketA
);
1500 commSetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1505 idnsParseNameservers();
1506 #ifndef _SQUID_MSWIN_
1509 idnsParseResolvConf();
1512 #ifdef _SQUID_WIN32_
1515 idnsParseWIN32Registry();
1520 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
1521 #ifdef _SQUID_WIN32_
1523 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
1526 debugs(78, 1, "Please check your /etc/resolv.conf file");
1529 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1530 idnsAddNameserver("127.0.0.1");
1534 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1535 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1536 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1540 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1541 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1542 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1543 max_shared_edns
= -1; // disable if we might receive random replies.
1547 idnsRegisterWithCacheManager();
1553 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1556 if (DnsSocketA
>= 0 ) {
1557 comm_close(DnsSocketA
);
1561 if (DnsSocketB
>= 0 ) {
1562 comm_close(DnsSocketB
);
1566 for (int i
= 0; i
< nns
; i
++) {
1567 if (nsvc
*vc
= nameservers
[i
].vc
) {
1573 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1574 idnsFreeNameservers();
1575 idnsFreeSearchpath();
1579 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1583 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1588 q
= cbdataAlloc(idns_query
);
1589 // idns_query is POD so no constructors are called after allocation
1590 q
->xact_id
.change();
1592 q
->callback
= callback
;
1594 q
->callback_data
= cbdataReference(data
);
1596 q
->queue
= old
->queue
;
1604 idnsCacheQuery(idns_query
*q
)
1606 q
->hash
.key
= q
->query
.name
;
1607 hash_join(idns_lookup_hash
, &q
->hash
);
1611 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1617 if (idnsCachedLookup(name
, callback
, data
))
1620 q
= cbdataAlloc(idns_query
);
1621 // idns_query is POD so no constructors are called after allocation
1622 q
->xact_id
.change();
1624 for (i
= 0; i
< strlen(name
); i
++)
1628 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[strlen(name
)-1] != '.') {
1629 q
->do_searchpath
= 1;
1631 q
->do_searchpath
= 0;
1634 strcpy(q
->orig
, name
);
1635 strcpy(q
->name
, q
->orig
);
1637 if (q
->do_searchpath
&& nd
< ndots
) {
1639 strcat(q
->name
, ".");
1640 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1641 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1644 if (Ip::EnableIpv6
) {
1645 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1648 // see EDNS notes at top of file why this sends 0
1649 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1654 /* problem with query data -- query not sent */
1655 callback(data
, NULL
, 0, "Internal error");
1660 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1661 ", id = 0x" << std::hex
<< q
->msg_id
);
1663 q
->callback
= callback
;
1665 q
->callback_data
= cbdataReference(data
);
1673 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1677 char ip
[MAX_IPSTRLEN
];
1679 addr
.NtoA(ip
,MAX_IPSTRLEN
);
1681 q
= cbdataAlloc(idns_query
);
1683 // idns_query is POD so no constructors are called after allocation
1684 q
->xact_id
.change();
1686 if (Ip::EnableIpv6
&& addr
.IsIPv6()) {
1687 struct in6_addr addr6
;
1688 addr
.GetInAddr(addr6
);
1689 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, Config
.dns
.packet_max
);
1691 struct in_addr addr4
;
1692 addr
.GetInAddr(addr4
);
1693 // see EDNS notes at top of file why this sends 0
1694 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), 0, &q
->query
, 0);
1697 /* PTR does not do inbound A/AAAA */
1701 /* problem with query data -- query not sent */
1702 callback(data
, NULL
, 0, "Internal error");
1707 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1712 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1713 ", id = 0x" << std::hex
<< q
->msg_id
);
1715 q
->callback
= callback
;
1717 q
->callback_data
= cbdataReference(data
);
1726 * The function to return the DNS via SNMP
1729 snmp_netIdnsFn(variable_list
* Var
, snint
* ErrP
)
1732 variable_list
*Answer
= NULL
;
1734 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1735 *ErrP
= SNMP_ERR_NOERROR
;
1737 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1741 for (i
= 0; i
< nns
; i
++)
1742 n
+= nameservers
[i
].nqueries
;
1744 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1751 for (i
= 0; i
< nns
; i
++)
1752 n
+= nameservers
[i
].nreplies
;
1754 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1761 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1768 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1776 #endif /*SQUID_SNMP */
1777 #endif /* USE_DNSSERVERS */