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