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