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