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