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