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