]> git.ipfire.org Git - thirdparty/squid.git/blame - src/dns_internal.cc
Summary: Fix bug #560.
[thirdparty/squid.git] / src / dns_internal.cc
CommitLineData
7b724b86 1
2/*
d947cc33 3 * $Id: dns_internal.cc,v 1.56 2003/03/02 09:59:32 hno 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
36#include "squid.h"
e6ccf245 37#include "Store.h"
063dc1eb 38#include "comm.h"
7b724b86 39
0e6d05ef 40#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
41#include <windows.h>
42#endif
7b724b86 43#ifndef _PATH_RESOLV_CONF
44#define _PATH_RESOLV_CONF "/etc/resolv.conf"
45#endif
46#ifndef DOMAIN_PORT
47#define DOMAIN_PORT 53
48#endif
49
42b51993 50#define IDNS_MAX_TRIES 20
558be27a 51#define MAX_RCODE 6
52#define MAX_ATTEMPT 3
53static int RcodeMatrix[MAX_RCODE][MAX_ATTEMPT];
54
58a39dc9 55typedef struct _idns_query idns_query;
62e76326 56
7b724b86 57typedef struct _ns ns;
58a39dc9 58
62e76326 59struct _idns_query
60{
58a39dc9 61 char buf[512];
62 size_t sz;
63 unsigned short id;
64 int nsends;
62e76326 65
58a39dc9 66 struct timeval start_t;
62e76326 67
58a39dc9 68 struct timeval sent_t;
69 dlink_node lru;
70 IDNSCB *callback;
71 void *callback_data;
558be27a 72 int attempt;
58a39dc9 73};
74
62e76326 75struct _ns
76{
77
7b724b86 78 struct sockaddr_in S;
79 int nqueries;
80 int nreplies;
d29b40de 81 int large_pkts;
7b724b86 82};
58a39dc9 83
7b724b86 84static ns *nameservers = NULL;
85static int nns = 0;
86static int nns_alloc = 0;
7b724b86 87static dlink_list lru_list;
7cfc1c9a 88static int event_queued = 0;
7b724b86 89
90static OBJH idnsStats;
91static void idnsAddNameserver(const char *buf);
92static void idnsFreeNameservers(void);
efd900cb 93static void idnsParseNameservers(void);
7b724b86 94static void idnsParseResolvConf(void);
0e6d05ef 95#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
96static void idnsParseWIN32Registry(void);
97#endif
7b724b86 98static void idnsSendQuery(idns_query * q);
62e76326 99
7b724b86 100static int idnsFromKnownNameserver(struct sockaddr_in *from);
101static idns_query *idnsFindQuery(unsigned short id);
102static void idnsGrokReply(const char *buf, size_t sz);
103static PF idnsRead;
7cfc1c9a 104static EVH idnsCheckQueue;
efd900cb 105static void idnsTickleQueue(void);
558be27a 106static void idnsRcodeCount(int, int);
7b724b86 107
108static void
109idnsAddNameserver(const char *buf)
110{
62e76326 111
d20b1cd0 112 struct in_addr A;
62e76326 113
d20b1cd0 114 if (!safe_inet_addr(buf, &A)) {
62e76326 115 debug(78, 0) ("WARNING: rejecting '%s' as a name server, because it is not a numeric IP address\n", buf);
116 return;
d20b1cd0 117 }
62e76326 118
5c5a349d 119 if (A.s_addr == 0) {
62e76326 120 debug(78, 0) ("WARNING: Squid does not accept 0.0.0.0 in DNS server specifications.\n");
121 debug(78, 0) ("Will be using 127.0.0.1 instead, assuming you meant that DNS is running on the same machine\n");
122 safe_inet_addr("127.0.0.1", &A);
5c5a349d 123 }
62e76326 124
7b724b86 125 if (nns == nns_alloc) {
62e76326 126 int oldalloc = nns_alloc;
127 ns *oldptr = nameservers;
128
129 if (nns_alloc == 0)
130 nns_alloc = 2;
131 else
132 nns_alloc <<= 1;
133
134 nameservers = (ns *)xcalloc(nns_alloc, sizeof(*nameservers));
135
136 if (oldptr && oldalloc)
137 xmemcpy(nameservers, oldptr, oldalloc * sizeof(*nameservers));
138
139 if (oldptr)
140 safe_free(oldptr);
7b724b86 141 }
62e76326 142
7b724b86 143 assert(nns < nns_alloc);
144 nameservers[nns].S.sin_family = AF_INET;
145 nameservers[nns].S.sin_port = htons(DOMAIN_PORT);
d20b1cd0 146 nameservers[nns].S.sin_addr.s_addr = A.s_addr;
efd900cb 147 debug(78, 3) ("idnsAddNameserver: Added nameserver #%d: %s\n",
62e76326 148 nns, inet_ntoa(nameservers[nns].S.sin_addr));
7b724b86 149 nns++;
150}
151
152static void
153idnsFreeNameservers(void)
154{
155 safe_free(nameservers);
156 nns = nns_alloc = 0;
157}
158
efd900cb 159static void
160idnsParseNameservers(void)
161{
162 wordlist *w;
62e76326 163
efd900cb 164 for (w = Config.dns_nameservers; w; w = w->next) {
62e76326 165 debug(78, 1) ("Adding nameserver %s from squid.conf\n", w->key);
166 idnsAddNameserver(w->key);
efd900cb 167 }
168}
169
7b724b86 170static void
171idnsParseResolvConf(void)
172{
173 FILE *fp;
174 char buf[512];
175 char *t;
176 fp = fopen(_PATH_RESOLV_CONF, "r");
62e76326 177
7b724b86 178 if (fp == NULL) {
62e76326 179 debug(78, 1) ("%s: %s\n", _PATH_RESOLV_CONF, xstrerror());
180 return;
7b724b86 181 }
62e76326 182
b671cc68 183#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
c4aefe96 184 setmode(fileno(fp), O_TEXT);
62e76326 185
c4aefe96 186#endif
62e76326 187
7b724b86 188 while (fgets(buf, 512, fp)) {
62e76326 189 t = strtok(buf, w_space);
190
191 if (NULL == t)
192 continue;
193
194 if (strcasecmp(t, "nameserver"))
195 continue;
196
197 t = strtok(NULL, w_space);
198
199 if (t == NULL)
200 continue;
201
202 debug(78, 1) ("Adding nameserver %s from %s\n", t, _PATH_RESOLV_CONF);
203
204 idnsAddNameserver(t);
7b724b86 205 }
62e76326 206
7b724b86 207 fclose(fp);
208}
209
0e6d05ef 210#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
211static void
212idnsParseWIN32Registry(void)
213{
e6ccf245 214 BYTE *t;
0e6d05ef 215 char *token;
216 HKEY hndKey, hndKey2;
217
218 idnsFreeNameservers();
62e76326 219
0e6d05ef 220 switch (WIN32_OS_version) {
62e76326 221
0e6d05ef 222 case _WIN_OS_WINNT:
62e76326 223 /* get nameservers from the Windows NT registry */
224
225 if (RegOpenKey(HKEY_LOCAL_MACHINE,
226 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
227 &hndKey) == ERROR_SUCCESS) {
228 DWORD Type = 0;
229 DWORD Size = 0;
230 LONG Result;
231 Result =
232 RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, NULL,
233 &Size);
234
235 if (Result == ERROR_SUCCESS && Size) {
236 t = (unsigned char *) xmalloc(Size);
237 RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, t,
238 &Size);
239 token = strtok((char *) t, ", ");
240
241 while (token) {
242 idnsAddNameserver(token);
243 debug(78, 1) ("Adding DHCP nameserver %s from Registry\n",
244 token);
245 token = strtok(NULL, ", ");
246 }
247 }
248
249 Result =
250 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
251
252 if (Result == ERROR_SUCCESS && Size) {
253 t = (unsigned char *) xmalloc(Size);
254 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, t, &Size);
255 token = strtok((char *) t, ", ");
256
257 while (token) {
258 debug(78, 1) ("Adding nameserver %s from Registry\n",
259 token);
260 idnsAddNameserver(token);
261 token = strtok(NULL, ", ");
262 }
263 }
264
265 RegCloseKey(hndKey);
266 }
267
268 break;
269
0e6d05ef 270 case _WIN_OS_WIN2K:
62e76326 271
b671cc68 272 case _WIN_OS_WINXP:
62e76326 273
6b1846cf 274 case _WIN_OS_WINNET:
62e76326 275 /* get nameservers from the Windows 2000 registry */
276 /* search all interfaces for DNS server addresses */
277
278 if (RegOpenKey(HKEY_LOCAL_MACHINE,
279 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces",
280 &hndKey) == ERROR_SUCCESS) {
281 int i;
282 char keyname[255];
283
284 for (i = 0; i < 10; i++) {
285 if (RegEnumKey(hndKey, i, (char *) &keyname,
286 255) == ERROR_SUCCESS) {
287 char newkeyname[255];
288 strcpy(newkeyname,
289 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
290 strcat(newkeyname, keyname);
291
292 if (RegOpenKey(HKEY_LOCAL_MACHINE, newkeyname,
293 &hndKey2) == ERROR_SUCCESS) {
294 DWORD Type = 0;
295 DWORD Size = 0;
296 LONG Result;
297 Result =
298 RegQueryValueEx(hndKey2, "DhcpNameServer", NULL,
299 &Type, NULL, &Size);
300
301 if (Result == ERROR_SUCCESS && Size) {
302 t = (unsigned char *) xmalloc(Size);
303 RegQueryValueEx(hndKey2, "DhcpNameServer", NULL,
304 &Type, t, &Size);
305 token = strtok((char *) t, ", ");
306
307 while (token) {
308 debug(78, 1)
309 ("Adding DHCP nameserver %s from Registry\n",
310 token);
311 idnsAddNameserver(token);
312 token = strtok(NULL, ", ");
313 }
314 }
315
316 Result =
317 RegQueryValueEx(hndKey2, "NameServer", NULL, &Type,
318 NULL, &Size);
319
320 if (Result == ERROR_SUCCESS && Size) {
321 t = (unsigned char *) xmalloc(Size);
322 RegQueryValueEx(hndKey2, "NameServer", NULL, &Type,
323 t, &Size);
324 token = strtok((char *) t, ", ");
325
326 while (token) {
327 debug(78,
328 1) ("Adding nameserver %s from Registry\n",
329 token);
330 idnsAddNameserver(token);
331 token = strtok(NULL, ", ");
332 }
333 }
334
335 RegCloseKey(hndKey2);
336 }
337 }
338 }
339
340 RegCloseKey(hndKey);
341 }
342
343 break;
344
0e6d05ef 345 case _WIN_OS_WIN95:
62e76326 346
0e6d05ef 347 case _WIN_OS_WIN98:
62e76326 348
be20dac7 349 case _WIN_OS_WINME:
62e76326 350 /* get nameservers from the Windows 9X registry */
351
352 if (RegOpenKey(HKEY_LOCAL_MACHINE,
353 "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
354 &hndKey) == ERROR_SUCCESS) {
355 DWORD Type = 0;
356 DWORD Size = 0;
357 LONG Result;
358 Result =
359 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
360
361 if (Result == ERROR_SUCCESS && Size) {
362 t = (unsigned char *) xmalloc(Size);
363 RegQueryValueEx(hndKey, "NameServer", NULL, &Type, t, &Size);
364 token = strtok((char *) t, ", ");
365
366 while (token) {
367 debug(78, 1) ("Adding nameserver %s from Registry\n",
368 token);
369 idnsAddNameserver(token);
370 token = strtok(NULL, ", ");
371 }
372 }
373
374 RegCloseKey(hndKey);
375 }
376
377 break;
378
0e6d05ef 379 default:
62e76326 380 debug(78, 1)
381 ("Failed to read nameserver from Registry: Unknown System Type.\n");
382 return;
0e6d05ef 383 }
384}
62e76326 385
0e6d05ef 386#endif
387
7b724b86 388static void
389idnsStats(StoreEntry * sentry)
390{
a16b4aa0 391 dlink_node *n;
392 idns_query *q;
7cfc1c9a 393 int i;
558be27a 394 int j;
7b724b86 395 storeAppendPrintf(sentry, "Internal DNS Statistics:\n");
a16b4aa0 396 storeAppendPrintf(sentry, "\nThe Queue:\n");
0a69973e 397 storeAppendPrintf(sentry, " DELAY SINCE\n");
398 storeAppendPrintf(sentry, " ID SIZE SENDS FIRST SEND LAST SEND\n");
399 storeAppendPrintf(sentry, "------ ---- ----- ---------- ---------\n");
62e76326 400
a16b4aa0 401 for (n = lru_list.head; n; n = n->next) {
62e76326 402 q = (idns_query *)n->data;
403 storeAppendPrintf(sentry, "%#06x %4d %5d %10.3f %9.3f\n",
404 (int) q->id, (int) q->sz, q->nsends,
405 tvSubDsec(q->start_t, current_time),
406 tvSubDsec(q->sent_t, current_time));
7cfc1c9a 407 }
62e76326 408
7cfc1c9a 409 storeAppendPrintf(sentry, "\nNameservers:\n");
410 storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES\n");
411 storeAppendPrintf(sentry, "--------------- --------- ---------\n");
62e76326 412
7cfc1c9a 413 for (i = 0; i < nns; i++) {
62e76326 414 storeAppendPrintf(sentry, "%-15s %9d %9d\n",
415 inet_ntoa(nameservers[i].S.sin_addr),
416 nameservers[i].nqueries,
417 nameservers[i].nreplies);
a16b4aa0 418 }
62e76326 419
558be27a 420 storeAppendPrintf(sentry, "\nRcode Matrix:\n");
421 storeAppendPrintf(sentry, "RCODE");
62e76326 422
558be27a 423 for (i = 0; i < MAX_ATTEMPT; i++)
62e76326 424 storeAppendPrintf(sentry, " ATTEMPT%d", i + 1);
425
7928b8df 426 storeAppendPrintf(sentry, "\n");
62e76326 427
558be27a 428 for (j = 0; j < MAX_RCODE; j++) {
62e76326 429 storeAppendPrintf(sentry, "%5d", j);
430
431 for (i = 0; i < MAX_ATTEMPT; i++)
432 storeAppendPrintf(sentry, " %8d", RcodeMatrix[j][i]);
433
434 storeAppendPrintf(sentry, "\n");
558be27a 435 }
7b724b86 436}
437
efd900cb 438static void
439idnsTickleQueue(void)
440{
441 if (event_queued)
62e76326 442 return;
443
efd900cb 444 if (NULL == lru_list.tail)
62e76326 445 return;
446
efd900cb 447 eventAdd("idnsCheckQueue", idnsCheckQueue, NULL, 1.0, 1);
62e76326 448
efd900cb 449 event_queued = 1;
450}
451
7b724b86 452static void
453idnsSendQuery(idns_query * q)
454{
455 int x;
ef523f99 456 int ns;
62e76326 457
0a69973e 458 if (DnsSocket < 0) {
62e76326 459 debug(78, 1) ("idnsSendQuery: Can't send query, no DNS socket!\n");
460 return;
0a69973e 461 }
62e76326 462
7b724b86 463 /* XXX Select nameserver */
464 assert(nns > 0);
62e76326 465
7b724b86 466 assert(q->lru.next == NULL);
62e76326 467
7b724b86 468 assert(q->lru.prev == NULL);
62e76326 469
470try_again:
ef523f99 471 ns = q->nsends % nns;
62e76326 472
ef523f99 473 x = comm_udp_sendto(DnsSocket,
62e76326 474 &nameservers[ns].S,
475 sizeof(nameservers[ns].S),
476 q->buf,
477 q->sz);
478
4fe0e1d0 479 q->nsends++;
62e76326 480
4fe0e1d0 481 q->sent_t = current_time;
62e76326 482
0a69973e 483 if (x < 0) {
62e76326 484 debug(50, 1) ("idnsSendQuery: FD %d: sendto: %s\n",
485 DnsSocket, xstrerror());
486
487 if (q->nsends % nns != 0)
488 goto try_again;
0a69973e 489 } else {
62e76326 490 fd_bytes(DnsSocket, x, FD_WRITE);
491 commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0);
0a69973e 492 }
62e76326 493
7cfc1c9a 494 nameservers[ns].nqueries++;
7b724b86 495 dlinkAdd(q, &q->lru, &lru_list);
efd900cb 496 idnsTickleQueue();
7b724b86 497}
498
499static int
62e76326 500
7b724b86 501idnsFromKnownNameserver(struct sockaddr_in *from)
502{
503 int i;
62e76326 504
505 for (i = 0; i < nns; i++)
506 {
507 if (nameservers[i].S.sin_addr.s_addr != from->sin_addr.s_addr)
508 continue;
509
510 if (nameservers[i].S.sin_port != from->sin_port)
511 continue;
512
513 return i;
7b724b86 514 }
62e76326 515
7cfc1c9a 516 return -1;
7b724b86 517}
518
519static idns_query *
520idnsFindQuery(unsigned short id)
521{
522 dlink_node *n;
523 idns_query *q;
62e76326 524
7b724b86 525 for (n = lru_list.tail; n; n = n->prev) {
62e76326 526 q = (idns_query*)n->data;
527
528 if (q->id == id)
529 return q;
7b724b86 530 }
62e76326 531
7b724b86 532 return NULL;
533}
534
535static void
536idnsGrokReply(const char *buf, size_t sz)
537{
538 int n;
7b724b86 539 rfc1035_rr *answers = NULL;
540 unsigned short rid = 0xFFFF;
541 idns_query *q;
fa80a8ef 542 IDNSCB *callback;
543 void *cbdata;
7b724b86 544 n = rfc1035AnswersUnpack(buf,
62e76326 545 sz,
546 &answers,
547 &rid);
a16b4aa0 548 debug(78, 3) ("idnsGrokReply: ID %#hx, %d answers\n", rid, n);
62e76326 549
7b724b86 550 if (rid == 0xFFFF) {
62e76326 551 debug(78, 1) ("idnsGrokReply: Unknown error\n");
552 /* XXX leak answers? */
553 return;
7b724b86 554 }
62e76326 555
7b724b86 556 q = idnsFindQuery(rid);
62e76326 557
7b724b86 558 if (q == NULL) {
62e76326 559 debug(78, 3) ("idnsGrokReply: Late response\n");
560 rfc1035RRDestroy(answers, n);
561 return;
7b724b86 562 }
62e76326 563
a16b4aa0 564 dlinkDelete(&q->lru, &lru_list);
558be27a 565 idnsRcodeCount(n, q->attempt);
62e76326 566
558be27a 567 if (n < 0) {
62e76326 568 debug(78, 3) ("idnsGrokReply: error %d\n", rfc1035_errno);
569
570 if (-2 == n && ++q->attempt < MAX_ATTEMPT) {
571 /*
572 * RCODE 2 is "Server failure - The name server was
573 * unable to process this query due to a problem with
574 * the name server."
575 */
576 assert(NULL == answers);
577 q->start_t = current_time;
578 q->id = rfc1035RetryQuery(q->buf);
579 idnsSendQuery(q);
580 return;
581 }
558be27a 582 }
62e76326 583
fa80a8ef 584 callback = q->callback;
585 q->callback = NULL;
62e76326 586
fa80a8ef 587 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
62e76326 588 callback(cbdata, answers, n);
589
7b724b86 590 rfc1035RRDestroy(answers, n);
62e76326 591
a16b4aa0 592 memFree(q, MEM_IDNS_QUERY);
7b724b86 593}
594
595static void
596idnsRead(int fd, void *data)
597{
d193a436 598 int *N = &incoming_sockets_accepted;
7b724b86 599 ssize_t len;
62e76326 600
7b724b86 601 struct sockaddr_in from;
602 socklen_t from_len;
42b51993 603 int max = INCOMING_DNS_MAX;
d29b40de 604 static char rbuf[SQUID_UDP_SO_RCVBUF];
7cfc1c9a 605 int ns;
62e76326 606
7b724b86 607 while (max--) {
62e76326 608 from_len = sizeof(from);
609 memset(&from, '\0', from_len);
610
611 len = comm_udp_recvfrom(fd, rbuf, 512, 0, (struct sockaddr *) &from, &from_len);
612
613 if (len == 0)
614 break;
615
616 if (len < 0) {
617 if (ignoreErrno(errno))
618 break;
619
7b724b86 620#ifdef _SQUID_LINUX_
62e76326 621 /* Some Linux systems seem to set the FD for reading and then
622 * return ECONNREFUSED when sendto() fails and generates an ICMP
623 * port unreachable message. */
624 /* or maybe an EHOSTUNREACH "No route to host" message */
625 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
7b724b86 626#endif
62e76326 627
628 debug(50, 1) ("idnsRead: FD %d recvfrom: %s\n",
629 fd, xstrerror());
630
631 break;
632 }
633
634 fd_bytes(DnsSocket, len, FD_READ);
635 assert(N);
636 (*N)++;
637 debug(78, 3) ("idnsRead: FD %d: received %d bytes from %s.\n",
638 fd,
639 (int) len,
640 inet_ntoa(from.sin_addr));
641 ns = idnsFromKnownNameserver(&from);
642
643 if (ns >= 0) {
644 nameservers[ns].nreplies++;
645 } else if (Config.onoff.ignore_unknown_nameservers) {
646 static time_t last_warning = 0;
647
648 if (squid_curtime - last_warning > 60) {
649 debug(78, 1) ("WARNING: Reply from unknown nameserver [%s]\n",
650 inet_ntoa(from.sin_addr));
651 last_warning = squid_curtime;
652 }
653
654 continue;
655 }
656
657 if (len > 512) {
658 /*
659 * Check for non-conforming replies. RFC 1035 says
660 * DNS/UDP messages must be 512 octets or less. If we
661 * get one that is too large, we generate a warning
662 * and then pretend that we only got 512 octets. This
663 * should prevent the rfc1035.c code from reading past
664 * the end of our buffer.
665 */
666 static int other_large_pkts = 0;
667 int x;
668 x = (ns < 0) ? ++other_large_pkts : ++nameservers[ns].large_pkts;
669
670 if (isPowTen(x))
671 debug(78, 1) ("WARNING: Got %d large DNS replies from %s\n",
672 x, inet_ntoa(from.sin_addr));
673
674 len = 512;
675 }
676
677 idnsGrokReply(rbuf, len);
7b724b86 678 }
62e76326 679
2e6caa54 680 if (lru_list.head)
62e76326 681 commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0);
7b724b86 682}
683
7cfc1c9a 684static void
685idnsCheckQueue(void *unused)
686{
687 dlink_node *n;
0c4fe9e4 688 dlink_node *p = NULL;
7cfc1c9a 689 idns_query *q;
690 event_queued = 0;
62e76326 691
0c4fe9e4 692 for (n = lru_list.tail; n; n = p) {
62e76326 693 if (0 == nns)
694 /* name servers went away; reconfiguring or shutting down */
695 break;
696
697 q = (idns_query *)n->data;
698
699 if (tvSubDsec(q->sent_t, current_time) < Config.Timeout.idns_retransmit * (1 << q->nsends % nns))
700 break;
701
702 debug(78, 3) ("idnsCheckQueue: ID %#04x timeout\n",
703 q->id);
704
705 p = n->prev;
706
707 dlinkDelete(&q->lru, &lru_list);
708
709 if (tvSubDsec(q->start_t, current_time) < Config.Timeout.idns_query) {
710 idnsSendQuery(q);
711 } else {
712 IDNSCB *callback;
713 void *cbdata;
714 debug(78, 2) ("idnsCheckQueue: ID %x: giving up after %d tries and %5.1f seconds\n",
715 (int) q->id, q->nsends,
716 tvSubDsec(q->start_t, current_time));
717 callback = q->callback;
718 q->callback = NULL;
719
720 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
721 callback(cbdata, NULL, 0);
722
723 memFree(q, MEM_IDNS_QUERY);
724 }
7cfc1c9a 725 }
62e76326 726
efd900cb 727 idnsTickleQueue();
7cfc1c9a 728}
729
558be27a 730/*
731 * rcode < 0 indicates an error, rocde >= 0 indicates success
732 */
733static void
734idnsRcodeCount(int rcode, int attempt)
735{
736 if (rcode > 0)
62e76326 737 rcode = 0;
558be27a 738 else if (rcode < 0)
62e76326 739 rcode = -rcode;
740
558be27a 741 if (rcode < MAX_RCODE)
62e76326 742 if (attempt < MAX_ATTEMPT)
743 RcodeMatrix[rcode][attempt]++;
558be27a 744}
745
7b724b86 746/* ====================================================================== */
747
748void
749idnsInit(void)
750{
751 static int init = 0;
62e76326 752
ef523f99 753 if (DnsSocket < 0) {
62e76326 754 int port;
755
756 struct in_addr addr;
757
758 if (Config.Addrs.udp_outgoing.s_addr != no_addr.s_addr)
759 addr = Config.Addrs.udp_outgoing;
760 else
761 addr = Config.Addrs.udp_incoming;
762
763 DnsSocket = comm_open(SOCK_DGRAM,
bdb741f4 764 IPPROTO_UDP,
62e76326 765 addr,
766 0,
767 COMM_NONBLOCKING,
768 "DNS Socket");
769
770 if (DnsSocket < 0)
771 fatal("Could not create a DNS socket");
772
773 /* Ouch... we can't call functions using debug from a debug
774 * statement. Doing so messes up the internal Debug::level
775 */
776 port = comm_local_port(DnsSocket);
777
778 debug(78, 1) ("DNS Socket created at %s, port %d, FD %d\n",
779 inet_ntoa(addr),
780 port, DnsSocket);
7b724b86 781 }
62e76326 782
efd900cb 783 assert(0 == nns);
784 idnsParseNameservers();
0e6d05ef 785#ifndef _SQUID_MSWIN_
62e76326 786
efd900cb 787 if (0 == nns)
62e76326 788 idnsParseResolvConf();
789
0e6d05ef 790#endif
791#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
62e76326 792
0e6d05ef 793 if (0 == nns)
62e76326 794 idnsParseWIN32Registry();
795
0e6d05ef 796#endif
62e76326 797
42b51993 798 if (0 == nns)
62e76326 799 fatal("Could not find any nameservers.\n"
0e6d05ef 800#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
62e76326 801 " Please check your TCP-IP settings or /etc/resolv.conf file\n"
0e6d05ef 802#else
62e76326 803 " Please check your /etc/resolv.conf file\n"
0e6d05ef 804#endif
62e76326 805 " or use the 'dns_nameservers' option in squid.conf.");
806
7b724b86 807 if (!init) {
62e76326 808 memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
809 cachemgrRegister("idns",
810 "Internal DNS Statistics",
811 idnsStats, 0, 1);
812 memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
813 init++;
7b724b86 814 }
7b724b86 815}
816
817void
818idnsShutdown(void)
819{
ef523f99 820 if (DnsSocket < 0)
62e76326 821 return;
822
ef523f99 823 comm_close(DnsSocket);
62e76326 824
ef523f99 825 DnsSocket = -1;
62e76326 826
efd900cb 827 idnsFreeNameservers();
7b724b86 828}
829
830void
831idnsALookup(const char *name, IDNSCB * callback, void *data)
832{
e6ccf245 833 idns_query *q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
7b724b86 834 q->sz = sizeof(q->buf);
835 q->id = rfc1035BuildAQuery(name, q->buf, &q->sz);
62e76326 836
76cb2b26 837 if (0 == q->id) {
62e76326 838 /* problem with query data -- query not sent */
839 callback(data, NULL, 0);
840 memFree(q, MEM_IDNS_QUERY);
841 return;
76cb2b26 842 }
62e76326 843
a16b4aa0 844 debug(78, 3) ("idnsALookup: buf is %d bytes for %s, id = %#hx\n",
62e76326 845 (int) q->sz, name, q->id);
7b724b86 846 q->callback = callback;
fa80a8ef 847 q->callback_data = cbdataReference(data);
7cfc1c9a 848 q->start_t = current_time;
7b724b86 849 idnsSendQuery(q);
850}
8db71107 851
852void
62e76326 853
8db71107 854idnsPTRLookup(const struct in_addr addr, IDNSCB * callback, void *data)
855{
e6ccf245 856 idns_query *q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
8db71107 857 q->sz = sizeof(q->buf);
858 q->id = rfc1035BuildPTRQuery(addr, q->buf, &q->sz);
859 debug(78, 3) ("idnsPTRLookup: buf is %d bytes for %s, id = %#hx\n",
62e76326 860 (int) q->sz, inet_ntoa(addr), q->id);
8db71107 861 q->callback = callback;
fa80a8ef 862 q->callback_data = cbdataReference(data);
8db71107 863 q->start_t = current_time;
864 idnsSendQuery(q);
865}
eb824054 866
3c573763 867#ifdef SQUID_SNMP
868/*
869 * The function to return the DNS via SNMP
870 */
871variable_list *
872snmp_netIdnsFn(variable_list * Var, snint * ErrP)
873{
874 int i, n = 0;
875 variable_list *Answer = NULL;
38650cc8 876 debug(49, 5) ("snmp_netDnsFn: Processing request: \n");
3c573763 877 snmpDebugOid(5, Var->name, Var->name_length);
878 *ErrP = SNMP_ERR_NOERROR;
62e76326 879
3c573763 880 switch (Var->name[LEN_SQ_NET + 1]) {
62e76326 881
3c573763 882 case DNS_REQ:
62e76326 883
884 for (i = 0; i < nns; i++)
885 n += nameservers[i].nqueries;
886
887 Answer = snmp_var_new_integer(Var->name, Var->name_length,
888 n,
889 SMI_COUNTER32);
890
891 break;
892
3c573763 893 case DNS_REP:
62e76326 894 for (i = 0; i < nns; i++)
895 n += nameservers[i].nreplies;
896
897 Answer = snmp_var_new_integer(Var->name, Var->name_length,
898 n,
899 SMI_COUNTER32);
900
901 break;
902
3c573763 903 case DNS_SERVERS:
62e76326 904 Answer = snmp_var_new_integer(Var->name, Var->name_length,
e494f5e9 905 nns,
62e76326 906 SMI_COUNTER32);
907
908 break;
909
3c573763 910 default:
62e76326 911 *ErrP = SNMP_ERR_NOSUCHNAME;
912
913 break;
3c573763 914 }
62e76326 915
3c573763 916 return Answer;
917}
62e76326 918
3c573763 919#endif /*SQUID_SNMP */