3 * $Id: dns_internal.cc,v 1.102 2007/12/14 23:11:46 amosjeffries Exp $
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 "CacheManager.h"
40 #include "SquidTime.h"
47 #if HAVE_ARPA_NAMESER_H
48 #include <arpa/nameser.h>
54 /* MS VisualStudio Projects are monolithic, so we need the following
55 #ifndef to exclude the internal DNS code from compile process when
56 using external DNS process.
58 #ifndef USE_DNSSERVERS
60 #include "squid_windows.h"
63 #define _PATH_RESCONF "/etc/resolv.conf"
65 #ifndef NS_DEFAULTPORT
66 #define NS_DEFAULTPORT 53
70 #define NS_MAXDNAME 1025
77 /* The buffer size required to store the maximum allowed search path */
79 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
82 #define IDNS_MAX_TRIES 20
85 static int RcodeMatrix
[MAX_RCODE
][MAX_ATTEMPT
];
87 typedef struct _idns_query idns_query
;
89 typedef struct _ns ns
;
91 typedef struct _sp sp
;
93 typedef struct _nsvc nsvc
;
99 char buf
[RESOLV_BUFSZ
];
100 char name
[NS_MAXDNAME
+ 1];
101 char orig
[NS_MAXDNAME
+ 1];
107 struct timeval start_t
;
109 struct timeval sent_t
;
117 unsigned short domain
;
118 unsigned short do_searchpath
;
126 unsigned short msglen
;
143 char domain
[NS_MAXDNAME
];
148 CBDATA_TYPE(idns_query
);
150 static ns
*nameservers
= NULL
;
151 static sp
*searchpath
= NULL
;
153 static int nns_alloc
= 0;
155 static int npc_alloc
= 0;
156 static int ndots
= 1;
157 static dlink_list lru_list
;
158 static int event_queued
= 0;
159 static hash_table
*idns_lookup_hash
= NULL
;
161 static OBJH idnsStats
;
162 static void idnsAddNameserver(const char *buf
);
163 static void idnsAddPathComponent(const char *buf
);
164 static void idnsFreeNameservers(void);
165 static void idnsFreeSearchpath(void);
166 static void idnsParseNameservers(void);
167 #ifndef _SQUID_MSWIN_
168 static void idnsParseResolvConf(void);
171 static void idnsParseWIN32Registry(void);
172 static void idnsParseWIN32SearchList(const char *);
174 static void idnsCacheQuery(idns_query
* q
);
175 static void idnsSendQuery(idns_query
* q
);
176 static IOCB idnsReadVCHeader
;
177 static void idnsDoSendQueryVC(nsvc
*vc
);
179 static int idnsFromKnownNameserver(IPAddress
const &from
);
180 static idns_query
*idnsFindQuery(unsigned short id
);
181 static void idnsGrokReply(const char *buf
, size_t sz
);
183 static EVH idnsCheckQueue
;
184 static void idnsTickleQueue(void);
185 static void idnsRcodeCount(int, int);
188 idnsAddNameserver(const char *buf
)
193 debugs(78, 0, "WARNING: rejecting '" << buf
<< "' as a name server, because it is not a numeric IP address");
198 debugs(78, 0, "WARNING: Squid does not accept " << A
<< " in DNS server specifications.");
200 debugs(78, 0, "Will be using " << A
<< " instead, assuming you meant that DNS is running on the same machine");
203 if (nns
== nns_alloc
) {
204 int oldalloc
= nns_alloc
;
205 ns
*oldptr
= nameservers
;
212 nameservers
= (ns
*)xcalloc(nns_alloc
, sizeof(*nameservers
));
214 if (oldptr
&& oldalloc
)
215 xmemcpy(nameservers
, oldptr
, oldalloc
* sizeof(*nameservers
));
221 assert(nns
< nns_alloc
);
222 A
.SetPort(NS_DEFAULTPORT
);
223 nameservers
[nns
].S
= A
;
224 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns
<< " (" << A
<< ")");
229 idnsAddPathComponent(const char *buf
)
231 if (npc
== npc_alloc
) {
232 int oldalloc
= npc_alloc
;
233 sp
*oldptr
= searchpath
;
240 searchpath
= (sp
*)xcalloc(npc_alloc
, sizeof(*searchpath
));
242 if (oldptr
&& oldalloc
)
243 xmemcpy(searchpath
, oldptr
, oldalloc
* sizeof(*searchpath
));
249 assert(npc
< npc_alloc
);
250 strcpy(searchpath
[npc
].domain
, buf
);
251 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc
<< ": " << searchpath
[npc
].domain
);
257 idnsFreeNameservers(void)
259 safe_free(nameservers
);
264 idnsFreeSearchpath(void)
266 safe_free(searchpath
);
273 idnsParseNameservers(void)
277 for (w
= Config
.dns_nameservers
; w
; w
= w
->next
) {
278 debugs(78, 1, "Adding nameserver " << w
->key
<< " from squid.conf");
279 idnsAddNameserver(w
->key
);
283 #ifndef _SQUID_MSWIN_
285 idnsParseResolvConf(void)
288 char buf
[RESOLV_BUFSZ
];
290 fp
= fopen(_PATH_RESCONF
, "r");
293 debugs(78, 1, "" << _PATH_RESCONF
<< ": " << xstrerror());
297 #if defined(_SQUID_CYGWIN_)
298 setmode(fileno(fp
), O_TEXT
);
302 while (fgets(buf
, RESOLV_BUFSZ
, fp
)) {
303 t
= strtok(buf
, w_space
);
307 } else if (strcasecmp(t
, "nameserver") == 0) {
308 t
= strtok(NULL
, w_space
);
313 debugs(78, 1, "Adding nameserver " << t
<< " from " << _PATH_RESCONF
);
315 idnsAddNameserver(t
);
316 } else if (strcasecmp(t
, "search") == 0) {
318 t
= strtok(NULL
, w_space
);
323 debugs(78, 1, "Adding domain " << t
<< " from " << _PATH_RESCONF
);
325 idnsAddPathComponent(t
);
327 } else if (strcasecmp(t
, "options") == 0) {
329 t
= strtok(NULL
, w_space
);
334 if (strncmp(t
, "ndots:", 6) != 0) {
340 debugs(78, 1, "Adding ndots " << ndots
<< " from " << _PATH_RESCONF
);
353 idnsParseWIN32SearchList(const char * Separator
)
359 if (RegOpenKey(HKEY_LOCAL_MACHINE
,
360 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
361 &hndKey
) == ERROR_SUCCESS
) {
366 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, NULL
,
369 if (Result
== ERROR_SUCCESS
&& Size
) {
370 t
= (unsigned char *) xmalloc(Size
);
371 RegQueryValueEx(hndKey
, "SearchList", NULL
, &Type
, t
,
373 token
= strtok((char *) t
, Separator
);
376 idnsAddPathComponent(token
);
377 debugs(78, 1, "Adding domain " << token
<< " from Registry");
378 token
= strtok(NULL
, Separator
);
387 idnsParseWIN32Registry(void)
391 HKEY hndKey
, hndKey2
;
393 idnsFreeNameservers();
395 switch (WIN32_OS_version
) {
398 /* get nameservers from the Windows NT registry */
400 if (RegOpenKey(HKEY_LOCAL_MACHINE
,
401 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
402 &hndKey
) == ERROR_SUCCESS
) {
407 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, NULL
,
410 if (Result
== ERROR_SUCCESS
&& Size
) {
411 t
= (unsigned char *) xmalloc(Size
);
412 RegQueryValueEx(hndKey
, "DhcpNameServer", NULL
, &Type
, t
,
414 token
= strtok((char *) t
, ", ");
417 idnsAddNameserver(token
);
418 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
419 token
= strtok(NULL
, ",");
424 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
426 if (Result
== ERROR_SUCCESS
&& Size
) {
427 t
= (unsigned char *) xmalloc(Size
);
428 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, t
, &Size
);
429 token
= strtok((char *) t
, ", ");
432 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
433 idnsAddNameserver(token
);
434 token
= strtok(NULL
, ", ");
441 idnsParseWIN32SearchList(" ");
452 /* get nameservers from the Windows 2000 registry */
453 /* search all interfaces for DNS server addresses */
455 if (RegOpenKey(HKEY_LOCAL_MACHINE
,
456 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces",
457 &hndKey
) == ERROR_SUCCESS
) {
461 for (i
= 0; i
< 10; i
++) {
462 if (RegEnumKey(hndKey
, i
, (char *) &keyname
,
463 255) == ERROR_SUCCESS
) {
464 char newkeyname
[255];
466 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
467 strcat(newkeyname
, keyname
);
469 if (RegOpenKey(HKEY_LOCAL_MACHINE
, newkeyname
,
470 &hndKey2
) == ERROR_SUCCESS
) {
475 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
,
478 if (Result
== ERROR_SUCCESS
&& Size
) {
479 t
= (unsigned char *) xmalloc(Size
);
480 RegQueryValueEx(hndKey2
, "DhcpNameServer", NULL
,
482 token
= strtok((char *) t
, ", ");
485 debugs(78, 1, "Adding DHCP nameserver " << token
<< " from Registry");
486 idnsAddNameserver(token
);
487 token
= strtok(NULL
, ", ");
492 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
,
495 if (Result
== ERROR_SUCCESS
&& Size
) {
496 t
= (unsigned char *) xmalloc(Size
);
497 RegQueryValueEx(hndKey2
, "NameServer", NULL
, &Type
,
499 token
= strtok((char *) t
, ", ");
502 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
503 idnsAddNameserver(token
);
504 token
= strtok(NULL
, ", ");
508 RegCloseKey(hndKey2
);
516 idnsParseWIN32SearchList(", ");
525 /* get nameservers from the Windows 9X registry */
527 if (RegOpenKey(HKEY_LOCAL_MACHINE
,
528 "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
529 &hndKey
) == ERROR_SUCCESS
) {
534 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, NULL
, &Size
);
536 if (Result
== ERROR_SUCCESS
&& Size
) {
537 t
= (unsigned char *) xmalloc(Size
);
538 RegQueryValueEx(hndKey
, "NameServer", NULL
, &Type
, t
, &Size
);
539 token
= strtok((char *) t
, ", ");
542 debugs(78, 1, "Adding nameserver " << token
<< " from Registry");
543 idnsAddNameserver(token
);
544 token
= strtok(NULL
, ", ");
554 debugs(78, 1, "Failed to read nameserver from Registry: Unknown System Type.");
562 idnsStats(StoreEntry
* sentry
)
568 char buf
[MAX_IPSTRLEN
];
569 storeAppendPrintf(sentry
, "Internal DNS Statistics:\n");
570 storeAppendPrintf(sentry
, "\nThe Queue:\n");
571 storeAppendPrintf(sentry
, " DELAY SINCE\n");
572 storeAppendPrintf(sentry
, " ID SIZE SENDS FIRST SEND LAST SEND\n");
573 storeAppendPrintf(sentry
, "------ ---- ----- ---------- ---------\n");
575 for (n
= lru_list
.head
; n
; n
= n
->next
) {
576 q
= (idns_query
*)n
->data
;
577 storeAppendPrintf(sentry
, "%#06x %4d %5d %10.3f %9.3f\n",
578 (int) q
->id
, (int) q
->sz
, q
->nsends
,
579 tvSubDsec(q
->start_t
, current_time
),
580 tvSubDsec(q
->sent_t
, current_time
));
583 storeAppendPrintf(sentry
, "\nNameservers:\n");
584 storeAppendPrintf(sentry
, "IP ADDRESS # QUERIES # REPLIES\n");
585 storeAppendPrintf(sentry
, "---------------------------------------------- --------- ---------\n");
587 for (i
= 0; i
< nns
; i
++) {
588 storeAppendPrintf(sentry
, "%-45s %9d %9d\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
589 nameservers
[i
].S
.NtoA(buf
,MAX_IPSTRLEN
),
590 nameservers
[i
].nqueries
,
591 nameservers
[i
].nreplies
);
594 storeAppendPrintf(sentry
, "\nRcode Matrix:\n");
595 storeAppendPrintf(sentry
, "RCODE");
597 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
598 storeAppendPrintf(sentry
, " ATTEMPT%d", i
+ 1);
600 storeAppendPrintf(sentry
, "\n");
602 for (j
= 0; j
< MAX_RCODE
; j
++) {
603 storeAppendPrintf(sentry
, "%5d", j
);
605 for (i
= 0; i
< MAX_ATTEMPT
; i
++)
606 storeAppendPrintf(sentry
, " %8d", RcodeMatrix
[j
][i
]);
608 storeAppendPrintf(sentry
, "\n");
612 storeAppendPrintf(sentry
, "\nSearch list:\n");
614 for (i
=0; i
< npc
; i
++)
615 storeAppendPrintf(sentry
, "%s\n", searchpath
[i
].domain
);
617 storeAppendPrintf(sentry
, "\n");
622 idnsTickleQueue(void)
627 if (NULL
== lru_list
.tail
)
630 eventAdd("idnsCheckQueue", idnsCheckQueue
, NULL
, 1.0, 1);
636 idnsSentQueryVC(int fd
, char *buf
, size_t size
, comm_err_t flag
, int xerrno
, void *data
)
638 nsvc
* vc
= (nsvc
*)data
;
640 if (flag
== COMM_ERR_CLOSING
)
643 if (flag
!= COMM_OK
|| size
<= 0) {
649 idnsDoSendQueryVC(vc
);
653 idnsDoSendQueryVC(nsvc
*vc
)
658 if (vc
->queue
->contentSize() == 0)
661 MemBuf
*mb
= vc
->queue
;
663 vc
->queue
= new MemBuf
;
667 commSetTimeout(vc
->fd
, Config
.Timeout
.idns_query
, NULL
, NULL
);
669 comm_write_mbuf(vc
->fd
, mb
, idnsSentQueryVC
, vc
);
675 idnsInitVCConnected(int fd
, comm_err_t status
, int xerrno
, void *data
)
677 nsvc
* vc
= (nsvc
*)data
;
679 if (status
!= COMM_OK
) {
684 comm_read(fd
, (char *)&vc
->msglen
, 2 , idnsReadVCHeader
, vc
);
686 idnsDoSendQueryVC(vc
);
690 idnsVCClosed(int fd
, void *data
)
692 nsvc
* vc
= (nsvc
*)data
;
695 nameservers
[vc
->ns
].vc
= NULL
;
702 char buf
[MAX_IPSTRLEN
];
704 nsvc
*vc
= cbdataAlloc(nsvc
);
705 nameservers
[ns
].vc
= vc
;
709 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
710 addr
= Config
.Addrs
.udp_outgoing
;
712 addr
= Config
.Addrs
.udp_incoming
;
714 vc
->queue
= new MemBuf
;
716 vc
->msg
= new MemBuf
;
718 vc
->fd
= comm_open(SOCK_STREAM
,
725 fatal("Could not create a DNS socket");
727 comm_add_close_handler(vc
->fd
, idnsVCClosed
, vc
);
731 commConnectStart(vc
->fd
, nameservers
[ns
].S
.NtoA(buf
,MAX_IPSTRLEN
), nameservers
[ns
].S
.GetPort(), idnsInitVCConnected
, vc
);
735 idnsSendQueryVC(idns_query
* q
, int ns
)
737 if (nameservers
[ns
].vc
== NULL
)
740 nsvc
*vc
= nameservers
[ns
].vc
;
744 short head
= htons(q
->sz
);
746 vc
->queue
->append((char *)&head
, 2);
748 vc
->queue
->append(q
->buf
, q
->sz
);
750 idnsDoSendQueryVC(vc
);
754 idnsSendQuery(idns_query
* q
)
760 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
765 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
769 assert(q
->lru
.next
== NULL
);
771 assert(q
->lru
.prev
== NULL
);
774 ns
= q
->nsends
% nns
;
777 idnsSendQueryVC(q
, ns
);
780 x
= comm_udp_sendto(DnsSocket
,
787 q
->sent_t
= current_time
;
790 debugs(50, 1, "idnsSendQuery: FD " << DnsSocket
<< ": sendto: " << xstrerror());
792 if (q
->nsends
% nns
!= 0)
795 fd_bytes(DnsSocket
, x
, FD_WRITE
);
796 commSetSelect(DnsSocket
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
799 nameservers
[ns
].nqueries
++;
800 dlinkAdd(q
, &q
->lru
, &lru_list
);
805 idnsFromKnownNameserver(IPAddress
const &from
)
809 for (i
= 0; i
< nns
; i
++)
811 if (nameservers
[i
].S
!= from
)
814 if (nameservers
[i
].S
.GetPort() != from
.GetPort())
824 idnsFindQuery(unsigned short id
)
829 for (n
= lru_list
.tail
; n
; n
= n
->prev
) {
830 q
= (idns_query
*)n
->data
;
839 static unsigned short
842 unsigned short id
= squid_random() & 0xFFFF;
843 unsigned short first_id
= id
;
845 while(idnsFindQuery(id
)) {
848 if (id
== first_id
) {
849 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
858 idnsCallback(idns_query
*q
, rfc1035_rr
*answers
, int n
, const char *error
)
863 callback
= q
->callback
;
866 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
867 callback(cbdata
, answers
, n
, error
);
870 idns_query
*q2
= q
->queue
;
871 q
->queue
= q2
->queue
;
872 callback
= q2
->callback
;
875 if (cbdataReferenceValidDone(q2
->callback_data
, &cbdata
))
876 callback(cbdata
, answers
, n
, error
);
882 hash_remove_link(idns_lookup_hash
, &q
->hash
);
888 idnsDropMessage(rfc1035_message
*message
, idns_query
*q
)
890 rfc1035MessageDestroy(&message
);
892 hash_remove_link(idns_lookup_hash
, &q
->hash
);
898 idnsGrokReply(const char *buf
, size_t sz
)
901 rfc1035_message
*message
= NULL
;
904 n
= rfc1035MessageUnpack(buf
, sz
, &message
);
906 if (message
== NULL
) {
907 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
911 debugs(78, 3, "idnsGrokReply: ID 0x" << std::hex
<< message
->id
<< ", " << std::dec
<< n
<< " answers");
913 q
= idnsFindQuery(message
->id
);
916 debugs(78, 3, "idnsGrokReply: Late response");
917 rfc1035MessageDestroy(&message
);
921 if (rfc1035QueryCompare(&q
->query
, message
->query
) != 0) {
922 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q
->query
.name
<< " != " << message
->query
->name
<< ")");
923 rfc1035MessageDestroy(&message
);
928 dlinkDelete(&q
->lru
, &lru_list
);
929 rfc1035MessageDestroy(&message
);
940 dlinkDelete(&q
->lru
, &lru_list
);
941 idnsRcodeCount(n
, q
->attempt
);
945 debugs(78, 3, "idnsGrokReply: error " << rfc1035_error_message
<< " (" << rfc1035_errno
<< ")");
947 q
->error
= rfc1035_error_message
;
950 if (q
->rcode
== 2 && ++q
->attempt
< MAX_ATTEMPT
) {
952 * RCODE 2 is "Server failure - The name server was
953 * unable to process this query due to a problem with
956 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
957 rfc1035MessageDestroy(&message
);
958 q
->start_t
= current_time
;
959 q
->id
= idnsQueryID();
960 rfc1035SetQueryID(q
->buf
, q
->id
);
965 if (q
->rcode
== 3 && q
->do_searchpath
&& q
->attempt
< MAX_ATTEMPT
) {
966 assert(NULL
== message
->answer
);
967 strcpy(q
->name
, q
->orig
);
969 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q
->name
);
971 if (q
->domain
< npc
) {
972 strcat(q
->name
, ".");
973 strcat(q
->name
, searchpath
[q
->domain
].domain
);
974 debugs(78, 3, "idnsGrokReply: searchpath used for " << q
->name
);
980 idnsDropMessage(message
, q
);
982 q
->start_t
= current_time
;
983 q
->id
= idnsQueryID();
984 rfc1035SetQueryID(q
->buf
, q
->id
);
986 if(q
->query
.qtype
== RFC1035_TYPE_AAAA
) {
987 debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q
->name
);
988 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->id
, &q
->query
);
993 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q
->name
);
994 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->id
, &q
->query
);
1003 if(q
->need_A
&& (Config
.onoff
.dns_require_A
== 1 || n
<= 0 ) )
1005 /* ERROR or NO AAAA exist. Failover to A records. */
1006 /* AYJ: Apparently its also a good idea to lookup and store the A records
1007 * just in case the AAAA are not available when we need them.
1008 * This could occur due to number of network failings beyond our control
1009 * thus the || above allowing the user to request always both.
1013 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " has no AAAA records. Looking up A record instead.");
1014 else if(q
->need_A
&& n
<= 0)
1015 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query failed. Trying A now instead.");
1016 else // admin requested this.
1017 debugs(78, 3, "idnsGrokReply: " << q
->name
<< " AAAA query done. Configured to retrieve A now also.");
1019 idnsDropMessage(message
, q
);
1021 q
->start_t
= current_time
;
1022 q
->id
= idnsQueryID();
1023 rfc1035SetQueryID(q
->buf
, q
->id
);
1024 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->id
, &q
->query
);
1032 idnsCallback(q
, message
->answer
, n
, q
->error
);
1033 rfc1035MessageDestroy(&message
);
1039 idnsRead(int fd
, void *data
)
1041 int *N
= &incoming_sockets_accepted
;
1043 int max
= INCOMING_DNS_MAX
;
1044 static char rbuf
[SQUID_UDP_SO_RCVBUF
];
1048 debugs(78, 1, "idnsRead: starting with FD " << fd
);
1051 * two code lines after returning from comm_udprecvfrom()
1052 * something overwrites the memory behind the from parameter.
1053 * NO matter where in the stack declaration list above it is placed
1054 * The cause of this is still unknown, however copying the data appears
1055 * to allow it to be passed further without this erasure.
1057 IPAddress bugbypass
;
1060 len
= comm_udp_recvfrom(fd
, rbuf
, SQUID_UDP_SO_RCVBUF
, 0, bugbypass
);
1062 from
= bugbypass
; // BUG BYPASS. see notes above.
1068 if (ignoreErrno(errno
))
1071 #ifdef _SQUID_LINUX_
1072 /* Some Linux systems seem to set the FD for reading and then
1073 * return ECONNREFUSED when sendto() fails and generates an ICMP
1074 * port unreachable message. */
1075 /* or maybe an EHOSTUNREACH "No route to host" message */
1076 if (errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
)
1079 debugs(50, 1, "idnsRead: FD " << fd
<< " recvfrom: " << xstrerror());
1084 fd_bytes(DnsSocket
, len
, FD_READ
);
1088 debugs(78, 3, "idnsRead: FD " << fd
<< ": received " << len
<< " bytes from " << from
);
1090 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1091 ns
= idnsFromKnownNameserver(from
);
1094 nameservers
[ns
].nreplies
++;
1095 } else if (Config
.onoff
.ignore_unknown_nameservers
) {
1096 static time_t last_warning
= 0;
1098 if (squid_curtime
- last_warning
> 60) {
1099 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
);
1100 last_warning
= squid_curtime
;
1103 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from
<< " (retrying..." << (squid_curtime
-last_warning
) << "<=60)" );
1109 idnsGrokReply(rbuf
, len
);
1113 commSetSelect(DnsSocket
, COMM_SELECT_READ
, idnsRead
, NULL
, 0);
1117 idnsCheckQueue(void *unused
)
1120 dlink_node
*p
= NULL
;
1124 for (n
= lru_list
.tail
; n
; n
= p
) {
1126 /* name servers went away; reconfiguring or shutting down */
1129 q
= (idns_query
*)n
->data
;
1131 if (tvSubDsec(q
->sent_t
, current_time
) < Config
.Timeout
.idns_retransmit
* (1 << (q
->nsends
- 1) % nns
))
1134 debugs(78, 3, "idnsCheckQueue: ID 0x" << std::hex
<< std::setfill('0') << std::setw(4) << q
->id
<< "timeout" );
1138 dlinkDelete(&q
->lru
, &lru_list
);
1140 if (tvSubDsec(q
->start_t
, current_time
) < Config
.Timeout
.idns_query
) {
1143 debugs(78, 2, "idnsCheckQueue: ID " << std::hex
<< q
->id
<<
1144 ": giving up after " << std::dec
<< q
->nsends
<< " tries and " <<
1145 std::setw(5)<< std::setprecision(2) << tvSubDsec(q
->start_t
, current_time
) << " seconds");
1148 idnsCallback(q
, NULL
, -q
->rcode
, q
->error
);
1150 idnsCallback(q
, NULL
, -16, "Timeout");
1160 idnsReadVC(int fd
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1162 nsvc
* vc
= (nsvc
*)data
;
1164 if (flag
== COMM_ERR_CLOSING
)
1167 if (flag
!= COMM_OK
|| len
<= 0) {
1172 vc
->msg
->size
+= len
; // XXX should not access -> size directly
1174 if (vc
->msg
->contentSize() < vc
->msglen
) {
1175 comm_read(fd
, buf
+ len
, vc
->msglen
- vc
->msg
->contentSize(), idnsReadVC
, vc
);
1179 debugs(78, 3, "idnsReadVC: FD " << fd
<< ": received " <<
1180 (int) vc
->msg
->contentSize() << " bytes via tcp from " <<
1181 nameservers
[vc
->ns
].S
<< ".");
1183 idnsGrokReply(vc
->msg
->buf
, vc
->msg
->contentSize());
1185 comm_read(fd
, (char *)&vc
->msglen
, 2 , idnsReadVCHeader
, vc
);
1189 idnsReadVCHeader(int fd
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
1191 nsvc
* vc
= (nsvc
*)data
;
1193 if (flag
== COMM_ERR_CLOSING
)
1196 if (flag
!= COMM_OK
|| len
<= 0) {
1201 vc
->read_msglen
+= len
;
1203 assert(vc
->read_msglen
<= 2);
1205 if (vc
->read_msglen
< 2) {
1206 comm_read(fd
, buf
+ len
, 2 - vc
->read_msglen
, idnsReadVCHeader
, vc
);
1210 vc
->read_msglen
= 0;
1212 vc
->msglen
= ntohs(vc
->msglen
);
1214 vc
->msg
->init(vc
->msglen
, vc
->msglen
);
1215 comm_read(fd
, vc
->msg
->buf
, vc
->msglen
, idnsReadVC
, vc
);
1219 * rcode < 0 indicates an error, rocde >= 0 indicates success
1222 idnsRcodeCount(int rcode
, int attempt
)
1229 if (rcode
< MAX_RCODE
)
1230 if (attempt
< MAX_ATTEMPT
)
1231 RcodeMatrix
[rcode
][attempt
]++;
1234 /* ====================================================================== */
1239 static int init
= 0;
1241 CBDATA_INIT_TYPE(nsvc
);
1242 CBDATA_INIT_TYPE(idns_query
);
1244 if (DnsSocket
< 0) {
1249 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr())
1250 addr
= Config
.Addrs
.udp_outgoing
;
1252 addr
= Config
.Addrs
.udp_incoming
;
1254 DnsSocket
= comm_open(SOCK_DGRAM
,
1260 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addr
);
1263 fatal("Could not create a DNS socket");
1265 /* Ouch... we can't call functions using debug from a debug
1266 * statement. Doing so messes up the internal Debug::level
1268 port
= comm_local_port(DnsSocket
);
1270 debugs(78, 1, "DNS Socket created at " << addr
<< ", FD " << DnsSocket
);
1274 idnsParseNameservers();
1275 #ifndef _SQUID_MSWIN_
1278 idnsParseResolvConf();
1281 #ifdef _SQUID_WIN32_
1284 idnsParseWIN32Registry();
1289 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
1290 #ifdef _SQUID_WIN32_
1292 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
1295 debugs(78, 1, "Please check your /etc/resolv.conf file");
1298 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1299 idnsAddNameserver("127.0.0.1");
1303 memDataInit(MEM_IDNS_QUERY
, "idns_query", sizeof(idns_query
), 0);
1304 memset(RcodeMatrix
, '\0', sizeof(RcodeMatrix
));
1305 idns_lookup_hash
= hash_create((HASHCMP
*) strcmp
, 103, hash_string
);
1311 idnsRegisterWithCacheManager(CacheManager
& manager
)
1313 manager
.registerAction("idns", "Internal DNS Statistics", idnsStats
, 0, 1);
1322 comm_close(DnsSocket
);
1326 for (int i
= 0; i
< nns
; i
++) {
1327 if (nsvc
*vc
= nameservers
[i
].vc
) {
1333 idnsFreeNameservers();
1335 idnsFreeSearchpath();
1339 idnsCachedLookup(const char *key
, IDNSCB
* callback
, void *data
)
1343 idns_query
*old
= (idns_query
*) hash_lookup(idns_lookup_hash
, key
);
1348 q
= cbdataAlloc(idns_query
);
1350 q
->callback
= callback
;
1352 q
->callback_data
= cbdataReference(data
);
1354 q
->queue
= old
->queue
;
1362 idnsCacheQuery(idns_query
*q
)
1364 q
->hash
.key
= q
->query
.name
;
1365 hash_join(idns_lookup_hash
, &q
->hash
);
1369 idnsALookup(const char *name
, IDNSCB
* callback
, void *data
)
1375 if (idnsCachedLookup(name
, callback
, data
))
1378 q
= cbdataAlloc(idns_query
);
1380 q
->id
= idnsQueryID();
1382 for (i
= 0; i
< strlen(name
); i
++)
1386 if (Config
.onoff
.res_defnames
&& npc
> 0 && name
[strlen(name
)-1] != '.') {
1387 q
->do_searchpath
= 1;
1389 q
->do_searchpath
= 0;
1392 strcpy(q
->orig
, name
);
1393 strcpy(q
->name
, q
->orig
);
1395 if (q
->do_searchpath
&& nd
< ndots
) {
1397 strcat(q
->name
, ".");
1398 strcat(q
->name
, searchpath
[q
->domain
].domain
);
1399 debugs(78, 3, "idnsALookup: searchpath used for " << q
->name
);
1403 q
->sz
= rfc3596BuildAAAAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->id
, &q
->query
);
1406 q
->sz
= rfc3596BuildAQuery(q
->name
, q
->buf
, sizeof(q
->buf
), q
->id
, &q
->query
);
1411 /* problem with query data -- query not sent */
1412 callback(data
, NULL
, 0, "Internal error");
1417 debugs(78, 3, "idnsALookup: buf is " << q
->sz
<< " bytes for " << q
->name
<<
1418 ", id = 0x" << std::hex
<< q
->id
);
1420 q
->callback
= callback
;
1422 q
->callback_data
= cbdataReference(data
);
1424 q
->start_t
= current_time
;
1432 idnsPTRLookup(const IPAddress
&addr
, IDNSCB
* callback
, void *data
)
1436 char ip
[MAX_IPSTRLEN
];
1438 addr
.NtoA(ip
,MAX_IPSTRLEN
);
1440 q
= cbdataAlloc(idns_query
);
1442 q
->id
= idnsQueryID();
1445 if( addr
.IsIPv6() ) {
1446 struct in6_addr addr6
;
1447 addr
.GetInAddr(addr6
);
1448 q
->sz
= rfc3596BuildPTRQuery6(addr6
, q
->buf
, sizeof(q
->buf
), q
->id
, &q
->query
);
1453 struct in_addr addr4
;
1454 addr
.GetInAddr(addr4
);
1455 q
->sz
= rfc3596BuildPTRQuery4(addr4
, q
->buf
, sizeof(q
->buf
), q
->id
, &q
->query
);
1458 /* PTR does not do inbound A/AAAA */
1463 /* problem with query data -- query not sent */
1464 callback(data
, NULL
, 0, "Internal error");
1469 if (idnsCachedLookup(q
->query
.name
, callback
, data
)) {
1474 debugs(78, 3, "idnsPTRLookup: buf is " << q
->sz
<< " bytes for " << ip
<<
1475 ", id = 0x" << std::hex
<< q
->id
);
1477 q
->callback
= callback
;
1479 q
->callback_data
= cbdataReference(data
);
1481 q
->start_t
= current_time
;
1490 * The function to return the DNS via SNMP
1493 snmp_netIdnsFn(variable_list
* Var
, snint
* ErrP
)
1496 variable_list
*Answer
= NULL
;
1497 debugs(49, 5, "snmp_netDnsFn: Processing request: ");
1498 snmpDebugOid(5, Var
->name
, Var
->name_length
);
1499 *ErrP
= SNMP_ERR_NOERROR
;
1501 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
1505 for (i
= 0; i
< nns
; i
++)
1506 n
+= nameservers
[i
].nqueries
;
1508 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1515 for (i
= 0; i
< nns
; i
++)
1516 n
+= nameservers
[i
].nreplies
;
1518 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1525 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
1532 *ErrP
= SNMP_ERR_NOSUCHNAME
;
1540 #endif /*SQUID_SNMP */
1541 #endif /* USE_DNSSERVERS */