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