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