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