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