]>
Commit | Line | Data |
---|---|---|
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 | |
85 | static int RcodeMatrix[MAX_RCODE][MAX_ATTEMPT]; | |
86 | ||
58a39dc9 | 87 | typedef struct _idns_query idns_query; |
62e76326 | 88 | |
7b724b86 | 89 | typedef struct _ns ns; |
58a39dc9 | 90 | |
68836b58 | 91 | typedef struct _sp sp; |
92 | ||
d24ef4e9 | 93 | typedef struct _nsvc nsvc; |
94 | ||
62e76326 | 95 | struct _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 | 121 | struct _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 | 132 | struct _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 | 142 | struct _sp |
143 | { | |
144 | char domain[NS_MAXDNAME]; | |
145 | int queries; | |
146 | }; | |
147 | ||
d24ef4e9 | 148 | CBDATA_TYPE(nsvc); |
149 | ||
7b724b86 | 150 | static ns *nameservers = NULL; |
68836b58 | 151 | static sp *searchpath = NULL; |
7b724b86 | 152 | static int nns = 0; |
153 | static int nns_alloc = 0; | |
68836b58 | 154 | static int npc = 0; |
155 | static int npc_alloc = 0; | |
156 | static int ndots = 1; | |
7b724b86 | 157 | static dlink_list lru_list; |
7cfc1c9a | 158 | static int event_queued = 0; |
3074b9d1 | 159 | static hash_table *idns_lookup_hash = NULL; |
7b724b86 | 160 | |
161 | static OBJH idnsStats; | |
162 | static void idnsAddNameserver(const char *buf); | |
68836b58 | 163 | static void idnsAddPathComponent(const char *buf); |
7b724b86 | 164 | static void idnsFreeNameservers(void); |
68836b58 | 165 | static void idnsFreeSearchpath(void); |
efd900cb | 166 | static void idnsParseNameservers(void); |
1f1ae50a | 167 | #ifndef _SQUID_MSWIN_ |
7b724b86 | 168 | static void idnsParseResolvConf(void); |
1f1ae50a | 169 | #endif |
ec4daaa5 | 170 | #ifdef _SQUID_WIN32_ |
0e6d05ef | 171 | static void idnsParseWIN32Registry(void); |
d02b72b4 | 172 | static void idnsParseWIN32SearchList(const char *); |
0e6d05ef | 173 | #endif |
68836b58 | 174 | static void idnsCacheQuery(idns_query * q); |
7b724b86 | 175 | static void idnsSendQuery(idns_query * q); |
d24ef4e9 | 176 | static IOCB idnsReadVCHeader; |
62e76326 | 177 | |
7b724b86 | 178 | static int idnsFromKnownNameserver(struct sockaddr_in *from); |
179 | static idns_query *idnsFindQuery(unsigned short id); | |
180 | static void idnsGrokReply(const char *buf, size_t sz); | |
181 | static PF idnsRead; | |
7cfc1c9a | 182 | static EVH idnsCheckQueue; |
efd900cb | 183 | static void idnsTickleQueue(void); |
558be27a | 184 | static void idnsRcodeCount(int, int); |
7b724b86 | 185 | |
186 | static void | |
187 | idnsAddNameserver(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 | 230 | static void |
231 | idnsAddPathComponent(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 | 259 | static void |
260 | idnsFreeNameservers(void) | |
261 | { | |
262 | safe_free(nameservers); | |
263 | nns = nns_alloc = 0; | |
264 | } | |
265 | ||
68836b58 | 266 | static void |
267 | idnsFreeSearchpath(void) | |
268 | { | |
269 | safe_free(searchpath); | |
270 | npc = npc_alloc = 0; | |
271 | } | |
272 | ||
273 | ||
274 | ||
efd900cb | 275 | static void |
276 | idnsParseNameservers(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 | 287 | static void |
288 | idnsParseResolvConf(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 | 355 | static void |
d02b72b4 | 356 | idnsParseWIN32SearchList(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 | 389 | static void |
390 | idnsParseWIN32Registry(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 | 564 | static void |
565 | idnsStats(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 | 623 | static void |
624 | idnsTickleQueue(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 | 637 | static void idnsDoSendQueryVC(nsvc *vc); |
638 | ||
639 | static void | |
640 | idnsSentQueryVC(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 | ||
656 | static void | |
657 | idnsDoSendQueryVC(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 | ||
678 | static void | |
679 | idnsInitVCConnected(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 | ||
693 | static void | |
694 | idnsVCClosed(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 | ||
703 | static void | |
704 | idnsInitVC(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 | ||
737 | static void | |
738 | idnsSendQueryVC(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 | 756 | static void |
757 | idnsSendQuery(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 | |
774 | try_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 | ||
807 | static int | |
62e76326 | 808 | |
7b724b86 | 809 | idnsFromKnownNameserver(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 | ||
827 | static idns_query * | |
828 | idnsFindQuery(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 | 843 | static unsigned short |
844 | idnsQueryID(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 | 861 | static void |
862 | idnsCallback(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 | 891 | static void |
892 | idnsGrokReply(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 | ||
993 | static void | |
994 | idnsRead(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 | 1062 | static void |
1063 | idnsCheckQueue(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 | 1106 | static void |
1107 | idnsReadVC(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 | ||
1136 | static void | |
1137 | idnsReadVCHeader(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 | */ | |
1169 | static void | |
1170 | idnsRcodeCount(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 | ||
1184 | void | |
1185 | idnsInit(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 | 1258 | void |
1259 | idnsRegisterWithCacheManager(CacheManager & manager) | |
1260 | { | |
1261 | manager.registerAction("idns", "Internal DNS Statistics", idnsStats, 0, 1); | |
1262 | } | |
1263 | ||
7b724b86 | 1264 | void |
1265 | idnsShutdown(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 | 1279 | static int |
1280 | idnsCachedLookup(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 | ||
1302 | static void | |
9e1f210d | 1303 | idnsCacheQuery(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 | 1309 | void |
1310 | idnsALookup(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 | |
1368 | void | |
62e76326 | 1369 | |
ddfcbc22 | 1370 | idnsPTRLookup(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 | */ | |
1411 | variable_list * | |
1412 | snmp_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 */ |