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