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