]>
Commit | Line | Data |
---|---|---|
f88bb09c | 1 | |
2 | /* | |
365e5b34 | 3 | * $Id: fqdncache.cc,v 1.57 1997/06/26 22:35:46 wessels Exp $ |
f88bb09c | 4 | * |
7cf620a9 | 5 | * DEBUG: section 35 FQDN Cache |
f88bb09c | 6 | * AUTHOR: Harvest Derived |
7 | * | |
42c04c16 | 8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ |
f88bb09c | 9 | * -------------------------------------------------------- |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
13 | * National Laboratory for Applied Network Research and funded by | |
14 | * the National Science Foundation. | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
29 | * | |
30 | */ | |
31 | ||
32 | /* | |
33 | * Copyright (c) 1994, 1995. All rights reserved. | |
34 | * | |
35 | * The Harvest software was developed by the Internet Research Task | |
36 | * Force Research Group on Resource Discovery (IRTF-RD): | |
37 | * | |
38 | * Mic Bowman of Transarc Corporation. | |
39 | * Peter Danzig of the University of Southern California. | |
40 | * Darren R. Hardy of the University of Colorado at Boulder. | |
41 | * Udi Manber of the University of Arizona. | |
42 | * Michael F. Schwartz of the University of Colorado at Boulder. | |
43 | * Duane Wessels of the University of Colorado at Boulder. | |
44 | * | |
45 | * This copyright notice applies to software in the Harvest | |
46 | * ``src/'' directory only. Users should consult the individual | |
47 | * copyright notices in the ``components/'' subdirectories for | |
48 | * copyright information about other software bundled with the | |
49 | * Harvest source code distribution. | |
50 | * | |
51 | * TERMS OF USE | |
52 | * | |
53 | * The Harvest software may be used and re-distributed without | |
54 | * charge, provided that the software origin and research team are | |
55 | * cited in any use of the system. Most commonly this is | |
56 | * accomplished by including a link to the Harvest Home Page | |
57 | * (http://harvest.cs.colorado.edu/) from the query page of any | |
58 | * Broker you deploy, as well as in the query result pages. These | |
59 | * links are generated automatically by the standard Broker | |
60 | * software distribution. | |
61 | * | |
62 | * The Harvest software is provided ``as is'', without express or | |
63 | * implied warranty, and with no support nor obligation to assist | |
64 | * in its use, correction, modification or enhancement. We assume | |
65 | * no liability with respect to the infringement of copyrights, | |
66 | * trade secrets, or any patents, and are not responsible for | |
67 | * consequential damages. Proper use of the Harvest software is | |
68 | * entirely the responsibility of the user. | |
69 | * | |
70 | * DERIVATIVE WORKS | |
71 | * | |
72 | * Users may make derivative works from the Harvest software, subject | |
73 | * to the following constraints: | |
74 | * | |
75 | * - You must include the above copyright notice and these | |
76 | * accompanying paragraphs in all forms of derivative works, | |
77 | * and any documentation and other materials related to such | |
78 | * distribution and use acknowledge that the software was | |
79 | * developed at the above institutions. | |
80 | * | |
81 | * - You must notify IRTF-RD regarding your distribution of | |
82 | * the derivative work. | |
83 | * | |
84 | * - You must clearly notify users that your are distributing | |
85 | * a modified version and not the original Harvest software. | |
86 | * | |
87 | * - Any derivative product is also subject to these copyright | |
88 | * and use restrictions. | |
89 | * | |
90 | * Note that the Harvest software is NOT in the public domain. We | |
91 | * retain copyright, as specified above. | |
92 | * | |
93 | * HISTORY OF FREE SOFTWARE STATUS | |
94 | * | |
95 | * Originally we required sites to license the software in cases | |
96 | * where they were going to build commercial products/services | |
97 | * around Harvest. In June 1995 we changed this policy. We now | |
98 | * allow people to use the core Harvest software (the code found in | |
99 | * the Harvest ``src/'' directory) for free. We made this change | |
100 | * in the interest of encouraging the widest possible deployment of | |
101 | * the technology. The Harvest software is really a reference | |
102 | * implementation of a set of protocols and formats, some of which | |
103 | * we intend to standardize. We encourage commercial | |
104 | * re-implementations of code complying to this set of standards. | |
105 | */ | |
106 | ||
107 | #include "squid.h" | |
108 | ||
109 | #define MAX_LINELEN (4096) | |
110 | ||
111 | #define MAX_FQDN 1024 /* Maximum cached FQDN */ | |
112 | #define FQDN_LOW_WATER 90 | |
113 | #define FQDN_HIGH_WATER 95 | |
f88bb09c | 114 | |
115 | struct _fqdn_pending { | |
582b6456 | 116 | FQDNH *handler; |
f88bb09c | 117 | void *handlerData; |
118 | struct _fqdn_pending *next; | |
119 | }; | |
120 | ||
121 | struct fqdncacheQueueData { | |
122 | struct fqdncacheQueueData *next; | |
123 | fqdncache_entry *f; | |
124 | }; | |
125 | ||
126 | static struct { | |
127 | int requests; | |
128 | int replies; | |
129 | int hits; | |
130 | int misses; | |
131 | int pending_hits; | |
132 | int negative_hits; | |
133 | int errors; | |
134 | int avg_svc_time; | |
135 | int ghba_calls; /* # calls to blocking gethostbyaddr() */ | |
136 | } FqdncacheStats; | |
137 | ||
67508012 | 138 | static int fqdncache_compareLastRef _PARAMS((fqdncache_entry **, fqdncache_entry **)); |
00046e88 | 139 | static void fqdncache_dnsHandleRead _PARAMS((int, void *)); |
0ee4272b | 140 | static fqdncache_entry *fqdncache_parsebuffer _PARAMS((const char *buf, dnsserver_t *)); |
67508012 | 141 | static int fqdncache_purgelru _PARAMS((void)); |
142 | static void fqdncache_release _PARAMS((fqdncache_entry *)); | |
143 | static fqdncache_entry *fqdncache_GetFirst _PARAMS((void)); | |
144 | static fqdncache_entry *fqdncache_GetNext _PARAMS((void)); | |
429fdbec | 145 | static fqdncache_entry *fqdncache_create _PARAMS((const char *name)); |
67508012 | 146 | static void fqdncache_add_to_hash _PARAMS((fqdncache_entry *)); |
147 | static void fqdncache_call_pending _PARAMS((fqdncache_entry *)); | |
429fdbec | 148 | static void fqdncacheAddHostent _PARAMS((fqdncache_entry *, const struct hostent *)); |
0ee4272b | 149 | static int fqdncacheHasPending _PARAMS((const fqdncache_entry *)); |
150 | static fqdncache_entry *fqdncache_get _PARAMS((const char *)); | |
348b2031 | 151 | static FQDNH dummy_handler; |
0ee4272b | 152 | static int fqdncacheExpiredEntry _PARAMS((const fqdncache_entry *)); |
348b2031 | 153 | static void fqdncacheAddPending _PARAMS((fqdncache_entry *, FQDNH *, void *)); |
67508012 | 154 | static void fqdncacheEnqueue _PARAMS((fqdncache_entry *)); |
155 | static void *fqdncacheDequeue _PARAMS((void)); | |
156 | static void fqdncache_dnsDispatch _PARAMS((dnsserver_t *, fqdncache_entry *)); | |
429fdbec | 157 | static void fqdncacheChangeKey _PARAMS((fqdncache_entry * i)); |
158 | static void fqdncacheLockEntry _PARAMS((fqdncache_entry * f)); | |
159 | static void fqdncacheUnlockEntry _PARAMS((fqdncache_entry * f)); | |
f88bb09c | 160 | |
365e5b34 | 161 | static hash_table *fqdn_table = NULL; |
f88bb09c | 162 | static struct fqdncacheQueueData *fqdncacheQueueHead = NULL; |
163 | static struct fqdncacheQueueData **fqdncacheQueueTailP = &fqdncacheQueueHead; | |
164 | ||
165 | static char fqdncache_status_char[] = | |
166 | { | |
167 | 'C', | |
168 | 'N', | |
169 | 'P', | |
170 | 'D' | |
171 | }; | |
172 | ||
24382924 | 173 | static long fqdncache_low = 180; |
174 | static long fqdncache_high = 200; | |
f88bb09c | 175 | |
b8d8561b | 176 | static void |
177 | fqdncacheEnqueue(fqdncache_entry * f) | |
f88bb09c | 178 | { |
179 | struct fqdncacheQueueData *new = xcalloc(1, sizeof(struct fqdncacheQueueData)); | |
180 | new->f = f; | |
181 | *fqdncacheQueueTailP = new; | |
182 | fqdncacheQueueTailP = &new->next; | |
183 | } | |
184 | ||
b8d8561b | 185 | static void * |
0673c0ba | 186 | fqdncacheDequeue(void) |
f88bb09c | 187 | { |
188 | struct fqdncacheQueueData *old = NULL; | |
189 | fqdncache_entry *f = NULL; | |
190 | if (fqdncacheQueueHead) { | |
191 | f = fqdncacheQueueHead->f; | |
192 | old = fqdncacheQueueHead; | |
193 | fqdncacheQueueHead = fqdncacheQueueHead->next; | |
194 | if (fqdncacheQueueHead == NULL) | |
195 | fqdncacheQueueTailP = &fqdncacheQueueHead; | |
196 | safe_free(old); | |
197 | } | |
429fdbec | 198 | if (f && f->status != FQDN_PENDING) |
199 | debug_trap("fqdncacheDequeue: status != FQDN_PENDING"); | |
f88bb09c | 200 | return f; |
201 | } | |
202 | ||
203 | /* removes the given fqdncache entry */ | |
b8d8561b | 204 | static void |
205 | fqdncache_release(fqdncache_entry * f) | |
f88bb09c | 206 | { |
f88bb09c | 207 | hash_link *table_entry = NULL; |
208 | int k; | |
209 | ||
210 | if ((table_entry = hash_lookup(fqdn_table, f->name)) == NULL) { | |
a3d5953d | 211 | debug(35, 0) ("fqdncache_release: Could not find key '%s'\n", f->name); |
f88bb09c | 212 | return; |
213 | } | |
429fdbec | 214 | if (f != (fqdncache_entry *) table_entry) |
215 | fatal_dump("fqdncache_release: f != table_entry!"); | |
f88bb09c | 216 | if (f->status == FQDN_PENDING) { |
a3d5953d | 217 | debug(35, 1) ("fqdncache_release: Someone called on a PENDING entry\n"); |
f88bb09c | 218 | return; |
219 | } | |
220 | if (f->status == FQDN_DISPATCHED) { | |
a3d5953d | 221 | debug(35, 1) ("fqdncache_release: Someone called on a DISPATCHED entry\n"); |
f88bb09c | 222 | return; |
223 | } | |
348b2031 | 224 | if (f->pending_head) |
225 | fatal_dump("fqdncache_release: still have pending clients"); | |
f88bb09c | 226 | if (hash_remove_link(fqdn_table, table_entry)) { |
a3d5953d | 227 | debug(35, 0) ("fqdncache_release: hash_remove_link() failed for '%s'\n", |
429fdbec | 228 | f->name); |
f88bb09c | 229 | return; |
230 | } | |
429fdbec | 231 | if (f->status == FQDN_CACHED) { |
f88bb09c | 232 | for (k = 0; k < (int) f->name_count; k++) |
233 | safe_free(f->names[k]); | |
a3d5953d | 234 | debug(35, 5) ("fqdncache_release: Released FQDN record for '%s'.\n", |
429fdbec | 235 | f->name); |
f88bb09c | 236 | } |
429fdbec | 237 | safe_free(f->name); |
238 | safe_free(f->error_message); | |
239 | safe_free(f); | |
f88bb09c | 240 | --meta_data.fqdncache_count; |
241 | return; | |
242 | } | |
243 | ||
244 | /* return match for given name */ | |
b8d8561b | 245 | static fqdncache_entry * |
0ee4272b | 246 | fqdncache_get(const char *name) |
f88bb09c | 247 | { |
248 | hash_link *e; | |
249 | static fqdncache_entry *f; | |
250 | ||
251 | f = NULL; | |
252 | if (fqdn_table) { | |
253 | if ((e = hash_lookup(fqdn_table, name)) != NULL) | |
254 | f = (fqdncache_entry *) e; | |
255 | } | |
256 | return f; | |
257 | } | |
258 | ||
b8d8561b | 259 | static fqdncache_entry * |
0673c0ba | 260 | fqdncache_GetFirst(void) |
f88bb09c | 261 | { |
262 | return (fqdncache_entry *) hash_first(fqdn_table); | |
263 | } | |
264 | ||
b8d8561b | 265 | static fqdncache_entry * |
0673c0ba | 266 | fqdncache_GetNext(void) |
f88bb09c | 267 | { |
268 | return (fqdncache_entry *) hash_next(fqdn_table); | |
269 | } | |
270 | ||
b8d8561b | 271 | static int |
272 | fqdncache_compareLastRef(fqdncache_entry ** e1, fqdncache_entry ** e2) | |
f88bb09c | 273 | { |
274 | if (!e1 || !e2) | |
275 | fatal_dump(NULL); | |
276 | if ((*e1)->lastref > (*e2)->lastref) | |
277 | return (1); | |
278 | if ((*e1)->lastref < (*e2)->lastref) | |
279 | return (-1); | |
280 | return (0); | |
281 | } | |
282 | ||
b8d8561b | 283 | static int |
fe4e214f | 284 | fqdncacheExpiredEntry(const fqdncache_entry * f) |
f88bb09c | 285 | { |
286 | if (f->status == FQDN_PENDING) | |
287 | return 0; | |
288 | if (f->status == FQDN_DISPATCHED) | |
289 | return 0; | |
429fdbec | 290 | if (f->locks != 0) |
291 | return 0; | |
e84703ad | 292 | if (f->expires > squid_curtime) |
f88bb09c | 293 | return 0; |
294 | return 1; | |
295 | } | |
296 | ||
297 | /* finds the LRU and deletes */ | |
b8d8561b | 298 | static int |
0673c0ba | 299 | fqdncache_purgelru(void) |
f88bb09c | 300 | { |
301 | fqdncache_entry *f = NULL; | |
302 | int local_fqdn_count = 0; | |
303 | int local_fqdn_notpending_count = 0; | |
304 | int removed = 0; | |
305 | int k; | |
306 | fqdncache_entry **LRU_list = NULL; | |
307 | int LRU_list_count = 0; | |
308 | int LRU_cur_size = meta_data.fqdncache_count; | |
309 | ||
310 | LRU_list = xcalloc(LRU_cur_size, sizeof(fqdncache_entry *)); | |
311 | ||
312 | for (f = fqdncache_GetFirst(); f; f = fqdncache_GetNext()) { | |
313 | if (fqdncacheExpiredEntry(f)) { | |
314 | fqdncache_release(f); | |
315 | removed++; | |
316 | continue; | |
317 | } | |
318 | local_fqdn_count++; | |
319 | ||
320 | if (LRU_list_count >= LRU_cur_size) { | |
321 | /* have to realloc */ | |
322 | LRU_cur_size += 16; | |
a3d5953d | 323 | debug(35, 3) ("fqdncache_purgelru: Have to grow LRU_list to %d. This shouldn't happen.\n", |
f88bb09c | 324 | LRU_cur_size); |
325 | LRU_list = xrealloc((char *) LRU_list, | |
326 | LRU_cur_size * sizeof(fqdncache_entry *)); | |
327 | } | |
328 | if (f->status == FQDN_PENDING) | |
329 | continue; | |
330 | if (f->status == FQDN_DISPATCHED) | |
331 | continue; | |
332 | local_fqdn_notpending_count++; | |
333 | LRU_list[LRU_list_count++] = f; | |
334 | } | |
335 | ||
a3d5953d | 336 | debug(35, 3) ("fqdncache_purgelru: fqdncache_count: %5d\n", meta_data.fqdncache_count); |
337 | debug(35, 3) (" actual count : %5d\n", local_fqdn_count); | |
338 | debug(35, 3) (" high W mark : %5d\n", fqdncache_high); | |
339 | debug(35, 3) (" low W mark : %5d\n", fqdncache_low); | |
340 | debug(35, 3) (" not pending : %5d\n", local_fqdn_notpending_count); | |
341 | debug(35, 3) (" LRU candidates : %5d\n", LRU_list_count); | |
f88bb09c | 342 | |
343 | /* sort LRU candidate list */ | |
344 | qsort((char *) LRU_list, | |
345 | LRU_list_count, | |
429fdbec | 346 | sizeof(fqdncache_entry *), |
582b6456 | 347 | (QS *) fqdncache_compareLastRef); |
429fdbec | 348 | for (k = 0; k < LRU_list_count; k++) { |
349 | if (meta_data.fqdncache_count < fqdncache_low) | |
350 | break; | |
351 | if (LRU_list[k] == NULL) | |
352 | break; | |
f88bb09c | 353 | fqdncache_release(LRU_list[k]); |
354 | removed++; | |
355 | } | |
356 | ||
a3d5953d | 357 | debug(35, 3) (" removed : %5d\n", removed); |
f88bb09c | 358 | safe_free(LRU_list); |
359 | return (removed > 0) ? 0 : -1; | |
360 | } | |
361 | ||
362 | ||
363 | /* create blank fqdncache_entry */ | |
b8d8561b | 364 | static fqdncache_entry * |
429fdbec | 365 | fqdncache_create(const char *name) |
f88bb09c | 366 | { |
367 | static fqdncache_entry *new; | |
368 | ||
369 | if (meta_data.fqdncache_count > fqdncache_high) { | |
370 | if (fqdncache_purgelru() < 0) | |
a3d5953d | 371 | debug(35, 0) ("HELP!! FQDN Cache is overflowing!\n"); |
f88bb09c | 372 | } |
373 | meta_data.fqdncache_count++; | |
374 | new = xcalloc(1, sizeof(fqdncache_entry)); | |
429fdbec | 375 | new->name = xstrdup(name); |
376 | new->expires = squid_curtime + Config.negativeDnsTtl; | |
377 | fqdncache_add_to_hash(new); | |
f88bb09c | 378 | return new; |
f88bb09c | 379 | } |
380 | ||
b8d8561b | 381 | static void |
382 | fqdncache_add_to_hash(fqdncache_entry * f) | |
f88bb09c | 383 | { |
384 | if (hash_join(fqdn_table, (hash_link *) f)) { | |
a3d5953d | 385 | debug(35, 1) ("fqdncache_add_to_hash: Cannot add %s (%p) to hash table %d.\n", |
f88bb09c | 386 | f->name, f, fqdn_table); |
387 | } | |
a3d5953d | 388 | debug(35, 5) ("fqdncache_add_to_hash: name <%s>\n", f->name); |
f88bb09c | 389 | } |
390 | ||
b8d8561b | 391 | static void |
429fdbec | 392 | fqdncacheAddHostent(fqdncache_entry * f, const struct hostent *hp) |
f88bb09c | 393 | { |
394 | int k; | |
429fdbec | 395 | f->name_count = 0; |
396 | f->names[f->name_count++] = xstrdup((char *) hp->h_name); | |
397 | for (k = 0; hp->h_aliases[k]; k++) { | |
398 | f->names[f->name_count++] = xstrdup(hp->h_aliases[k]); | |
399 | if (f->name_count == FQDN_MAX_NAMES) | |
400 | break; | |
401 | } | |
402 | } | |
f88bb09c | 403 | |
429fdbec | 404 | static fqdncache_entry * |
405 | fqdncacheAddNew(const char *name, const struct hostent *hp, fqdncache_status_t status) | |
406 | { | |
407 | fqdncache_entry *f; | |
f88bb09c | 408 | if (fqdncache_get(name)) |
429fdbec | 409 | fatal_dump("fqdncacheAddNew: somebody adding a duplicate!"); |
a3d5953d | 410 | debug(14, 10) ("fqdncacheAddNew: Adding '%s', status=%c\n", |
429fdbec | 411 | name, |
412 | fqdncache_status_char[status]); | |
413 | f = fqdncache_create(name); | |
414 | if (hp) | |
415 | fqdncacheAddHostent(f, hp); | |
416 | f->status = status; | |
417 | f->lastref = squid_curtime; | |
418 | return f; | |
f88bb09c | 419 | } |
420 | ||
421 | /* walks down the pending list, calling handlers */ | |
b8d8561b | 422 | static void |
423 | fqdncache_call_pending(fqdncache_entry * f) | |
f88bb09c | 424 | { |
425 | struct _fqdn_pending *p = NULL; | |
426 | int nhandler = 0; | |
427 | ||
428 | f->lastref = squid_curtime; | |
429 | ||
429fdbec | 430 | fqdncacheLockEntry(f); |
f88bb09c | 431 | while (f->pending_head != NULL) { |
432 | p = f->pending_head; | |
433 | f->pending_head = p->next; | |
434 | if (p->handler) { | |
435 | nhandler++; | |
436 | dns_error_message = f->error_message; | |
348b2031 | 437 | p->handler((f->status == FQDN_CACHED) ? f->names[0] : NULL, |
f88bb09c | 438 | p->handlerData); |
439 | } | |
f88bb09c | 440 | safe_free(p); |
441 | } | |
442 | f->pending_head = NULL; /* nuke list */ | |
a3d5953d | 443 | debug(35, 10) ("fqdncache_call_pending: Called %d handlers.\n", nhandler); |
429fdbec | 444 | fqdncacheUnlockEntry(f); |
f88bb09c | 445 | } |
446 | ||
b8d8561b | 447 | static fqdncache_entry * |
fe4e214f | 448 | fqdncache_parsebuffer(const char *inbuf, dnsserver_t * dnsData) |
f88bb09c | 449 | { |
e84703ad | 450 | char *buf = xstrdup(inbuf); |
451 | char *token; | |
452 | static fqdncache_entry f; | |
453 | int k; | |
f88bb09c | 454 | int ipcount; |
455 | int aliascount; | |
a3d5953d | 456 | debug(35, 5) ("fqdncache_parsebuffer: parsing:\n%s", inbuf); |
e84703ad | 457 | memset(&f, '\0', sizeof(fqdncache_entry)); |
458 | f.expires = squid_curtime + Config.positiveDnsTtl; | |
620da955 | 459 | f.status = FQDN_DISPATCHED; |
e84703ad | 460 | for (token = strtok(buf, w_space); token; token = strtok(NULL, w_space)) { |
461 | if (!strcmp(token, "$end")) { | |
f88bb09c | 462 | break; |
e84703ad | 463 | } else if (!strcmp(token, "$alive")) { |
f88bb09c | 464 | dnsData->answer = squid_curtime; |
e84703ad | 465 | } else if (!strcmp(token, "$fail")) { |
4bcfeca1 | 466 | if ((token = strtok(NULL, "\n")) == NULL) |
e84703ad | 467 | fatal_dump("Invalid $fail"); |
468 | f.expires = squid_curtime + Config.negativeDnsTtl; | |
620da955 | 469 | f.status = FQDN_NEGATIVE_CACHED; |
e84703ad | 470 | } else if (!strcmp(token, "$message")) { |
471 | if ((token = strtok(NULL, "\n")) == NULL) | |
472 | fatal_dump("Invalid $message"); | |
473 | f.error_message = xstrdup(token); | |
474 | } else if (!strcmp(token, "$name")) { | |
475 | if ((token = strtok(NULL, w_space)) == NULL) | |
476 | fatal_dump("Invalid $name"); | |
620da955 | 477 | f.status = FQDN_CACHED; |
e84703ad | 478 | } else if (!strcmp(token, "$h_name")) { |
479 | if ((token = strtok(NULL, w_space)) == NULL) | |
480 | fatal_dump("Invalid $h_name"); | |
481 | f.names[0] = xstrdup(token); | |
482 | f.name_count = 1; | |
483 | } else if (!strcmp(token, "$h_len")) { | |
484 | if ((token = strtok(NULL, w_space)) == NULL) | |
485 | fatal_dump("Invalid $h_len"); | |
486 | } else if (!strcmp(token, "$ipcount")) { | |
487 | if ((token = strtok(NULL, w_space)) == NULL) | |
488 | fatal_dump("Invalid $ipcount"); | |
489 | ipcount = atoi(token); | |
490 | for (k = 0; k < ipcount; k++) { | |
491 | if ((token = strtok(NULL, w_space)) == NULL) | |
620da955 | 492 | fatal_dump("Invalid FQDN address"); |
f88bb09c | 493 | } |
e84703ad | 494 | } else if (!strcmp(token, "$aliascount")) { |
495 | if ((token = strtok(NULL, w_space)) == NULL) | |
496 | fatal_dump("Invalid $aliascount"); | |
497 | aliascount = atoi(token); | |
498 | for (k = 0; k < aliascount; k++) { | |
499 | if ((token = strtok(NULL, w_space)) == NULL) | |
500 | fatal_dump("Invalid alias"); | |
f88bb09c | 501 | } |
e84703ad | 502 | } else if (!strcmp(token, "$ttl")) { |
503 | if ((token = strtok(NULL, w_space)) == NULL) | |
504 | fatal_dump("Invalid $ttl"); | |
505 | f.expires = squid_curtime + atoi(token); | |
f88bb09c | 506 | } else { |
e84703ad | 507 | fatal_dump("Invalid dnsserver output"); |
f88bb09c | 508 | } |
509 | } | |
e84703ad | 510 | xfree(buf); |
511 | return &f; | |
f88bb09c | 512 | } |
513 | ||
429fdbec | 514 | static void |
515 | fqdncacheNudgeQueue(void) | |
516 | { | |
517 | dnsserver_t *dnsData; | |
518 | fqdncache_entry *f = NULL; | |
519 | while ((dnsData = dnsGetFirstAvailable()) && (f = fqdncacheDequeue())) | |
520 | fqdncache_dnsDispatch(dnsData, f); | |
521 | } | |
522 | ||
b785f8ca | 523 | static void |
4f07153c | 524 | fqdncache_dnsHandleRead(int fd, void *data) |
f88bb09c | 525 | { |
2f549d83 | 526 | dnsserver_t *dnsData = data; |
f88bb09c | 527 | int len; |
f88bb09c | 528 | int n; |
529 | fqdncache_entry *f = NULL; | |
e84703ad | 530 | fqdncache_entry *x = NULL; |
f88bb09c | 531 | |
532 | len = read(fd, | |
533 | dnsData->ip_inbuf + dnsData->offset, | |
534 | dnsData->size - dnsData->offset); | |
4f92c80c | 535 | fd_bytes(fd, len, FD_READ); |
a3d5953d | 536 | debug(35, 5) ("fqdncache_dnsHandleRead: Result from DNS ID %d (%d bytes)\n", |
f88bb09c | 537 | dnsData->id, len); |
538 | if (len <= 0) { | |
0a0bf5db | 539 | if (len < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)) { |
540 | commSetSelect(fd, | |
541 | COMM_SELECT_READ, | |
542 | fqdncache_dnsHandleRead, | |
543 | dnsData, 0); | |
544 | return; | |
545 | } | |
a3d5953d | 546 | debug(35, dnsData->flags & DNS_FLAG_CLOSING ? 5 : 1) |
547 | ("FD %d: Connection from DNSSERVER #%d is closed, disabling\n", | |
f88bb09c | 548 | fd, dnsData->id); |
549 | dnsData->flags = 0; | |
b177367b | 550 | commSetSelect(fd, |
f88bb09c | 551 | COMM_SELECT_WRITE, |
552 | NULL, | |
b177367b | 553 | NULL, |
85d7ea98 | 554 | 0); |
f88bb09c | 555 | comm_close(fd); |
2f549d83 | 556 | return; |
f88bb09c | 557 | } |
558 | n = ++FqdncacheStats.replies; | |
b0c9fba9 | 559 | DnsStats.replies++; |
f88bb09c | 560 | dnsData->offset += len; |
561 | dnsData->ip_inbuf[dnsData->offset] = '\0'; | |
429fdbec | 562 | f = dnsData->data; |
563 | if (f->status != FQDN_DISPATCHED) | |
564 | fatal_dump("fqdncache_dnsHandleRead: bad status"); | |
f88bb09c | 565 | if (strstr(dnsData->ip_inbuf, "$end\n")) { |
566 | /* end of record found */ | |
9e4ad609 | 567 | FqdncacheStats.avg_svc_time = |
568 | intAverage(FqdncacheStats.avg_svc_time, | |
569 | tvSubMsec(dnsData->dispatch_time, current_time), | |
570 | n, FQDNCACHE_AV_FACTOR); | |
e84703ad | 571 | if ((x = fqdncache_parsebuffer(dnsData->ip_inbuf, dnsData)) == NULL) { |
a3d5953d | 572 | debug(35, 0) ("fqdncache_dnsHandleRead: fqdncache_parsebuffer failed?!\n"); |
e84703ad | 573 | } else { |
574 | dnsData->offset = 0; | |
575 | dnsData->ip_inbuf[0] = '\0'; | |
e84703ad | 576 | f->name_count = x->name_count; |
7690e8eb | 577 | for (n = 0; n < (int) f->name_count; n++) |
e84703ad | 578 | f->names[n] = x->names[n]; |
579 | f->error_message = x->error_message; | |
580 | f->status = x->status; | |
581 | f->expires = x->expires; | |
582 | fqdncache_call_pending(f); | |
f88bb09c | 583 | } |
429fdbec | 584 | fqdncacheUnlockEntry(f); /* unlock from FQDN_DISPATCHED */ |
f88bb09c | 585 | } |
586 | if (dnsData->offset == 0) { | |
587 | dnsData->data = NULL; | |
588 | dnsData->flags &= ~DNS_FLAG_BUSY; | |
589 | } | |
2f549d83 | 590 | /* reschedule */ |
591 | commSetSelect(dnsData->inpipe, | |
592 | COMM_SELECT_READ, | |
593 | fqdncache_dnsHandleRead, | |
594 | dnsData, 0); | |
429fdbec | 595 | fqdncacheNudgeQueue(); |
f88bb09c | 596 | } |
597 | ||
b8d8561b | 598 | static void |
348b2031 | 599 | fqdncacheAddPending(fqdncache_entry * f, FQDNH * handler, void *handlerData) |
f88bb09c | 600 | { |
601 | struct _fqdn_pending *pending = xcalloc(1, sizeof(struct _fqdn_pending)); | |
602 | struct _fqdn_pending **I = NULL; | |
429fdbec | 603 | f->lastref = squid_curtime; |
f88bb09c | 604 | pending->handler = handler; |
605 | pending->handlerData = handlerData; | |
f88bb09c | 606 | for (I = &(f->pending_head); *I; I = &((*I)->next)); |
607 | *I = pending; | |
429fdbec | 608 | if (f->status == IP_PENDING) |
609 | fqdncacheNudgeQueue(); | |
f88bb09c | 610 | } |
611 | ||
429fdbec | 612 | void |
348b2031 | 613 | fqdncache_nbgethostbyaddr(struct in_addr addr, FQDNH * handler, void *handlerData) |
f88bb09c | 614 | { |
615 | fqdncache_entry *f = NULL; | |
616 | dnsserver_t *dnsData = NULL; | |
617 | char *name = inet_ntoa(addr); | |
618 | ||
619 | if (!handler) | |
620 | fatal_dump("fqdncache_nbgethostbyaddr: NULL handler"); | |
621 | ||
a3d5953d | 622 | debug(35, 4) ("fqdncache_nbgethostbyaddr: Name '%s'.\n", name); |
f88bb09c | 623 | FqdncacheStats.requests++; |
624 | ||
625 | if (name == NULL || name[0] == '\0') { | |
a3d5953d | 626 | debug(35, 4) ("fqdncache_nbgethostbyaddr: Invalid name!\n"); |
348b2031 | 627 | handler(NULL, handlerData); |
429fdbec | 628 | return; |
f88bb09c | 629 | } |
630 | if ((f = fqdncache_get(name))) { | |
631 | if (fqdncacheExpiredEntry(f)) { | |
632 | fqdncache_release(f); | |
633 | f = NULL; | |
634 | } | |
635 | } | |
636 | if (f == NULL) { | |
637 | /* MISS: No entry, create the new one */ | |
a3d5953d | 638 | debug(35, 5) ("fqdncache_nbgethostbyaddr: MISS for '%s'\n", name); |
f88bb09c | 639 | FqdncacheStats.misses++; |
429fdbec | 640 | f = fqdncacheAddNew(name, NULL, FQDN_PENDING); |
348b2031 | 641 | fqdncacheAddPending(f, handler, handlerData); |
f88bb09c | 642 | } else if (f->status == FQDN_CACHED || f->status == FQDN_NEGATIVE_CACHED) { |
643 | /* HIT */ | |
a3d5953d | 644 | debug(35, 4) ("fqdncache_nbgethostbyaddr: HIT for '%s'\n", name); |
f88bb09c | 645 | if (f->status == FQDN_NEGATIVE_CACHED) |
646 | FqdncacheStats.negative_hits++; | |
647 | else | |
648 | FqdncacheStats.hits++; | |
348b2031 | 649 | fqdncacheAddPending(f, handler, handlerData); |
f88bb09c | 650 | fqdncache_call_pending(f); |
429fdbec | 651 | return; |
f88bb09c | 652 | } else if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) { |
a3d5953d | 653 | debug(35, 4) ("fqdncache_nbgethostbyaddr: PENDING for '%s'\n", name); |
f88bb09c | 654 | FqdncacheStats.pending_hits++; |
348b2031 | 655 | fqdncacheAddPending(f, handler, handlerData); |
429fdbec | 656 | if (squid_curtime - f->expires > 600) { |
a3d5953d | 657 | debug(14, 0) ("fqdncache_nbgethostbyname: '%s' PENDING for %d seconds, aborting\n", name, squid_curtime + Config.negativeDnsTtl - f->expires); |
429fdbec | 658 | fqdncacheChangeKey(f); |
659 | fqdncache_call_pending(f); | |
660 | } | |
661 | return; | |
f88bb09c | 662 | } else { |
663 | fatal_dump("fqdncache_nbgethostbyaddr: BAD fqdncache_entry status"); | |
664 | } | |
665 | ||
666 | /* for HIT, PENDING, DISPATCHED we've returned. For MISS we continue */ | |
667 | ||
429fdbec | 668 | if ((dnsData = dnsGetFirstAvailable())) { |
f88bb09c | 669 | fqdncache_dnsDispatch(dnsData, f); |
429fdbec | 670 | return; |
671 | } | |
672 | if (NDnsServersAlloc > 0) { | |
f88bb09c | 673 | fqdncacheEnqueue(f); |
429fdbec | 674 | return; |
675 | } | |
676 | fqdncache_gethostbyaddr(addr, FQDN_BLOCKING_LOOKUP); | |
677 | fqdncache_call_pending(f); | |
f88bb09c | 678 | } |
679 | ||
b8d8561b | 680 | static void |
681 | fqdncache_dnsDispatch(dnsserver_t * dns, fqdncache_entry * f) | |
f88bb09c | 682 | { |
683 | char *buf = NULL; | |
9d169279 | 684 | if (!BIT_TEST(dns->flags, DNS_FLAG_ALIVE)) |
0c77d853 | 685 | debug_trap("Dispatching a dead DNS server"); |
f88bb09c | 686 | if (!fqdncacheHasPending(f)) { |
a3d5953d | 687 | debug(35, 0) ("fqdncache_dnsDispatch: skipping '%s' because no handler.\n", |
f88bb09c | 688 | f->name); |
689 | f->status = FQDN_NEGATIVE_CACHED; | |
690 | fqdncache_release(f); | |
691 | return; | |
692 | } | |
429fdbec | 693 | if (f->status != FQDN_PENDING) |
694 | debug_trap("fqdncache_dnsDispatch: status != FQDN_PENDING"); | |
f88bb09c | 695 | buf = xcalloc(1, 256); |
696 | sprintf(buf, "%1.254s\n", f->name); | |
697 | dns->flags |= DNS_FLAG_BUSY; | |
698 | dns->data = f; | |
429fdbec | 699 | f->status = FQDN_DISPATCHED; |
f88bb09c | 700 | comm_write(dns->outpipe, |
701 | buf, | |
702 | strlen(buf), | |
f88bb09c | 703 | NULL, /* Handler */ |
704 | NULL, /* Handler-data */ | |
705 | xfree); | |
b177367b | 706 | commSetSelect(dns->outpipe, |
f88bb09c | 707 | COMM_SELECT_READ, |
2f549d83 | 708 | fqdncache_dnsHandleRead, |
b177367b | 709 | dns, |
710 | 0); | |
a3d5953d | 711 | debug(35, 5) ("fqdncache_dnsDispatch: Request sent to DNS server #%d.\n", |
f88bb09c | 712 | dns->id); |
713 | dns->dispatch_time = current_time; | |
714 | DnsStats.requests++; | |
715 | DnsStats.hist[dns->id - 1]++; | |
429fdbec | 716 | fqdncacheLockEntry(f); /* lock while IP_DISPATCHED */ |
f88bb09c | 717 | } |
718 | ||
719 | ||
720 | /* initialize the fqdncache */ | |
b8d8561b | 721 | void |
0673c0ba | 722 | fqdncache_init(void) |
f88bb09c | 723 | { |
19054954 | 724 | if (fqdn_table) |
725 | return; | |
a3d5953d | 726 | debug(35, 3) ("Initializing FQDN Cache...\n"); |
f88bb09c | 727 | memset(&FqdncacheStats, '\0', sizeof(FqdncacheStats)); |
aabcd584 | 728 | /* small hash table */ |
1b50df4b | 729 | fqdn_table = hash_create(urlcmp, 229, hash4); |
f88bb09c | 730 | fqdncache_high = (long) (((float) MAX_FQDN * |
731 | (float) FQDN_HIGH_WATER) / (float) 100); | |
732 | fqdncache_low = (long) (((float) MAX_FQDN * | |
733 | (float) FQDN_LOW_WATER) / (float) 100); | |
734 | } | |
735 | ||
736 | /* clean up the pending entries in dnsserver */ | |
737 | /* return 1 if we found the host, 0 otherwise */ | |
b8d8561b | 738 | int |
b69f7771 | 739 | fqdncacheUnregister(struct in_addr addr, void *data) |
f88bb09c | 740 | { |
03047798 | 741 | char *name = inet_ntoa(addr); |
f88bb09c | 742 | fqdncache_entry *f = NULL; |
743 | struct _fqdn_pending *p = NULL; | |
744 | int n = 0; | |
a3d5953d | 745 | debug(35, 3) ("fqdncacheUnregister: FD %d, name '%s'\n", name); |
f88bb09c | 746 | if ((f = fqdncache_get(name)) == NULL) |
747 | return 0; | |
748 | if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) { | |
749 | for (p = f->pending_head; p; p = p->next) { | |
b69f7771 | 750 | if (p->handlerData != data) |
751 | continue; | |
752 | p->handler = NULL; | |
b69f7771 | 753 | n++; |
f88bb09c | 754 | } |
755 | } | |
b69f7771 | 756 | if (n == 0) |
757 | debug_trap("fqdncacheUnregister: callback data not found"); | |
a3d5953d | 758 | debug(35, 3) ("fqdncacheUnregister: unregistered %d handlers\n", n); |
f88bb09c | 759 | return n; |
760 | } | |
761 | ||
0ee4272b | 762 | const char * |
b8d8561b | 763 | fqdncache_gethostbyaddr(struct in_addr addr, int flags) |
f88bb09c | 764 | { |
765 | char *name = inet_ntoa(addr); | |
766 | fqdncache_entry *f = NULL; | |
0ee4272b | 767 | const struct hostent *hp = NULL; |
429fdbec | 768 | struct in_addr ip; |
e924600d | 769 | static char *static_name = NULL; |
f88bb09c | 770 | |
771 | if (!name) | |
772 | fatal_dump("fqdncache_gethostbyaddr: NULL name"); | |
773 | FqdncacheStats.requests++; | |
774 | if ((f = fqdncache_get(name))) { | |
429fdbec | 775 | if (fqdncacheExpiredEntry(f)) { |
776 | fqdncache_release(f); | |
777 | f = NULL; | |
778 | } | |
779 | } | |
780 | if (f) { | |
f88bb09c | 781 | if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) { |
429fdbec | 782 | if (!BIT_TEST(flags, IP_BLOCKING_LOOKUP)) { |
783 | FqdncacheStats.pending_hits++; | |
784 | return NULL; | |
785 | } | |
f88bb09c | 786 | } else if (f->status == FQDN_NEGATIVE_CACHED) { |
787 | FqdncacheStats.negative_hits++; | |
788 | dns_error_message = f->error_message; | |
789 | return NULL; | |
790 | } else { | |
791 | FqdncacheStats.hits++; | |
792 | f->lastref = squid_curtime; | |
793 | return f->names[0]; | |
794 | } | |
795 | } | |
f88bb09c | 796 | /* check if it's already a FQDN address in text form. */ |
429fdbec | 797 | if (!safe_inet_addr(name, &ip)) |
f88bb09c | 798 | return name; |
429fdbec | 799 | FqdncacheStats.misses++; |
800 | if (BIT_TEST(flags, FQDN_BLOCKING_LOOKUP)) { | |
801 | if (NDnsServersAlloc) | |
a3d5953d | 802 | debug(14, 0) ("WARNING: blocking on gethostbyaddr() for '%s'\n", name); |
f88bb09c | 803 | FqdncacheStats.ghba_calls++; |
429fdbec | 804 | hp = gethostbyaddr((char *) &ip.s_addr, 4, AF_INET); |
f88bb09c | 805 | if (hp && hp->h_name && (hp->h_name[0] != '\0') && fqdn_table) { |
429fdbec | 806 | if (f == NULL) { |
807 | f = fqdncacheAddNew(name, hp, FQDN_CACHED); | |
808 | } else if (f->status == FQDN_DISPATCHED) { | |
809 | /* only dnsHandleRead() can change from DISPATCHED to CACHED */ | |
e924600d | 810 | xfree(static_name); |
811 | static_name = xstrdup(hp->h_name); | |
812 | return static_name; | |
429fdbec | 813 | } else { |
814 | fqdncacheAddHostent(f, hp); | |
815 | f->status = FQDN_CACHED; | |
e924600d | 816 | } |
429fdbec | 817 | f->expires = squid_curtime + Config.positiveDnsTtl; |
f88bb09c | 818 | return f->names[0]; |
819 | } | |
820 | /* bad address, negative cached */ | |
429fdbec | 821 | if (fqdn_table && f == NULL) { |
822 | f = fqdncacheAddNew(name, hp, FQDN_NEGATIVE_CACHED); | |
823 | f->expires = squid_curtime + Config.negativeDnsTtl; | |
824 | return NULL; | |
825 | } | |
f88bb09c | 826 | } |
827 | if (flags & FQDN_LOOKUP_IF_MISS) | |
348b2031 | 828 | fqdncache_nbgethostbyaddr(addr, dummy_handler, NULL); |
f88bb09c | 829 | return NULL; |
830 | } | |
831 | ||
832 | ||
833 | /* process objects list */ | |
b8d8561b | 834 | void |
835 | fqdnStats(StoreEntry * sentry) | |
f88bb09c | 836 | { |
837 | fqdncache_entry *f = NULL; | |
838 | int k; | |
839 | int ttl; | |
840 | ||
841 | if (!fqdn_table) | |
842 | return; | |
843 | ||
844 | storeAppendPrintf(sentry, "{FQDN Cache Statistics:\n"); | |
845 | storeAppendPrintf(sentry, "{FQDNcache Entries: %d}\n", | |
846 | meta_data.fqdncache_count); | |
847 | storeAppendPrintf(sentry, "{FQDNcache Requests: %d}\n", | |
848 | FqdncacheStats.requests); | |
849 | storeAppendPrintf(sentry, "{FQDNcache Hits: %d}\n", | |
850 | FqdncacheStats.hits); | |
851 | storeAppendPrintf(sentry, "{FQDNcache Pending Hits: %d}\n", | |
852 | FqdncacheStats.pending_hits); | |
853 | storeAppendPrintf(sentry, "{FQDNcache Negative Hits: %d}\n", | |
854 | FqdncacheStats.negative_hits); | |
855 | storeAppendPrintf(sentry, "{FQDNcache Misses: %d}\n", | |
856 | FqdncacheStats.misses); | |
857 | storeAppendPrintf(sentry, "{Blocking calls to gethostbyaddr(): %d}\n", | |
858 | FqdncacheStats.ghba_calls); | |
859 | storeAppendPrintf(sentry, "{dnsserver avg service time: %d msec}\n", | |
860 | FqdncacheStats.avg_svc_time); | |
861 | storeAppendPrintf(sentry, "}\n\n"); | |
862 | storeAppendPrintf(sentry, "{FQDN Cache Contents:\n\n"); | |
863 | ||
864 | for (f = fqdncache_GetFirst(); f; f = fqdncache_GetNext()) { | |
865 | if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) | |
866 | ttl = 0; | |
867 | else | |
e84703ad | 868 | ttl = (f->expires - squid_curtime); |
f88bb09c | 869 | storeAppendPrintf(sentry, " {%-32.32s %c %6d %d", |
870 | f->name, | |
871 | fqdncache_status_char[f->status], | |
872 | ttl, | |
873 | (int) f->name_count); | |
874 | for (k = 0; k < (int) f->name_count; k++) | |
875 | storeAppendPrintf(sentry, " %s", f->names[k]); | |
876 | storeAppendPrintf(sentry, close_bracket); | |
877 | } | |
878 | storeAppendPrintf(sentry, close_bracket); | |
879 | } | |
880 | ||
b8d8561b | 881 | static void |
348b2031 | 882 | dummy_handler(const char *u2, void *u3) |
f88bb09c | 883 | { |
884 | return; | |
885 | } | |
886 | ||
b8d8561b | 887 | static int |
fe4e214f | 888 | fqdncacheHasPending(const fqdncache_entry * f) |
f88bb09c | 889 | { |
0ee4272b | 890 | const struct _fqdn_pending *p = NULL; |
f88bb09c | 891 | if (f->status != FQDN_PENDING) |
892 | return 0; | |
893 | for (p = f->pending_head; p; p = p->next) | |
894 | if (p->handler) | |
895 | return 1; | |
896 | return 0; | |
897 | } | |
898 | ||
b8d8561b | 899 | void |
0ee4272b | 900 | fqdncacheReleaseInvalid(const char *name) |
f88bb09c | 901 | { |
902 | fqdncache_entry *f; | |
903 | if ((f = fqdncache_get(name)) == NULL) | |
904 | return; | |
905 | if (f->status != FQDN_NEGATIVE_CACHED) | |
906 | return; | |
907 | fqdncache_release(f); | |
908 | } | |
28ab0c0a | 909 | |
0ee4272b | 910 | const char * |
b8d8561b | 911 | fqdnFromAddr(struct in_addr addr) |
28ab0c0a | 912 | { |
0ee4272b | 913 | const char *n; |
39de381a | 914 | static char buf[32]; |
b0c9fba9 | 915 | if (Config.Log.log_fqdn && (n = fqdncache_gethostbyaddr(addr, 0))) |
28ab0c0a | 916 | return n; |
f2052513 | 917 | xstrncpy(buf, inet_ntoa(addr), 32); |
39de381a | 918 | return buf; |
28ab0c0a | 919 | } |
f201f309 | 920 | |
b8d8561b | 921 | int |
0673c0ba | 922 | fqdncacheQueueDrain(void) |
f201f309 | 923 | { |
924 | fqdncache_entry *i; | |
925 | dnsserver_t *dnsData; | |
926 | if (!fqdncacheQueueHead) | |
a8f7d3ee | 927 | return 0; |
f201f309 | 928 | while ((dnsData = dnsGetFirstAvailable()) && (i = fqdncacheDequeue())) |
a8f7d3ee | 929 | fqdncache_dnsDispatch(dnsData, i); |
f201f309 | 930 | return 1; |
931 | } | |
56e15c50 | 932 | |
429fdbec | 933 | static void |
934 | fqdncacheLockEntry(fqdncache_entry * f) | |
935 | { | |
936 | f->locks++; | |
937 | } | |
938 | ||
939 | static void | |
940 | fqdncacheUnlockEntry(fqdncache_entry * f) | |
941 | { | |
942 | if (f->locks == 0) { | |
943 | debug_trap("fqdncacheUnlockEntry: Entry has no locks"); | |
944 | return; | |
945 | } | |
946 | f->locks--; | |
947 | if (fqdncacheExpiredEntry(f)) | |
948 | fqdncache_release(f); | |
949 | } | |
950 | ||
56e15c50 | 951 | void |
952 | fqdncacheFreeMemory(void) | |
953 | { | |
954 | fqdncache_entry *f; | |
955 | fqdncache_entry **list; | |
c7433536 | 956 | int i = 0; |
957 | int j = 0; | |
56e15c50 | 958 | int k = 0; |
56e15c50 | 959 | list = xcalloc(meta_data.fqdncache_count, sizeof(fqdncache_entry *)); |
960 | f = (fqdncache_entry *) hash_first(fqdn_table); | |
c7433536 | 961 | while (f && i < meta_data.fqdncache_count) { |
f6610c4e | 962 | *(list + i) = f; |
963 | i++; | |
964 | f = (fqdncache_entry *) hash_next(fqdn_table); | |
56e15c50 | 965 | } |
c7433536 | 966 | for (j = 0; j < i; j++) { |
f6610c4e | 967 | f = *(list + j); |
968 | for (k = 0; k < (int) f->name_count; k++) | |
969 | safe_free(f->names[k]); | |
970 | safe_free(f->name); | |
971 | safe_free(f->error_message); | |
972 | safe_free(f); | |
56e15c50 | 973 | } |
974 | xfree(list); | |
975 | hashFreeMemory(fqdn_table); | |
976 | } | |
429fdbec | 977 | |
978 | static void | |
979 | fqdncacheChangeKey(fqdncache_entry * f) | |
980 | { | |
981 | static int index = 0; | |
982 | LOCAL_ARRAY(char, new_key, 256); | |
983 | hash_link *table_entry = hash_lookup(fqdn_table, f->name); | |
984 | if (table_entry == NULL) { | |
a3d5953d | 985 | debug(14, 0) ("fqdncacheChangeKey: Could not find key '%s'\n", f->name); |
429fdbec | 986 | return; |
987 | } | |
988 | if (f != (fqdncache_entry *) table_entry) { | |
989 | debug_trap("fqdncacheChangeKey: f != table_entry!"); | |
990 | return; | |
991 | } | |
992 | if (hash_remove_link(fqdn_table, table_entry)) { | |
993 | debug_trap("fqdncacheChangeKey: hash_remove_link() failed\n"); | |
994 | return; | |
995 | } | |
996 | sprintf(new_key, "%d/", ++index); | |
997 | strncat(new_key, f->name, 128); | |
a3d5953d | 998 | debug(14, 1) ("fqdncacheChangeKey: from '%s' to '%s'\n", f->name, new_key); |
429fdbec | 999 | safe_free(f->name); |
1000 | f->name = xstrdup(new_key); | |
1001 | fqdncache_add_to_hash(f); | |
1002 | } | |
1003 | ||
1004 | /* call during reconfigure phase to clear out all the | |
1005 | * pending and dispatched reqeusts that got lost */ | |
1006 | void | |
1007 | fqdncache_restart(void) | |
1008 | { | |
1009 | fqdncache_entry *this; | |
1010 | fqdncache_entry *next; | |
1011 | if (fqdn_table == 0) | |
1012 | fatal_dump("fqdncache_restart: fqdn_table == 0\n"); | |
1013 | while (fqdncacheDequeue()); | |
1014 | next = (fqdncache_entry *) hash_first(fqdn_table); | |
1015 | while ((this = next)) { | |
1016 | next = (fqdncache_entry *) hash_next(fqdn_table); | |
1017 | if (this->status == FQDN_CACHED) | |
1018 | continue; | |
1019 | if (this->status == FQDN_NEGATIVE_CACHED) | |
1020 | continue; | |
1021 | /* else its PENDING or DISPATCHED; there are no dnsservers | |
1022 | * running, so abort it */ | |
1023 | this->status = FQDN_NEGATIVE_CACHED; | |
1024 | fqdncache_release(this); | |
1025 | } | |
1026 | } |