2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 78 DNS lookups; interacts with dns/rfc1035.cc */
12 #include "base/InstanceId.h"
14 #include "comm/Connection.h"
15 #include "comm/ConnOpener.h"
16 #include "comm/Loops.h"
17 #include "comm/Read.h"
18 #include "comm/Write.h"
20 #include "dns/forward.h"
21 #include "dns/rfc3596.h"
27 #include "mgr/Registration.h"
28 #include "SquidConfig.h"
29 #include "SquidTime.h"
36 #include "snmp_core.h"
39 #if HAVE_ARPA_NAMESER_H
40 #include <arpa/nameser.h>
48 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
49 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
50 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
53 #define _PATH_RESCONF "/etc/resolv.conf"
55 #ifndef NS_DEFAULTPORT
56 #define NS_DEFAULTPORT 53
60 #define NS_MAXDNAME 1025
67 /* The buffer size required to store the maximum allowed search path */
69 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
72 #define IDNS_MAX_TRIES 20
75 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
76 // NP: see http://www.iana.org/assignments/dns-parameters
77 static const char *Rcodes
[] = {
80 "Packet Format Error",
82 "Non-Existent Domain",
86 "Name Exists when it should not",
87 "RR Set Exists when it should not",
88 "RR Set that should exist does not",
89 "Server Not Authoritative for zone",
90 "Name not contained in zone",
94 "Bad OPT Version or TSIG Signature Failure"
97 typedef struct _ns ns
;
99 typedef struct _sp sp
;
103 CBDATA_CLASS(idns_query
);
126 memset(&hash
, 0, sizeof(hash
));
127 memset(&query
, 0, sizeof(query
));
131 memset(&start_t
, 0, sizeof(start_t
));
132 memset(&sent_t
, 0, sizeof(sent_t
));
133 memset(&queue_t
, 0, sizeof(queue_t
));
138 rfc1035MessageDestroy(&message
);
141 // master is just a back-reference
142 cbdataReferenceDone(callback_data
);
147 char buf
[RESOLV_BUFSZ
];
148 char name
[NS_MAXDNAME
+ 1];
149 char orig
[NS_MAXDNAME
+ 1];
151 unsigned short query_id
; /// random query ID sent to server; changes with every query sent
152 InstanceId
<idns_query
> xact_id
; /// identifies our "transaction", stays constant when query is retried
159 struct timeval start_t
;
160 struct timeval sent_t
;
161 struct timeval queue_t
;
168 idns_query
*slave
; // single linked list
169 idns_query
*master
; // single pointer to a shared master
170 unsigned short domain
;
171 unsigned short do_searchpath
;
172 rfc1035_message
*message
;
177 InstanceIdDefinitions(idns_query
, "dns");
179 CBDATA_CLASS_INIT(idns_query
);
186 explicit nsvc(int nsv
) : ns(nsv
), msglen(0), read_msglen(0), msg(new MemBuf()), queue(new MemBuf()), busy(true) {}
190 Comm::ConnectionPointer conn
;
191 unsigned short msglen
;
198 CBDATA_CLASS_INIT(nsvc
);
204 #if WHEN_EDNS_RESPONSES_ARE_PARSED
212 char domain
[NS_MAXDNAME
];
216 static ns
*nameservers
= NULL
;
217 static sp
*searchpath
= NULL
;
219 static int nns_alloc
= 0;
220 static int nns_mdns_count
= 0;
222 static int npc_alloc
= 0;
223 static int ndots
= 1;
224 static dlink_list lru_list
;
225 static int event_queued
= 0;
226 static hash_table
*idns_lookup_hash
= NULL
;
232 * EDNS as specified may be sent as an additional record for any request.
233 * early testing has revealed that it works on common devices, but cannot
234 * be reliably used on any A or PTR requet done for IPv4 addresses.
236 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
239 * Squid is optimized to generate one packet and re-send it to all NS
240 * due to this we cannot customize the EDNS size per NS.
242 * As such we take the configuration option value as fixed.
245 * This may not be worth doing, but if/when additional-records are parsed
246 * we will be able to recover the OPT value specific to any one NS and
247 * cache it. Effectively automating the tuning of EDNS advertised to the
248 * size our active NS are capable.
249 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
250 * Responses from the configured NS may cause this to be raised or turned off.
252 #if WHEN_EDNS_RESPONSES_ARE_PARSED
253 static int max_shared_edns
= RFC1035_DEFAULT_PACKET_SZ
;
256 static OBJH idnsStats
;
257 static void idnsAddNameserver(const char *buf
);
258 static void idnsAddMDNSNameservers();
259 static void idnsAddPathComponent(const char *buf
);
260 static void idnsFreeNameservers(void);
261 static void idnsFreeSearchpath(void);
262 static bool idnsParseNameservers(void);
263 static bool idnsParseResolvConf(void);
265 static bool idnsParseWIN32Registry(void);
266 static void idnsParseWIN32SearchList(const char *);
268 static void idnsStartQuery(idns_query
* q
, IDNSCB
* callback
, void *data
);
269 static void idnsSendQuery(idns_query
* q
);
270 static IOCB idnsReadVCHeader
;
271 static void idnsDoSendQueryVC(nsvc
*vc
);
272 static CNCB idnsInitVCConnected
;
273 static IOCB idnsReadVC
;
274 static IOCB idnsSentQueryVC
;
276 static int idnsFromKnownNameserver(Ip::Address
const &from
);
277 static idns_query
*idnsFindQuery(unsigned short id
);
278 static void idnsGrokReply(const char *buf
, size_t sz
, int from_ns
);
280 static EVH idnsCheckQueue
;
281 static void idnsTickleQueue(void);
282 static void idnsRcodeCount(int, int);
283 static CLCB idnsVCClosed
;
284 static unsigned short idnsQueryID(void);
285 static void idnsSendSlaveAAAAQuery(idns_query
*q
);
288 idnsCheckMDNS(idns_query
*q
)
290 if (!Config
.onoff
.dns_mdns
|| q
->permit_mdns
)
293 size_t slen
= strlen(q
->name
);
294 if (slen
> 6 && memcmp(q
->name
+(slen
-6),".local", 6) == 0) {
295 q
->permit_mdns
= true;
300 idnsAddMDNSNameservers()
305 if (!Config
.onoff
.dns_mdns
)
308 // mDNS resolver addresses are explicit multicast group IPs
309 if (Ip::EnableIpv6
) {
310 idnsAddNameserver("FF02::FB");
311 nameservers
[nns
-1].S
.port(5353);
312 nameservers
[nns
-1].mDNSResolver
= true;
316 idnsAddNameserver("224.0.0.251");
317 nameservers
[nns
-1].S
.port(5353);
318 nameservers
[nns
-1].mDNSResolver
= true;
324 idnsAddNameserver(const char *buf
)
329 debugs(78, DBG_CRITICAL
, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
334 debugs(78, DBG_CRITICAL
, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
336 debugs(78, DBG_CRITICAL
, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
339 if (!Ip::EnableIpv6
&& !A
.setIPv4()) {
340 debugs(78, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Discarding " << A
<< " in DNS server specifications.");
344 if (nns
== nns_alloc
) {
345 int oldalloc
= nns_alloc
;
346 ns
*oldptr
= nameservers
;
353 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
355 if (oldptr
&& oldalloc
)
356 memcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
362 assert(nns
< nns_alloc
);
363 A
.port(NS_DEFAULTPORT
);
364 nameservers
[nns
].S
= A
;
365 #if WHEN_EDNS_RESPONSES_ARE_PARSED
366 nameservers
[nns
].last_seen_edns
= RFC1035_DEFAULT_PACKET_SZ
;
367 // TODO generate a test packet to probe this NS from EDNS size and ability.
369 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
374 idnsAddPathComponent(const char *buf
)
376 if (npc
== npc_alloc
) {
377 int oldalloc
= npc_alloc
;
378 sp
*oldptr
= searchpath
;
385 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
387 if (oldptr
&& oldalloc
)
388 memcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
394 assert(npc
< npc_alloc
);
395 strncpy(searchpath
[npc
].domain
, buf
, sizeof(searchpath
[npc
].domain
)-1);
396 searchpath
[npc
].domain
[sizeof(searchpath
[npc
].domain
)-1] = '\0';
397 Tolower(searchpath
[npc
].domain
);
398 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
403 idnsFreeNameservers(void)
405 safe_free(nameservers
);
410 idnsFreeSearchpath(void)
412 safe_free(searchpath
);
417 idnsParseNameservers(void)
420 for (wordlist
*w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
421 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << w
->key
<< " from squid.conf");
422 idnsAddNameserver(w
->key
);
429 idnsParseResolvConf(void)
433 FILE *fp
= fopen(_PATH_RESCONF
, "r");
436 debugs(78, DBG_IMPORTANT
, "" << _PATH_RESCONF
<< ": " << xstrerror());
440 char buf
[RESOLV_BUFSZ
];
441 const char *t
= NULL
;
442 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
443 t
= strtok(buf
, w_space
);
447 } else if (strcmp(t
, "nameserver") == 0) {
448 t
= strtok(NULL
, w_space
);
453 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
455 idnsAddNameserver(t
);
457 } else if (strcmp(t
, "domain") == 0) {
458 idnsFreeSearchpath();
459 t
= strtok(NULL
, w_space
);
464 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
466 idnsAddPathComponent(t
);
467 } else if (strcmp(t
, "search") == 0) {
468 idnsFreeSearchpath();
470 t
= strtok(NULL
, w_space
);
475 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
477 idnsAddPathComponent(t
);
479 } else if (strcmp(t
, "options") == 0) {
481 t
= strtok(NULL
, w_space
);
486 if (strncmp(t
, "ndots:", 6) == 0) {
492 debugs(78, DBG_IMPORTANT
, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
497 if (npc
== 0 && (t
= getMyHostname())) {
500 idnsAddPathComponent(t
+1);
510 idnsParseWIN32SearchList(const char * Separator
)
516 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
520 Result
= RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, NULL
, &Size
);
522 if (Result
== ERROR_SUCCESS
&& Size
) {
523 t
= (char *) xmalloc(Size
);
524 RegQueryValueEx(hndKey
, "Domain", NULL
, &Type
, (LPBYTE
) t
, &Size
);
525 debugs(78, DBG_IMPORTANT
, "Adding domain " << t
<< " from Registry");
526 idnsAddPathComponent(t
);
529 Result
= RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
, &Size
);
531 if (Result
== ERROR_SUCCESS
&& Size
) {
532 t
= (char *) xmalloc(Size
);
533 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, (LPBYTE
) t
, &Size
);
534 token
= strtok(t
, Separator
);
537 idnsAddPathComponent(token
);
538 debugs(78, DBG_IMPORTANT
, "Adding domain " << token
<< " from Registry");
539 token
= strtok(NULL
, Separator
);
546 if (npc
== 0 && (t
= (char *) getMyHostname())) {
549 idnsAddPathComponent(t
+ 1);
554 idnsParseWIN32Registry(void)
558 HKEY hndKey
, hndKey2
;
561 switch (WIN32_OS_version
) {
564 /* get nameservers from the Windows NT registry */
566 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
570 Result
= RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
572 if (Result
== ERROR_SUCCESS
&& Size
) {
573 t
= (char *) xmalloc(Size
);
574 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
575 token
= strtok(t
, ", ");
578 idnsAddNameserver(token
);
580 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
581 token
= strtok(NULL
, ",");
586 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
588 if (Result
== ERROR_SUCCESS
&& Size
) {
589 t
= (char *) xmalloc(Size
);
590 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
591 token
= strtok(t
, ", ");
594 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
595 idnsAddNameserver(token
);
597 token
= strtok(NULL
, ", ");
605 idnsParseWIN32SearchList(" ");
618 /* get nameservers from the Windows 2000 registry */
619 /* search all interfaces for DNS server addresses */
621 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_TCPIP_PARA_INTERFACES
, 0, KEY_READ
, &hndKey
) == ERROR_SUCCESS
) {
623 DWORD MaxSubkeyLen
, InterfacesCount
;
625 FILETIME ftLastWriteTime
;
627 if (RegQueryInfoKey(hndKey
, NULL
, NULL
, NULL
, &InterfacesCount
, &MaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
628 keyname
= (char *) xmalloc(++MaxSubkeyLen
);
629 for (i
= 0; i
< (int) InterfacesCount
; ++i
) {
632 if (RegEnumKeyEx(hndKey
, i
, keyname
, &j
, NULL
, NULL
, NULL
, &ftLastWriteTime
) == ERROR_SUCCESS
) {
634 newkeyname
= (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES
) + j
+ 2);
635 strcpy(newkeyname
, REG_TCPIP_PARA_INTERFACES
);
636 strcat(newkeyname
, "\\");
637 strcat(newkeyname
, keyname
);
638 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, newkeyname
, 0, KEY_QUERY_VALUE
, &hndKey2
) == ERROR_SUCCESS
) {
642 Result
= RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, NULL
, &Size
);
643 if (Result
== ERROR_SUCCESS
&& Size
) {
644 t
= (char *) xmalloc(Size
);
645 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
646 token
= strtok(t
, ", ");
648 debugs(78, DBG_IMPORTANT
, "Adding DHCP nameserver " << token
<< " from Registry");
649 idnsAddNameserver(token
);
651 token
= strtok(NULL
, ", ");
656 Result
= RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, NULL
, &Size
);
657 if (Result
== ERROR_SUCCESS
&& Size
) {
658 t
= (char *) xmalloc(Size
);
659 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
, (LPBYTE
)t
, &Size
);
660 token
= strtok(t
, ", ");
662 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
663 idnsAddNameserver(token
);
665 token
= strtok(NULL
, ", ");
671 RegCloseKey(hndKey2
);
684 idnsParseWIN32SearchList(", ");
693 /* get nameservers from the Windows 9X registry */
695 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REG_VXD_MSTCP
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
699 Result
= RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
701 if (Result
== ERROR_SUCCESS
&& Size
) {
702 t
= (char *) xmalloc(Size
);
703 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, (LPBYTE
) t
, &Size
);
704 token
= strtok(t
, ", ");
707 debugs(78, DBG_IMPORTANT
, "Adding nameserver " << token
<< " from Registry");
708 idnsAddNameserver(token
);
710 token
= strtok(NULL
, ", ");
721 debugs(78, DBG_IMPORTANT
, "Failed to read nameserver from Registry: Unknown System Type.");
730 idnsStats(StoreEntry
* sentry
)
736 char buf
[MAX_IPSTRLEN
];
737 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
738 storeAppendPrintf(sentry
, "\nThe Queue:\n");
739 storeAppendPrintf(sentry
, " DELAY SINCE\n");
740 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND M FQDN\n");
741 storeAppendPrintf(sentry
, "------ ---- ----- ---------- --------- - ----\n");
743 for (n
= lru_list
.head
; n
; n
= n
->next
) {
744 q
= (idns_query
*)n
->data
;
745 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f %c %s\n",
746 (int) q
->query_id
, (int) q
->sz
, q
->nsends
,
747 tvSubDsec(q
->start_t
, current_time
),
748 tvSubDsec(q
->sent_t
, current_time
),
749 (q
->permit_mdns
? 'M':' '),
753 if (Config
.dns
.packet_max
> 0)
754 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: %zd Bytes\n", Config
.dns
.packet_max
);
756 storeAppendPrintf(sentry
, "\nDNS jumbo-grams: not working\n");
758 storeAppendPrintf(sentry
, "\nNameservers:\n");
759 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES Type\n");
760 storeAppendPrintf(sentry
, "---------------------------------------------- --------- --------- --------\n");
762 for (i
= 0; i
< nns
; ++i
) {
763 storeAppendPrintf(sentry
, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
764 nameservers
[i
].S
.toStr(buf
,MAX_IPSTRLEN
),
765 nameservers
[i
].nqueries
,
766 nameservers
[i
].nreplies
,
767 nameservers
[i
].mDNSResolver
?"multicast":"recurse");
770 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
771 storeAppendPrintf(sentry
, "RCODE");
773 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
774 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
776 storeAppendPrintf(sentry
, " PROBLEM\n");
778 for (j
= 0; j
< MAX_RCODE
; ++j
) {
779 if (j
> 10 && j
< 16)
780 continue; // unassigned by IANA.
782 storeAppendPrintf(sentry
, "%5d", j
);
784 for (i
= 0; i
< MAX_ATTEMPT
; ++i
)
785 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
787 storeAppendPrintf(sentry
, " : %s\n",Rcodes
[j
]);
791 storeAppendPrintf(sentry
, "\nSearch list:\n");
793 for (i
=0; i
< npc
; ++i
)
794 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
796 storeAppendPrintf(sentry
, "\n");
801 idnsTickleQueue(void)
806 if (NULL
== lru_list
.tail
)
809 const double when
= min(Config
.Timeout
.idns_query
, Config
.Timeout
.idns_retransmit
)/1000.0;
811 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, when
, 1);
817 idnsSentQueryVC(const Comm::ConnectionPointer
&conn
, char *, size_t size
, Comm::Flag flag
, int, void *data
)
819 nsvc
* vc
= (nsvc
*)data
;
821 if (flag
== Comm::ERR_CLOSING
)
824 // XXX: irrelevant now that we have conn pointer?
825 if (!Comm::IsConnOpen(conn
) || fd_table
[conn
->fd
].closing())
828 if (flag
!= Comm::OK
|| size
<= 0) {
834 idnsDoSendQueryVC(vc
);
838 idnsDoSendQueryVC(nsvc
*vc
)
843 if (vc
->queue
->contentSize() == 0)
846 // if retrying after a TC UDP response, our close handler cb may be pending
847 if (fd_table
[vc
->conn
->fd
].closing())
850 MemBuf
*mb
= vc
->queue
;
852 vc
->queue
= new MemBuf
;
856 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
857 const int timeout
= (Config
.Timeout
.idns_query
% 1000 ?
858 Config
.Timeout
.idns_query
+ 1000 : Config
.Timeout
.idns_query
) / 1000;
859 AsyncCall::Pointer nil
;
861 commSetConnTimeout(vc
->conn
, timeout
, nil
);
863 AsyncCall::Pointer call
= commCbCall(78, 5, "idnsSentQueryVC",
864 CommIoCbPtrFun(&idnsSentQueryVC
, vc
));
865 Comm::Write(vc
->conn
, mb
, call
);
871 idnsInitVCConnected(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int, void *data
)
873 nsvc
* vc
= (nsvc
*)data
;
875 if (status
!= Comm::OK
|| !conn
) {
876 char buf
[MAX_IPSTRLEN
] = "";
878 nameservers
[vc
->ns
].S
.toStr(buf
,MAX_IPSTRLEN
);
879 debugs(78, DBG_IMPORTANT
, HERE
<< "Failed to connect to nameserver " << buf
<< " using TCP.");
885 comm_add_close_handler(conn
->fd
, idnsVCClosed
, vc
);
886 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
887 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
888 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
890 idnsDoSendQueryVC(vc
);
894 idnsVCClosed(const CommCloseCbParams
¶ms
)
896 nsvc
* vc
= (nsvc
*)params
.data
;
904 if (ns
< nns
) // XXX: Dns::Shutdown may have freed nameservers[]
905 nameservers
[ns
].vc
= NULL
;
911 nsvc
*vc
= new nsvc(nsv
);
913 assert(vc
->conn
== NULL
); // MUST be NULL from the construction process!
914 nameservers
[nsv
].vc
= vc
;
916 Comm::ConnectionPointer conn
= new Comm::Connection();
918 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
919 conn
->setAddrs(Config
.Addrs
.udp_outgoing
, nameservers
[nsv
].S
);
921 conn
->setAddrs(Config
.Addrs
.udp_incoming
, nameservers
[nsv
].S
);
923 if (conn
->remote
.isIPv4())
924 conn
->local
.setIPv4();
926 AsyncCall::Pointer call
= commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected
, vc
));
928 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, Config
.Timeout
.connect
);
929 cs
->setHost("DNS TCP Socket");
934 idnsSendQueryVC(idns_query
* q
, int nsn
)
937 if (nameservers
[nsn
].vc
== NULL
)
940 nsvc
*vc
= nameservers
[nsn
].vc
;
943 char buf
[MAX_IPSTRLEN
];
944 debugs(78, DBG_IMPORTANT
, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers
[nsn
].S
.toStr(buf
,MAX_IPSTRLEN
) << "!");
951 short head
= htons(q
->sz
);
953 vc
->queue
->append((char *)&head
, 2);
955 vc
->queue
->append(q
->buf
, q
->sz
);
957 idnsDoSendQueryVC(vc
);
961 idnsSendQuery(idns_query
* q
)
963 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
964 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
969 debugs(78, DBG_IMPORTANT
, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
973 assert(q
->lru
.next
== NULL
);
975 assert(q
->lru
.prev
== NULL
);
981 // only use mDNS resolvers for mDNS compatible queries
983 nsn
= nns_mdns_count
+ q
->nsends
% (nns
-nns_mdns_count
);
985 nsn
= q
->nsends
% nns
;
988 idnsSendQueryVC(q
, nsn
);
991 if (DnsSocketB
>= 0 && nameservers
[nsn
].S
.isIPv6())
992 y
= comm_udp_sendto(DnsSocketB
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
993 else if (DnsSocketA
>= 0)
994 x
= comm_udp_sendto(DnsSocketA
, nameservers
[nsn
].S
, q
->buf
, q
->sz
);
999 q
->sent_t
= current_time
;
1001 if (y
< 0 && nameservers
[nsn
].S
.isIPv6())
1002 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketB
<< ": sendto: " << xstrerror());
1003 if (x
< 0 && nameservers
[nsn
].S
.isIPv4())
1004 debugs(50, DBG_IMPORTANT
, "idnsSendQuery: FD " << DnsSocketA
<< ": sendto: " << xstrerror());
1006 } while ( (x
<0 && y
<0) && q
->nsends
% nns
!= 0);
1009 fd_bytes(DnsSocketB
, y
, FD_WRITE
);
1012 fd_bytes(DnsSocketA
, x
, FD_WRITE
);
1015 ++ nameservers
[nsn
].nqueries
;
1016 q
->queue_t
= current_time
;
1017 dlinkAdd(q
, &q
->lru
, &lru_list
);
1023 idnsFromKnownNameserver(Ip::Address
const &from
)
1027 for (i
= 0; i
< nns
; ++i
) {
1028 if (nameservers
[i
].S
!= from
)
1031 if (nameservers
[i
].S
.port() != from
.port())
1041 idnsFindQuery(unsigned short id
)
1046 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
1047 q
= (idns_query
*)n
->data
;
1049 if (q
->query_id
== id
)
1056 static unsigned short
1059 unsigned short id
= squid_random() & 0xFFFF;
1060 unsigned short first_id
= id
;
1062 while (idnsFindQuery(id
)) {
1065 if (id
== first_id
) {
1066 debugs(78, DBG_IMPORTANT
, "idnsQueryID: Warning, too many pending DNS requests");
1075 idnsCallback(idns_query
*q
, const char *error
)
1086 // If any of our subqueries are still pending then wait for them to complete before continuing
1087 for (idns_query
*q2
= q
; q2
; q2
= q2
->slave
) {
1094 rfc1035_message
*message
= q
->message
;
1099 while ( idns_query
*q2
= q
->slave
) {
1100 debugs(78, 6, HERE
<< "Merging DNS results " << q
->name
<< " A has " << n
<< " RR, AAAA has " << q2
->ancount
<< " RR");
1101 q
->slave
= q2
->slave
;
1105 // two sets of RR need merging
1106 rfc1035_rr
*result
= (rfc1035_rr
*) xmalloc( sizeof(rfc1035_rr
)*(n
+ q2
->ancount
) );
1107 if (Config
.dns
.v4_first
) {
1108 memcpy(result
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1109 memcpy(result
+n
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1111 memcpy(result
, q2
->message
->answer
, (sizeof(rfc1035_rr
)*q2
->ancount
) );
1112 memcpy(result
+q2
->ancount
, message
->answer
, (sizeof(rfc1035_rr
)*n
) );
1115 // HACK WARNING, the answer rr:s have been copied in-place to
1116 // result, do not free them here
1117 safe_free(message
->answer
);
1118 safe_free(q2
->message
->answer
);
1119 message
->answer
= result
;
1120 message
->ancount
+= q2
->message
->ancount
;
1122 // first response empty or failed, just use the second
1123 rfc1035MessageDestroy(&message
);
1124 message
= q2
->message
;
1133 debugs(78, 6, HERE
<< "Sending " << n
<< " (" << (error
? error
: "OK") << ") DNS results to caller.");
1135 callback
= q
->callback
;
1137 const rfc1035_rr
*answers
= message
? message
->answer
: NULL
;
1139 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
1140 callback(cbdata
, answers
, n
, error
);
1143 idns_query
*q2
= q
->queue
;
1144 q
->queue
= q2
->queue
;
1147 callback
= q2
->callback
;
1148 q2
->callback
= NULL
;
1150 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
1151 callback(cbdata
, answers
, n
, error
);
1157 hash_remove_link(idns_lookup_hash
, &q
->hash
);
1161 rfc1035MessageDestroy(&message
);
1166 idnsGrokReply(const char *buf
, size_t sz
, int /*from_ns*/)
1168 rfc1035_message
*message
= NULL
;
1170 int n
= rfc1035MessageUnpack(buf
, sz
, &message
);
1172 if (message
== NULL
) {
1173 debugs(78, DBG_IMPORTANT
, "idnsGrokReply: Malformed DNS response");
1177 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
1179 idns_query
*q
= idnsFindQuery(message
->id
);
1182 debugs(78, 3, "idnsGrokReply: Late response");
1183 rfc1035MessageDestroy(&message
);
1187 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
1188 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
1189 rfc1035MessageDestroy(&message
);
1193 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1194 // TODO: actually gr the message right here.
1195 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1196 // this is overall better than force-feeding A response with AAAA an section later anyway.
1197 // AND allows us to merge AN+AR sections from both responses (one day)
1199 if (q
->edns_seen
>= 0) {
1200 if (max_shared_edns
== nameservers
[from_ns
].last_seen_edns
&& max_shared_edns
< q
->edns_seen
) {
1201 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1202 // the altered NS was limiting the whole group.
1203 max_shared_edns
= q
->edns_seen
;
1204 // may be limited by one of the others still
1205 for (int i
= 0; i
< nns
; ++i
)
1206 max_shared_edns
= min(max_shared_edns
, nameservers
[i
].last_seen_edns
);
1208 nameservers
[from_ns
].last_seen_edns
= q
->edns_seen
;
1209 // maybe reduce the global limit downwards to accomodate this NS
1210 max_shared_edns
= min(max_shared_edns
, q
->edns_seen
);
1212 if (max_shared_edns
< RFC1035_DEFAULT_PACKET_SZ
)
1213 max_shared_edns
= -1;
1217 dlinkDelete(&q
->lru
, &lru_list
);
1221 debugs(78, 3, HERE
<< "Resolver requested TC (" << q
->query
.name
<< ")");
1222 rfc1035MessageDestroy(&message
);
1229 // Strange: A TCP DNS response with the truncation bit (TC) set.
1230 // Return an error and cleanup; no point in trying TCP again.
1231 debugs(78, 3, HERE
<< "TCP DNS response");
1232 idnsCallback(q
, "Truncated TCP DNS response");
1238 idnsRcodeCount(n
, q
->attempt
);
1242 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n
) << " (" << q
->rcode
<< ")");
1244 if (q
->rcode
== 2 && (++ q
->attempt
) < MAX_ATTEMPT
) {
1246 * RCODE 2 is "Server failure - The name server was
1247 * unable to process this query due to a problem with
1250 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1251 rfc1035MessageDestroy(&message
);
1256 // Do searchpath processing on the master A query only to keep
1257 // things simple. NXDOMAIN is authorative for the label, not
1259 if (q
->rcode
== 3 && !q
->master
&& q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
1260 assert(NULL
== message
->answer
);
1261 strcpy(q
->name
, q
->orig
);
1263 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
1265 if (q
->domain
< npc
) {
1266 strcat(q
->name
, ".");
1267 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1268 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
1274 rfc1035MessageDestroy(&message
);
1276 // cleanup slave AAAA query
1277 while (idns_query
*slave
= q
->slave
) {
1278 dlinkDelete(&slave
->lru
, &lru_list
);
1279 q
->slave
= slave
->slave
;
1280 slave
->slave
= NULL
;
1285 q
->query_id
= idnsQueryID();
1286 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
1287 // see EDNS notes at top of file why this sends 0
1288 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1290 /* problem with query data -- query not sent */
1291 idnsCallback(q
, "Internal error");
1300 idnsSendSlaveAAAAQuery(q
);
1305 q
->message
= message
;
1309 idnsCallback(q
, NULL
);
1311 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1316 idnsRead(int fd
, void *)
1318 int *N
= &incoming_sockets_accepted
;
1320 int max
= INCOMING_DNS_MAX
;
1321 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1324 debugs(78, 3, "idnsRead: starting with FD " << fd
);
1326 // Always keep reading. This stops (or at least makes harder) several
1327 // attacks on the DNS client.
1328 Comm::SetSelect(fd
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1331 * two code lines after returning from comm_udprecvfrom()
1332 * something overwrites the memory behind the from parameter.
1333 * NO matter where in the stack declaration list above it is placed
1334 * The cause of this is still unknown, however copying the data appears
1335 * to allow it to be passed further without this erasure.
1337 Ip::Address bugbypass
;
1341 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1343 from
= bugbypass
; // BUG BYPASS. see notes above.
1349 if (ignoreErrno(errno
))
1353 /* Some Linux systems seem to set the FD for reading and then
1354 * return ECONNREFUSED when sendto() fails and generates an ICMP
1355 * port unreachable message. */
1356 /* or maybe an EHOSTUNREACH "No route to host" message */
1357 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1360 debugs(50, DBG_IMPORTANT
, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1365 fd_bytes(fd
, len
, FD_READ
);
1370 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1372 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1373 int nsn
= idnsFromKnownNameserver(from
);
1376 ++ nameservers
[nsn
].nreplies
;
1379 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1380 // but after the ++ above to keep statistics right.
1382 continue; // Don't process replies if there is no pending query.
1384 if (nsn
< 0 && Config
.onoff
.ignore_unknown_nameservers
) {
1385 static time_t last_warning
= 0;
1387 if (squid_curtime
- last_warning
> 60) {
1388 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
);
1389 last_warning
= squid_curtime
;
1391 debugs(78, DBG_IMPORTANT
, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1396 idnsGrokReply(rbuf
, len
, nsn
);
1401 idnsCheckQueue(void *)
1404 dlink_node
*p
= NULL
;
1409 /* name servers went away; reconfiguring or shutting down */
1412 for (n
= lru_list
.tail
; n
; n
= p
) {
1415 q
= static_cast<idns_query
*>(n
->data
);
1417 /* Anything to process in the queue? */
1418 if ((time_msec_t
)tvSubMsec(q
->queue_t
, current_time
) < Config
.Timeout
.idns_retransmit
)
1421 /* Query timer still running? */
1422 if ((time_msec_t
)tvSubMsec(q
->sent_t
, current_time
) < (Config
.Timeout
.idns_retransmit
* 1 << ((q
->nsends
- 1) / nns
))) {
1423 dlinkDelete(&q
->lru
, &lru_list
);
1424 q
->queue_t
= current_time
;
1425 dlinkAdd(q
, &q
->lru
, &lru_list
);
1429 debugs(78, 3, "idnsCheckQueue: ID " << q
->xact_id
<<
1430 " QID 0x" << std::hex
<< std::setfill('0') <<
1431 std::setw(4) << q
->query_id
<< ": timeout" );
1433 dlinkDelete(&q
->lru
, &lru_list
);
1436 if ((time_msec_t
)tvSubMsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1439 debugs(78, 2, "idnsCheckQueue: ID " << q
->xact_id
<<
1440 " QID 0x" << std::hex
<< q
->query_id
<<
1441 " : giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1442 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1445 idnsCallback(q
, rfc1035ErrorMessage(q
->rcode
));
1447 idnsCallback(q
, "Timeout");
1455 idnsReadVC(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1457 nsvc
* vc
= (nsvc
*)data
;
1459 if (flag
== Comm::ERR_CLOSING
)
1462 if (flag
!= Comm::OK
|| len
<= 0) {
1463 if (Comm::IsConnOpen(conn
))
1468 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1470 if (vc
->msg
->contentSize() < vc
->msglen
) {
1471 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1472 CommIoCbPtrFun(idnsReadVC
, vc
));
1473 comm_read(conn
, buf
+len
, vc
->msglen
- vc
->msg
->contentSize(), call
);
1477 assert(vc
->ns
< nns
);
1478 debugs(78, 3, HERE
<< conn
<< ": received " << vc
->msg
->contentSize() << " bytes via TCP from " << nameservers
[vc
->ns
].S
<< ".");
1480 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize(), vc
->ns
);
1482 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1483 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1484 comm_read(conn
, (char *)&vc
->msglen
, 2, call
);
1488 idnsReadVCHeader(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int, void *data
)
1490 nsvc
* vc
= (nsvc
*)data
;
1492 if (flag
== Comm::ERR_CLOSING
)
1495 if (flag
!= Comm::OK
|| len
<= 0) {
1496 if (Comm::IsConnOpen(conn
))
1501 vc
->read_msglen
+= len
;
1503 assert(vc
->read_msglen
<= 2);
1505 if (vc
->read_msglen
< 2) {
1506 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVCHeader",
1507 CommIoCbPtrFun(idnsReadVCHeader
, vc
));
1508 comm_read(conn
, buf
+len
, 2 - vc
->read_msglen
, call
);
1512 vc
->read_msglen
= 0;
1514 vc
->msglen
= ntohs(vc
->msglen
);
1517 if (Comm::IsConnOpen(conn
))
1522 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1523 AsyncCall::Pointer call
= commCbCall(5,4, "idnsReadVC",
1524 CommIoCbPtrFun(idnsReadVC
, vc
));
1525 comm_read(conn
, vc
->msg
->buf
, vc
->msglen
, call
);
1529 * rcode < 0 indicates an error, rocde >= 0 indicates success
1532 idnsRcodeCount(int rcode
, int attempt
)
1539 if (rcode
< MAX_RCODE
)
1540 if (attempt
< MAX_ATTEMPT
)
1541 ++ RcodeMatrix
[rcode
][attempt
];
1547 static int init
= 0;
1549 if (DnsSocketA
< 0 && DnsSocketB
< 0) {
1550 Ip::Address addrV6
; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1552 if (!Config
.Addrs
.udp_outgoing
.isNoAddr())
1553 addrV6
= Config
.Addrs
.udp_outgoing
;
1555 addrV6
= Config
.Addrs
.udp_incoming
;
1557 Ip::Address addrV4
= addrV6
;
1560 if (Ip::EnableIpv6
&& addrV6
.isIPv6()) {
1561 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6
);
1562 DnsSocketB
= comm_open_listener(SOCK_DGRAM
,
1569 if (addrV4
.isIPv4()) {
1570 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4
);
1571 DnsSocketA
= comm_open_listener(SOCK_DGRAM
,
1578 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1579 fatal("Could not create a DNS socket");
1581 /* Ouch... we can't call functions using debug from a debug
1582 * statement. Doing so messes up the internal Debug::level
1584 if (DnsSocketB
>= 0) {
1585 comm_local_port(DnsSocketB
);
1586 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV6
<< ", FD " << DnsSocketB
);
1587 Comm::SetSelect(DnsSocketB
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1589 if (DnsSocketA
>= 0) {
1590 comm_local_port(DnsSocketA
);
1591 debugs(78, DBG_IMPORTANT
, "DNS Socket created at " << addrV4
<< ", FD " << DnsSocketA
);
1592 Comm::SetSelect(DnsSocketA
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1597 idnsAddMDNSNameservers();
1598 bool nsFound
= idnsParseNameservers();
1601 nsFound
= idnsParseResolvConf();
1605 nsFound
= idnsParseWIN32Registry();
1609 debugs(78, DBG_IMPORTANT
, "Warning: Could not find any nameservers. Trying to use localhost");
1611 debugs(78, DBG_IMPORTANT
, "Please check your TCP-IP settings or /etc/resolv.conf file");
1613 debugs(78, DBG_IMPORTANT
, "Please check your /etc/resolv.conf file");
1616 debugs(78, DBG_IMPORTANT
, "or use the 'dns_nameservers' option in squid.conf.");
1618 idnsAddNameserver("::1");
1619 idnsAddNameserver("127.0.0.1");
1623 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1624 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1625 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1629 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1630 if (Config
.onoff
.ignore_unknown_nameservers
&& max_shared_edns
> 0) {
1631 debugs(0, DBG_IMPORTANT
, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1632 max_shared_edns
= -1; // disable if we might receive random replies.
1636 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1642 if (DnsSocketA
< 0 && DnsSocketB
< 0)
1645 if (DnsSocketA
>= 0 ) {
1646 comm_close(DnsSocketA
);
1650 if (DnsSocketB
>= 0 ) {
1651 comm_close(DnsSocketB
);
1655 for (int i
= 0; i
< nns
; ++i
) {
1656 if (nsvc
*vc
= nameservers
[i
].vc
) {
1657 if (Comm::IsConnOpen(vc
->conn
))
1662 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1663 idnsFreeNameservers();
1664 idnsFreeSearchpath();
1668 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1670 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1675 idns_query
*q
= new idns_query
;
1676 // no query_id on this instance.
1678 q
->callback
= callback
;
1679 q
->callback_data
= cbdataReference(data
);
1681 q
->queue
= old
->queue
;
1688 idnsStartQuery(idns_query
*q
, IDNSCB
* callback
, void *data
)
1690 q
->start_t
= current_time
;
1691 q
->callback
= callback
;
1692 q
->callback_data
= cbdataReference(data
);
1694 q
->hash
.key
= q
->orig
;
1695 hash_join(idns_lookup_hash
, &q
->hash
);
1701 idnsSendSlaveAAAAQuery(idns_query
*master
)
1703 idns_query
*q
= new idns_query
;
1704 memcpy(q
->name
, master
->name
, sizeof(q
->name
));
1705 memcpy(q
->orig
, master
->orig
, sizeof(q
->orig
));
1707 q
->query_id
= idnsQueryID();
1708 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1710 debugs(78, 3, HERE
<< "buf is " << q
->sz
<< " bytes for " << q
->name
<<
1711 ", id = 0x" << std::hex
<< q
->query_id
);
1717 q
->start_t
= master
->start_t
;
1718 q
->slave
= master
->slave
;
1726 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1728 size_t nameLength
= strlen(name
);
1730 // Prevent buffer overflow on q->name
1731 if (nameLength
> NS_MAXDNAME
) {
1732 debugs(23, DBG_IMPORTANT
, "SECURITY ALERT: DNS name too long to perform lookup: '" << name
<< "'. see access.log for details.");
1733 callback(data
, NULL
, 0, "Internal error");
1737 if (idnsCachedLookup(name
, callback
, data
))
1740 idns_query
*q
= new idns_query
;
1741 q
->query_id
= idnsQueryID();
1744 for (unsigned int i
= 0; i
< nameLength
; ++i
)
1748 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[nameLength
-1] != '.') {
1749 q
->do_searchpath
= 1;
1751 q
->do_searchpath
= 0;
1754 strcpy(q
->orig
, name
);
1755 strcpy(q
->name
, q
->orig
);
1757 if (q
->do_searchpath
&& nd
< ndots
) {
1759 strcat(q
->name
, ".");
1760 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1761 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1764 // see EDNS notes at top of file why this sends 0
1765 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1768 /* problem with query data -- query not sent */
1769 callback(data
, NULL
, 0, "Internal error");
1774 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1775 ", id = 0x" << std::hex
<< q
->query_id
);
1778 idnsStartQuery(q
, callback
, data
);
1781 idnsSendSlaveAAAAQuery(q
);
1785 idnsPTRLookup(const Ip::Address
&addr
, IDNSCB
* callback
, void *data
)
1787 char ip
[MAX_IPSTRLEN
];
1789 addr
.toStr(ip
,MAX_IPSTRLEN
);
1791 idns_query
*q
= new idns_query
;
1792 q
->query_id
= idnsQueryID();
1794 if (addr
.isIPv6()) {
1795 struct in6_addr addr6
;
1796 addr
.getInAddr(addr6
);
1797 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, Config
.dns
.packet_max
);
1799 struct in_addr addr4
;
1800 addr
.getInAddr(addr4
);
1801 // see EDNS notes at top of file why this sends 0
1802 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->query_id
, &q
->query
, 0);
1806 /* problem with query data -- query not sent */
1807 callback(data
, NULL
, 0, "Internal error");
1812 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1817 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1818 ", id = 0x" << std::hex
<< q
->query_id
);
1820 q
->permit_mdns
= Config
.onoff
.dns_mdns
;
1821 idnsStartQuery(q
, callback
, data
);
1826 * The function to return the DNS via SNMP
1829 snmp_netDnsFn(variable_list
* Var
, snint
* ErrP
)
1832 variable_list
*Answer
= NULL
;
1834 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
1835 *ErrP
= SNMP_ERR_NOERROR
;
1837 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1841 for (i
= 0; i
< nns
; ++i
)
1842 n
+= nameservers
[i
].nqueries
;
1844 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1851 for (i
= 0; i
< nns
; ++i
)
1852 n
+= nameservers
[i
].nreplies
;
1854 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1861 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1868 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1876 #endif /*SQUID_SNMP */