]> git.ipfire.org Git - thirdparty/squid.git/blob - src/dns_internal.cc
Fix typo-omission in rev.12882
[thirdparty/squid.git] / src / dns_internal.cc
1 /*
2 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
3 * AUTHOR: Duane Wessels
4 *
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
7 *
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 */
32
33 #include "squid.h"
34 #include "base/InstanceId.h"
35 #include "comm/Connection.h"
36 #include "comm/ConnOpener.h"
37 #include "comm.h"
38 #include "comm/Loops.h"
39 #include "comm/Write.h"
40 #include "event.h"
41 #include "fd.h"
42 #include "fde.h"
43 #include "ip/tools.h"
44 #include "Mem.h"
45 #include "MemBuf.h"
46 #include "mgr/Registration.h"
47 #include "rfc3596.h"
48 #include "SquidConfig.h"
49 #include "SquidTime.h"
50 #include "Store.h"
51 #include "tools.h"
52 #include "util.h"
53 #include "wordlist.h"
54
55 #if SQUID_SNMP
56 #include "snmp_core.h"
57 #endif
58
59 #if HAVE_ARPA_NAMESER_H
60 #include <arpa/nameser.h>
61 #endif
62 #if HAVE_RESOLV_H
63 #include <resolv.h>
64 #endif
65 #if HAVE_ERRNO_H
66 #include <errno.h>
67 #endif
68
69 /* MS Visual Studio Projects are monolithic, so we need the following
70 #ifndef to exclude the internal DNS code from compile process when
71 using external DNS process.
72 */
73 #if !USE_DNSHELPER
74 #if _SQUID_WINDOWS_
75 #define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
76 #define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
77 #define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
78 #endif
79 #ifndef _PATH_RESCONF
80 #define _PATH_RESCONF "/etc/resolv.conf"
81 #endif
82 #ifndef NS_DEFAULTPORT
83 #define NS_DEFAULTPORT 53
84 #endif
85
86 #ifndef NS_MAXDNAME
87 #define NS_MAXDNAME 1025
88 #endif
89
90 #ifndef MAXDNSRCH
91 #define MAXDNSRCH 6
92 #endif
93
94 /* The buffer size required to store the maximum allowed search path */
95 #ifndef RESOLV_BUFSZ
96 #define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
97 #endif
98
99 #define IDNS_MAX_TRIES 20
100 #define MAX_RCODE 17
101 #define MAX_ATTEMPT 3
102 static int RcodeMatrix[MAX_RCODE][MAX_ATTEMPT];
103 // NP: see http://www.iana.org/assignments/dns-parameters
104 static const char *Rcodes[] = {
105 /* RFC 1035 */
106 "Success",
107 "Packet Format Error",
108 "DNS Server Failure",
109 "Non-Existent Domain",
110 "Not Implemented",
111 "Query Refused",
112 /* RFC 2136 */
113 "Name Exists when it should not",
114 "RR Set Exists when it should not",
115 "RR Set that should exist does not",
116 "Server Not Authoritative for zone",
117 "Name not contained in zone",
118 /* unassigned */
119 "","","","","",
120 /* RFC 2671 */
121 "Bad OPT Version or TSIG Signature Failure"
122 };
123
124 typedef struct _idns_query idns_query;
125
126 typedef struct _ns ns;
127
128 typedef struct _sp sp;
129
130 typedef struct _nsvc nsvc;
131
132 struct _idns_query {
133 hash_link hash;
134 rfc1035_query query;
135 char buf[RESOLV_BUFSZ];
136 char name[NS_MAXDNAME + 1];
137 char orig[NS_MAXDNAME + 1];
138 ssize_t sz;
139 unsigned short query_id; /// random query ID sent to server; changes with every query sent
140 InstanceId<idns_query> xact_id; /// identifies our "transaction", stays constant when query is retried
141
142 int nsends;
143 int need_vc;
144 bool permit_mdns;
145 int pending;
146
147 struct timeval start_t;
148 struct timeval sent_t;
149 struct timeval queue_t;
150 dlink_node lru;
151 IDNSCB *callback;
152 void *callback_data;
153 int attempt;
154 int rcode;
155 idns_query *queue;
156 idns_query *slave; // single linked list
157 idns_query *master; // single pointer to a shared master
158 unsigned short domain;
159 unsigned short do_searchpath;
160 rfc1035_message *message;
161 int ancount;
162 const char *error;
163 };
164 InstanceIdDefinitions(idns_query, "dns");
165
166 struct _nsvc {
167 int ns;
168 Comm::ConnectionPointer conn;
169 unsigned short msglen;
170 int read_msglen;
171 MemBuf *msg;
172 MemBuf *queue;
173 bool busy;
174 };
175
176 struct _ns {
177 Ip::Address S;
178 int nqueries;
179 int nreplies;
180 #if WHEN_EDNS_RESPONSES_ARE_PARSED
181 int last_seen_edns;
182 #endif
183 bool mDNSResolver;
184 nsvc *vc;
185 };
186
187 struct _sp {
188 char domain[NS_MAXDNAME];
189 int queries;
190 };
191
192 CBDATA_TYPE(nsvc);
193 CBDATA_TYPE(idns_query);
194
195 static ns *nameservers = NULL;
196 static sp *searchpath = NULL;
197 static int nns = 0;
198 static int nns_alloc = 0;
199 static int npc = 0;
200 static int npc_alloc = 0;
201 static int ndots = 1;
202 static dlink_list lru_list;
203 static int event_queued = 0;
204 static hash_table *idns_lookup_hash = NULL;
205
206 /*
207 * Notes on EDNS:
208 *
209 * IPv4:
210 * EDNS as specified may be sent as an additional record for any request.
211 * early testing has revealed that it works on common devices, but cannot
212 * be reliably used on any A or PTR requet done for IPv4 addresses.
213 *
214 * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
215 *
216 * Squid design:
217 * Squid is optimized to generate one packet and re-send it to all NS
218 * due to this we cannot customize the EDNS size per NS.
219 *
220 * As such we take the configuration option value as fixed.
221 *
222 * FUTURE TODO:
223 * This may not be worth doing, but if/when additional-records are parsed
224 * we will be able to recover the OPT value specific to any one NS and
225 * cache it. Effectively automating the tuning of EDNS advertised to the
226 * size our active NS are capable.
227 * Default would need to start with 512 bytes RFC1035 says every NS must accept.
228 * Responses from the configured NS may cause this to be raised or turned off.
229 */
230 #if WHEN_EDNS_RESPONSES_ARE_PARSED
231 static int max_shared_edns = RFC1035_DEFAULT_PACKET_SZ;
232 #endif
233
234 static OBJH idnsStats;
235 static void idnsAddNameserver(const char *buf);
236 static void idnsAddMDNSNameservers();
237 static void idnsAddPathComponent(const char *buf);
238 static void idnsFreeNameservers(void);
239 static void idnsFreeSearchpath(void);
240 static bool idnsParseNameservers(void);
241 #if _SQUID_WINDOWS_
242 static bool idnsParseResolvConf(void);
243 #endif
244 #if _SQUID_WINDOWS_
245 static bool idnsParseWIN32Registry(void);
246 static void idnsParseWIN32SearchList(const char *);
247 #endif
248 static void idnsStartQuery(idns_query * q, IDNSCB * callback, void *data);
249 static void idnsSendQuery(idns_query * q);
250 static IOCB idnsReadVCHeader;
251 static void idnsDoSendQueryVC(nsvc *vc);
252 static CNCB idnsInitVCConnected;
253 static IOCB idnsReadVC;
254 static IOCB idnsSentQueryVC;
255
256 static int idnsFromKnownNameserver(Ip::Address const &from);
257 static idns_query *idnsFindQuery(unsigned short id);
258 static void idnsGrokReply(const char *buf, size_t sz, int from_ns);
259 static PF idnsRead;
260 static EVH idnsCheckQueue;
261 static void idnsTickleQueue(void);
262 static void idnsRcodeCount(int, int);
263 static CLCB idnsVCClosed;
264 static unsigned short idnsQueryID(void);
265 static void idnsSendSlaveAAAAQuery(idns_query *q);
266
267 static void
268 idnsCheckMDNS(idns_query *q)
269 {
270 size_t slen = strlen(q->name);
271 if (slen > 6 && memcmp(q->name +(slen-6),".local", 6) == 0) {
272 q->permit_mdns = true;
273 }
274 }
275
276 static void
277 idnsAddMDNSNameservers()
278 {
279 #define MDNS_RESOLVER_COUNT 2
280
281 // mDNS resolver addresses are explicit multicast group IPs
282 idnsAddNameserver("FF02::FB");
283 nameservers[nns-1].S.port(5353);
284 nameservers[nns-1].mDNSResolver = true;
285
286 idnsAddNameserver("224.0.0.251");
287 nameservers[nns-1].S.port(5353);
288 nameservers[nns-1].mDNSResolver = true;
289 }
290
291 static void
292 idnsAddNameserver(const char *buf)
293 {
294 Ip::Address A;
295
296 if (!(A = buf)) {
297 debugs(78, DBG_CRITICAL, "WARNING: rejecting '" << buf << "' as a name server, because it is not a numeric IP address");
298 return;
299 }
300
301 if (A.isAnyAddr()) {
302 debugs(78, DBG_CRITICAL, "WARNING: Squid does not accept " << A << " in DNS server specifications.");
303 A.setLocalhost();
304 debugs(78, DBG_CRITICAL, "Will be using " << A << " instead, assuming you meant that DNS is running on the same machine");
305 }
306
307 if (!Ip::EnableIpv6 && !A.setIPv4()) {
308 debugs(78, DBG_IMPORTANT, "WARNING: IPv6 is disabled. Discarding " << A << " in DNS server specifications.");
309 return;
310 }
311
312 if (nns == nns_alloc) {
313 int oldalloc = nns_alloc;
314 ns *oldptr = nameservers;
315
316 if (nns_alloc == 0)
317 nns_alloc = 2;
318 else
319 nns_alloc <<= 1;
320
321 nameservers = (ns *)xcalloc(nns_alloc, sizeof(*nameservers));
322
323 if (oldptr && oldalloc)
324 memcpy(nameservers, oldptr, oldalloc * sizeof(*nameservers));
325
326 if (oldptr)
327 safe_free(oldptr);
328 }
329
330 assert(nns < nns_alloc);
331 A.port(NS_DEFAULTPORT);
332 nameservers[nns].S = A;
333 #if WHEN_EDNS_RESPONSES_ARE_PARSED
334 nameservers[nns].last_seen_edns = RFC1035_DEFAULT_PACKET_SZ;
335 // TODO generate a test packet to probe this NS from EDNS size and ability.
336 #endif
337 debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns << " (" << A << ")");
338 ++nns;
339 }
340
341 static void
342 idnsAddPathComponent(const char *buf)
343 {
344 if (npc == npc_alloc) {
345 int oldalloc = npc_alloc;
346 sp *oldptr = searchpath;
347
348 if (0 == npc_alloc)
349 npc_alloc = 2;
350 else
351 npc_alloc <<= 1;
352
353 searchpath = (sp *)xcalloc(npc_alloc, sizeof(*searchpath));
354
355 if (oldptr && oldalloc)
356 memcpy(searchpath, oldptr, oldalloc * sizeof(*searchpath));
357
358 if (oldptr)
359 safe_free(oldptr);
360 }
361
362 assert(npc < npc_alloc);
363 strncpy(searchpath[npc].domain, buf, sizeof(searchpath[npc].domain)-1);
364 searchpath[npc].domain[sizeof(searchpath[npc].domain)-1] = '\0';
365 Tolower(searchpath[npc].domain);
366 debugs(78, 3, "idnsAddPathComponent: Added domain #" << npc << ": " << searchpath[npc].domain);
367 ++npc;
368 }
369
370 static void
371 idnsFreeNameservers(void)
372 {
373 safe_free(nameservers);
374 nns = nns_alloc = 0;
375 }
376
377 static void
378 idnsFreeSearchpath(void)
379 {
380 safe_free(searchpath);
381 npc = npc_alloc = 0;
382 }
383
384 static bool
385 idnsParseNameservers(void)
386 {
387 bool result = false;
388 for (wordlist *w = Config.dns_nameservers; w; w = w->next) {
389 debugs(78, DBG_IMPORTANT, "Adding nameserver " << w->key << " from squid.conf");
390 idnsAddNameserver(w->key);
391 result = true;
392 }
393 return result;
394 }
395
396 #if !_SQUID_WINDOWS_
397 static bool
398 idnsParseResolvConf(void)
399 {
400 FILE *fp;
401 char buf[RESOLV_BUFSZ];
402 const char *t;
403 bool result = false;
404 fp = fopen(_PATH_RESCONF, "r");
405
406 if (fp == NULL) {
407 debugs(78, DBG_IMPORTANT, "" << _PATH_RESCONF << ": " << xstrerror());
408 return false;
409 }
410
411 #if _SQUID_CYGWIN_
412 setmode(fileno(fp), O_TEXT);
413 #endif
414
415 while (fgets(buf, RESOLV_BUFSZ, fp)) {
416 t = strtok(buf, w_space);
417
418 if (NULL == t) {
419 continue;
420 } else if (strcmp(t, "nameserver") == 0) {
421 t = strtok(NULL, w_space);
422
423 if (NULL == t)
424 continue;
425
426 debugs(78, DBG_IMPORTANT, "Adding nameserver " << t << " from " << _PATH_RESCONF);
427
428 idnsAddNameserver(t);
429 result = true;
430 } else if (strcmp(t, "domain") == 0) {
431 idnsFreeSearchpath();
432 t = strtok(NULL, w_space);
433
434 if (NULL == t)
435 continue;
436
437 debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from " << _PATH_RESCONF);
438
439 idnsAddPathComponent(t);
440 } else if (strcmp(t, "search") == 0) {
441 idnsFreeSearchpath();
442 while (NULL != t) {
443 t = strtok(NULL, w_space);
444
445 if (NULL == t)
446 continue;
447
448 debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from " << _PATH_RESCONF);
449
450 idnsAddPathComponent(t);
451 }
452 } else if (strcmp(t, "options") == 0) {
453 while (NULL != t) {
454 t = strtok(NULL, w_space);
455
456 if (NULL == t)
457 continue;
458
459 if (strncmp(t, "ndots:", 6) == 0) {
460 ndots = atoi(t + 6);
461
462 if (ndots < 1)
463 ndots = 1;
464
465 debugs(78, DBG_IMPORTANT, "Adding ndots " << ndots << " from " << _PATH_RESCONF);
466 }
467 }
468 }
469 }
470 if (npc == 0 && (t = getMyHostname())) {
471 t = strchr(t, '.');
472 if (t)
473 idnsAddPathComponent(t+1);
474 }
475
476 fclose(fp);
477 return result;
478 }
479
480 #endif
481
482 #if _SQUID_WINDOWS_
483 static void
484 idnsParseWIN32SearchList(const char * Separator)
485 {
486 char *t;
487 char *token;
488 HKEY hndKey;
489
490 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
491 DWORD Type = 0;
492 DWORD Size = 0;
493 LONG Result;
494 Result = RegQueryValueEx(hndKey, "Domain", NULL, &Type, NULL, &Size);
495
496 if (Result == ERROR_SUCCESS && Size) {
497 t = (char *) xmalloc(Size);
498 RegQueryValueEx(hndKey, "Domain", NULL, &Type, (LPBYTE) t, &Size);
499 debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from Registry");
500 idnsAddPathComponent(t);
501 xfree(t);
502 }
503 Result = RegQueryValueEx(hndKey, "SearchList", NULL, &Type, NULL, &Size);
504
505 if (Result == ERROR_SUCCESS && Size) {
506 t = (char *) xmalloc(Size);
507 RegQueryValueEx(hndKey, "SearchList", NULL, &Type, (LPBYTE) t, &Size);
508 token = strtok(t, Separator);
509
510 while (token) {
511 idnsAddPathComponent(token);
512 debugs(78, DBG_IMPORTANT, "Adding domain " << token << " from Registry");
513 token = strtok(NULL, Separator);
514 }
515 xfree(t);
516 }
517
518 RegCloseKey(hndKey);
519 }
520 if (npc == 0 && (t = (char *) getMyHostname())) {
521 t = strchr(t, '.');
522 if (t)
523 idnsAddPathComponent(t + 1);
524 }
525 }
526
527 static bool
528 idnsParseWIN32Registry(void)
529 {
530 char *t;
531 char *token;
532 HKEY hndKey, hndKey2;
533 bool result = false;
534
535 switch (WIN32_OS_version) {
536
537 case _WIN_OS_WINNT:
538 /* get nameservers from the Windows NT registry */
539
540 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
541 DWORD Type = 0;
542 DWORD Size = 0;
543 LONG Result;
544 Result = RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, NULL, &Size);
545
546 if (Result == ERROR_SUCCESS && Size) {
547 t = (char *) xmalloc(Size);
548 RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, (LPBYTE) t, &Size);
549 token = strtok(t, ", ");
550
551 while (token) {
552 idnsAddNameserver(token);
553 result = true;
554 debugs(78, DBG_IMPORTANT, "Adding DHCP nameserver " << token << " from Registry");
555 token = strtok(NULL, ",");
556 }
557 xfree(t);
558 }
559
560 Result = RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
561
562 if (Result == ERROR_SUCCESS && Size) {
563 t = (char *) xmalloc(Size);
564 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, (LPBYTE) t, &Size);
565 token = strtok(t, ", ");
566
567 while (token) {
568 debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
569 idnsAddNameserver(token);
570 result = true;
571 token = strtok(NULL, ", ");
572 }
573 xfree(t);
574 }
575
576 RegCloseKey(hndKey);
577 }
578
579 idnsParseWIN32SearchList(" ");
580
581 break;
582
583 case _WIN_OS_WIN2K:
584
585 case _WIN_OS_WINXP:
586
587 case _WIN_OS_WINNET:
588
589 case _WIN_OS_WINLON:
590
591 case _WIN_OS_WIN7:
592 /* get nameservers from the Windows 2000 registry */
593 /* search all interfaces for DNS server addresses */
594
595 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA_INTERFACES, 0, KEY_READ, &hndKey) == ERROR_SUCCESS) {
596 int i;
597 DWORD MaxSubkeyLen, InterfacesCount;
598 char *keyname;
599 FILETIME ftLastWriteTime;
600
601 if (RegQueryInfoKey(hndKey, NULL, NULL, NULL, &InterfacesCount, &MaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
602 keyname = (char *) xmalloc(++MaxSubkeyLen);
603 for (i = 0; i < (int) InterfacesCount; ++i) {
604 DWORD j;
605 j = MaxSubkeyLen;
606 if (RegEnumKeyEx(hndKey, i, keyname, &j, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS) {
607 char *newkeyname;
608 newkeyname = (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES) + j + 2);
609 strcpy(newkeyname, REG_TCPIP_PARA_INTERFACES);
610 strcat(newkeyname, "\\");
611 strcat(newkeyname, keyname);
612 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newkeyname, 0, KEY_QUERY_VALUE, &hndKey2) == ERROR_SUCCESS) {
613 DWORD Type = 0;
614 DWORD Size = 0;
615 LONG Result;
616 Result = RegQueryValueEx(hndKey2, "DhcpNameServer", NULL, &Type, NULL, &Size);
617 if (Result == ERROR_SUCCESS && Size) {
618 t = (char *) xmalloc(Size);
619 RegQueryValueEx(hndKey2, "DhcpNameServer", NULL, &Type, (LPBYTE)t, &Size);
620 token = strtok(t, ", ");
621 while (token) {
622 debugs(78, DBG_IMPORTANT, "Adding DHCP nameserver " << token << " from Registry");
623 idnsAddNameserver(token);
624 result = true;
625 token = strtok(NULL, ", ");
626 }
627 xfree(t);
628 }
629
630 Result = RegQueryValueEx(hndKey2, "NameServer", NULL, &Type, NULL, &Size);
631 if (Result == ERROR_SUCCESS && Size) {
632 t = (char *) xmalloc(Size);
633 RegQueryValueEx(hndKey2, "NameServer", NULL, &Type, (LPBYTE)t, &Size);
634 token = strtok(t, ", ");
635 while (token) {
636 debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
637 idnsAddNameserver(token);
638 result = true;
639 token = strtok(NULL, ", ");
640 }
641
642 xfree(t);
643 }
644
645 RegCloseKey(hndKey2);
646 }
647
648 xfree(newkeyname);
649 }
650 }
651
652 xfree(keyname);
653 }
654
655 RegCloseKey(hndKey);
656 }
657
658 idnsParseWIN32SearchList(", ");
659
660 break;
661
662 case _WIN_OS_WIN95:
663
664 case _WIN_OS_WIN98:
665
666 case _WIN_OS_WINME:
667 /* get nameservers from the Windows 9X registry */
668
669 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_VXD_MSTCP, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
670 DWORD Type = 0;
671 DWORD Size = 0;
672 LONG Result;
673 Result = RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
674
675 if (Result == ERROR_SUCCESS && Size) {
676 t = (char *) xmalloc(Size);
677 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, (LPBYTE) t, &Size);
678 token = strtok(t, ", ");
679
680 while (token) {
681 debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
682 idnsAddNameserver(token);
683 result = true;
684 token = strtok(NULL, ", ");
685 }
686 xfree(t);
687 }
688
689 RegCloseKey(hndKey);
690 }
691
692 break;
693
694 default:
695 debugs(78, DBG_IMPORTANT, "Failed to read nameserver from Registry: Unknown System Type.");
696 }
697
698 return result;
699 }
700
701 #endif
702
703 static void
704 idnsStats(StoreEntry * sentry)
705 {
706 dlink_node *n;
707 idns_query *q;
708 int i;
709 int j;
710 char buf[MAX_IPSTRLEN];
711 storeAppendPrintf(sentry, "Internal DNS Statistics:\n");
712 storeAppendPrintf(sentry, "\nThe Queue:\n");
713 storeAppendPrintf(sentry, " DELAY SINCE\n");
714 storeAppendPrintf(sentry, " ID SIZE SENDS FIRST SEND LAST SEND\n");
715 storeAppendPrintf(sentry, "------ ---- ----- ---------- ---------\n");
716
717 for (n = lru_list.head; n; n = n->next) {
718 q = (idns_query *)n->data;
719 storeAppendPrintf(sentry, "%#06x %4d %5d %10.3f %9.3f\n",
720 (int) q->query_id, (int) q->sz, q->nsends,
721 tvSubDsec(q->start_t, current_time),
722 tvSubDsec(q->sent_t, current_time));
723 }
724
725 if (Config.dns.packet_max > 0)
726 storeAppendPrintf(sentry, "DNS jumbo-grams: %zd Bytes\n", Config.dns.packet_max);
727 else
728 storeAppendPrintf(sentry, "DNS jumbo-grams: not working\n");
729
730 storeAppendPrintf(sentry, "\nNameservers:\n");
731 storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES Type\n");
732 storeAppendPrintf(sentry, "---------------------------------------------- --------- --------- --------\n");
733
734 for (i = 0; i < nns; ++i) {
735 storeAppendPrintf(sentry, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
736 nameservers[i].S.toStr(buf,MAX_IPSTRLEN),
737 nameservers[i].nqueries,
738 nameservers[i].nreplies,
739 nameservers[i].mDNSResolver?"multicast":"recurse");
740 }
741
742 storeAppendPrintf(sentry, "\nRcode Matrix:\n");
743 storeAppendPrintf(sentry, "RCODE");
744
745 for (i = 0; i < MAX_ATTEMPT; ++i)
746 storeAppendPrintf(sentry, " ATTEMPT%d", i + 1);
747
748 storeAppendPrintf(sentry, " PROBLEM\n");
749
750 for (j = 0; j < MAX_RCODE; ++j) {
751 if (j > 10 && j < 16)
752 continue; // unassigned by IANA.
753
754 storeAppendPrintf(sentry, "%5d", j);
755
756 for (i = 0; i < MAX_ATTEMPT; ++i)
757 storeAppendPrintf(sentry, " %8d", RcodeMatrix[j][i]);
758
759 storeAppendPrintf(sentry, " : %s\n",Rcodes[j]);
760 }
761
762 if (npc) {
763 storeAppendPrintf(sentry, "\nSearch list:\n");
764
765 for (i=0; i < npc; ++i)
766 storeAppendPrintf(sentry, "%s\n", searchpath[i].domain);
767
768 storeAppendPrintf(sentry, "\n");
769 }
770 }
771
772 static void
773 idnsTickleQueue(void)
774 {
775 if (event_queued)
776 return;
777
778 if (NULL == lru_list.tail)
779 return;
780
781 const double when = min(Config.Timeout.idns_query, Config.Timeout.idns_retransmit)/1000.0;
782
783 eventAdd("idnsCheckQueue", idnsCheckQueue, NULL, when, 1);
784
785 event_queued = 1;
786 }
787
788 static void
789 idnsSentQueryVC(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
790 {
791 nsvc * vc = (nsvc *)data;
792
793 if (flag == COMM_ERR_CLOSING)
794 return;
795
796 // XXX: irrelevant now that we have conn pointer?
797 if (!Comm::IsConnOpen(conn) || fd_table[conn->fd].closing())
798 return;
799
800 if (flag != COMM_OK || size <= 0) {
801 conn->close();
802 return;
803 }
804
805 vc->busy = 0;
806 idnsDoSendQueryVC(vc);
807 }
808
809 static void
810 idnsDoSendQueryVC(nsvc *vc)
811 {
812 if (vc->busy)
813 return;
814
815 if (vc->queue->contentSize() == 0)
816 return;
817
818 // if retrying after a TC UDP response, our close handler cb may be pending
819 if (fd_table[vc->conn->fd].closing())
820 return;
821
822 MemBuf *mb = vc->queue;
823
824 vc->queue = new MemBuf;
825
826 vc->busy = 1;
827
828 // Comm needs seconds but idnsCheckQueue() will check the exact timeout
829 const int timeout = (Config.Timeout.idns_query % 1000 ?
830 Config.Timeout.idns_query + 1000 : Config.Timeout.idns_query) / 1000;
831 AsyncCall::Pointer nil;
832
833 commSetConnTimeout(vc->conn, timeout, nil);
834
835 AsyncCall::Pointer call = commCbCall(78, 5, "idnsSentQueryVC",
836 CommIoCbPtrFun(&idnsSentQueryVC, vc));
837 Comm::Write(vc->conn, mb, call);
838
839 delete mb;
840 }
841
842 static void
843 idnsInitVCConnected(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
844 {
845 nsvc * vc = (nsvc *)data;
846
847 if (status != COMM_OK || !conn) {
848 char buf[MAX_IPSTRLEN] = "";
849 if (vc->ns < nns)
850 nameservers[vc->ns].S.toStr(buf,MAX_IPSTRLEN);
851 debugs(78, DBG_IMPORTANT, HERE << "Failed to connect to nameserver " << buf << " using TCP.");
852 return;
853 }
854
855 vc->conn = conn;
856
857 comm_add_close_handler(conn->fd, idnsVCClosed, vc);
858 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
859 CommIoCbPtrFun(idnsReadVCHeader, vc));
860 comm_read(conn, (char *)&vc->msglen, 2, call);
861 vc->busy = 0;
862 idnsDoSendQueryVC(vc);
863 }
864
865 static void
866 idnsVCClosed(const CommCloseCbParams &params)
867 {
868 nsvc * vc = (nsvc *)params.data;
869 delete vc->queue;
870 delete vc->msg;
871 vc->conn = NULL;
872 if (vc->ns < nns) // XXX: dnsShutdown may have freed nameservers[]
873 nameservers[vc->ns].vc = NULL;
874 cbdataFree(vc);
875 }
876
877 static void
878 idnsInitVC(int nsv)
879 {
880 nsvc *vc = cbdataAlloc(nsvc);
881 assert(nsv < nns);
882 assert(vc->conn == NULL); // MUST be NULL from the construction process!
883 nameservers[nsv].vc = vc;
884 vc->ns = nsv;
885 vc->queue = new MemBuf;
886 vc->msg = new MemBuf;
887 vc->busy = 1;
888
889 Comm::ConnectionPointer conn = new Comm::Connection();
890
891 if (!Config.Addrs.udp_outgoing.isNoAddr())
892 conn->local = Config.Addrs.udp_outgoing;
893 else
894 conn->local = Config.Addrs.udp_incoming;
895
896 conn->remote = nameservers[nsv].S;
897
898 if (conn->remote.isIPv4()) {
899 conn->local.setIPv4();
900 }
901
902 AsyncCall::Pointer call = commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected, vc));
903
904 Comm::ConnOpener *cs = new Comm::ConnOpener(conn, call, Config.Timeout.connect);
905 cs->setHost("DNS TCP Socket");
906 AsyncJob::Start(cs);
907 }
908
909 static void
910 idnsSendQueryVC(idns_query * q, int nsn)
911 {
912 assert(nsn < nns);
913 if (nameservers[nsn].vc == NULL)
914 idnsInitVC(nsn);
915
916 nsvc *vc = nameservers[nsn].vc;
917
918 if (!vc) {
919 char buf[MAX_IPSTRLEN];
920 debugs(78, DBG_IMPORTANT, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers[nsn].S.toStr(buf,MAX_IPSTRLEN) << "!");
921
922 return;
923 }
924
925 vc->queue->reset();
926
927 short head = htons(q->sz);
928
929 vc->queue->append((char *)&head, 2);
930
931 vc->queue->append(q->buf, q->sz);
932
933 idnsDoSendQueryVC(vc);
934 }
935
936 static void
937 idnsSendQuery(idns_query * q)
938 {
939 if (DnsSocketA < 0 && DnsSocketB < 0) {
940 debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
941 return;
942 }
943
944 if (nns <= 0) {
945 debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
946 return;
947 }
948
949 assert(q->lru.next == NULL);
950
951 assert(q->lru.prev == NULL);
952
953 int x = -1, y = -1;
954 int nsn;
955
956 do {
957 // only use mDNS resolvers for mDNS compatible queries
958 if (!q->permit_mdns)
959 nsn = MDNS_RESOLVER_COUNT + q->nsends % (nns-MDNS_RESOLVER_COUNT);
960 else
961 nsn = q->nsends % nns;
962
963 if (q->need_vc) {
964 idnsSendQueryVC(q, nsn);
965 x = y = 0;
966 } else {
967 if (DnsSocketB >= 0 && nameservers[nsn].S.isIPv6())
968 y = comm_udp_sendto(DnsSocketB, nameservers[nsn].S, q->buf, q->sz);
969 else if (DnsSocketA >= 0)
970 x = comm_udp_sendto(DnsSocketA, nameservers[nsn].S, q->buf, q->sz);
971 }
972
973 ++ q->nsends;
974
975 q->sent_t = current_time;
976
977 if (y < 0 && nameservers[nsn].S.isIPv6())
978 debugs(50, DBG_IMPORTANT, "idnsSendQuery: FD " << DnsSocketB << ": sendto: " << xstrerror());
979 if (x < 0 && nameservers[nsn].S.isIPv4())
980 debugs(50, DBG_IMPORTANT, "idnsSendQuery: FD " << DnsSocketA << ": sendto: " << xstrerror());
981
982 } while ( (x<0 && y<0) && q->nsends % nns != 0);
983
984 if (y > 0) {
985 fd_bytes(DnsSocketB, y, FD_WRITE);
986 }
987 if (x > 0) {
988 fd_bytes(DnsSocketA, x, FD_WRITE);
989 }
990
991 ++ nameservers[nsn].nqueries;
992 q->queue_t = current_time;
993 dlinkAdd(q, &q->lru, &lru_list);
994 q->pending = 1;
995 idnsTickleQueue();
996 }
997
998 static int
999 idnsFromKnownNameserver(Ip::Address const &from)
1000 {
1001 int i;
1002
1003 for (i = 0; i < nns; ++i) {
1004 if (nameservers[i].S != from)
1005 continue;
1006
1007 if (nameservers[i].S.port() != from.port())
1008 continue;
1009
1010 return i;
1011 }
1012
1013 return -1;
1014 }
1015
1016 static idns_query *
1017 idnsFindQuery(unsigned short id)
1018 {
1019 dlink_node *n;
1020 idns_query *q;
1021
1022 for (n = lru_list.tail; n; n = n->prev) {
1023 q = (idns_query*)n->data;
1024
1025 if (q->query_id == id)
1026 return q;
1027 }
1028
1029 return NULL;
1030 }
1031
1032 static unsigned short
1033 idnsQueryID(void)
1034 {
1035 unsigned short id = squid_random() & 0xFFFF;
1036 unsigned short first_id = id;
1037
1038 while (idnsFindQuery(id)) {
1039 ++id;
1040
1041 if (id == first_id) {
1042 debugs(78, DBG_IMPORTANT, "idnsQueryID: Warning, too many pending DNS requests");
1043 break;
1044 }
1045 }
1046
1047 return id;
1048 }
1049
1050 static void
1051 idnsCallback(idns_query *q, const char *error)
1052 {
1053 IDNSCB *callback;
1054 void *cbdata;
1055
1056 if (error)
1057 q->error = error;
1058
1059 if (q->master)
1060 q = q->master;
1061
1062 // If any of our subqueries are still pending then wait for them to complete before continuing
1063 for (idns_query *q2 = q; q2; q2 = q2->slave) {
1064 if (q2->pending) {
1065 return;
1066 }
1067 }
1068
1069 /* Merge results */
1070 rfc1035_message *message = q->message;
1071 q->message = NULL;
1072 int n = q->ancount;
1073 error = q->error;
1074
1075 while ( idns_query *q2 = q->slave ) {
1076 debugs(78, 6, HERE << "Merging DNS results " << q->name << " A has " << n << " RR, AAAA has " << q2->ancount << " RR");
1077 q->slave = q2->slave;
1078 if ( !q2->error ) {
1079 if (n > 0) {
1080 // two sets of RR need merging
1081 rfc1035_rr *result = (rfc1035_rr*) xmalloc( sizeof(rfc1035_rr)*(n + q2->ancount) );
1082 if (Config.dns.v4_first) {
1083 memcpy(result, message->answer, (sizeof(rfc1035_rr)*n) );
1084 memcpy(result+n, q2->message->answer, (sizeof(rfc1035_rr)*q2->ancount) );
1085 } else {
1086 memcpy(result, q2->message->answer, (sizeof(rfc1035_rr)*q2->ancount) );
1087 memcpy(result+q2->ancount, message->answer, (sizeof(rfc1035_rr)*n) );
1088 }
1089 n += q2->ancount;
1090 // HACK WARNING, the answer rr:s have been copied in-place to
1091 // result, do not free them here
1092 safe_free(message->answer);
1093 safe_free(q2->message->answer);
1094 message->answer = result;
1095 message->ancount += q2->message->ancount;
1096 } else {
1097 // first response empty or failed, just use the second
1098 rfc1035MessageDestroy(&message);
1099 message = q2->message;
1100 q2->message = NULL;
1101 n = q2->ancount;
1102 error = NULL;
1103 }
1104 }
1105 rfc1035MessageDestroy(&q2->message);
1106 cbdataFree(q2);
1107 }
1108
1109 debugs(78, 6, HERE << "Sending " << n << " (" << (error ? error : "OK") << ") DNS results to caller.");
1110
1111 callback = q->callback;
1112 q->callback = NULL;
1113 const rfc1035_rr *answers = message ? message->answer : NULL;
1114
1115 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
1116 callback(cbdata, answers, n, error);
1117
1118 while (q->queue) {
1119 idns_query *q2 = q->queue;
1120 q->queue = q2->queue;
1121 callback = q2->callback;
1122 q2->callback = NULL;
1123
1124 if (cbdataReferenceValidDone(q2->callback_data, &cbdata))
1125 callback(cbdata, answers, n, error);
1126
1127 cbdataFree(q2);
1128 }
1129
1130 if (q->hash.key) {
1131 hash_remove_link(idns_lookup_hash, &q->hash);
1132 q->hash.key = NULL;
1133 }
1134
1135 rfc1035MessageDestroy(&message);
1136 cbdataFree(q);
1137 }
1138
1139 static void
1140 idnsGrokReply(const char *buf, size_t sz, int from_ns)
1141 {
1142 int n;
1143 rfc1035_message *message = NULL;
1144 idns_query *q;
1145
1146 n = rfc1035MessageUnpack(buf, sz, &message);
1147
1148 if (message == NULL) {
1149 debugs(78, DBG_IMPORTANT, "idnsGrokReply: Malformed DNS response");
1150 return;
1151 }
1152
1153 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex << message->id << ", " << std::dec << n << " answers");
1154
1155 q = idnsFindQuery(message->id);
1156
1157 if (q == NULL) {
1158 debugs(78, 3, "idnsGrokReply: Late response");
1159 rfc1035MessageDestroy(&message);
1160 return;
1161 }
1162
1163 if (rfc1035QueryCompare(&q->query, message->query) != 0) {
1164 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q->query.name << " != " << message->query->name << ")");
1165 rfc1035MessageDestroy(&message);
1166 return;
1167 }
1168
1169 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1170 // TODO: actually gr the message right here.
1171 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1172 // this is overall better than force-feeding A response with AAAA an section later anyway.
1173 // AND allows us to merge AN+AR sections from both responses (one day)
1174
1175 if (q->edns_seen >= 0) {
1176 if (max_shared_edns == nameservers[from_ns].last_seen_edns && max_shared_edns < q->edns_seen) {
1177 nameservers[from_ns].last_seen_edns = q->edns_seen;
1178 // the altered NS was limiting the whole group.
1179 max_shared_edns = q->edns_seen;
1180 // may be limited by one of the others still
1181 for (int i = 0; i < nns; ++i)
1182 max_shared_edns = min(max_shared_edns, nameservers[i].last_seen_edns);
1183 } else {
1184 nameservers[from_ns].last_seen_edns = q->edns_seen;
1185 // maybe reduce the global limit downwards to accomodate this NS
1186 max_shared_edns = min(max_shared_edns, q->edns_seen);
1187 }
1188 if (max_shared_edns < RFC1035_DEFAULT_PACKET_SZ)
1189 max_shared_edns = -1;
1190 }
1191 #endif
1192
1193 dlinkDelete(&q->lru, &lru_list);
1194 q->pending = 0;
1195
1196 if (message->tc) {
1197 debugs(78, 3, HERE << "Resolver requested TC (" << q->query.name << ")");
1198 rfc1035MessageDestroy(&message);
1199
1200 if (!q->need_vc) {
1201 q->need_vc = 1;
1202 -- q->nsends;
1203 idnsSendQuery(q);
1204 } else {
1205 // Strange: A TCP DNS response with the truncation bit (TC) set.
1206 // Return an error and cleanup; no point in trying TCP again.
1207 debugs(78, 3, HERE << "TCP DNS response");
1208 idnsCallback(q, "Truncated TCP DNS response");
1209 }
1210
1211 return;
1212 }
1213
1214 idnsRcodeCount(n, q->attempt);
1215
1216 if (n < 0) {
1217 q->rcode = -n;
1218 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n) << " (" << q->rcode << ")");
1219
1220 if (q->rcode == 2 && (++ q->attempt) < MAX_ATTEMPT) {
1221 /*
1222 * RCODE 2 is "Server failure - The name server was
1223 * unable to process this query due to a problem with
1224 * the name server."
1225 */
1226 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1227 rfc1035MessageDestroy(&message);
1228 idnsSendQuery(q);
1229 return;
1230 }
1231
1232 // Do searchpath processing on the master A query only to keep
1233 // things simple. NXDOMAIN is authorative for the label, not
1234 // the record type.
1235 if (q->rcode == 3 && !q->master && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
1236 assert(NULL == message->answer);
1237 strcpy(q->name, q->orig);
1238
1239 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q->name );
1240
1241 if (q->domain < npc) {
1242 strcat(q->name, ".");
1243 strcat(q->name, searchpath[q->domain].domain);
1244 debugs(78, 3, "idnsGrokReply: searchpath used for " << q->name);
1245 ++ q->domain;
1246 } else {
1247 ++ q->attempt;
1248 }
1249
1250 rfc1035MessageDestroy(&message);
1251
1252 // cleanup slave AAAA query
1253 while (idns_query *slave = q->slave) {
1254 dlinkDelete(&slave->lru, &lru_list);
1255 q->slave = slave->slave;
1256 rfc1035MessageDestroy(&slave->message);
1257 cbdataFree(slave);
1258 }
1259
1260 // Build new query
1261 q->query_id = idnsQueryID();
1262 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
1263 // see EDNS notes at top of file why this sends 0
1264 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
1265 if (q->sz < 0) {
1266 /* problem with query data -- query not sent */
1267 idnsCallback(q, "Internal error");
1268 return;
1269 }
1270
1271 q->nsends = 0;
1272
1273 idnsCheckMDNS(q);
1274 idnsSendQuery(q);
1275 if (Ip::EnableIpv6)
1276 idnsSendSlaveAAAAQuery(q);
1277 return;
1278 }
1279 }
1280
1281 q->message = message;
1282 q->ancount = n;
1283
1284 if (n >= 0)
1285 idnsCallback(q, NULL);
1286 else
1287 idnsCallback(q, rfc1035ErrorMessage(q->rcode));
1288
1289 }
1290
1291 static void
1292 idnsRead(int fd, void *data)
1293 {
1294 int *N = &incoming_sockets_accepted;
1295 int len;
1296 int max = INCOMING_DNS_MAX;
1297 static char rbuf[SQUID_UDP_SO_RCVBUF];
1298 Ip::Address from;
1299
1300 debugs(78, 3, "idnsRead: starting with FD " << fd);
1301
1302 // Always keep reading. This stops (or at least makes harder) several
1303 // attacks on the DNS client.
1304 Comm::SetSelect(fd, COMM_SELECT_READ, idnsRead, NULL, 0);
1305
1306 /* BUG (UNRESOLVED)
1307 * two code lines after returning from comm_udprecvfrom()
1308 * something overwrites the memory behind the from parameter.
1309 * NO matter where in the stack declaration list above it is placed
1310 * The cause of this is still unknown, however copying the data appears
1311 * to allow it to be passed further without this erasure.
1312 */
1313 Ip::Address bugbypass;
1314
1315 while (max) {
1316 --max;
1317 len = comm_udp_recvfrom(fd, rbuf, SQUID_UDP_SO_RCVBUF, 0, bugbypass);
1318
1319 from = bugbypass; // BUG BYPASS. see notes above.
1320
1321 if (len == 0)
1322 break;
1323
1324 if (len < 0) {
1325 if (ignoreErrno(errno))
1326 break;
1327
1328 #if _SQUID_LINUX_
1329 /* Some Linux systems seem to set the FD for reading and then
1330 * return ECONNREFUSED when sendto() fails and generates an ICMP
1331 * port unreachable message. */
1332 /* or maybe an EHOSTUNREACH "No route to host" message */
1333 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
1334 #endif
1335
1336 debugs(50, DBG_IMPORTANT, "idnsRead: FD " << fd << " recvfrom: " << xstrerror());
1337
1338 break;
1339 }
1340
1341 fd_bytes(fd, len, FD_READ);
1342
1343 assert(N);
1344 ++(*N);
1345
1346 debugs(78, 3, "idnsRead: FD " << fd << ": received " << len << " bytes from " << from);
1347
1348 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1349 int nsn = idnsFromKnownNameserver(from);
1350
1351 if (nsn >= 0) {
1352 ++ nameservers[nsn].nreplies;
1353 }
1354
1355 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1356 // but after the ++ above to keep statistics right.
1357 if (!lru_list.head)
1358 continue; // Don't process replies if there is no pending query.
1359
1360 if (nsn < 0 && Config.onoff.ignore_unknown_nameservers) {
1361 static time_t last_warning = 0;
1362
1363 if (squid_curtime - last_warning > 60) {
1364 debugs(78, DBG_IMPORTANT, "WARNING: Reply from unknown nameserver " << from);
1365 last_warning = squid_curtime;
1366 } else {
1367 debugs(78, DBG_IMPORTANT, "WARNING: Reply from unknown nameserver " << from << " (retrying..." << (squid_curtime-last_warning) << "<=60)" );
1368 }
1369 continue;
1370 }
1371
1372 idnsGrokReply(rbuf, len, nsn);
1373 }
1374 }
1375
1376 static void
1377 idnsCheckQueue(void *unused)
1378 {
1379 dlink_node *n;
1380 dlink_node *p = NULL;
1381 idns_query *q;
1382 event_queued = 0;
1383
1384 if (0 == nns)
1385 /* name servers went away; reconfiguring or shutting down */
1386 return;
1387
1388 for (n = lru_list.tail; n; n = p) {
1389
1390 p = n->prev;
1391 q = static_cast<idns_query*>(n->data);
1392
1393 /* Anything to process in the queue? */
1394 if ((time_msec_t)tvSubMsec(q->queue_t, current_time) < Config.Timeout.idns_retransmit )
1395 break;
1396
1397 /* Query timer still running? */
1398 if ((time_msec_t)tvSubMsec(q->sent_t, current_time) < (Config.Timeout.idns_retransmit * 1 << ((q->nsends - 1) / nns))) {
1399 dlinkDelete(&q->lru, &lru_list);
1400 q->queue_t = current_time;
1401 dlinkAdd(q, &q->lru, &lru_list);
1402 continue;
1403 }
1404
1405 debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
1406 " QID 0x" << std::hex << std::setfill('0') <<
1407 std::setw(4) << q->query_id << ": timeout" );
1408
1409 dlinkDelete(&q->lru, &lru_list);
1410 q->pending = 0;
1411
1412 if ((time_msec_t)tvSubMsec(q->start_t, current_time) < Config.Timeout.idns_query) {
1413 idnsSendQuery(q);
1414 } else {
1415 debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
1416 " QID 0x" << std::hex << q->query_id <<
1417 " : giving up after " << std::dec << q->nsends << " tries and " <<
1418 std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
1419
1420 if (q->rcode != 0)
1421 idnsCallback(q, rfc1035ErrorMessage(q->rcode));
1422 else
1423 idnsCallback(q, "Timeout");
1424 }
1425 }
1426
1427 idnsTickleQueue();
1428 }
1429
1430 static void
1431 idnsReadVC(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1432 {
1433 nsvc * vc = (nsvc *)data;
1434
1435 if (flag == COMM_ERR_CLOSING)
1436 return;
1437
1438 if (flag != COMM_OK || len <= 0) {
1439 if (Comm::IsConnOpen(conn))
1440 conn->close();
1441 return;
1442 }
1443
1444 vc->msg->size += len; // XXX should not access -> size directly
1445
1446 if (vc->msg->contentSize() < vc->msglen) {
1447 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1448 CommIoCbPtrFun(idnsReadVC, vc));
1449 comm_read(conn, buf+len, vc->msglen - vc->msg->contentSize(), call);
1450 return;
1451 }
1452
1453 assert(vc->ns < nns);
1454 debugs(78, 3, HERE << conn << ": received " << vc->msg->contentSize() << " bytes via TCP from " << nameservers[vc->ns].S << ".");
1455
1456 idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
1457 vc->msg->clean();
1458 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1459 CommIoCbPtrFun(idnsReadVCHeader, vc));
1460 comm_read(conn, (char *)&vc->msglen, 2, call);
1461 }
1462
1463 static void
1464 idnsReadVCHeader(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1465 {
1466 nsvc * vc = (nsvc *)data;
1467
1468 if (flag == COMM_ERR_CLOSING)
1469 return;
1470
1471 if (flag != COMM_OK || len <= 0) {
1472 if (Comm::IsConnOpen(conn))
1473 conn->close();
1474 return;
1475 }
1476
1477 vc->read_msglen += len;
1478
1479 assert(vc->read_msglen <= 2);
1480
1481 if (vc->read_msglen < 2) {
1482 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
1483 CommIoCbPtrFun(idnsReadVCHeader, vc));
1484 comm_read(conn, buf+len, 2 - vc->read_msglen, call);
1485 return;
1486 }
1487
1488 vc->read_msglen = 0;
1489
1490 vc->msglen = ntohs(vc->msglen);
1491
1492 vc->msg->init(vc->msglen, vc->msglen);
1493 AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
1494 CommIoCbPtrFun(idnsReadVC, vc));
1495 comm_read(conn, vc->msg->buf, vc->msglen, call);
1496 }
1497
1498 /*
1499 * rcode < 0 indicates an error, rocde >= 0 indicates success
1500 */
1501 static void
1502 idnsRcodeCount(int rcode, int attempt)
1503 {
1504 if (rcode > 0)
1505 rcode = 0;
1506 else if (rcode < 0)
1507 rcode = -rcode;
1508
1509 if (rcode < MAX_RCODE)
1510 if (attempt < MAX_ATTEMPT)
1511 ++ RcodeMatrix[rcode][attempt];
1512 }
1513
1514 /* ====================================================================== */
1515
1516 static void
1517 idnsRegisterWithCacheManager(void)
1518 {
1519 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
1520 }
1521
1522 void
1523 dnsInit(void)
1524 {
1525 static int init = 0;
1526
1527 CBDATA_INIT_TYPE(nsvc);
1528 CBDATA_INIT_TYPE(idns_query);
1529
1530 if (DnsSocketA < 0 && DnsSocketB < 0) {
1531 Ip::Address addrV6; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1532
1533 if (!Config.Addrs.udp_outgoing.isNoAddr())
1534 addrV6 = Config.Addrs.udp_outgoing;
1535 else
1536 addrV6 = Config.Addrs.udp_incoming;
1537
1538 Ip::Address addrV4 = addrV6;
1539 addrV4.setIPv4();
1540
1541 if (Ip::EnableIpv6 && addrV6.isIPv6()) {
1542 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6);
1543 DnsSocketB = comm_open_listener(SOCK_DGRAM,
1544 IPPROTO_UDP,
1545 addrV6,
1546 COMM_NONBLOCKING,
1547 "DNS Socket IPv6");
1548 }
1549
1550 if (addrV4.isIPv4()) {
1551 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4);
1552 DnsSocketA = comm_open_listener(SOCK_DGRAM,
1553 IPPROTO_UDP,
1554 addrV4,
1555 COMM_NONBLOCKING,
1556 "DNS Socket IPv4");
1557 }
1558
1559 if (DnsSocketA < 0 && DnsSocketB < 0)
1560 fatal("Could not create a DNS socket");
1561
1562 /* Ouch... we can't call functions using debug from a debug
1563 * statement. Doing so messes up the internal Debug::level
1564 */
1565 if (DnsSocketB >= 0) {
1566 comm_local_port(DnsSocketB);
1567 debugs(78, DBG_IMPORTANT, "DNS Socket created at " << addrV6 << ", FD " << DnsSocketB);
1568 Comm::SetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, NULL, 0);
1569 }
1570 if (DnsSocketA >= 0) {
1571 comm_local_port(DnsSocketA);
1572 debugs(78, DBG_IMPORTANT, "DNS Socket created at " << addrV4 << ", FD " << DnsSocketA);
1573 Comm::SetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, NULL, 0);
1574 }
1575 }
1576
1577 assert(0 == nns);
1578 idnsAddMDNSNameservers();
1579 bool nsFound = idnsParseNameservers();
1580 #if !_SQUID_WINDOWS_
1581
1582 if (!nsFound)
1583 nsFound = idnsParseResolvConf();
1584
1585 #endif
1586 #if _SQUID_WINDOWS_
1587 if (!nsFound)
1588 nsFound = idnsParseWIN32Registry();
1589 #endif
1590
1591 if (!nsFound) {
1592 debugs(78, DBG_IMPORTANT, "Warning: Could not find any nameservers. Trying to use localhost");
1593 #if _SQUID_WINDOWS_
1594 debugs(78, DBG_IMPORTANT, "Please check your TCP-IP settings or /etc/resolv.conf file");
1595 #else
1596 debugs(78, DBG_IMPORTANT, "Please check your /etc/resolv.conf file");
1597 #endif
1598
1599 debugs(78, DBG_IMPORTANT, "or use the 'dns_nameservers' option in squid.conf.");
1600 idnsAddNameserver("127.0.0.1");
1601 }
1602
1603 if (!init) {
1604 memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
1605 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
1606 idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
1607 ++init;
1608 }
1609
1610 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1611 if (Config.onoff.ignore_unknown_nameservers && max_shared_edns > 0) {
1612 debugs(0, DBG_IMPORTANT, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1613 max_shared_edns = -1; // disable if we might receive random replies.
1614 }
1615 #endif
1616
1617 idnsRegisterWithCacheManager();
1618 }
1619
1620 void
1621 dnsShutdown(void)
1622 {
1623 if (DnsSocketA < 0 && DnsSocketB < 0)
1624 return;
1625
1626 if (DnsSocketA >= 0 ) {
1627 comm_close(DnsSocketA);
1628 DnsSocketA = -1;
1629 }
1630
1631 if (DnsSocketB >= 0 ) {
1632 comm_close(DnsSocketB);
1633 DnsSocketB = -1;
1634 }
1635
1636 for (int i = 0; i < nns; ++i) {
1637 if (nsvc *vc = nameservers[i].vc) {
1638 if (Comm::IsConnOpen(vc->conn))
1639 vc->conn->close();
1640 }
1641 }
1642
1643 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1644 idnsFreeNameservers();
1645 idnsFreeSearchpath();
1646 }
1647
1648 static int
1649 idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1650 {
1651 idns_query *q;
1652
1653 idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
1654
1655 if (!old)
1656 return 0;
1657
1658 q = cbdataAlloc(idns_query);
1659 // idns_query is POD so no constructors are called after allocation
1660 q->xact_id.change();
1661 // no query_id on this instance.
1662
1663 q->callback = callback;
1664
1665 q->callback_data = cbdataReference(data);
1666
1667 q->queue = old->queue;
1668
1669 old->queue = q;
1670
1671 return 1;
1672 }
1673
1674 static void
1675 idnsStartQuery(idns_query *q, IDNSCB * callback, void *data)
1676 {
1677 q->start_t = current_time;
1678 q->callback = callback;
1679 q->callback_data = cbdataReference(data);
1680
1681 q->hash.key = q->orig;
1682 hash_join(idns_lookup_hash, &q->hash);
1683
1684 idnsSendQuery(q);
1685 }
1686
1687 static void
1688 idnsSendSlaveAAAAQuery(idns_query *master)
1689 {
1690 idns_query *q = cbdataAlloc(idns_query);
1691 memcpy(q->name, master->name, sizeof(q->name));
1692 memcpy(q->orig, master->orig, sizeof(q->orig));
1693 q->master = master;
1694 q->query_id = idnsQueryID();
1695 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
1696 q->start_t = master->start_t;
1697 q->slave = master->slave;
1698
1699 debugs(78, 3, HERE << "buf is " << q->sz << " bytes for " << q->name <<
1700 ", id = 0x" << std::hex << q->query_id);
1701 if (!q->sz) {
1702 cbdataFree(q);
1703 return;
1704 }
1705 idnsCheckMDNS(q);
1706 master->slave = q;
1707 idnsSendQuery(q);
1708 }
1709
1710 void
1711 idnsALookup(const char *name, IDNSCB * callback, void *data)
1712 {
1713 unsigned int i;
1714 int nd = 0;
1715 idns_query *q;
1716
1717 if (idnsCachedLookup(name, callback, data))
1718 return;
1719
1720 q = cbdataAlloc(idns_query);
1721 // idns_query is POD so no constructors are called after allocation
1722 q->xact_id.change();
1723 q->query_id = idnsQueryID();
1724
1725 for (i = 0; i < strlen(name); ++i)
1726 if (name[i] == '.')
1727 ++nd;
1728
1729 if (Config.onoff.res_defnames && npc > 0 && name[strlen(name)-1] != '.') {
1730 q->do_searchpath = 1;
1731 } else {
1732 q->do_searchpath = 0;
1733 }
1734
1735 strcpy(q->orig, name);
1736 strcpy(q->name, q->orig);
1737
1738 if (q->do_searchpath && nd < ndots) {
1739 q->domain = 0;
1740 strcat(q->name, ".");
1741 strcat(q->name, searchpath[q->domain].domain);
1742 debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
1743 }
1744
1745 // see EDNS notes at top of file why this sends 0
1746 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
1747
1748 if (q->sz < 0) {
1749 /* problem with query data -- query not sent */
1750 callback(data, NULL, 0, "Internal error");
1751 cbdataFree(q);
1752 return;
1753 }
1754
1755 debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
1756 ", id = 0x" << std::hex << q->query_id);
1757
1758 idnsCheckMDNS(q);
1759 idnsStartQuery(q, callback, data);
1760
1761 if (Ip::EnableIpv6)
1762 idnsSendSlaveAAAAQuery(q);
1763
1764 }
1765
1766 void
1767 idnsPTRLookup(const Ip::Address &addr, IDNSCB * callback, void *data)
1768 {
1769 idns_query *q;
1770
1771 char ip[MAX_IPSTRLEN];
1772
1773 addr.toStr(ip,MAX_IPSTRLEN);
1774
1775 q = cbdataAlloc(idns_query);
1776
1777 // idns_query is POD so no constructors are called after allocation
1778 q->xact_id.change();
1779 q->query_id = idnsQueryID();
1780
1781 if (addr.isIPv6()) {
1782 struct in6_addr addr6;
1783 addr.getInAddr(addr6);
1784 q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
1785 } else {
1786 struct in_addr addr4;
1787 addr.getInAddr(addr4);
1788 // see EDNS notes at top of file why this sends 0
1789 q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
1790 }
1791
1792 if (q->sz < 0) {
1793 /* problem with query data -- query not sent */
1794 callback(data, NULL, 0, "Internal error");
1795 cbdataFree(q);
1796 return;
1797 }
1798
1799 if (idnsCachedLookup(q->query.name, callback, data)) {
1800 cbdataFree(q);
1801 return;
1802 }
1803
1804 debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
1805 ", id = 0x" << std::hex << q->query_id);
1806
1807 q->permit_mdns = true;
1808 idnsStartQuery(q, callback, data);
1809 }
1810
1811 #if SQUID_SNMP
1812 /*
1813 * The function to return the DNS via SNMP
1814 */
1815 variable_list *
1816 snmp_netDnsFn(variable_list * Var, snint * ErrP)
1817 {
1818 int i, n = 0;
1819 variable_list *Answer = NULL;
1820 MemBuf tmp;
1821 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var->name, Var->name_length, tmp));
1822 *ErrP = SNMP_ERR_NOERROR;
1823
1824 switch (Var->name[LEN_SQ_NET + 1]) {
1825
1826 case DNS_REQ:
1827
1828 for (i = 0; i < nns; ++i)
1829 n += nameservers[i].nqueries;
1830
1831 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1832 n,
1833 SMI_COUNTER32);
1834
1835 break;
1836
1837 case DNS_REP:
1838 for (i = 0; i < nns; ++i)
1839 n += nameservers[i].nreplies;
1840
1841 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1842 n,
1843 SMI_COUNTER32);
1844
1845 break;
1846
1847 case DNS_SERVERS:
1848 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1849 nns,
1850 SMI_COUNTER32);
1851
1852 break;
1853
1854 default:
1855 *ErrP = SNMP_ERR_NOSUCHNAME;
1856
1857 break;
1858 }
1859
1860 return Answer;
1861 }
1862
1863 #endif /*SQUID_SNMP */
1864 #endif /* USE_DNSHELPER */