]> git.ipfire.org Git - thirdparty/squid.git/blob - src/dns_internal.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / dns_internal.cc
1
2 /*
3 * $Id$
4 *
5 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "config.h"
37 #include "squid.h"
38 #include "event.h"
39 #include "SquidTime.h"
40 #include "Store.h"
41 #include "comm.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 #ifdef _SQUID_WIN32_
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 size_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 #ifdef _SQUID_WIN32_
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 xmemcpy(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 xmemcpy(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 defined(_SQUID_CYGWIN_)
368 setmode(fileno(fp), O_TEXT);
369
370 #endif
371
372 while (fgets(buf, RESOLV_BUFSZ, fp)) {
373 t = strtok(buf, w_space);
374
375 if (NULL == t) {
376 continue;
377 } else if (strcasecmp(t, "nameserver") == 0) {
378 t = strtok(NULL, w_space);
379
380 if (NULL == t)
381 continue;
382
383 debugs(78, 1, "Adding nameserver " << t << " from " << _PATH_RESCONF);
384
385 idnsAddNameserver(t);
386 } else if (strcasecmp(t, "domain") == 0) {
387 idnsFreeSearchpath();
388 t = strtok(NULL, w_space);
389
390 if (NULL == t)
391 continue;
392
393 debugs(78, 1, "Adding domain " << t << " from " << _PATH_RESCONF);
394
395 idnsAddPathComponent(t);
396 } else if (strcasecmp(t, "search") == 0) {
397 idnsFreeSearchpath();
398 while (NULL != t) {
399 t = strtok(NULL, w_space);
400
401 if (NULL == t)
402 continue;
403
404 debugs(78, 1, "Adding domain " << t << " from " << _PATH_RESCONF);
405
406 idnsAddPathComponent(t);
407 }
408 } else if (strcasecmp(t, "options") == 0) {
409 while (NULL != t) {
410 t = strtok(NULL, w_space);
411
412 if (NULL == t)
413 continue;
414
415 if (strncmp(t, "ndots:", 6) == 0) {
416 ndots = atoi(t + 6);
417
418 if (ndots < 1)
419 ndots = 1;
420
421 debugs(78, 1, "Adding ndots " << ndots << " from " << _PATH_RESCONF);
422 }
423 }
424 }
425 }
426 if (npc == 0 && (t = getMyHostname())) {
427 t = strchr(t, '.');
428 if (t)
429 idnsAddPathComponent(t+1);
430 }
431
432 fclose(fp);
433 }
434
435 #endif
436
437 #ifdef _SQUID_WIN32_
438 static void
439 idnsParseWIN32SearchList(const char * Separator)
440 {
441 char *t;
442 char *token;
443 HKEY hndKey;
444
445 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
446 DWORD Type = 0;
447 DWORD Size = 0;
448 LONG Result;
449 Result = RegQueryValueEx(hndKey, "Domain", NULL, &Type, NULL, &Size);
450
451 if (Result == ERROR_SUCCESS && Size) {
452 t = (char *) xmalloc(Size);
453 RegQueryValueEx(hndKey, "Domain", NULL, &Type, (LPBYTE) t, &Size);
454 debugs(78, 1, "Adding domain " << t << " from Registry");
455 idnsAddPathComponent(t);
456 xfree(t);
457 }
458 Result = RegQueryValueEx(hndKey, "SearchList", NULL, &Type, NULL, &Size);
459
460 if (Result == ERROR_SUCCESS && Size) {
461 t = (char *) xmalloc(Size);
462 RegQueryValueEx(hndKey, "SearchList", NULL, &Type, (LPBYTE) t, &Size);
463 token = strtok(t, Separator);
464
465 while (token) {
466 idnsAddPathComponent(token);
467 debugs(78, 1, "Adding domain " << token << " from Registry");
468 token = strtok(NULL, Separator);
469 }
470 xfree(t);
471 }
472
473 RegCloseKey(hndKey);
474 }
475 if (npc == 0 && (t = (char *) getMyHostname())) {
476 t = strchr(t, '.');
477 if (t)
478 idnsAddPathComponent(t + 1);
479 }
480 }
481
482 static void
483 idnsParseWIN32Registry(void)
484 {
485 char *t;
486 char *token;
487 HKEY hndKey, hndKey2;
488
489 switch (WIN32_OS_version) {
490
491 case _WIN_OS_WINNT:
492 /* get nameservers from the Windows NT registry */
493
494 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
495 DWORD Type = 0;
496 DWORD Size = 0;
497 LONG Result;
498 Result = RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, NULL, &Size);
499
500 if (Result == ERROR_SUCCESS && Size) {
501 t = (char *) xmalloc(Size);
502 RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, (LPBYTE) t, &Size);
503 token = strtok(t, ", ");
504
505 while (token) {
506 idnsAddNameserver(token);
507 debugs(78, 1, "Adding DHCP nameserver " << token << " from Registry");
508 token = strtok(NULL, ",");
509 }
510 xfree(t);
511 }
512
513 Result = RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
514
515 if (Result == ERROR_SUCCESS && Size) {
516 t = (char *) xmalloc(Size);
517 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, (LPBYTE) t, &Size);
518 token = strtok(t, ", ");
519
520 while (token) {
521 debugs(78, 1, "Adding nameserver " << token << " from Registry");
522 idnsAddNameserver(token);
523 token = strtok(NULL, ", ");
524 }
525 xfree(t);
526 }
527
528 RegCloseKey(hndKey);
529 }
530
531 idnsParseWIN32SearchList(" ");
532
533 break;
534
535 case _WIN_OS_WIN2K:
536
537 case _WIN_OS_WINXP:
538
539 case _WIN_OS_WINNET:
540
541 case _WIN_OS_WINLON:
542
543 case _WIN_OS_WIN7:
544 /* get nameservers from the Windows 2000 registry */
545 /* search all interfaces for DNS server addresses */
546
547 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA_INTERFACES, 0, KEY_READ, &hndKey) == ERROR_SUCCESS) {
548 int i;
549 DWORD MaxSubkeyLen, InterfacesCount;
550 char *keyname;
551 FILETIME ftLastWriteTime;
552
553 if (RegQueryInfoKey(hndKey, NULL, NULL, NULL, &InterfacesCount, &MaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
554 keyname = (char *) xmalloc(++MaxSubkeyLen);
555 for (i = 0; i < (int) InterfacesCount; i++) {
556 DWORD j;
557 j = MaxSubkeyLen;
558 if (RegEnumKeyEx(hndKey, i, keyname, &j, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS) {
559 char *newkeyname;
560 newkeyname = (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES) + j + 2);
561 strcpy(newkeyname, REG_TCPIP_PARA_INTERFACES);
562 strcat(newkeyname, "\\");
563 strcat(newkeyname, keyname);
564 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newkeyname, 0, KEY_QUERY_VALUE, &hndKey2) == ERROR_SUCCESS) {
565 DWORD Type = 0;
566 DWORD Size = 0;
567 LONG Result;
568 Result = RegQueryValueEx(hndKey2, "DhcpNameServer", NULL, &Type, NULL, &Size);
569 if (Result == ERROR_SUCCESS && Size) {
570 t = (char *) xmalloc(Size);
571 RegQueryValueEx(hndKey2, "DhcpNameServer", NULL, &Type, (LPBYTE)t, &Size);
572 token = strtok(t, ", ");
573 while (token) {
574 debugs(78, 1, "Adding DHCP nameserver " << token << " from Registry");
575 idnsAddNameserver(token);
576 token = strtok(NULL, ", ");
577 }
578 xfree(t);
579 }
580
581 Result = RegQueryValueEx(hndKey2, "NameServer", NULL, &Type, NULL, &Size);
582 if (Result == ERROR_SUCCESS && Size) {
583 t = (char *) xmalloc(Size);
584 RegQueryValueEx(hndKey2, "NameServer", NULL, &Type, (LPBYTE)t, &Size);
585 token = strtok(t, ", ");
586 while (token) {
587 debugs(78, 1, "Adding nameserver " << token << " from Registry");
588 idnsAddNameserver(token);
589 token = strtok(NULL, ", ");
590 }
591
592 xfree(t);
593 }
594
595 RegCloseKey(hndKey2);
596 }
597
598 xfree(newkeyname);
599 }
600 }
601
602 xfree(keyname);
603 }
604
605 RegCloseKey(hndKey);
606 }
607
608 idnsParseWIN32SearchList(", ");
609
610 break;
611
612 case _WIN_OS_WIN95:
613
614 case _WIN_OS_WIN98:
615
616 case _WIN_OS_WINME:
617 /* get nameservers from the Windows 9X registry */
618
619 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_VXD_MSTCP, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
620 DWORD Type = 0;
621 DWORD Size = 0;
622 LONG Result;
623 Result = RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
624
625 if (Result == ERROR_SUCCESS && Size) {
626 t = (char *) xmalloc(Size);
627 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, (LPBYTE) t, &Size);
628 token = strtok(t, ", ");
629
630 while (token) {
631 debugs(78, 1, "Adding nameserver " << token << " from Registry");
632 idnsAddNameserver(token);
633 token = strtok(NULL, ", ");
634 }
635 xfree(t);
636 }
637
638 RegCloseKey(hndKey);
639 }
640
641 break;
642
643 default:
644 debugs(78, 1, "Failed to read nameserver from Registry: Unknown System Type.");
645 return;
646 }
647 }
648
649 #endif
650
651 static void
652 idnsStats(StoreEntry * sentry)
653 {
654 dlink_node *n;
655 idns_query *q;
656 int i;
657 int j;
658 char buf[MAX_IPSTRLEN];
659 storeAppendPrintf(sentry, "Internal DNS Statistics:\n");
660 storeAppendPrintf(sentry, "\nThe Queue:\n");
661 storeAppendPrintf(sentry, " DELAY SINCE\n");
662 storeAppendPrintf(sentry, " ID SIZE SENDS FIRST SEND LAST SEND\n");
663 storeAppendPrintf(sentry, "------ ---- ----- ---------- ---------\n");
664
665 for (n = lru_list.head; n; n = n->next) {
666 q = (idns_query *)n->data;
667 storeAppendPrintf(sentry, "%#06x %4d %5d %10.3f %9.3f\n",
668 (int) q->msg_id, (int) q->sz, q->nsends,
669 tvSubDsec(q->start_t, current_time),
670 tvSubDsec(q->sent_t, current_time));
671 }
672
673 if (Config.dns.packet_max > 0)
674 storeAppendPrintf(sentry, "DNS jumbo-grams: %Zd Bytes\n", Config.dns.packet_max);
675 else
676 storeAppendPrintf(sentry, "DNS jumbo-grams: not working\n");
677
678 storeAppendPrintf(sentry, "\nNameservers:\n");
679 storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES\n");
680 storeAppendPrintf(sentry, "---------------------------------------------- --------- ---------\n");
681
682 for (i = 0; i < nns; i++) {
683 storeAppendPrintf(sentry, "%-45s %9d %9d\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
684 nameservers[i].S.NtoA(buf,MAX_IPSTRLEN),
685 nameservers[i].nqueries,
686 nameservers[i].nreplies);
687 }
688
689 storeAppendPrintf(sentry, "\nRcode Matrix:\n");
690 storeAppendPrintf(sentry, "RCODE");
691
692 for (i = 0; i < MAX_ATTEMPT; i++)
693 storeAppendPrintf(sentry, " ATTEMPT%d", i + 1);
694
695 storeAppendPrintf(sentry, " PROBLEM\n");
696
697 for (j = 0; j < MAX_RCODE; j++) {
698 if (j > 10 && j < 16)
699 continue; // unassigned by IANA.
700
701 storeAppendPrintf(sentry, "%5d", j);
702
703 for (i = 0; i < MAX_ATTEMPT; i++)
704 storeAppendPrintf(sentry, " %8d", RcodeMatrix[j][i]);
705
706 storeAppendPrintf(sentry, " : %s\n",Rcodes[j]);
707 }
708
709 if (npc) {
710 storeAppendPrintf(sentry, "\nSearch list:\n");
711
712 for (i=0; i < npc; i++)
713 storeAppendPrintf(sentry, "%s\n", searchpath[i].domain);
714
715 storeAppendPrintf(sentry, "\n");
716 }
717 }
718
719 static void
720 idnsTickleQueue(void)
721 {
722 if (event_queued)
723 return;
724
725 if (NULL == lru_list.tail)
726 return;
727
728 eventAdd("idnsCheckQueue", idnsCheckQueue, NULL, 1.0, 1);
729
730 event_queued = 1;
731 }
732
733 static void
734 idnsSentQueryVC(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
735 {
736 nsvc * vc = (nsvc *)data;
737
738 if (flag == COMM_ERR_CLOSING)
739 return;
740
741 if (fd_table[fd].closing())
742 return;
743
744 if (flag != COMM_OK || size <= 0) {
745 comm_close(fd);
746 return;
747 }
748
749 vc->busy = 0;
750 idnsDoSendQueryVC(vc);
751 }
752
753 static void
754 idnsDoSendQueryVC(nsvc *vc)
755 {
756 if (vc->busy)
757 return;
758
759 if (vc->queue->contentSize() == 0)
760 return;
761
762 MemBuf *mb = vc->queue;
763
764 vc->queue = new MemBuf;
765
766 vc->busy = 1;
767
768 commSetTimeout(vc->fd, Config.Timeout.idns_query, NULL, NULL);
769
770 comm_write_mbuf(vc->fd, mb, idnsSentQueryVC, vc);
771
772 delete mb;
773 }
774
775 static void
776 idnsInitVCConnected(int fd, const DnsLookupDetails &details, comm_err_t status, int xerrno, void *data)
777 {
778 nsvc * vc = (nsvc *)data;
779
780 if (status != COMM_OK) {
781 char buf[MAX_IPSTRLEN] = "";
782 if (vc->ns < nns)
783 nameservers[vc->ns].S.NtoA(buf,MAX_IPSTRLEN);
784 debugs(78, 1, HERE << "Failed to connect to nameserver " << buf << " using TCP: " << details);
785 comm_close(fd);
786 return;
787 }
788
789 comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
790 vc->busy = 0;
791 idnsDoSendQueryVC(vc);
792 }
793
794 static void
795 idnsVCClosed(int fd, void *data)
796 {
797 nsvc * vc = (nsvc *)data;
798 delete vc->queue;
799 delete vc->msg;
800 if (vc->ns < nns) // XXX: idnsShutdown may have freed nameservers[]
801 nameservers[vc->ns].vc = NULL;
802 cbdataFree(vc);
803 }
804
805 static void
806 idnsInitVC(int ns)
807 {
808 char buf[MAX_IPSTRLEN];
809
810 nsvc *vc = cbdataAlloc(nsvc);
811 assert(ns < nns);
812 nameservers[ns].vc = vc;
813 vc->ns = ns;
814
815 Ip::Address addr;
816
817 if (!Config.Addrs.udp_outgoing.IsNoAddr())
818 addr = Config.Addrs.udp_outgoing;
819 else
820 addr = Config.Addrs.udp_incoming;
821
822 if (nameservers[ns].S.IsIPv4() && !addr.SetIPv4()) {
823 debugs(31, DBG_CRITICAL, "ERROR: Cannot contact DNS nameserver " << nameservers[ns].S << " from " << addr);
824 addr.SetAnyAddr();
825 addr.SetIPv4();
826 }
827
828 vc->queue = new MemBuf;
829
830 vc->msg = new MemBuf;
831
832 vc->fd = comm_open(SOCK_STREAM,
833 IPPROTO_TCP,
834 addr,
835 COMM_NONBLOCKING,
836 "DNS TCP Socket");
837
838 if (vc->fd < 0)
839 fatal("Could not create a DNS socket");
840
841 comm_add_close_handler(vc->fd, idnsVCClosed, vc);
842
843 vc->busy = 1;
844
845 commConnectStart(vc->fd, nameservers[ns].S.NtoA(buf,MAX_IPSTRLEN), nameservers[ns].S.GetPort(), idnsInitVCConnected, vc);
846 }
847
848 static void
849 idnsSendQueryVC(idns_query * q, int ns)
850 {
851 assert(ns < nns);
852 if (nameservers[ns].vc == NULL)
853 idnsInitVC(ns);
854
855 nsvc *vc = nameservers[ns].vc;
856
857 if (!vc) {
858 char buf[MAX_IPSTRLEN];
859 debugs(78, 1, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers[ns].S.NtoA(buf,MAX_IPSTRLEN) << "!");
860
861 return;
862 }
863
864 vc->queue->reset();
865
866 short head = htons(q->sz);
867
868 vc->queue->append((char *)&head, 2);
869
870 vc->queue->append(q->buf, q->sz);
871
872 idnsDoSendQueryVC(vc);
873 }
874
875 static void
876 idnsSendQuery(idns_query * q)
877 {
878 if (DnsSocketA < 0 && DnsSocketB < 0) {
879 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
880 return;
881 }
882
883 if (nns <= 0) {
884 debugs(78, 1, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
885 return;
886 }
887
888 assert(q->lru.next == NULL);
889
890 assert(q->lru.prev == NULL);
891
892 int x = -1, y = -1;
893 int ns;
894
895 q->start_t = current_time;
896 q->msg_id = idnsQueryID();
897 rfc1035SetQueryID(q->buf, q->msg_id);
898
899 do {
900 ns = q->nsends % nns;
901
902 if (q->need_vc) {
903 idnsSendQueryVC(q, ns);
904 x = y = 0;
905 } else {
906 if (DnsSocketB >= 0 && nameservers[ns].S.IsIPv6())
907 y = comm_udp_sendto(DnsSocketB, nameservers[ns].S, q->buf, q->sz);
908 else if (DnsSocketA)
909 x = comm_udp_sendto(DnsSocketA, nameservers[ns].S, q->buf, q->sz);
910 }
911
912 q->nsends++;
913
914 q->queue_t = q->sent_t = current_time;
915
916 if (y < 0 && nameservers[ns].S.IsIPv6())
917 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketB << ": sendto: " << xstrerror());
918 if (x < 0 && nameservers[ns].S.IsIPv4())
919 debugs(50, 1, "idnsSendQuery: FD " << DnsSocketA << ": sendto: " << xstrerror());
920
921 } while ( (x<0 && y<0) && q->nsends % nns != 0);
922
923 if (y > 0) {
924 fd_bytes(DnsSocketB, y, FD_WRITE);
925 }
926 if (x > 0) {
927 fd_bytes(DnsSocketA, x, FD_WRITE);
928 }
929
930 nameservers[ns].nqueries++;
931 q->queue_t = current_time;
932 dlinkAdd(q, &q->lru, &lru_list);
933 idnsTickleQueue();
934 }
935
936 static int
937 idnsFromKnownNameserver(Ip::Address const &from)
938 {
939 int i;
940
941 for (i = 0; i < nns; i++) {
942 if (nameservers[i].S != from)
943 continue;
944
945 if (nameservers[i].S.GetPort() != from.GetPort())
946 continue;
947
948 return i;
949 }
950
951 return -1;
952 }
953
954 static idns_query *
955 idnsFindQuery(unsigned short id)
956 {
957 dlink_node *n;
958 idns_query *q;
959
960 for (n = lru_list.tail; n; n = n->prev) {
961 q = (idns_query*)n->data;
962
963 if (q->msg_id == id)
964 return q;
965 }
966
967 return NULL;
968 }
969
970 static unsigned short
971 idnsQueryID(void)
972 {
973 unsigned short id = squid_random() & 0xFFFF;
974 unsigned short first_id = id;
975
976 while (idnsFindQuery(id)) {
977 id++;
978
979 if (id == first_id) {
980 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
981 break;
982 }
983 }
984
985 return id;
986 }
987
988 static void
989 idnsCallback(idns_query *q, rfc1035_rr *answers, int n, const char *error)
990 {
991 IDNSCB *callback;
992 void *cbdata;
993
994 callback = q->callback;
995 q->callback = NULL;
996
997 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
998 callback(cbdata, answers, n, error);
999
1000 while (q->queue) {
1001 idns_query *q2 = q->queue;
1002 q->queue = q2->queue;
1003 callback = q2->callback;
1004 q2->callback = NULL;
1005
1006 if (cbdataReferenceValidDone(q2->callback_data, &cbdata))
1007 callback(cbdata, answers, n, error);
1008
1009 cbdataFree(q2);
1010 }
1011
1012 if (q->hash.key) {
1013 hash_remove_link(idns_lookup_hash, &q->hash);
1014 q->hash.key = NULL;
1015 }
1016 }
1017
1018 void
1019 idnsDropMessage(rfc1035_message *message, idns_query *q)
1020 {
1021 rfc1035MessageDestroy(&message);
1022 if (q->hash.key) {
1023 hash_remove_link(idns_lookup_hash, &q->hash);
1024 q->hash.key = NULL;
1025 }
1026 }
1027
1028 static void
1029 idnsGrokReply(const char *buf, size_t sz, int from_ns)
1030 {
1031 int n;
1032 rfc1035_message *message = NULL;
1033 idns_query *q;
1034
1035 n = rfc1035MessageUnpack(buf, sz, &message);
1036
1037 if (message == NULL) {
1038 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
1039 return;
1040 }
1041
1042 debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex << message->id << ", " << std::dec << n << " answers");
1043
1044 q = idnsFindQuery(message->id);
1045
1046 if (q == NULL) {
1047 debugs(78, 3, "idnsGrokReply: Late response");
1048 rfc1035MessageDestroy(&message);
1049 return;
1050 }
1051
1052 if (rfc1035QueryCompare(&q->query, message->query) != 0) {
1053 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q->query.name << " != " << message->query->name << ")");
1054 rfc1035MessageDestroy(&message);
1055 return;
1056 }
1057
1058 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1059 // TODO: actually gr the message right here.
1060 // pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
1061 // this is overall better than force-feeding A response with AAAA an section later anyway.
1062 // AND allows us to merge AN+AR sections from both responses (one day)
1063
1064 if (q->edns_seen >= 0) {
1065 if (max_shared_edns == nameservers[from_ns].last_seen_edns && max_shared_edns < q->edns_seen) {
1066 nameservers[from_ns].last_seen_edns = q->edns_seen;
1067 // the altered NS was limiting the whole group.
1068 max_shared_edns = q->edns_seen;
1069 // may be limited by one of the others still
1070 for (int i = 0; i < nns; i++)
1071 max_shared_edns = min(max_shared_edns, nameservers[i].last_seen_edns);
1072 } else {
1073 nameservers[from_ns].last_seen_edns = q->edns_seen;
1074 // maybe reduce the global limit downwards to accomodate this NS
1075 max_shared_edns = min(max_shared_edns, q->edns_seen);
1076 }
1077 if (max_shared_edns < RFC1035_DEFAULT_PACKET_SZ)
1078 max_shared_edns = -1;
1079 }
1080 #endif
1081
1082 if (message->tc) {
1083 debugs(78, 3, HERE << "Resolver requested TC (" << q->query.name << ")");
1084 dlinkDelete(&q->lru, &lru_list);
1085 rfc1035MessageDestroy(&message);
1086
1087 if (!q->need_vc) {
1088 q->need_vc = 1;
1089 q->nsends--;
1090 idnsSendQuery(q);
1091 } else {
1092 // Strange: A TCP DNS response with the truncation bit (TC) set.
1093 // Return an error and cleanup; no point in trying TCP again.
1094 debugs(78, 3, HERE << "TCP DNS response");
1095 idnsCallback(q, NULL, 0, "Truncated TCP DNS response");
1096 cbdataFree(q);
1097 }
1098
1099 return;
1100 }
1101
1102 dlinkDelete(&q->lru, &lru_list);
1103 idnsRcodeCount(n, q->attempt);
1104
1105 if (n < 0) {
1106 q->rcode = -n;
1107 debugs(78, 3, "idnsGrokReply: error " << rfc1035ErrorMessage(n) << " (" << q->rcode << ")");
1108
1109 if (q->rcode == 2 && ++q->attempt < MAX_ATTEMPT) {
1110 /*
1111 * RCODE 2 is "Server failure - The name server was
1112 * unable to process this query due to a problem with
1113 * the name server."
1114 */
1115 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
1116 rfc1035MessageDestroy(&message);
1117 idnsSendQuery(q);
1118 return;
1119 }
1120
1121 if (q->rcode == 3 && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
1122 assert(NULL == message->answer);
1123 strcpy(q->name, q->orig);
1124
1125 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q->name );
1126
1127 if (q->domain < npc) {
1128 strcat(q->name, ".");
1129 strcat(q->name, searchpath[q->domain].domain);
1130 debugs(78, 3, "idnsGrokReply: searchpath used for " << q->name);
1131 q->domain++;
1132 } else {
1133 q->attempt++;
1134 }
1135
1136 idnsDropMessage(message, q);
1137
1138 if (Ip::EnableIpv6 && q->query.qtype == RFC1035_TYPE_AAAA) {
1139 debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q->name);
1140 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, Config.dns.packet_max);
1141 } else {
1142 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
1143 // see EDNS notes at top of file why this sends 0
1144 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, 0);
1145 }
1146 idnsCacheQuery(q);
1147 idnsSendQuery(q);
1148 return;
1149 }
1150 }
1151
1152 if (q->need_A && (Config.onoff.dns_require_A == 1 || n <= 0 ) ) {
1153 /* ERROR or NO AAAA exist. Failover to A records. */
1154 /* Apparently its also a good idea to lookup and store the A records
1155 * just in case the AAAA are not available when we need them.
1156 * This could occur due to number of network failings beyond our control
1157 * thus the || above allowing the user to request always both.
1158 */
1159
1160 if (n == 0)
1161 debugs(78, 3, "idnsGrokReply: " << q->name << " has no AAAA records. Looking up A record instead.");
1162 else if (q->need_A && n <= 0)
1163 debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query failed. Trying A now instead.");
1164 else // admin requested this.
1165 debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query done. Configured to retrieve A now also.");
1166
1167 // move the initial message results into the failover query for merging later.
1168 if (n > 0) {
1169 q->initial_AAAA.count = message->ancount;
1170 q->initial_AAAA.answers = message->answer;
1171 message->answer = NULL;
1172 }
1173
1174 // remove the hashed query info
1175 idnsDropMessage(message, q);
1176
1177 // reset the query as an A query
1178 q->nsends = 0;
1179 // see EDNS notes at top of file why this sends 0
1180 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, 0);
1181 q->need_A = false;
1182 idnsCacheQuery(q);
1183 idnsSendQuery(q);
1184 return;
1185 }
1186
1187 /** If there are two result sets from preceeding AAAA and A lookups merge them with a preference for AAAA */
1188 if (q->initial_AAAA.count > 0 && n > 0) {
1189 /* two sets of RR need merging */
1190 rfc1035_rr *result = (rfc1035_rr*) xmalloc( sizeof(rfc1035_rr)*(n + q->initial_AAAA.count) );
1191 rfc1035_rr *tmp = result;
1192
1193 debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
1194
1195 memcpy(tmp, q->initial_AAAA.answers, (sizeof(rfc1035_rr)*(q->initial_AAAA.count)) );
1196 tmp += q->initial_AAAA.count;
1197 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1198 safe_free(q->initial_AAAA.answers);
1199
1200 memcpy( tmp, message->answer, (sizeof(rfc1035_rr)*n) );
1201 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1202 safe_free(message->answer);
1203
1204 message->answer = result;
1205 message->ancount += q->initial_AAAA.count;
1206 n += q->initial_AAAA.count;
1207 q->initial_AAAA.count=0;
1208 } else if (q->initial_AAAA.count > 0 && n <= 0) {
1209 /* initial of dual queries was the only result set. */
1210 debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
1211 rfc1035RRDestroy(&(message->answer), n);
1212 message->answer = q->initial_AAAA.answers;
1213 n = q->initial_AAAA.count;
1214 }
1215 /* else initial results were empty. just use the final set as authoritative */
1216
1217 debugs(78, 6, HERE << "Sending " << n << " DNS results to caller.");
1218 idnsCallback(q, message->answer, n, rfc1035ErrorMessage(n));
1219 rfc1035MessageDestroy(&message);
1220 cbdataFree(q);
1221 }
1222
1223 static void
1224 idnsRead(int fd, void *data)
1225 {
1226 int *N = &incoming_sockets_accepted;
1227 int len;
1228 int max = INCOMING_DNS_MAX;
1229 static char rbuf[SQUID_UDP_SO_RCVBUF];
1230 int ns;
1231 Ip::Address from;
1232
1233 debugs(78, 3, "idnsRead: starting with FD " << fd);
1234
1235 // Always keep reading. This stops (or at least makes harder) several
1236 // attacks on the DNS client.
1237 commSetSelect(fd, COMM_SELECT_READ, idnsRead, NULL, 0);
1238
1239 /* BUG (UNRESOLVED)
1240 * two code lines after returning from comm_udprecvfrom()
1241 * something overwrites the memory behind the from parameter.
1242 * NO matter where in the stack declaration list above it is placed
1243 * The cause of this is still unknown, however copying the data appears
1244 * to allow it to be passed further without this erasure.
1245 */
1246 Ip::Address bugbypass;
1247
1248 while (max--) {
1249 len = comm_udp_recvfrom(fd, rbuf, SQUID_UDP_SO_RCVBUF, 0, bugbypass);
1250
1251 from = bugbypass; // BUG BYPASS. see notes above.
1252
1253 if (len == 0)
1254 break;
1255
1256 if (len < 0) {
1257 if (ignoreErrno(errno))
1258 break;
1259
1260 #ifdef _SQUID_LINUX_
1261 /* Some Linux systems seem to set the FD for reading and then
1262 * return ECONNREFUSED when sendto() fails and generates an ICMP
1263 * port unreachable message. */
1264 /* or maybe an EHOSTUNREACH "No route to host" message */
1265 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
1266 #endif
1267
1268 debugs(50, 1, "idnsRead: FD " << fd << " recvfrom: " << xstrerror());
1269
1270 break;
1271 }
1272
1273 fd_bytes(fd, len, FD_READ);
1274
1275 assert(N);
1276 (*N)++;
1277
1278 debugs(78, 3, "idnsRead: FD " << fd << ": received " << len << " bytes from " << from);
1279
1280 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1281 ns = idnsFromKnownNameserver(from);
1282
1283 if (ns >= 0) {
1284 nameservers[ns].nreplies++;
1285 }
1286
1287 // Before unknown_nameservers check to avoid flooding cache.log on attacks,
1288 // but after the ++ above to keep statistics right.
1289 if (!lru_list.head)
1290 continue; // Don't process replies if there is no pending query.
1291
1292 if (ns < 0 && Config.onoff.ignore_unknown_nameservers) {
1293 static time_t last_warning = 0;
1294
1295 if (squid_curtime - last_warning > 60) {
1296 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from);
1297 last_warning = squid_curtime;
1298 } else {
1299 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from << " (retrying..." << (squid_curtime-last_warning) << "<=60)" );
1300 }
1301 continue;
1302 }
1303
1304 idnsGrokReply(rbuf, len, ns);
1305 }
1306 }
1307
1308 static void
1309 idnsCheckQueue(void *unused)
1310 {
1311 dlink_node *n;
1312 dlink_node *p = NULL;
1313 idns_query *q;
1314 event_queued = 0;
1315
1316 if (0 == nns)
1317 /* name servers went away; reconfiguring or shutting down */
1318 return;
1319
1320 for (n = lru_list.tail; n; n = p) {
1321
1322 p = n->prev;
1323 q = static_cast<idns_query*>(n->data);
1324
1325 /* Anything to process in the queue? */
1326 if (tvSubDsec(q->queue_t, current_time) < Config.Timeout.idns_retransmit )
1327 break;
1328
1329 /* Query timer expired? */
1330 if (tvSubDsec(q->sent_t, current_time) < Config.Timeout.idns_retransmit * 1 << ((q->nsends - 1) / nns)) {
1331 dlinkDelete(&q->lru, &lru_list);
1332 q->queue_t = current_time;
1333 dlinkAdd(q, &q->lru, &lru_list);
1334 continue;
1335 }
1336
1337 debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
1338 " QID 0x" << std::hex << std::setfill('0') <<
1339 std::setw(4) << q->msg_id << ": timeout" );
1340
1341 dlinkDelete(&q->lru, &lru_list);
1342
1343 if (tvSubDsec(q->start_t, current_time) < Config.Timeout.idns_query) {
1344 idnsSendQuery(q);
1345 } else {
1346 debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
1347 " QID 0x" << std::hex << q->msg_id <<
1348 " : giving up after " << std::dec << q->nsends << " tries and " <<
1349 std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
1350
1351 if (q->rcode != 0)
1352 idnsCallback(q, NULL, -q->rcode, rfc1035ErrorMessage(q->rcode));
1353 else
1354 idnsCallback(q, NULL, -16, "Timeout");
1355
1356 cbdataFree(q);
1357 }
1358 }
1359
1360 idnsTickleQueue();
1361 }
1362
1363 static void
1364 idnsReadVC(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1365 {
1366 nsvc * vc = (nsvc *)data;
1367
1368 if (flag == COMM_ERR_CLOSING)
1369 return;
1370
1371 if (flag != COMM_OK || len <= 0) {
1372 comm_close(fd);
1373 return;
1374 }
1375
1376 vc->msg->size += len; // XXX should not access -> size directly
1377
1378 if (vc->msg->contentSize() < vc->msglen) {
1379 comm_read(fd, buf + len, vc->msglen - vc->msg->contentSize(), idnsReadVC, vc);
1380 return;
1381 }
1382
1383 assert(vc->ns < nns);
1384 debugs(78, 3, "idnsReadVC: FD " << fd << ": received " <<
1385 (int) vc->msg->contentSize() << " bytes via tcp from " <<
1386 nameservers[vc->ns].S << ".");
1387
1388 idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
1389 vc->msg->clean();
1390 comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
1391 }
1392
1393 static void
1394 idnsReadVCHeader(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1395 {
1396 nsvc * vc = (nsvc *)data;
1397
1398 if (flag == COMM_ERR_CLOSING)
1399 return;
1400
1401 if (flag != COMM_OK || len <= 0) {
1402 comm_close(fd);
1403 return;
1404 }
1405
1406 vc->read_msglen += len;
1407
1408 assert(vc->read_msglen <= 2);
1409
1410 if (vc->read_msglen < 2) {
1411 comm_read(fd, buf + len, 2 - vc->read_msglen, idnsReadVCHeader, vc);
1412 return;
1413 }
1414
1415 vc->read_msglen = 0;
1416
1417 vc->msglen = ntohs(vc->msglen);
1418
1419 vc->msg->init(vc->msglen, vc->msglen);
1420 comm_read(fd, vc->msg->buf, vc->msglen, idnsReadVC, vc);
1421 }
1422
1423 /*
1424 * rcode < 0 indicates an error, rocde >= 0 indicates success
1425 */
1426 static void
1427 idnsRcodeCount(int rcode, int attempt)
1428 {
1429 if (rcode > 0)
1430 rcode = 0;
1431 else if (rcode < 0)
1432 rcode = -rcode;
1433
1434 if (rcode < MAX_RCODE)
1435 if (attempt < MAX_ATTEMPT)
1436 RcodeMatrix[rcode][attempt]++;
1437 }
1438
1439 /* ====================================================================== */
1440
1441 static void
1442 idnsRegisterWithCacheManager(void)
1443 {
1444 Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
1445 }
1446
1447 void
1448 idnsInit(void)
1449 {
1450 static int init = 0;
1451
1452 CBDATA_INIT_TYPE(nsvc);
1453 CBDATA_INIT_TYPE(idns_query);
1454
1455 if (DnsSocketA < 0 && DnsSocketB < 0) {
1456 int port;
1457
1458 Ip::Address addrA; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
1459
1460 if (!Config.Addrs.udp_outgoing.IsNoAddr())
1461 addrA = Config.Addrs.udp_outgoing;
1462 else
1463 addrA = Config.Addrs.udp_incoming;
1464
1465 Ip::Address addrB = addrA;
1466 addrA.SetIPv4();
1467
1468 if (Ip::EnableIpv6 && (addrB.IsAnyAddr() || addrB.IsIPv6())) {
1469 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrB);
1470 DnsSocketB = comm_open_listener(SOCK_DGRAM,
1471 IPPROTO_UDP,
1472 addrB,
1473 COMM_NONBLOCKING,
1474 "DNS Socket IPv6");
1475 }
1476
1477 if (addrA.IsAnyAddr() || addrA.IsIPv4()) {
1478 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrA);
1479 DnsSocketA = comm_open_listener(SOCK_DGRAM,
1480 IPPROTO_UDP,
1481 addrA,
1482 COMM_NONBLOCKING,
1483 "DNS Socket IPv4");
1484 }
1485
1486 if (DnsSocketA < 0 && DnsSocketB < 0)
1487 fatal("Could not create a DNS socket");
1488
1489 /* Ouch... we can't call functions using debug from a debug
1490 * statement. Doing so messes up the internal Debug::level
1491 */
1492 if (DnsSocketB >= 0) {
1493 port = comm_local_port(DnsSocketB);
1494 debugs(78, 1, "DNS Socket created at " << addrB << ", FD " << DnsSocketB);
1495 commSetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, NULL, 0);
1496 }
1497 if (DnsSocketA >= 0) {
1498 port = comm_local_port(DnsSocketA);
1499 debugs(78, 1, "DNS Socket created at " << addrA << ", FD " << DnsSocketA);
1500 commSetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, NULL, 0);
1501 }
1502 }
1503
1504 assert(0 == nns);
1505 idnsParseNameservers();
1506 #ifndef _SQUID_MSWIN_
1507
1508 if (0 == nns)
1509 idnsParseResolvConf();
1510
1511 #endif
1512 #ifdef _SQUID_WIN32_
1513
1514 if (0 == nns)
1515 idnsParseWIN32Registry();
1516
1517 #endif
1518
1519 if (0 == nns) {
1520 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
1521 #ifdef _SQUID_WIN32_
1522
1523 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
1524 #else
1525
1526 debugs(78, 1, "Please check your /etc/resolv.conf file");
1527 #endif
1528
1529 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1530 idnsAddNameserver("127.0.0.1");
1531 }
1532
1533 if (!init) {
1534 memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
1535 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
1536 idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
1537 init++;
1538 }
1539
1540 #if WHEN_EDNS_RESPONSES_ARE_PARSED
1541 if (Config.onoff.ignore_unknown_nameservers && max_shared_edns > 0) {
1542 debugs(0, DBG_IMPORTANT, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1543 max_shared_edns = -1; // disable if we might receive random replies.
1544 }
1545 #endif
1546
1547 idnsRegisterWithCacheManager();
1548 }
1549
1550 void
1551 idnsShutdown(void)
1552 {
1553 if (DnsSocketA < 0 && DnsSocketB < 0)
1554 return;
1555
1556 if (DnsSocketA >= 0 ) {
1557 comm_close(DnsSocketA);
1558 DnsSocketA = -1;
1559 }
1560
1561 if (DnsSocketB >= 0 ) {
1562 comm_close(DnsSocketB);
1563 DnsSocketB = -1;
1564 }
1565
1566 for (int i = 0; i < nns; i++) {
1567 if (nsvc *vc = nameservers[i].vc) {
1568 if (vc->fd >= 0)
1569 comm_close(vc->fd);
1570 }
1571 }
1572
1573 // XXX: vcs are not closed/freed yet and may try to access nameservers[]
1574 idnsFreeNameservers();
1575 idnsFreeSearchpath();
1576 }
1577
1578 static int
1579 idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1580 {
1581 idns_query *q;
1582
1583 idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
1584
1585 if (!old)
1586 return 0;
1587
1588 q = cbdataAlloc(idns_query);
1589 // idns_query is POD so no constructors are called after allocation
1590 q->xact_id.change();
1591
1592 q->callback = callback;
1593
1594 q->callback_data = cbdataReference(data);
1595
1596 q->queue = old->queue;
1597
1598 old->queue = q;
1599
1600 return 1;
1601 }
1602
1603 static void
1604 idnsCacheQuery(idns_query *q)
1605 {
1606 q->hash.key = q->query.name;
1607 hash_join(idns_lookup_hash, &q->hash);
1608 }
1609
1610 void
1611 idnsALookup(const char *name, IDNSCB * callback, void *data)
1612 {
1613 unsigned int i;
1614 int nd = 0;
1615 idns_query *q;
1616
1617 if (idnsCachedLookup(name, callback, data))
1618 return;
1619
1620 q = cbdataAlloc(idns_query);
1621 // idns_query is POD so no constructors are called after allocation
1622 q->xact_id.change();
1623
1624 for (i = 0; i < strlen(name); i++)
1625 if (name[i] == '.')
1626 nd++;
1627
1628 if (Config.onoff.res_defnames && npc > 0 && name[strlen(name)-1] != '.') {
1629 q->do_searchpath = 1;
1630 } else {
1631 q->do_searchpath = 0;
1632 }
1633
1634 strcpy(q->orig, name);
1635 strcpy(q->name, q->orig);
1636
1637 if (q->do_searchpath && nd < ndots) {
1638 q->domain = 0;
1639 strcat(q->name, ".");
1640 strcat(q->name, searchpath[q->domain].domain);
1641 debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
1642 }
1643
1644 if (Ip::EnableIpv6) {
1645 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, Config.dns.packet_max);
1646 q->need_A = true;
1647 } else {
1648 // see EDNS notes at top of file why this sends 0
1649 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, 0);
1650 q->need_A = false;
1651 }
1652
1653 if (q->sz < 0) {
1654 /* problem with query data -- query not sent */
1655 callback(data, NULL, 0, "Internal error");
1656 cbdataFree(q);
1657 return;
1658 }
1659
1660 debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
1661 ", id = 0x" << std::hex << q->msg_id);
1662
1663 q->callback = callback;
1664
1665 q->callback_data = cbdataReference(data);
1666
1667 idnsCacheQuery(q);
1668
1669 idnsSendQuery(q);
1670 }
1671
1672 void
1673 idnsPTRLookup(const Ip::Address &addr, IDNSCB * callback, void *data)
1674 {
1675 idns_query *q;
1676
1677 char ip[MAX_IPSTRLEN];
1678
1679 addr.NtoA(ip,MAX_IPSTRLEN);
1680
1681 q = cbdataAlloc(idns_query);
1682
1683 // idns_query is POD so no constructors are called after allocation
1684 q->xact_id.change();
1685
1686 if (Ip::EnableIpv6 && addr.IsIPv6()) {
1687 struct in6_addr addr6;
1688 addr.GetInAddr(addr6);
1689 q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), 0, &q->query, Config.dns.packet_max);
1690 } else {
1691 struct in_addr addr4;
1692 addr.GetInAddr(addr4);
1693 // see EDNS notes at top of file why this sends 0
1694 q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), 0, &q->query, 0);
1695 }
1696
1697 /* PTR does not do inbound A/AAAA */
1698 q->need_A = false;
1699
1700 if (q->sz < 0) {
1701 /* problem with query data -- query not sent */
1702 callback(data, NULL, 0, "Internal error");
1703 cbdataFree(q);
1704 return;
1705 }
1706
1707 if (idnsCachedLookup(q->query.name, callback, data)) {
1708 cbdataFree(q);
1709 return;
1710 }
1711
1712 debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
1713 ", id = 0x" << std::hex << q->msg_id);
1714
1715 q->callback = callback;
1716
1717 q->callback_data = cbdataReference(data);
1718
1719 idnsCacheQuery(q);
1720
1721 idnsSendQuery(q);
1722 }
1723
1724 #if SQUID_SNMP
1725 /*
1726 * The function to return the DNS via SNMP
1727 */
1728 variable_list *
1729 snmp_netIdnsFn(variable_list * Var, snint * ErrP)
1730 {
1731 int i, n = 0;
1732 variable_list *Answer = NULL;
1733 MemBuf tmp;
1734 debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var->name, Var->name_length, tmp));
1735 *ErrP = SNMP_ERR_NOERROR;
1736
1737 switch (Var->name[LEN_SQ_NET + 1]) {
1738
1739 case DNS_REQ:
1740
1741 for (i = 0; i < nns; i++)
1742 n += nameservers[i].nqueries;
1743
1744 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1745 n,
1746 SMI_COUNTER32);
1747
1748 break;
1749
1750 case DNS_REP:
1751 for (i = 0; i < nns; i++)
1752 n += nameservers[i].nreplies;
1753
1754 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1755 n,
1756 SMI_COUNTER32);
1757
1758 break;
1759
1760 case DNS_SERVERS:
1761 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1762 nns,
1763 SMI_COUNTER32);
1764
1765 break;
1766
1767 default:
1768 *ErrP = SNMP_ERR_NOSUCHNAME;
1769
1770 break;
1771 }
1772
1773 return Answer;
1774 }
1775
1776 #endif /*SQUID_SNMP */
1777 #endif /* USE_DNSSERVERS */