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