]> git.ipfire.org Git - thirdparty/squid.git/blame - src/dns_internal.cc
Fix out-of-tree builds after the inclusion of libltdl
[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;
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
213b6c90
AJ
777 do {
778 ns = q->nsends % nns;
779
780 if (q->need_vc) {
781 idnsSendQueryVC(q, ns);
782 x = 0;
783 } else {
784 x = comm_udp_sendto(DnsSocket, nameservers[ns].S, q->buf, q->sz);
785 }
62e76326 786
213b6c90 787 q->nsends++;
62e76326 788
213b6c90 789 q->sent_t = current_time;
62e76326 790
213b6c90
AJ
791 if (x < 0)
792 debugs(50, 1, "idnsSendQuery: FD " << DnsSocket << ": sendto: " << xstrerror());
62e76326 793
213b6c90 794 } while( x<0 && q->nsends % nns != 0);
62e76326 795
213b6c90 796 if(x >= 0) {
62e76326 797 fd_bytes(DnsSocket, x, FD_WRITE);
798 commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0);
0a69973e 799 }
62e76326 800
7cfc1c9a 801 nameservers[ns].nqueries++;
7b724b86 802 dlinkAdd(q, &q->lru, &lru_list);
efd900cb 803 idnsTickleQueue();
7b724b86 804}
805
806static int
cc192b50 807idnsFromKnownNameserver(IPAddress const &from)
7b724b86 808{
809 int i;
62e76326 810
811 for (i = 0; i < nns; i++)
812 {
cc192b50 813 if (nameservers[i].S != from)
62e76326 814 continue;
815
cc192b50 816 if (nameservers[i].S.GetPort() != from.GetPort())
62e76326 817 continue;
818
819 return i;
7b724b86 820 }
62e76326 821
7cfc1c9a 822 return -1;
7b724b86 823}
824
825static idns_query *
826idnsFindQuery(unsigned short id)
827{
828 dlink_node *n;
829 idns_query *q;
62e76326 830
7b724b86 831 for (n = lru_list.tail; n; n = n->prev) {
62e76326 832 q = (idns_query*)n->data;
833
834 if (q->id == id)
835 return q;
7b724b86 836 }
62e76326 837
7b724b86 838 return NULL;
839}
840
108d67a0 841static unsigned short
842idnsQueryID(void)
843{
844 unsigned short id = squid_random() & 0xFFFF;
845 unsigned short first_id = id;
846
847 while(idnsFindQuery(id)) {
848 id++;
849
846c8960 850 if (id == first_id) {
bf8fe701 851 debugs(78, 1, "idnsQueryID: Warning, too many pending DNS requests");
108d67a0 852 break;
846c8960 853 }
108d67a0 854 }
855
846c8960 856 return id;
108d67a0 857}
858
3074b9d1 859static void
860idnsCallback(idns_query *q, rfc1035_rr *answers, int n, const char *error)
861{
862 IDNSCB *callback;
863 void *cbdata;
864
865 callback = q->callback;
866 q->callback = NULL;
867
868 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
869 callback(cbdata, answers, n, error);
870
871 while(q->queue) {
872 idns_query *q2 = q->queue;
873 q->queue = q2->queue;
874 callback = q2->callback;
875 q2->callback = NULL;
876
877 if (cbdataReferenceValidDone(q2->callback_data, &cbdata))
878 callback(cbdata, answers, n, error);
879
63a0e6b7 880 cbdataFree(q2);
3074b9d1 881 }
882
883 if (q->hash.key) {
884 hash_remove_link(idns_lookup_hash, &q->hash);
885 q->hash.key = NULL;
886 }
887}
888
cc192b50 889void
890idnsDropMessage(rfc1035_message *message, idns_query *q)
891{
892 rfc1035MessageDestroy(&message);
893 if (q->hash.key) {
894 hash_remove_link(idns_lookup_hash, &q->hash);
895 q->hash.key = NULL;
896 }
897}
898
7b724b86 899static void
900idnsGrokReply(const char *buf, size_t sz)
901{
902 int n;
ec7bade0 903 rfc1035_message *message = NULL;
7b724b86 904 idns_query *q;
3074b9d1 905
cc192b50 906 n = rfc1035MessageUnpack(buf, sz, &message);
62e76326 907
ec7bade0 908 if (message == NULL) {
bf8fe701 909 debugs(78, 1, "idnsGrokReply: Malformed DNS response");
62e76326 910 return;
7b724b86 911 }
62e76326 912
cc192b50 913 debugs(78, 3, "idnsGrokReply: ID 0x" << std::hex << message->id << ", " << std::dec << n << " answers");
ec7bade0 914
915 q = idnsFindQuery(message->id);
916
7b724b86 917 if (q == NULL) {
bf8fe701 918 debugs(78, 3, "idnsGrokReply: Late response");
cc192b50 919 rfc1035MessageDestroy(&message);
62e76326 920 return;
7b724b86 921 }
62e76326 922
9e1f210d 923 if (rfc1035QueryCompare(&q->query, message->query) != 0) {
bf8fe701 924 debugs(78, 3, "idnsGrokReply: Query mismatch (" << q->query.name << " != " << message->query->name << ")");
cc192b50 925 rfc1035MessageDestroy(&message);
9e1f210d 926 return;
927 }
928
d24ef4e9 929 if (message->tc) {
bae9832d 930 debugs(78, 3, HERE << "Resolver requested TC (" << q->query.name << ")");
d24ef4e9 931 dlinkDelete(&q->lru, &lru_list);
cc192b50 932 rfc1035MessageDestroy(&message);
d24ef4e9 933
934 if (!q->need_vc) {
935 q->need_vc = 1;
936 q->nsends--;
937 idnsSendQuery(q);
938 }
939
940 return;
941 }
9e1f210d 942
a16b4aa0 943 dlinkDelete(&q->lru, &lru_list);
558be27a 944 idnsRcodeCount(n, q->attempt);
7ba8d0b8 945 q->error = NULL;
62e76326 946
558be27a 947 if (n < 0) {
bf8fe701 948 debugs(78, 3, "idnsGrokReply: error " << rfc1035_error_message << " (" << rfc1035_errno << ")");
62e76326 949
7ba8d0b8 950 q->error = rfc1035_error_message;
951 q->rcode = -n;
952
953 if (q->rcode == 2 && ++q->attempt < MAX_ATTEMPT) {
62e76326 954 /*
955 * RCODE 2 is "Server failure - The name server was
956 * unable to process this query due to a problem with
957 * the name server."
958 */
cc192b50 959 debugs(78, 3, "idnsGrokReply: Query result: SERV_FAIL");
960 rfc1035MessageDestroy(&message);
62e76326 961 q->start_t = current_time;
108d67a0 962 q->id = idnsQueryID();
963 rfc1035SetQueryID(q->buf, q->id);
62e76326 964 idnsSendQuery(q);
965 return;
966 }
68836b58 967
968 if (q->rcode == 3 && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
969 assert(NULL == message->answer);
970 strcpy(q->name, q->orig);
971
cc192b50 972 debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q->name );
973
68836b58 974 if (q->domain < npc) {
975 strcat(q->name, ".");
976 strcat(q->name, searchpath[q->domain].domain);
bf8fe701 977 debugs(78, 3, "idnsGrokReply: searchpath used for " << q->name);
68836b58 978 q->domain++;
979 } else {
980 q->attempt++;
981 }
982
cc192b50 983 idnsDropMessage(message, q);
984
68836b58 985 q->start_t = current_time;
986 q->id = idnsQueryID();
987 rfc1035SetQueryID(q->buf, q->id);
cc192b50 988#if USE_IPV6
989 if(q->query.qtype == RFC1035_TYPE_AAAA) {
990 debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q->name);
991 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
992 }
993 else
994#endif
995 {
996 debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
997 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
998 }
68836b58 999 idnsCacheQuery(q);
1000 idnsSendQuery(q);
1001 return;
1002 }
558be27a 1003 }
62e76326 1004
cc192b50 1005#if USE_IPV6
1006 if(q->need_A && (Config.onoff.dns_require_A == 1 || n <= 0 ) )
1007 {
1008 /* ERROR or NO AAAA exist. Failover to A records. */
bae9832d 1009 /* Apparently its also a good idea to lookup and store the A records
cc192b50 1010 * just in case the AAAA are not available when we need them.
1011 * This could occur due to number of network failings beyond our control
1012 * thus the || above allowing the user to request always both.
1013 */
1014
1015 if(n == 0)
1016 debugs(78, 3, "idnsGrokReply: " << q->name << " has no AAAA records. Looking up A record instead.");
1017 else if(q->need_A && n <= 0)
1018 debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query failed. Trying A now instead.");
1019 else // admin requested this.
1020 debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query done. Configured to retrieve A now also.");
1021
bae9832d 1022 // move the initial message results into the failover query for merging later.
1023 if(n > 0) {
1024 q->initial_AAAA.count = message->ancount;
1025 q->initial_AAAA.answers = message->answer;
1026 message->answer = NULL;
1027 }
1028
1029 // remove the hashed query info
cc192b50 1030 idnsDropMessage(message, q);
1031
1032 q->start_t = current_time;
1033 q->id = idnsQueryID();
1034 rfc1035SetQueryID(q->buf, q->id);
1035 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
1036 q->need_A = false;
1037 idnsCacheQuery(q);
1038 idnsSendQuery(q);
1039 return;
1040 }
1041#endif
1042
bae9832d 1043 /** If there are two result sets from preceeding AAAA and A lookups merge them with a preference for AAAA */
1044 if(q->initial_AAAA.count > 0 && n > 0) {
1045 /* two sets of RR need merging */
1046 rfc1035_rr *result = (rfc1035_rr*) xmalloc( sizeof(rfc1035_rr)*(n + q->initial_AAAA.count) );
1047 rfc1035_rr *tmp = result;
1048
1049 debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
1050
1051 memcpy(tmp, q->initial_AAAA.answers, (sizeof(rfc1035_rr)*(q->initial_AAAA.count)) );
1052 tmp += q->initial_AAAA.count;
1053 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1054 safe_free(q->initial_AAAA.answers);
1055
1056 memcpy( tmp, message->answer, (sizeof(rfc1035_rr)*n) );
1057 /* free the RR object without freeing its child strings (they are now taken by the copy above) */
1058 safe_free(message->answer);
1059
1060 message->answer = result;
1061 n += q->initial_AAAA.count;
1062 q->initial_AAAA.count=0;
1063 }
1064 else if(q->initial_AAAA.count > 0 && n <= 0) {
1065 /* initial of dual queries was the only result set. */
1066 debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
1067 rfc1035RRDestroy(&(message->answer), n);
1068 message->answer = q->initial_AAAA.answers;
1069 n = q->initial_AAAA.count;
1070 }
1071 /* else initial results were empty. just use the final set as authoritative */
1072
1073 debugs(78, 6, HERE << "Sending " << n << " DNS results to caller.");
ec7bade0 1074 idnsCallback(q, message->answer, n, q->error);
cc192b50 1075 rfc1035MessageDestroy(&message);
63a0e6b7 1076 cbdataFree(q);
7b724b86 1077}
1078
1079static void
1080idnsRead(int fd, void *data)
1081{
d193a436 1082 int *N = &incoming_sockets_accepted;
0b6d1955 1083 int len;
42b51993 1084 int max = INCOMING_DNS_MAX;
d29b40de 1085 static char rbuf[SQUID_UDP_SO_RCVBUF];
7cfc1c9a 1086 int ns;
cc192b50 1087 IPAddress from;
1088
d7e7eaa7 1089 debugs(78, 3, "idnsRead: starting with FD " << fd);
cc192b50 1090
1091 /* BUG (UNRESOLVED)
1092 * two code lines after returning from comm_udprecvfrom()
1093 * something overwrites the memory behind the from parameter.
1094 * NO matter where in the stack declaration list above it is placed
1095 * The cause of this is still unknown, however copying the data appears
1096 * to allow it to be passed further without this erasure.
1097 */
1098 IPAddress bugbypass;
62e76326 1099
7b724b86 1100 while (max--) {
cc192b50 1101 len = comm_udp_recvfrom(fd, rbuf, SQUID_UDP_SO_RCVBUF, 0, bugbypass);
62e76326 1102
cc192b50 1103 from = bugbypass; // BUG BYPASS. see notes above.
62e76326 1104
1105 if (len == 0)
1106 break;
1107
1108 if (len < 0) {
1109 if (ignoreErrno(errno))
1110 break;
1111
7b724b86 1112#ifdef _SQUID_LINUX_
62e76326 1113 /* Some Linux systems seem to set the FD for reading and then
1114 * return ECONNREFUSED when sendto() fails and generates an ICMP
1115 * port unreachable message. */
1116 /* or maybe an EHOSTUNREACH "No route to host" message */
1117 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
7b724b86 1118#endif
62e76326 1119
bf8fe701 1120 debugs(50, 1, "idnsRead: FD " << fd << " recvfrom: " << xstrerror());
62e76326 1121
1122 break;
1123 }
1124
1125 fd_bytes(DnsSocket, len, FD_READ);
1126 assert(N);
1127 (*N)++;
cc192b50 1128
1129 debugs(78, 3, "idnsRead: FD " << fd << ": received " << len << " bytes from " << from);
1130
1131 /* BUG: see above. Its here that it becomes apparent that the content of bugbypass is gone. */
1132 ns = idnsFromKnownNameserver(from);
62e76326 1133
1134 if (ns >= 0) {
1135 nameservers[ns].nreplies++;
1136 } else if (Config.onoff.ignore_unknown_nameservers) {
1137 static time_t last_warning = 0;
1138
1139 if (squid_curtime - last_warning > 60) {
cc192b50 1140 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from);
62e76326 1141 last_warning = squid_curtime;
1142 }
cc192b50 1143 else {
1144 debugs(78, 1, "WARNING: Reply from unknown nameserver " << from << " (retrying..." << (squid_curtime-last_warning) << "<=60)" );
2fadd50d 1145 } continue;
62e76326 1146 }
1147
62e76326 1148 idnsGrokReply(rbuf, len);
7b724b86 1149 }
62e76326 1150
2e6caa54 1151 if (lru_list.head)
62e76326 1152 commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0);
7b724b86 1153}
1154
7cfc1c9a 1155static void
1156idnsCheckQueue(void *unused)
1157{
1158 dlink_node *n;
0c4fe9e4 1159 dlink_node *p = NULL;
7cfc1c9a 1160 idns_query *q;
1161 event_queued = 0;
62e76326 1162
0c4fe9e4 1163 for (n = lru_list.tail; n; n = p) {
62e76326 1164 if (0 == nns)
1165 /* name servers went away; reconfiguring or shutting down */
1166 break;
1167
1168 q = (idns_query *)n->data;
1169
da0c4437 1170 if (tvSubDsec(q->sent_t, current_time) < Config.Timeout.idns_retransmit * (1 << (q->nsends - 1) % nns))
62e76326 1171 break;
1172
bf8fe701 1173 debugs(78, 3, "idnsCheckQueue: ID 0x" << std::hex << std::setfill('0') << std::setw(4) << q->id << "timeout" );
62e76326 1174
1175 p = n->prev;
1176
1177 dlinkDelete(&q->lru, &lru_list);
1178
1179 if (tvSubDsec(q->start_t, current_time) < Config.Timeout.idns_query) {
1180 idnsSendQuery(q);
1181 } else {
4a7a3d56 1182 debugs(78, 2, "idnsCheckQueue: ID " << std::hex << q->id <<
bf8fe701 1183 ": giving up after " << std::dec << q->nsends << " tries and " <<
1184 std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
3074b9d1 1185
1186 if (q->rcode != 0)
1187 idnsCallback(q, NULL, -q->rcode, q->error);
1188 else
1189 idnsCallback(q, NULL, -16, "Timeout");
62e76326 1190
63a0e6b7 1191 cbdataFree(q);
62e76326 1192 }
7cfc1c9a 1193 }
62e76326 1194
efd900cb 1195 idnsTickleQueue();
7cfc1c9a 1196}
1197
d24ef4e9 1198static void
1199idnsReadVC(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1200{
1201 nsvc * vc = (nsvc *)data;
1202
1203 if (flag == COMM_ERR_CLOSING)
1204 return;
1205
1206 if (flag != COMM_OK || len <= 0) {
1207 comm_close(fd);
1208 return;
1209 }
1210
032785bf 1211 vc->msg->size += len; // XXX should not access -> size directly
d24ef4e9 1212
032785bf 1213 if (vc->msg->contentSize() < vc->msglen) {
1214 comm_read(fd, buf + len, vc->msglen - vc->msg->contentSize(), idnsReadVC, vc);
d24ef4e9 1215 return;
1216 }
1217
bf8fe701 1218 debugs(78, 3, "idnsReadVC: FD " << fd << ": received " <<
1219 (int) vc->msg->contentSize() << " bytes via tcp from " <<
cc192b50 1220 nameservers[vc->ns].S << ".");
d24ef4e9 1221
032785bf 1222 idnsGrokReply(vc->msg->buf, vc->msg->contentSize());
2fe7eff9 1223 vc->msg->clean();
d24ef4e9 1224 comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
1225}
1226
1227static void
1228idnsReadVCHeader(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1229{
1230 nsvc * vc = (nsvc *)data;
1231
1232 if (flag == COMM_ERR_CLOSING)
1233 return;
1234
1235 if (flag != COMM_OK || len <= 0) {
1236 comm_close(fd);
1237 return;
1238 }
1239
1240 vc->read_msglen += len;
1241
1242 assert(vc->read_msglen <= 2);
1243
1244 if (vc->read_msglen < 2) {
1245 comm_read(fd, buf + len, 2 - vc->read_msglen, idnsReadVCHeader, vc);
1246 return;
1247 }
1248
1249 vc->read_msglen = 0;
1250
1251 vc->msglen = ntohs(vc->msglen);
1252
2fe7eff9 1253 vc->msg->init(vc->msglen, vc->msglen);
032785bf 1254 comm_read(fd, vc->msg->buf, vc->msglen, idnsReadVC, vc);
d24ef4e9 1255}
1256
558be27a 1257/*
1258 * rcode < 0 indicates an error, rocde >= 0 indicates success
1259 */
1260static void
1261idnsRcodeCount(int rcode, int attempt)
1262{
1263 if (rcode > 0)
62e76326 1264 rcode = 0;
558be27a 1265 else if (rcode < 0)
62e76326 1266 rcode = -rcode;
1267
558be27a 1268 if (rcode < MAX_RCODE)
62e76326 1269 if (attempt < MAX_ATTEMPT)
1270 RcodeMatrix[rcode][attempt]++;
558be27a 1271}
1272
7b724b86 1273/* ====================================================================== */
1274
1275void
1276idnsInit(void)
1277{
1278 static int init = 0;
62e76326 1279
d24ef4e9 1280 CBDATA_INIT_TYPE(nsvc);
63a0e6b7 1281 CBDATA_INIT_TYPE(idns_query);
d24ef4e9 1282
ef523f99 1283 if (DnsSocket < 0) {
62e76326 1284 int port;
1285
cc192b50 1286 IPAddress addr;
62e76326 1287
cc192b50 1288 if (!Config.Addrs.udp_outgoing.IsNoAddr())
62e76326 1289 addr = Config.Addrs.udp_outgoing;
1290 else
1291 addr = Config.Addrs.udp_incoming;
1292
1293 DnsSocket = comm_open(SOCK_DGRAM,
bdb741f4 1294 IPPROTO_UDP,
62e76326 1295 addr,
62e76326 1296 COMM_NONBLOCKING,
1297 "DNS Socket");
1298
cc192b50 1299 debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addr);
1300
62e76326 1301 if (DnsSocket < 0)
1302 fatal("Could not create a DNS socket");
1303
1304 /* Ouch... we can't call functions using debug from a debug
1305 * statement. Doing so messes up the internal Debug::level
1306 */
1307 port = comm_local_port(DnsSocket);
1308
cc192b50 1309 debugs(78, 1, "DNS Socket created at " << addr << ", FD " << DnsSocket);
7b724b86 1310 }
62e76326 1311
efd900cb 1312 assert(0 == nns);
1313 idnsParseNameservers();
0e6d05ef 1314#ifndef _SQUID_MSWIN_
62e76326 1315
efd900cb 1316 if (0 == nns)
62e76326 1317 idnsParseResolvConf();
1318
0e6d05ef 1319#endif
ec4daaa5 1320#ifdef _SQUID_WIN32_
62e76326 1321
0e6d05ef 1322 if (0 == nns)
62e76326 1323 idnsParseWIN32Registry();
1324
0e6d05ef 1325#endif
62e76326 1326
29fe9bd5 1327 if (0 == nns) {
1328 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
ec4daaa5 1329#ifdef _SQUID_WIN32_
29fe9bd5 1330
1331 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
0e6d05ef 1332#else
29fe9bd5 1333
1334 debugs(78, 1, "Please check your /etc/resolv.conf file");
0e6d05ef 1335#endif
29fe9bd5 1336
1337 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1338 idnsAddNameserver("127.0.0.1");
1339 }
62e76326 1340
7b724b86 1341 if (!init) {
62e76326 1342 memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
62e76326 1343 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
30abd221 1344 idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
62e76326 1345 init++;
7b724b86 1346 }
7b724b86 1347}
1348
62ee09ca 1349void
1350idnsRegisterWithCacheManager(CacheManager & manager)
1351{
1352 manager.registerAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
1353}
1354
7b724b86 1355void
1356idnsShutdown(void)
1357{
ef523f99 1358 if (DnsSocket < 0)
62e76326 1359 return;
1360
ef523f99 1361 comm_close(DnsSocket);
62e76326 1362
ef523f99 1363 DnsSocket = -1;
62e76326 1364
b26754c4 1365 for (int i = 0; i < nns; i++) {
1366 if (nsvc *vc = nameservers[i].vc) {
1367 if (vc->fd >= 0)
1368 comm_close(vc->fd);
1369 }
1370 }
1371
efd900cb 1372 idnsFreeNameservers();
68836b58 1373
1374 idnsFreeSearchpath();
7b724b86 1375}
1376
3074b9d1 1377static int
1378idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1379{
1380 idns_query *q;
1381
1382 idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
1383
1384 if (!old)
1385 return 0;
1386
63a0e6b7 1387 q = cbdataAlloc(idns_query);
3074b9d1 1388
1389 q->callback = callback;
1390
1391 q->callback_data = cbdataReference(data);
1392
1393 q->queue = old->queue;
1394
1395 old->queue = q;
1396
1397 return 1;
1398}
1399
1400static void
9e1f210d 1401idnsCacheQuery(idns_query *q)
3074b9d1 1402{
9e1f210d 1403 q->hash.key = q->query.name;
3074b9d1 1404 hash_join(idns_lookup_hash, &q->hash);
1405}
1406
7b724b86 1407void
1408idnsALookup(const char *name, IDNSCB * callback, void *data)
1409{
68836b58 1410 unsigned int i;
1411 int nd = 0;
3074b9d1 1412 idns_query *q;
1413
1414 if (idnsCachedLookup(name, callback, data))
1415 return;
1416
63a0e6b7 1417 q = cbdataAlloc(idns_query);
3074b9d1 1418
71952967 1419 q->id = idnsQueryID();
1420
68836b58 1421 for (i = 0; i < strlen(name); i++)
1422 if (name[i] == '.')
1423 nd++;
1424
1425 if (Config.onoff.res_defnames && npc > 0 && name[strlen(name)-1] != '.') {
1426 q->do_searchpath = 1;
1427 } else {
1428 q->do_searchpath = 0;
1429 }
1430
1431 strcpy(q->orig, name);
1432 strcpy(q->name, q->orig);
1433
1434 if (q->do_searchpath && nd < ndots) {
1435 q->domain = 0;
1436 strcat(q->name, ".");
1437 strcat(q->name, searchpath[q->domain].domain);
bf8fe701 1438 debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
68836b58 1439 }
1440
cc192b50 1441#if USE_IPV6
1442 q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
1443 q->need_A = true;
1444#else
1445 q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
1446 q->need_A = false;
1447#endif
62e76326 1448
2041330b 1449 if (q->sz < 0) {
1450 /* problem with query data -- query not sent */
1451 callback(data, NULL, 0, "Internal error");
63a0e6b7 1452 cbdataFree(q);
2041330b 1453 return;
1454 }
1455
4a7a3d56 1456 debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
bf8fe701 1457 ", id = 0x" << std::hex << q->id);
aa6c61e3 1458
7b724b86 1459 q->callback = callback;
aa6c61e3 1460
fa80a8ef 1461 q->callback_data = cbdataReference(data);
aa6c61e3 1462
7cfc1c9a 1463 q->start_t = current_time;
aa6c61e3 1464
9e1f210d 1465 idnsCacheQuery(q);
aa6c61e3 1466
7b724b86 1467 idnsSendQuery(q);
1468}
8db71107 1469
1470void
cc192b50 1471idnsPTRLookup(const IPAddress &addr, IDNSCB * callback, void *data)
8db71107 1472{
3074b9d1 1473 idns_query *q;
1474
cc192b50 1475 char ip[MAX_IPSTRLEN];
1476
1477 addr.NtoA(ip,MAX_IPSTRLEN);
3074b9d1 1478
63a0e6b7 1479 q = cbdataAlloc(idns_query);
3074b9d1 1480
71952967 1481 q->id = idnsQueryID();
1482
cc192b50 1483#if USE_IPV6
1484 if( addr.IsIPv6() ) {
1485 struct in6_addr addr6;
1486 addr.GetInAddr(addr6);
1487 q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), q->id, &q->query);
1488 }
1489 else
1490#endif
1491 {
1492 struct in_addr addr4;
1493 addr.GetInAddr(addr4);
1494 q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), q->id, &q->query);
1495 }
1496
1497 /* PTR does not do inbound A/AAAA */
1498 q->need_A = false;
3074b9d1 1499
2041330b 1500 if (q->sz < 0)
1501 {
1502 /* problem with query data -- query not sent */
1503 callback(data, NULL, 0, "Internal error");
63a0e6b7 1504 cbdataFree(q);
2041330b 1505 return;
1506 }
1507
37f3da43 1508 if (idnsCachedLookup(q->query.name, callback, data)) {
1509 cbdataFree(q);
1510 return;
1511 }
1512
4a7a3d56 1513 debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
bf8fe701 1514 ", id = 0x" << std::hex << q->id);
3074b9d1 1515
8db71107 1516 q->callback = callback;
3074b9d1 1517
fa80a8ef 1518 q->callback_data = cbdataReference(data);
3074b9d1 1519
8db71107 1520 q->start_t = current_time;
3074b9d1 1521
9e1f210d 1522 idnsCacheQuery(q);
3074b9d1 1523
8db71107 1524 idnsSendQuery(q);
1525}
eb824054 1526
3c573763 1527#ifdef SQUID_SNMP
1528/*
1529 * The function to return the DNS via SNMP
1530 */
1531variable_list *
1532snmp_netIdnsFn(variable_list * Var, snint * ErrP)
1533{
1534 int i, n = 0;
1535 variable_list *Answer = NULL;
bf8fe701 1536 debugs(49, 5, "snmp_netDnsFn: Processing request: ");
3c573763 1537 snmpDebugOid(5, Var->name, Var->name_length);
1538 *ErrP = SNMP_ERR_NOERROR;
62e76326 1539
3c573763 1540 switch (Var->name[LEN_SQ_NET + 1]) {
62e76326 1541
3c573763 1542 case DNS_REQ:
62e76326 1543
1544 for (i = 0; i < nns; i++)
1545 n += nameservers[i].nqueries;
1546
1547 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1548 n,
1549 SMI_COUNTER32);
1550
1551 break;
1552
3c573763 1553 case DNS_REP:
62e76326 1554 for (i = 0; i < nns; i++)
1555 n += nameservers[i].nreplies;
1556
1557 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1558 n,
1559 SMI_COUNTER32);
1560
1561 break;
1562
3c573763 1563 case DNS_SERVERS:
62e76326 1564 Answer = snmp_var_new_integer(Var->name, Var->name_length,
e494f5e9 1565 nns,
62e76326 1566 SMI_COUNTER32);
1567
1568 break;
1569
3c573763 1570 default:
62e76326 1571 *ErrP = SNMP_ERR_NOSUCHNAME;
1572
1573 break;
3c573763 1574 }
62e76326 1575
3c573763 1576 return Answer;
1577}
62e76326 1578
3c573763 1579#endif /*SQUID_SNMP */
1f1ae50a 1580#endif /* USE_DNSSERVERS */