]> git.ipfire.org Git - thirdparty/squid.git/blame - src/dns_internal.cc
Fix Squid crash when using %a in ERR_INVALID_REQ and ERR_INVALID_URL error messages.
[thirdparty/squid.git] / src / dns_internal.cc
CommitLineData
7b724b86 1
2/*
a553a5a3 3 * $Id: dns_internal.cc,v 1.91 2006/08/07 02:28:22 robertc 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;
58a39dc9 119};
120
d24ef4e9 121struct _nsvc
122{
123 int ns;
124 int fd;
125 unsigned short msglen;
126 int read_msglen;
032785bf 127 MemBuf *msg;
128 MemBuf *queue;
d24ef4e9 129 bool busy;
130};
131
62e76326 132struct _ns
133{
134
7b724b86 135 struct sockaddr_in S;
136 int nqueries;
137 int nreplies;
d29b40de 138 int large_pkts;
d24ef4e9 139 nsvc *vc;
7b724b86 140};
58a39dc9 141
68836b58 142struct _sp
143{
144 char domain[NS_MAXDNAME];
145 int queries;
146};
147
d24ef4e9 148CBDATA_TYPE(nsvc);
149
7b724b86 150static ns *nameservers = NULL;
68836b58 151static sp *searchpath = NULL;
7b724b86 152static int nns = 0;
153static int nns_alloc = 0;
68836b58 154static int npc = 0;
155static int npc_alloc = 0;
156static int ndots = 1;
7b724b86 157static dlink_list lru_list;
7cfc1c9a 158static int event_queued = 0;
3074b9d1 159static hash_table *idns_lookup_hash = NULL;
7b724b86 160
161static OBJH idnsStats;
162static void idnsAddNameserver(const char *buf);
68836b58 163static void idnsAddPathComponent(const char *buf);
7b724b86 164static void idnsFreeNameservers(void);
68836b58 165static void idnsFreeSearchpath(void);
efd900cb 166static void idnsParseNameservers(void);
1f1ae50a 167#ifndef _SQUID_MSWIN_
7b724b86 168static void idnsParseResolvConf(void);
1f1ae50a 169#endif
ec4daaa5 170#ifdef _SQUID_WIN32_
0e6d05ef 171static void idnsParseWIN32Registry(void);
d02b72b4 172static void idnsParseWIN32SearchList(const char *);
0e6d05ef 173#endif
68836b58 174static void idnsCacheQuery(idns_query * q);
7b724b86 175static void idnsSendQuery(idns_query * q);
d24ef4e9 176static IOCB idnsReadVCHeader;
62e76326 177
7b724b86 178static int idnsFromKnownNameserver(struct sockaddr_in *from);
179static idns_query *idnsFindQuery(unsigned short id);
180static void idnsGrokReply(const char *buf, size_t sz);
181static PF idnsRead;
7cfc1c9a 182static EVH idnsCheckQueue;
efd900cb 183static void idnsTickleQueue(void);
558be27a 184static void idnsRcodeCount(int, int);
7b724b86 185
186static void
187idnsAddNameserver(const char *buf)
188{
62e76326 189
ddfcbc22 190 struct IN_ADDR A;
62e76326 191
d20b1cd0 192 if (!safe_inet_addr(buf, &A)) {
62e76326 193 debug(78, 0) ("WARNING: rejecting '%s' as a name server, because it is not a numeric IP address\n", buf);
194 return;
d20b1cd0 195 }
62e76326 196
5c5a349d 197 if (A.s_addr == 0) {
62e76326 198 debug(78, 0) ("WARNING: Squid does not accept 0.0.0.0 in DNS server specifications.\n");
199 debug(78, 0) ("Will be using 127.0.0.1 instead, assuming you meant that DNS is running on the same machine\n");
200 safe_inet_addr("127.0.0.1", &A);
5c5a349d 201 }
62e76326 202
7b724b86 203 if (nns == nns_alloc) {
62e76326 204 int oldalloc = nns_alloc;
205 ns *oldptr = nameservers;
206
207 if (nns_alloc == 0)
208 nns_alloc = 2;
209 else
210 nns_alloc <<= 1;
211
212 nameservers = (ns *)xcalloc(nns_alloc, sizeof(*nameservers));
213
214 if (oldptr && oldalloc)
215 xmemcpy(nameservers, oldptr, oldalloc * sizeof(*nameservers));
216
217 if (oldptr)
218 safe_free(oldptr);
7b724b86 219 }
62e76326 220
7b724b86 221 assert(nns < nns_alloc);
222 nameservers[nns].S.sin_family = AF_INET;
68836b58 223 nameservers[nns].S.sin_port = htons(NS_DEFAULTPORT);
d20b1cd0 224 nameservers[nns].S.sin_addr.s_addr = A.s_addr;
efd900cb 225 debug(78, 3) ("idnsAddNameserver: Added nameserver #%d: %s\n",
62e76326 226 nns, inet_ntoa(nameservers[nns].S.sin_addr));
7b724b86 227 nns++;
228}
229
68836b58 230static void
231idnsAddPathComponent(const char *buf)
232{
233 if (npc == npc_alloc) {
234 int oldalloc = npc_alloc;
235 sp *oldptr = searchpath;
236
237 if (0 == npc_alloc)
238 npc_alloc = 2;
239 else
240 npc_alloc <<= 1;
241
242 searchpath = (sp *)xcalloc(npc_alloc, sizeof(*searchpath));
243
244 if (oldptr && oldalloc)
245 xmemcpy(searchpath, oldptr, oldalloc * sizeof(*searchpath));
246
247 if (oldptr)
248 safe_free(oldptr);
249 }
250
251 assert(npc < npc_alloc);
252 strcpy(searchpath[npc].domain, buf);
253 debug(78, 3) ("idnsAddPathComponent: Added domain #%d: %s\n",
254 npc, searchpath[npc].domain);
255 npc++;
256}
257
2ea84e89 258
7b724b86 259static void
260idnsFreeNameservers(void)
261{
262 safe_free(nameservers);
263 nns = nns_alloc = 0;
264}
265
68836b58 266static void
267idnsFreeSearchpath(void)
268{
269 safe_free(searchpath);
270 npc = npc_alloc = 0;
271}
272
273
274
efd900cb 275static void
276idnsParseNameservers(void)
277{
278 wordlist *w;
62e76326 279
efd900cb 280 for (w = Config.dns_nameservers; w; w = w->next) {
62e76326 281 debug(78, 1) ("Adding nameserver %s from squid.conf\n", w->key);
282 idnsAddNameserver(w->key);
efd900cb 283 }
284}
285
1f1ae50a 286#ifndef _SQUID_MSWIN_
7b724b86 287static void
288idnsParseResolvConf(void)
289{
290 FILE *fp;
68836b58 291 char buf[RESOLV_BUFSZ];
7b724b86 292 char *t;
68836b58 293 fp = fopen(_PATH_RESCONF, "r");
62e76326 294
7b724b86 295 if (fp == NULL) {
68836b58 296 debug(78, 1) ("%s: %s\n", _PATH_RESCONF, xstrerror());
62e76326 297 return;
7b724b86 298 }
62e76326 299
1f1ae50a 300#if defined(_SQUID_CYGWIN_)
c4aefe96 301 setmode(fileno(fp), O_TEXT);
62e76326 302
c4aefe96 303#endif
62e76326 304
68836b58 305 while (fgets(buf, RESOLV_BUFSZ, fp)) {
62e76326 306 t = strtok(buf, w_space);
307
68836b58 308 if (NULL == t) {
62e76326 309 continue;
68836b58 310 } else if (strcasecmp(t, "nameserver") == 0) {
311 t = strtok(NULL, w_space);
62e76326 312
68836b58 313 if (NULL == t)
314 continue;
62e76326 315
68836b58 316 debug(78, 1) ("Adding nameserver %s from %s\n", t, _PATH_RESCONF);
62e76326 317
68836b58 318 idnsAddNameserver(t);
319 } else if (strcasecmp(t, "search") == 0) {
320 while (NULL != t) {
321 t = strtok(NULL, w_space);
322
323 if (NULL == t)
324 continue;
325
326 debug(78, 1) ("Adding domain %s from %s\n", t, _PATH_RESCONF);
327
328 idnsAddPathComponent(t);
329 }
330 } else if (strcasecmp(t, "options") == 0) {
331 while (NULL != t) {
332 t = strtok(NULL, w_space);
62e76326 333
68836b58 334 if (NULL == t)
335 continue;
62e76326 336
68836b58 337 if (strncmp(t, "ndots:", 6) != 0) {
338 ndots = atoi(t + 6);
339
340 if (ndots < 1)
341 ndots = 1;
342
343 debug(78, 1) ("Adding ndots %d from %s\n", ndots, _PATH_RESCONF);
344 }
345 }
346 }
7b724b86 347 }
62e76326 348
7b724b86 349 fclose(fp);
350}
351
1f1ae50a 352#endif
353
ec4daaa5 354#ifdef _SQUID_WIN32_
6b610e34 355static void
d02b72b4 356idnsParseWIN32SearchList(const char * Separator)
6b610e34 357{
358 BYTE *t;
359 char *token;
360 HKEY hndKey;
361
362 if (RegOpenKey(HKEY_LOCAL_MACHINE,
363 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
364 &hndKey) == ERROR_SUCCESS) {
365 DWORD Type = 0;
366 DWORD Size = 0;
367 LONG Result;
368 Result =
369 RegQueryValueEx(hndKey, "SearchList", NULL, &Type, NULL,
370 &Size);
371
372 if (Result == ERROR_SUCCESS && Size) {
373 t = (unsigned char *) xmalloc(Size);
374 RegQueryValueEx(hndKey, "SearchList", NULL, &Type, t,
375 &Size);
376 token = strtok((char *) t, Separator);
377
378 while (token) {
379 idnsAddPathComponent(token);
380 debugs(78, 1, "Adding domain " << token << " from Registry");
381 token = strtok(NULL, Separator);
382 }
383 }
384
385 RegCloseKey(hndKey);
386 }
387}
388
0e6d05ef 389static void
390idnsParseWIN32Registry(void)
391{
e6ccf245 392 BYTE *t;
0e6d05ef 393 char *token;
394 HKEY hndKey, hndKey2;
395
396 idnsFreeNameservers();
62e76326 397
0e6d05ef 398 switch (WIN32_OS_version) {
62e76326 399
0e6d05ef 400 case _WIN_OS_WINNT:
62e76326 401 /* get nameservers from the Windows NT registry */
402
403 if (RegOpenKey(HKEY_LOCAL_MACHINE,
404 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
405 &hndKey) == ERROR_SUCCESS) {
406 DWORD Type = 0;
407 DWORD Size = 0;
408 LONG Result;
409 Result =
410 RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, NULL,
411 &Size);
412
413 if (Result == ERROR_SUCCESS && Size) {
414 t = (unsigned char *) xmalloc(Size);
415 RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, t,
416 &Size);
417 token = strtok((char *) t, ", ");
418
419 while (token) {
420 idnsAddNameserver(token);
6b610e34 421 debugs(78, 1, "Adding DHCP nameserver " << token << " from Registry");
422 token = strtok(NULL, ",");
62e76326 423 }
424 }
425
426 Result =
427 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
428
429 if (Result == ERROR_SUCCESS && Size) {
430 t = (unsigned char *) xmalloc(Size);
431 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, t, &Size);
432 token = strtok((char *) t, ", ");
433
434 while (token) {
6b610e34 435 debugs(78, 1, "Adding nameserver " << token << " from Registry");
62e76326 436 idnsAddNameserver(token);
437 token = strtok(NULL, ", ");
438 }
439 }
440
441 RegCloseKey(hndKey);
442 }
443
6b610e34 444 idnsParseWIN32SearchList(" ");
445
62e76326 446 break;
447
0e6d05ef 448 case _WIN_OS_WIN2K:
62e76326 449
b671cc68 450 case _WIN_OS_WINXP:
62e76326 451
6b1846cf 452 case _WIN_OS_WINNET:
28170269 453
454 case _WIN_OS_WINLON:
62e76326 455 /* get nameservers from the Windows 2000 registry */
456 /* search all interfaces for DNS server addresses */
457
458 if (RegOpenKey(HKEY_LOCAL_MACHINE,
459 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces",
460 &hndKey) == ERROR_SUCCESS) {
461 int i;
462 char keyname[255];
463
464 for (i = 0; i < 10; i++) {
465 if (RegEnumKey(hndKey, i, (char *) &keyname,
466 255) == ERROR_SUCCESS) {
467 char newkeyname[255];
468 strcpy(newkeyname,
469 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
470 strcat(newkeyname, keyname);
471
472 if (RegOpenKey(HKEY_LOCAL_MACHINE, newkeyname,
473 &hndKey2) == ERROR_SUCCESS) {
474 DWORD Type = 0;
475 DWORD Size = 0;
476 LONG Result;
477 Result =
478 RegQueryValueEx(hndKey2, "DhcpNameServer", NULL,
479 &Type, NULL, &Size);
480
481 if (Result == ERROR_SUCCESS && Size) {
482 t = (unsigned char *) xmalloc(Size);
483 RegQueryValueEx(hndKey2, "DhcpNameServer", NULL,
484 &Type, t, &Size);
485 token = strtok((char *) t, ", ");
486
487 while (token) {
6b610e34 488 debugs(78, 1, "Adding DHCP nameserver " << token << " from Registry");
62e76326 489 idnsAddNameserver(token);
490 token = strtok(NULL, ", ");
491 }
492 }
493
494 Result =
495 RegQueryValueEx(hndKey2, "NameServer", NULL, &Type,
496 NULL, &Size);
497
498 if (Result == ERROR_SUCCESS && Size) {
499 t = (unsigned char *) xmalloc(Size);
500 RegQueryValueEx(hndKey2, "NameServer", NULL, &Type,
501 t, &Size);
502 token = strtok((char *) t, ", ");
503
504 while (token) {
6b610e34 505 debugs(78, 1, "Adding nameserver " << token << " from Registry");
62e76326 506 idnsAddNameserver(token);
507 token = strtok(NULL, ", ");
508 }
509 }
510
511 RegCloseKey(hndKey2);
512 }
513 }
514 }
515
516 RegCloseKey(hndKey);
517 }
518
6b610e34 519 idnsParseWIN32SearchList(", ");
520
62e76326 521 break;
522
0e6d05ef 523 case _WIN_OS_WIN95:
62e76326 524
0e6d05ef 525 case _WIN_OS_WIN98:
62e76326 526
be20dac7 527 case _WIN_OS_WINME:
62e76326 528 /* get nameservers from the Windows 9X registry */
529
530 if (RegOpenKey(HKEY_LOCAL_MACHINE,
531 "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
532 &hndKey) == ERROR_SUCCESS) {
533 DWORD Type = 0;
534 DWORD Size = 0;
535 LONG Result;
536 Result =
537 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
538
539 if (Result == ERROR_SUCCESS && Size) {
540 t = (unsigned char *) xmalloc(Size);
541 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, t, &Size);
542 token = strtok((char *) t, ", ");
543
544 while (token) {
6b610e34 545 debugs(78, 1, "Adding nameserver " << token << " from Registry");
62e76326 546 idnsAddNameserver(token);
547 token = strtok(NULL, ", ");
548 }
549 }
550
551 RegCloseKey(hndKey);
552 }
553
554 break;
555
0e6d05ef 556 default:
6b610e34 557 debugs(78, 1, "Failed to read nameserver from Registry: Unknown System Type.");
62e76326 558 return;
0e6d05ef 559 }
560}
62e76326 561
0e6d05ef 562#endif
563
7b724b86 564static void
565idnsStats(StoreEntry * sentry)
566{
a16b4aa0 567 dlink_node *n;
568 idns_query *q;
7cfc1c9a 569 int i;
558be27a 570 int j;
7b724b86 571 storeAppendPrintf(sentry, "Internal DNS Statistics:\n");
a16b4aa0 572 storeAppendPrintf(sentry, "\nThe Queue:\n");
0a69973e 573 storeAppendPrintf(sentry, " DELAY SINCE\n");
574 storeAppendPrintf(sentry, " ID SIZE SENDS FIRST SEND LAST SEND\n");
575 storeAppendPrintf(sentry, "------ ---- ----- ---------- ---------\n");
62e76326 576
a16b4aa0 577 for (n = lru_list.head; n; n = n->next) {
62e76326 578 q = (idns_query *)n->data;
579 storeAppendPrintf(sentry, "%#06x %4d %5d %10.3f %9.3f\n",
580 (int) q->id, (int) q->sz, q->nsends,
581 tvSubDsec(q->start_t, current_time),
582 tvSubDsec(q->sent_t, current_time));
7cfc1c9a 583 }
62e76326 584
7cfc1c9a 585 storeAppendPrintf(sentry, "\nNameservers:\n");
586 storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES\n");
587 storeAppendPrintf(sentry, "--------------- --------- ---------\n");
62e76326 588
7cfc1c9a 589 for (i = 0; i < nns; i++) {
62e76326 590 storeAppendPrintf(sentry, "%-15s %9d %9d\n",
591 inet_ntoa(nameservers[i].S.sin_addr),
592 nameservers[i].nqueries,
593 nameservers[i].nreplies);
a16b4aa0 594 }
62e76326 595
558be27a 596 storeAppendPrintf(sentry, "\nRcode Matrix:\n");
597 storeAppendPrintf(sentry, "RCODE");
62e76326 598
558be27a 599 for (i = 0; i < MAX_ATTEMPT; i++)
62e76326 600 storeAppendPrintf(sentry, " ATTEMPT%d", i + 1);
601
7928b8df 602 storeAppendPrintf(sentry, "\n");
62e76326 603
558be27a 604 for (j = 0; j < MAX_RCODE; j++) {
62e76326 605 storeAppendPrintf(sentry, "%5d", j);
606
607 for (i = 0; i < MAX_ATTEMPT; i++)
608 storeAppendPrintf(sentry, " %8d", RcodeMatrix[j][i]);
609
610 storeAppendPrintf(sentry, "\n");
558be27a 611 }
6b610e34 612
613 if (npc) {
614 storeAppendPrintf(sentry, "\nSearch list:\n");
615
616 for (i=0; i < npc; i++)
617 storeAppendPrintf(sentry, "%s\n", searchpath[i].domain);
618
619 storeAppendPrintf(sentry, "\n");
620 }
7b724b86 621}
622
efd900cb 623static void
624idnsTickleQueue(void)
625{
626 if (event_queued)
62e76326 627 return;
628
efd900cb 629 if (NULL == lru_list.tail)
62e76326 630 return;
631
efd900cb 632 eventAdd("idnsCheckQueue", idnsCheckQueue, NULL, 1.0, 1);
62e76326 633
efd900cb 634 event_queued = 1;
635}
636
d24ef4e9 637static void idnsDoSendQueryVC(nsvc *vc);
638
639static void
640idnsSentQueryVC(int fd, char *buf, size_t size, comm_err_t flag, void *data)
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
673 comm_old_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;
699 // XXX need to free and/or cbdataReferenceDone(vc) ?
d24ef4e9 700 nameservers[vc->ns].vc = NULL;
701}
702
703static void
704idnsInitVC(int ns)
705{
706 nsvc *vc = cbdataAlloc(nsvc);
707 nameservers[ns].vc = vc;
708
709 struct IN_ADDR addr;
710
711 if (Config.Addrs.udp_outgoing.s_addr != no_addr.s_addr)
712 addr = Config.Addrs.udp_outgoing;
713 else
714 addr = Config.Addrs.udp_incoming;
715
032785bf 716 vc->queue = new MemBuf;
d24ef4e9 717
032785bf 718 vc->msg = new MemBuf;
d24ef4e9 719
720 vc->fd = comm_open(SOCK_STREAM,
721 IPPROTO_TCP,
722 addr,
723 0,
724 COMM_NONBLOCKING,
725 "DNS Socket");
726
727 if (vc->fd < 0)
728 fatal("Could not create a DNS socket");
729
730 comm_add_close_handler(vc->fd, idnsVCClosed, vc);
731
732 vc->busy = 1;
733
734 commConnectStart(vc->fd, inet_ntoa(nameservers[ns].S.sin_addr), ntohs(nameservers[ns].S.sin_port), idnsInitVCConnected, vc);
735}
736
737static void
738idnsSendQueryVC(idns_query * q, int ns)
739{
740 if (nameservers[ns].vc == NULL)
741 idnsInitVC(ns);
742
743 nsvc *vc = nameservers[ns].vc;
744
2fe7eff9 745 vc->queue->reset();
d24ef4e9 746
747 short head = htons(q->sz);
748
2fe7eff9 749 vc->queue->append((char *)&head, 2);
d24ef4e9 750
2fe7eff9 751 vc->queue->append(q->buf, q->sz);
d24ef4e9 752
753 idnsDoSendQueryVC(vc);
754}
755
7b724b86 756static void
757idnsSendQuery(idns_query * q)
758{
759 int x;
ef523f99 760 int ns;
62e76326 761
0a69973e 762 if (DnsSocket < 0) {
62e76326 763 debug(78, 1) ("idnsSendQuery: Can't send query, no DNS socket!\n");
764 return;
0a69973e 765 }
62e76326 766
7b724b86 767 /* XXX Select nameserver */
768 assert(nns > 0);
62e76326 769
7b724b86 770 assert(q->lru.next == NULL);
62e76326 771
7b724b86 772 assert(q->lru.prev == NULL);
62e76326 773
774try_again:
ef523f99 775 ns = q->nsends % nns;
62e76326 776
d24ef4e9 777 if (q->need_vc) {
778 idnsSendQueryVC(q, ns);
779 x = 0;
780 } else
781 x = comm_udp_sendto(DnsSocket,
782 &nameservers[ns].S,
783 sizeof(nameservers[ns].S),
784 q->buf,
785 q->sz);
62e76326 786
4fe0e1d0 787 q->nsends++;
62e76326 788
4fe0e1d0 789 q->sent_t = current_time;
62e76326 790
0a69973e 791 if (x < 0) {
62e76326 792 debug(50, 1) ("idnsSendQuery: FD %d: sendto: %s\n",
793 DnsSocket, xstrerror());
794
795 if (q->nsends % nns != 0)
796 goto try_again;
0a69973e 797 } else {
62e76326 798 fd_bytes(DnsSocket, x, FD_WRITE);
799 commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0);
0a69973e 800 }
62e76326 801
7cfc1c9a 802 nameservers[ns].nqueries++;
7b724b86 803 dlinkAdd(q, &q->lru, &lru_list);
efd900cb 804 idnsTickleQueue();
7b724b86 805}
806
807static int
62e76326 808
7b724b86 809idnsFromKnownNameserver(struct sockaddr_in *from)
810{
811 int i;
62e76326 812
813 for (i = 0; i < nns; i++)
814 {
815 if (nameservers[i].S.sin_addr.s_addr != from->sin_addr.s_addr)
816 continue;
817
818 if (nameservers[i].S.sin_port != from->sin_port)
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) {
853 debug(78, 1) ("idnsQueryID: Warning, too many pending DNS requests\n");
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
882 memFree(q2, MEM_IDNS_QUERY);
883 }
884
885 if (q->hash.key) {
886 hash_remove_link(idns_lookup_hash, &q->hash);
887 q->hash.key = NULL;
888 }
889}
890
7b724b86 891static void
892idnsGrokReply(const char *buf, size_t sz)
893{
894 int n;
ec7bade0 895 rfc1035_message *message = NULL;
7b724b86 896 idns_query *q;
3074b9d1 897
ec7bade0 898 n = rfc1035MessageUnpack(buf,
62e76326 899 sz,
ec7bade0 900 &message);
62e76326 901
ec7bade0 902 if (message == NULL) {
4f3b04b7 903 debug(78, 1) ("idnsGrokReply: Malformed DNS response\n");
62e76326 904 return;
7b724b86 905 }
62e76326 906
ec7bade0 907 debug(78, 3) ("idnsGrokReply: ID %#hx, %d answers\n", message->id, n);
908
909 q = idnsFindQuery(message->id);
910
7b724b86 911 if (q == NULL) {
62e76326 912 debug(78, 3) ("idnsGrokReply: Late response\n");
ec7bade0 913 rfc1035MessageDestroy(message);
62e76326 914 return;
7b724b86 915 }
62e76326 916
9e1f210d 917 if (rfc1035QueryCompare(&q->query, message->query) != 0) {
918 debug(78, 3) ("idnsGrokReply: Query mismatch (%s != %s)\n", q->query.name, message->query->name);
919 rfc1035MessageDestroy(message);
920 return;
921 }
922
d24ef4e9 923 if (message->tc) {
924 dlinkDelete(&q->lru, &lru_list);
925 rfc1035MessageDestroy(message);
926
927 if (!q->need_vc) {
928 q->need_vc = 1;
929 q->nsends--;
930 idnsSendQuery(q);
931 }
932
933 return;
934 }
9e1f210d 935
a16b4aa0 936 dlinkDelete(&q->lru, &lru_list);
558be27a 937 idnsRcodeCount(n, q->attempt);
7ba8d0b8 938 q->error = NULL;
62e76326 939
558be27a 940 if (n < 0) {
ec7bade0 941 debug(78, 3) ("idnsGrokReply: error %s (%d)\n", rfc1035_error_message, rfc1035_errno);
62e76326 942
7ba8d0b8 943 q->error = rfc1035_error_message;
944 q->rcode = -n;
945
946 if (q->rcode == 2 && ++q->attempt < MAX_ATTEMPT) {
62e76326 947 /*
948 * RCODE 2 is "Server failure - The name server was
949 * unable to process this query due to a problem with
950 * the name server."
951 */
ec7bade0 952 rfc1035MessageDestroy(message);
62e76326 953 q->start_t = current_time;
108d67a0 954 q->id = idnsQueryID();
955 rfc1035SetQueryID(q->buf, q->id);
62e76326 956 idnsSendQuery(q);
957 return;
958 }
68836b58 959
960 if (q->rcode == 3 && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
961 assert(NULL == message->answer);
962 strcpy(q->name, q->orig);
963
964 if (q->domain < npc) {
965 strcat(q->name, ".");
966 strcat(q->name, searchpath[q->domain].domain);
967 debug(78, 3) ("idnsGrokReply: searchpath used for %s\n",
968 q->name);
969 q->domain++;
970 } else {
971 q->attempt++;
972 }
973
974 rfc1035MessageDestroy(message);
975 q->start_t = current_time;
976 q->id = idnsQueryID();
977 rfc1035SetQueryID(q->buf, q->id);
978 q->sz = rfc1035BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id,
979 &q->query);
980
981 idnsCacheQuery(q);
982 idnsSendQuery(q);
983 return;
984 }
558be27a 985 }
62e76326 986
ec7bade0 987 idnsCallback(q, message->answer, n, q->error);
988 rfc1035MessageDestroy(message);
62e76326 989
a16b4aa0 990 memFree(q, MEM_IDNS_QUERY);
7b724b86 991}
992
993static void
994idnsRead(int fd, void *data)
995{
d193a436 996 int *N = &incoming_sockets_accepted;
7b724b86 997 ssize_t len;
62e76326 998
7b724b86 999 struct sockaddr_in from;
1000 socklen_t from_len;
42b51993 1001 int max = INCOMING_DNS_MAX;
d29b40de 1002 static char rbuf[SQUID_UDP_SO_RCVBUF];
7cfc1c9a 1003 int ns;
62e76326 1004
7b724b86 1005 while (max--) {
62e76326 1006 from_len = sizeof(from);
1007 memset(&from, '\0', from_len);
1008
0343293b 1009 len = comm_udp_recvfrom(fd, rbuf, sizeof(rbuf), 0, (struct sockaddr *) &from, &from_len);
62e76326 1010
1011 if (len == 0)
1012 break;
1013
1014 if (len < 0) {
1015 if (ignoreErrno(errno))
1016 break;
1017
7b724b86 1018#ifdef _SQUID_LINUX_
62e76326 1019 /* Some Linux systems seem to set the FD for reading and then
1020 * return ECONNREFUSED when sendto() fails and generates an ICMP
1021 * port unreachable message. */
1022 /* or maybe an EHOSTUNREACH "No route to host" message */
1023 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
7b724b86 1024#endif
62e76326 1025
1026 debug(50, 1) ("idnsRead: FD %d recvfrom: %s\n",
1027 fd, xstrerror());
1028
1029 break;
1030 }
1031
1032 fd_bytes(DnsSocket, len, FD_READ);
1033 assert(N);
1034 (*N)++;
1035 debug(78, 3) ("idnsRead: FD %d: received %d bytes from %s.\n",
1036 fd,
1037 (int) len,
1038 inet_ntoa(from.sin_addr));
1039 ns = idnsFromKnownNameserver(&from);
1040
1041 if (ns >= 0) {
1042 nameservers[ns].nreplies++;
1043 } else if (Config.onoff.ignore_unknown_nameservers) {
1044 static time_t last_warning = 0;
1045
1046 if (squid_curtime - last_warning > 60) {
1047 debug(78, 1) ("WARNING: Reply from unknown nameserver [%s]\n",
1048 inet_ntoa(from.sin_addr));
1049 last_warning = squid_curtime;
1050 }
1051
1052 continue;
1053 }
1054
62e76326 1055 idnsGrokReply(rbuf, len);
7b724b86 1056 }
62e76326 1057
2e6caa54 1058 if (lru_list.head)
62e76326 1059 commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0);
7b724b86 1060}
1061
7cfc1c9a 1062static void
1063idnsCheckQueue(void *unused)
1064{
1065 dlink_node *n;
0c4fe9e4 1066 dlink_node *p = NULL;
7cfc1c9a 1067 idns_query *q;
1068 event_queued = 0;
62e76326 1069
0c4fe9e4 1070 for (n = lru_list.tail; n; n = p) {
62e76326 1071 if (0 == nns)
1072 /* name servers went away; reconfiguring or shutting down */
1073 break;
1074
1075 q = (idns_query *)n->data;
1076
da0c4437 1077 if (tvSubDsec(q->sent_t, current_time) < Config.Timeout.idns_retransmit * (1 << (q->nsends - 1) % nns))
62e76326 1078 break;
1079
1080 debug(78, 3) ("idnsCheckQueue: ID %#04x timeout\n",
1081 q->id);
1082
1083 p = n->prev;
1084
1085 dlinkDelete(&q->lru, &lru_list);
1086
1087 if (tvSubDsec(q->start_t, current_time) < Config.Timeout.idns_query) {
1088 idnsSendQuery(q);
1089 } else {
62e76326 1090 debug(78, 2) ("idnsCheckQueue: ID %x: giving up after %d tries and %5.1f seconds\n",
1091 (int) q->id, q->nsends,
1092 tvSubDsec(q->start_t, current_time));
3074b9d1 1093
1094 if (q->rcode != 0)
1095 idnsCallback(q, NULL, -q->rcode, q->error);
1096 else
1097 idnsCallback(q, NULL, -16, "Timeout");
62e76326 1098
1099 memFree(q, MEM_IDNS_QUERY);
1100 }
7cfc1c9a 1101 }
62e76326 1102
efd900cb 1103 idnsTickleQueue();
7cfc1c9a 1104}
1105
d24ef4e9 1106static void
1107idnsReadVC(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1108{
1109 nsvc * vc = (nsvc *)data;
1110
1111 if (flag == COMM_ERR_CLOSING)
1112 return;
1113
1114 if (flag != COMM_OK || len <= 0) {
1115 comm_close(fd);
1116 return;
1117 }
1118
032785bf 1119 vc->msg->size += len; // XXX should not access -> size directly
d24ef4e9 1120
032785bf 1121 if (vc->msg->contentSize() < vc->msglen) {
1122 comm_read(fd, buf + len, vc->msglen - vc->msg->contentSize(), idnsReadVC, vc);
d24ef4e9 1123 return;
1124 }
1125
1126 debug(78, 3) ("idnsReadVC: FD %d: received %d bytes via tcp from %s.\n",
1127 fd,
032785bf 1128 (int) vc->msg->contentSize(),
d24ef4e9 1129 inet_ntoa(nameservers[vc->ns].S.sin_addr));
1130
032785bf 1131 idnsGrokReply(vc->msg->buf, vc->msg->contentSize());
2fe7eff9 1132 vc->msg->clean();
d24ef4e9 1133 comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
1134}
1135
1136static void
1137idnsReadVCHeader(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1138{
1139 nsvc * vc = (nsvc *)data;
1140
1141 if (flag == COMM_ERR_CLOSING)
1142 return;
1143
1144 if (flag != COMM_OK || len <= 0) {
1145 comm_close(fd);
1146 return;
1147 }
1148
1149 vc->read_msglen += len;
1150
1151 assert(vc->read_msglen <= 2);
1152
1153 if (vc->read_msglen < 2) {
1154 comm_read(fd, buf + len, 2 - vc->read_msglen, idnsReadVCHeader, vc);
1155 return;
1156 }
1157
1158 vc->read_msglen = 0;
1159
1160 vc->msglen = ntohs(vc->msglen);
1161
2fe7eff9 1162 vc->msg->init(vc->msglen, vc->msglen);
032785bf 1163 comm_read(fd, vc->msg->buf, vc->msglen, idnsReadVC, vc);
d24ef4e9 1164}
1165
558be27a 1166/*
1167 * rcode < 0 indicates an error, rocde >= 0 indicates success
1168 */
1169static void
1170idnsRcodeCount(int rcode, int attempt)
1171{
1172 if (rcode > 0)
62e76326 1173 rcode = 0;
558be27a 1174 else if (rcode < 0)
62e76326 1175 rcode = -rcode;
1176
558be27a 1177 if (rcode < MAX_RCODE)
62e76326 1178 if (attempt < MAX_ATTEMPT)
1179 RcodeMatrix[rcode][attempt]++;
558be27a 1180}
1181
7b724b86 1182/* ====================================================================== */
1183
1184void
1185idnsInit(void)
1186{
1187 static int init = 0;
62e76326 1188
d24ef4e9 1189 CBDATA_INIT_TYPE(nsvc);
1190
ef523f99 1191 if (DnsSocket < 0) {
62e76326 1192 int port;
1193
ddfcbc22 1194 struct IN_ADDR addr;
62e76326 1195
1196 if (Config.Addrs.udp_outgoing.s_addr != no_addr.s_addr)
1197 addr = Config.Addrs.udp_outgoing;
1198 else
1199 addr = Config.Addrs.udp_incoming;
1200
1201 DnsSocket = comm_open(SOCK_DGRAM,
bdb741f4 1202 IPPROTO_UDP,
62e76326 1203 addr,
1204 0,
1205 COMM_NONBLOCKING,
1206 "DNS Socket");
1207
1208 if (DnsSocket < 0)
1209 fatal("Could not create a DNS socket");
1210
1211 /* Ouch... we can't call functions using debug from a debug
1212 * statement. Doing so messes up the internal Debug::level
1213 */
1214 port = comm_local_port(DnsSocket);
1215
1216 debug(78, 1) ("DNS Socket created at %s, port %d, FD %d\n",
1217 inet_ntoa(addr),
1218 port, DnsSocket);
7b724b86 1219 }
62e76326 1220
efd900cb 1221 assert(0 == nns);
1222 idnsParseNameservers();
0e6d05ef 1223#ifndef _SQUID_MSWIN_
62e76326 1224
efd900cb 1225 if (0 == nns)
62e76326 1226 idnsParseResolvConf();
1227
0e6d05ef 1228#endif
ec4daaa5 1229#ifdef _SQUID_WIN32_
62e76326 1230
0e6d05ef 1231 if (0 == nns)
62e76326 1232 idnsParseWIN32Registry();
1233
0e6d05ef 1234#endif
62e76326 1235
29fe9bd5 1236 if (0 == nns) {
1237 debugs(78, 1, "Warning: Could not find any nameservers. Trying to use localhost");
ec4daaa5 1238#ifdef _SQUID_WIN32_
29fe9bd5 1239
1240 debugs(78, 1, "Please check your TCP-IP settings or /etc/resolv.conf file");
0e6d05ef 1241#else
29fe9bd5 1242
1243 debugs(78, 1, "Please check your /etc/resolv.conf file");
0e6d05ef 1244#endif
29fe9bd5 1245
1246 debugs(78, 1, "or use the 'dns_nameservers' option in squid.conf.");
1247 idnsAddNameserver("127.0.0.1");
1248 }
62e76326 1249
7b724b86 1250 if (!init) {
62e76326 1251 memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
62e76326 1252 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
3074b9d1 1253 idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
62e76326 1254 init++;
7b724b86 1255 }
7b724b86 1256}
1257
62ee09ca 1258void
1259idnsRegisterWithCacheManager(CacheManager & manager)
1260{
1261 manager.registerAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
1262}
1263
7b724b86 1264void
1265idnsShutdown(void)
1266{
ef523f99 1267 if (DnsSocket < 0)
62e76326 1268 return;
1269
ef523f99 1270 comm_close(DnsSocket);
62e76326 1271
ef523f99 1272 DnsSocket = -1;
62e76326 1273
efd900cb 1274 idnsFreeNameservers();
68836b58 1275
1276 idnsFreeSearchpath();
7b724b86 1277}
1278
3074b9d1 1279static int
1280idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
1281{
1282 idns_query *q;
1283
1284 idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
1285
1286 if (!old)
1287 return 0;
1288
1289 q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
1290
1291 q->callback = callback;
1292
1293 q->callback_data = cbdataReference(data);
1294
1295 q->queue = old->queue;
1296
1297 old->queue = q;
1298
1299 return 1;
1300}
1301
1302static void
9e1f210d 1303idnsCacheQuery(idns_query *q)
3074b9d1 1304{
9e1f210d 1305 q->hash.key = q->query.name;
3074b9d1 1306 hash_join(idns_lookup_hash, &q->hash);
1307}
1308
7b724b86 1309void
1310idnsALookup(const char *name, IDNSCB * callback, void *data)
1311{
68836b58 1312 unsigned int i;
1313 int nd = 0;
3074b9d1 1314 idns_query *q;
1315
1316 if (idnsCachedLookup(name, callback, data))
1317 return;
1318
1319 q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
1320
71952967 1321 q->id = idnsQueryID();
1322
68836b58 1323 for (i = 0; i < strlen(name); i++)
1324 if (name[i] == '.')
1325 nd++;
1326
1327 if (Config.onoff.res_defnames && npc > 0 && name[strlen(name)-1] != '.') {
1328 q->do_searchpath = 1;
1329 } else {
1330 q->do_searchpath = 0;
1331 }
1332
1333 strcpy(q->orig, name);
1334 strcpy(q->name, q->orig);
1335
1336 if (q->do_searchpath && nd < ndots) {
1337 q->domain = 0;
1338 strcat(q->name, ".");
1339 strcat(q->name, searchpath[q->domain].domain);
1340 debug(78, 3) ("idnsALookup: searchpath used for %s\n",
1341 q->name);
1342 }
1343
1344 q->sz = rfc1035BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id,
1345 &q->query);
62e76326 1346
2041330b 1347 if (q->sz < 0) {
1348 /* problem with query data -- query not sent */
1349 callback(data, NULL, 0, "Internal error");
1350 memFree(q, MEM_IDNS_QUERY);
1351 return;
1352 }
1353
a16b4aa0 1354 debug(78, 3) ("idnsALookup: buf is %d bytes for %s, id = %#hx\n",
68836b58 1355 (int) q->sz, q->name, q->id);
aa6c61e3 1356
7b724b86 1357 q->callback = callback;
aa6c61e3 1358
fa80a8ef 1359 q->callback_data = cbdataReference(data);
aa6c61e3 1360
7cfc1c9a 1361 q->start_t = current_time;
aa6c61e3 1362
9e1f210d 1363 idnsCacheQuery(q);
aa6c61e3 1364
7b724b86 1365 idnsSendQuery(q);
1366}
8db71107 1367
1368void
62e76326 1369
ddfcbc22 1370idnsPTRLookup(const struct IN_ADDR addr, IDNSCB * callback, void *data)
8db71107 1371{
3074b9d1 1372 idns_query *q;
1373
1374 const char *ip = inet_ntoa(addr);
1375
1376 if (idnsCachedLookup(ip, callback, data))
1377 return;
1378
1379 q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
1380
71952967 1381 q->id = idnsQueryID();
1382
9e1f210d 1383 q->sz = rfc1035BuildPTRQuery(addr, q->buf, sizeof(q->buf), q->id, &q->query);
3074b9d1 1384
2041330b 1385 if (q->sz < 0)
1386 {
1387 /* problem with query data -- query not sent */
1388 callback(data, NULL, 0, "Internal error");
1389 memFree(q, MEM_IDNS_QUERY);
1390 return;
1391 }
1392
8db71107 1393 debug(78, 3) ("idnsPTRLookup: buf is %d bytes for %s, id = %#hx\n",
3074b9d1 1394 (int) q->sz, ip, q->id);
1395
8db71107 1396 q->callback = callback;
3074b9d1 1397
fa80a8ef 1398 q->callback_data = cbdataReference(data);
3074b9d1 1399
8db71107 1400 q->start_t = current_time;
3074b9d1 1401
9e1f210d 1402 idnsCacheQuery(q);
3074b9d1 1403
8db71107 1404 idnsSendQuery(q);
1405}
eb824054 1406
3c573763 1407#ifdef SQUID_SNMP
1408/*
1409 * The function to return the DNS via SNMP
1410 */
1411variable_list *
1412snmp_netIdnsFn(variable_list * Var, snint * ErrP)
1413{
1414 int i, n = 0;
1415 variable_list *Answer = NULL;
38650cc8 1416 debug(49, 5) ("snmp_netDnsFn: Processing request: \n");
3c573763 1417 snmpDebugOid(5, Var->name, Var->name_length);
1418 *ErrP = SNMP_ERR_NOERROR;
62e76326 1419
3c573763 1420 switch (Var->name[LEN_SQ_NET + 1]) {
62e76326 1421
3c573763 1422 case DNS_REQ:
62e76326 1423
1424 for (i = 0; i < nns; i++)
1425 n += nameservers[i].nqueries;
1426
1427 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1428 n,
1429 SMI_COUNTER32);
1430
1431 break;
1432
3c573763 1433 case DNS_REP:
62e76326 1434 for (i = 0; i < nns; i++)
1435 n += nameservers[i].nreplies;
1436
1437 Answer = snmp_var_new_integer(Var->name, Var->name_length,
1438 n,
1439 SMI_COUNTER32);
1440
1441 break;
1442
3c573763 1443 case DNS_SERVERS:
62e76326 1444 Answer = snmp_var_new_integer(Var->name, Var->name_length,
e494f5e9 1445 nns,
62e76326 1446 SMI_COUNTER32);
1447
1448 break;
1449
3c573763 1450 default:
62e76326 1451 *ErrP = SNMP_ERR_NOSUCHNAME;
1452
1453 break;
3c573763 1454 }
62e76326 1455
3c573763 1456 return Answer;
1457}
62e76326 1458
3c573763 1459#endif /*SQUID_SNMP */
1f1ae50a 1460#endif /* USE_DNSSERVERS */