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