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