]>
Commit | Line | Data |
---|---|---|
f88bb09c | 1 | |
2 | /* | |
998adf71 | 3 | * $Id: fqdncache.cc,v 1.154 2003/02/13 20:47:53 wessels Exp $ |
f88bb09c | 4 | * |
7cf620a9 | 5 | * DEBUG: section 35 FQDN Cache |
f88bb09c | 6 | * AUTHOR: Harvest Derived |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
f88bb09c | 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. | |
f88bb09c | 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 | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
f88bb09c | 34 | */ |
35 | ||
36 | #include "squid.h" | |
e6ccf245 | 37 | #include "Store.h" |
f88bb09c | 38 | |
f88bb09c | 39 | #define FQDN_LOW_WATER 90 |
40 | #define FQDN_HIGH_WATER 95 | |
f88bb09c | 41 | |
add5d21f | 42 | typedef struct _fqdncache_entry fqdncache_entry; |
43 | ||
44 | struct _fqdncache_entry { | |
186477c1 | 45 | hash_link hash; /* must be first */ |
add5d21f | 46 | time_t lastref; |
47 | time_t expires; | |
48 | unsigned char name_count; | |
49 | char *names[FQDN_MAX_NAMES + 1]; | |
50 | FQDNH *handler; | |
51 | void *handlerData; | |
52 | char *error_message; | |
53 | struct timeval request_time; | |
54 | dlink_node lru; | |
ac06f720 | 55 | unsigned short locks; |
add5d21f | 56 | struct { |
57 | unsigned int negcached:1; | |
0e70aa1e | 58 | unsigned int fromhosts:1; |
add5d21f | 59 | } flags; |
60 | }; | |
61 | ||
f88bb09c | 62 | static struct { |
63 | int requests; | |
64 | int replies; | |
65 | int hits; | |
66 | int misses; | |
f88bb09c | 67 | int negative_hits; |
f88bb09c | 68 | } FqdncacheStats; |
69 | ||
4bc76d59 | 70 | static dlink_list lru_list; |
71 | ||
59f34d62 | 72 | #if USE_DNSSERVERS |
74addf6c | 73 | static HLPCB fqdncacheHandleReply; |
74 | static fqdncache_entry *fqdncacheParse(const char *buf); | |
59f34d62 | 75 | #else |
76 | static IDNSCB fqdncacheHandleReply; | |
77 | static fqdncache_entry *fqdncacheParse(rfc1035_rr *, int); | |
78 | #endif | |
add5d21f | 79 | static void fqdncacheRelease(fqdncache_entry *); |
80 | static fqdncache_entry *fqdncacheCreateEntry(const char *name); | |
81 | static void fqdncacheCallback(fqdncache_entry *); | |
f5b8bbc4 | 82 | static fqdncache_entry *fqdncache_get(const char *); |
348b2031 | 83 | static FQDNH dummy_handler; |
f5b8bbc4 | 84 | static int fqdncacheExpiredEntry(const fqdncache_entry *); |
f5b8bbc4 | 85 | static void fqdncacheLockEntry(fqdncache_entry * f); |
86 | static void fqdncacheUnlockEntry(fqdncache_entry * f); | |
ec878047 | 87 | static FREE fqdncacheFreeEntry; |
add5d21f | 88 | static void fqdncacheAddEntry(fqdncache_entry * f); |
f88bb09c | 89 | |
365e5b34 | 90 | static hash_table *fqdn_table = NULL; |
f88bb09c | 91 | |
24382924 | 92 | static long fqdncache_low = 180; |
93 | static long fqdncache_high = 200; | |
f88bb09c | 94 | |
f88bb09c | 95 | /* removes the given fqdncache entry */ |
b8d8561b | 96 | static void |
add5d21f | 97 | fqdncacheRelease(fqdncache_entry * f) |
f88bb09c | 98 | { |
f88bb09c | 99 | int k; |
3fda0827 | 100 | hash_remove_link(fqdn_table, (hash_link *) f); |
add5d21f | 101 | for (k = 0; k < (int) f->name_count; k++) |
102 | safe_free(f->names[k]); | |
103 | debug(35, 5) ("fqdncacheRelease: Released FQDN record for '%s'.\n", | |
186477c1 | 104 | hashKeyStr(&f->hash)); |
4bc76d59 | 105 | dlinkDelete(&f->lru, &lru_list); |
186477c1 | 106 | safe_free(f->hash.key); |
429fdbec | 107 | safe_free(f->error_message); |
db1cd23c | 108 | memFree(f, MEM_FQDNCACHE_ENTRY); |
f88bb09c | 109 | } |
110 | ||
111 | /* return match for given name */ | |
b8d8561b | 112 | static fqdncache_entry * |
0ee4272b | 113 | fqdncache_get(const char *name) |
f88bb09c | 114 | { |
115 | hash_link *e; | |
116 | static fqdncache_entry *f; | |
f88bb09c | 117 | f = NULL; |
118 | if (fqdn_table) { | |
e6ccf245 | 119 | if ((e = (hash_link *)hash_lookup(fqdn_table, name)) != NULL) |
f88bb09c | 120 | f = (fqdncache_entry *) e; |
121 | } | |
122 | return f; | |
123 | } | |
124 | ||
b8d8561b | 125 | static int |
fe4e214f | 126 | fqdncacheExpiredEntry(const fqdncache_entry * f) |
f88bb09c | 127 | { |
0e70aa1e | 128 | /* all static entries are locked, so this takes care of them too */ |
429fdbec | 129 | if (f->locks != 0) |
130 | return 0; | |
e84703ad | 131 | if (f->expires > squid_curtime) |
f88bb09c | 132 | return 0; |
133 | return 1; | |
134 | } | |
135 | ||
59c4d35b | 136 | void |
137 | fqdncache_purgelru(void *notused) | |
f88bb09c | 138 | { |
4bc76d59 | 139 | dlink_node *m; |
140 | dlink_node *prev = NULL; | |
141 | fqdncache_entry *f; | |
f88bb09c | 142 | int removed = 0; |
52040193 | 143 | eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 10.0, 1); |
4bc76d59 | 144 | for (m = lru_list.tail; m; m = prev) { |
59c4d35b | 145 | if (memInUse(MEM_FQDNCACHE_ENTRY) < fqdncache_low) |
4bc76d59 | 146 | break; |
147 | prev = m->prev; | |
e6ccf245 | 148 | f = (fqdncache_entry *)m->data; |
4bc76d59 | 149 | if (f->locks != 0) |
150 | continue; | |
add5d21f | 151 | fqdncacheRelease(f); |
f88bb09c | 152 | removed++; |
153 | } | |
ac750329 | 154 | debug(35, 9) ("fqdncache_purgelru: removed %d entries\n", removed); |
f88bb09c | 155 | } |
156 | ||
0e70aa1e | 157 | static void |
158 | purge_entries_fromhosts(void) | |
159 | { | |
160 | dlink_node *m = lru_list.head; | |
161 | fqdncache_entry *i = NULL; | |
162 | fqdncache_entry *t; | |
163 | while (m) { | |
164 | if (i != NULL) { /* need to delay deletion */ | |
165 | fqdncacheRelease(i); /* we just override locks */ | |
166 | i = NULL; | |
167 | } | |
e6ccf245 | 168 | t = (fqdncache_entry *)m->data; |
0e70aa1e | 169 | if (t->flags.fromhosts) |
170 | i = t; | |
171 | m = m->next; | |
172 | } | |
173 | if (i != NULL) | |
174 | fqdncacheRelease(i); | |
175 | } | |
176 | ||
f88bb09c | 177 | /* create blank fqdncache_entry */ |
b8d8561b | 178 | static fqdncache_entry * |
add5d21f | 179 | fqdncacheCreateEntry(const char *name) |
f88bb09c | 180 | { |
4bc76d59 | 181 | static fqdncache_entry *f; |
e6ccf245 | 182 | f = (fqdncache_entry *)memAllocate(MEM_FQDNCACHE_ENTRY); |
186477c1 | 183 | f->hash.key = xstrdup(name); |
4bc76d59 | 184 | f->expires = squid_curtime + Config.negativeDnsTtl; |
4bc76d59 | 185 | return f; |
f88bb09c | 186 | } |
187 | ||
b8d8561b | 188 | static void |
add5d21f | 189 | fqdncacheAddEntry(fqdncache_entry * f) |
f88bb09c | 190 | { |
e6ccf245 | 191 | hash_link *e = (hash_link *)hash_lookup(fqdn_table, f->hash.key); |
add5d21f | 192 | if (NULL != e) { |
193 | /* avoid colission */ | |
194 | fqdncache_entry *q = (fqdncache_entry *) e; | |
195 | fqdncacheRelease(q); | |
429fdbec | 196 | } |
186477c1 | 197 | hash_join(fqdn_table, &f->hash); |
add5d21f | 198 | dlinkAdd(f, &f->lru, &lru_list); |
429fdbec | 199 | f->lastref = squid_curtime; |
f88bb09c | 200 | } |
201 | ||
202 | /* walks down the pending list, calling handlers */ | |
b8d8561b | 203 | static void |
add5d21f | 204 | fqdncacheCallback(fqdncache_entry * f) |
f88bb09c | 205 | { |
fa80a8ef | 206 | FQDNH *callback; |
207 | void *cbdata; | |
f88bb09c | 208 | f->lastref = squid_curtime; |
fa80a8ef | 209 | if (!f->handler) |
add5d21f | 210 | return; |
5a2aa048 | 211 | fqdncacheLockEntry(f); |
fa80a8ef | 212 | callback = f->handler; |
add5d21f | 213 | f->handler = NULL; |
fa80a8ef | 214 | if (cbdataReferenceValidDone(f->handlerData, &cbdata)) { |
add5d21f | 215 | dns_error_message = f->error_message; |
fa80a8ef | 216 | callback(f->flags.negcached ? NULL : f->names[0], cbdata); |
f88bb09c | 217 | } |
429fdbec | 218 | fqdncacheUnlockEntry(f); |
f88bb09c | 219 | } |
220 | ||
b8d8561b | 221 | static fqdncache_entry * |
b18baa48 | 222 | #if USE_DNSSERVERS |
74addf6c | 223 | fqdncacheParse(const char *inbuf) |
f88bb09c | 224 | { |
bd34f258 | 225 | LOCAL_ARRAY(char, buf, DNS_INBUF_SZ); |
e84703ad | 226 | char *token; |
227 | static fqdncache_entry f; | |
bd34f258 | 228 | int ttl; |
f6c6cd66 | 229 | memset(&f, '\0', sizeof(f)); |
bd34f258 | 230 | f.expires = squid_curtime; |
add5d21f | 231 | f.flags.negcached = 1; |
c68e9c6b | 232 | if (inbuf == NULL) { |
233 | debug(35, 1) ("fqdncacheParse: Got <NULL> reply\n"); | |
234 | return &f; | |
235 | } | |
c579f632 | 236 | xstrncpy(buf, inbuf, DNS_INBUF_SZ); |
237 | debug(35, 5) ("fqdncacheParse: parsing: {%s}\n", buf); | |
bd34f258 | 238 | token = strtok(buf, w_space); |
239 | if (NULL == token) { | |
6a78c18e | 240 | debug(35, 1) ("fqdncacheParse: Got <NULL>, expecting '$name'\n"); |
bd34f258 | 241 | return &f; |
242 | } | |
243 | if (0 == strcmp(token, "$fail")) { | |
244 | f.expires = squid_curtime + Config.negativeDnsTtl; | |
245 | token = strtok(NULL, "\n"); | |
246 | assert(NULL != token); | |
247 | f.error_message = xstrdup(token); | |
248 | return &f; | |
249 | } | |
250 | if (0 != strcmp(token, "$name")) { | |
6a78c18e | 251 | debug(35, 1) ("fqdncacheParse: Got '%s', expecting '$name'\n", token); |
bd34f258 | 252 | return &f; |
253 | } | |
254 | token = strtok(NULL, w_space); | |
255 | if (NULL == token) { | |
6a78c18e | 256 | debug(35, 1) ("fqdncacheParse: Got <NULL>, expecting TTL\n"); |
bd34f258 | 257 | return &f; |
258 | } | |
add5d21f | 259 | f.flags.negcached = 0; |
bd34f258 | 260 | ttl = atoi(token); |
261 | if (ttl > 0) | |
262 | f.expires = squid_curtime + ttl; | |
263 | else | |
264 | f.expires = squid_curtime + Config.positiveDnsTtl; | |
265 | token = strtok(NULL, w_space); | |
266 | if (NULL != token) { | |
267 | f.names[0] = xstrdup(token); | |
268 | f.name_count = 1; | |
f88bb09c | 269 | } |
e84703ad | 270 | return &f; |
f88bb09c | 271 | } |
59f34d62 | 272 | #else |
59f34d62 | 273 | fqdncacheParse(rfc1035_rr * answers, int nr) |
274 | { | |
275 | static fqdncache_entry f; | |
276 | int k; | |
59f34d62 | 277 | int na = 0; |
278 | memset(&f, '\0', sizeof(f)); | |
279 | f.expires = squid_curtime; | |
add5d21f | 280 | f.flags.negcached = 1; |
59f34d62 | 281 | if (nr < 0) { |
b18baa48 | 282 | debug(35, 3) ("fqdncacheParse: Lookup failed (error %d)\n", |
59f34d62 | 283 | rfc1035_errno); |
284 | assert(rfc1035_error_message); | |
285 | f.error_message = xstrdup(rfc1035_error_message); | |
286 | return &f; | |
287 | } | |
288 | if (nr == 0) { | |
b18baa48 | 289 | debug(35, 3) ("fqdncacheParse: No DNS records\n"); |
59f34d62 | 290 | f.error_message = xstrdup("No DNS records"); |
291 | return &f; | |
292 | } | |
39d5df9b | 293 | debug(35, 3) ("fqdncacheParse: %d answers\n", nr); |
59f34d62 | 294 | assert(answers); |
1810dde6 | 295 | for (k = 0; k < nr; k++) { |
59f34d62 | 296 | if (answers[k].type != RFC1035_TYPE_PTR) |
297 | continue; | |
29b8d8d6 | 298 | if (answers[k]._class != RFC1035_CLASS_IN) |
59f34d62 | 299 | continue; |
300 | na++; | |
add5d21f | 301 | f.flags.negcached = 0; |
59f34d62 | 302 | f.names[0] = xstrdup(answers[k].rdata); |
303 | f.name_count = 1; | |
304 | f.expires = squid_curtime + answers[k].ttl; | |
305 | return &f; | |
306 | } | |
307 | debug(35, 1) ("fqdncacheParse: No PTR record\n"); | |
308 | f.error_message = xstrdup("No PTR record"); | |
309 | return &f; | |
310 | } | |
311 | #endif | |
f88bb09c | 312 | |
429fdbec | 313 | static void |
59f34d62 | 314 | #if USE_DNSSERVERS |
74addf6c | 315 | fqdncacheHandleReply(void *data, char *reply) |
59f34d62 | 316 | #else |
317 | fqdncacheHandleReply(void *data, rfc1035_rr * answers, int na) | |
318 | #endif | |
f88bb09c | 319 | { |
f88bb09c | 320 | int n; |
e6ccf245 | 321 | generic_cbdata *c = (generic_cbdata *)data; |
322 | fqdncache_entry *f = (fqdncache_entry *)c->data; | |
e84703ad | 323 | fqdncache_entry *x = NULL; |
74addf6c | 324 | cbdataFree(c); |
325 | c = NULL; | |
c68e9c6b | 326 | n = ++FqdncacheStats.replies; |
83704487 | 327 | statHistCount(&statCounter.dns.svc_time, |
74addf6c | 328 | tvSubMsec(f->request_time, current_time)); |
59f34d62 | 329 | #if USE_DNSSERVERS |
c68e9c6b | 330 | x = fqdncacheParse(reply); |
59f34d62 | 331 | #else |
332 | x = fqdncacheParse(answers, na); | |
333 | #endif | |
c68e9c6b | 334 | assert(x); |
335 | f->name_count = x->name_count; | |
336 | for (n = 0; n < (int) f->name_count; n++) | |
337 | f->names[n] = x->names[n]; | |
338 | f->error_message = x->error_message; | |
c68e9c6b | 339 | f->expires = x->expires; |
add5d21f | 340 | f->flags = x->flags; |
341 | fqdncacheAddEntry(f); | |
342 | fqdncacheCallback(f); | |
f88bb09c | 343 | } |
344 | ||
429fdbec | 345 | void |
348b2031 | 346 | fqdncache_nbgethostbyaddr(struct in_addr addr, FQDNH * handler, void *handlerData) |
f88bb09c | 347 | { |
348 | fqdncache_entry *f = NULL; | |
f88bb09c | 349 | char *name = inet_ntoa(addr); |
74addf6c | 350 | generic_cbdata *c; |
698e6f16 | 351 | assert(handler); |
a3d5953d | 352 | debug(35, 4) ("fqdncache_nbgethostbyaddr: Name '%s'.\n", name); |
f88bb09c | 353 | FqdncacheStats.requests++; |
f88bb09c | 354 | if (name == NULL || name[0] == '\0') { |
a3d5953d | 355 | debug(35, 4) ("fqdncache_nbgethostbyaddr: Invalid name!\n"); |
348b2031 | 356 | handler(NULL, handlerData); |
429fdbec | 357 | return; |
f88bb09c | 358 | } |
add5d21f | 359 | f = fqdncache_get(name); |
360 | if (NULL == f) { | |
361 | /* miss */ | |
362 | (void) 0; | |
363 | } else if (fqdncacheExpiredEntry(f)) { | |
364 | /* hit, but expired -- bummer */ | |
365 | fqdncacheRelease(f); | |
366 | f = NULL; | |
367 | } else { | |
368 | /* hit */ | |
a3d5953d | 369 | debug(35, 4) ("fqdncache_nbgethostbyaddr: HIT for '%s'\n", name); |
add5d21f | 370 | if (f->flags.negcached) |
f88bb09c | 371 | FqdncacheStats.negative_hits++; |
372 | else | |
373 | FqdncacheStats.hits++; | |
add5d21f | 374 | f->handler = handler; |
fa80a8ef | 375 | f->handlerData = cbdataReference(handlerData); |
add5d21f | 376 | fqdncacheCallback(f); |
429fdbec | 377 | return; |
f88bb09c | 378 | } |
add5d21f | 379 | |
380 | debug(35, 5) ("fqdncache_nbgethostbyaddr: MISS for '%s'\n", name); | |
381 | FqdncacheStats.misses++; | |
382 | f = fqdncacheCreateEntry(name); | |
383 | f->handler = handler; | |
fa80a8ef | 384 | f->handlerData = cbdataReference(handlerData); |
add5d21f | 385 | f->request_time = current_time; |
72711e31 | 386 | c = cbdataAlloc(generic_cbdata); |
74addf6c | 387 | c->data = f; |
59f34d62 | 388 | #if USE_DNSSERVERS |
186477c1 | 389 | dnsSubmit(hashKeyStr(&f->hash), fqdncacheHandleReply, c); |
59f34d62 | 390 | #else |
391 | idnsPTRLookup(addr, fqdncacheHandleReply, c); | |
392 | #endif | |
f88bb09c | 393 | } |
394 | ||
f88bb09c | 395 | /* initialize the fqdncache */ |
b8d8561b | 396 | void |
0673c0ba | 397 | fqdncache_init(void) |
f88bb09c | 398 | { |
aa9e2cab | 399 | int n; |
19054954 | 400 | if (fqdn_table) |
401 | return; | |
a3d5953d | 402 | debug(35, 3) ("Initializing FQDN Cache...\n"); |
f88bb09c | 403 | memset(&FqdncacheStats, '\0', sizeof(FqdncacheStats)); |
3eb55834 | 404 | memset(&lru_list, '\0', sizeof(lru_list)); |
e55650e3 | 405 | fqdncache_high = (long) (((float) Config.fqdncache.size * |
f88bb09c | 406 | (float) FQDN_HIGH_WATER) / (float) 100); |
e55650e3 | 407 | fqdncache_low = (long) (((float) Config.fqdncache.size * |
f88bb09c | 408 | (float) FQDN_LOW_WATER) / (float) 100); |
aa9e2cab | 409 | n = hashPrime(fqdncache_high / 4); |
6a78c18e | 410 | fqdn_table = hash_create((HASHCMP *) strcmp, n, hash4); |
22f3fd98 | 411 | cachemgrRegister("fqdncache", |
412 | "FQDN Cache Stats and Contents", | |
1da3b90b | 413 | fqdnStats, 0, 1); |
add5d21f | 414 | memDataInit(MEM_FQDNCACHE_ENTRY, "fqdncache_entry", |
415 | sizeof(fqdncache_entry), 0); | |
f88bb09c | 416 | } |
417 | ||
0ee4272b | 418 | const char * |
b8d8561b | 419 | fqdncache_gethostbyaddr(struct in_addr addr, int flags) |
f88bb09c | 420 | { |
421 | char *name = inet_ntoa(addr); | |
422 | fqdncache_entry *f = NULL; | |
429fdbec | 423 | struct in_addr ip; |
698e6f16 | 424 | assert(name); |
f88bb09c | 425 | FqdncacheStats.requests++; |
add5d21f | 426 | f = fqdncache_get(name); |
427 | if (NULL == f) { | |
428 | (void) 0; | |
429 | } else if (fqdncacheExpiredEntry(f)) { | |
430 | fqdncacheRelease(f); | |
431 | f = NULL; | |
432 | } else if (f->flags.negcached) { | |
433 | FqdncacheStats.negative_hits++; | |
434 | dns_error_message = f->error_message; | |
435 | return NULL; | |
436 | } else { | |
437 | FqdncacheStats.hits++; | |
438 | f->lastref = squid_curtime; | |
439 | return f->names[0]; | |
f88bb09c | 440 | } |
f88bb09c | 441 | /* check if it's already a FQDN address in text form. */ |
429fdbec | 442 | if (!safe_inet_addr(name, &ip)) |
f88bb09c | 443 | return name; |
429fdbec | 444 | FqdncacheStats.misses++; |
f88bb09c | 445 | if (flags & FQDN_LOOKUP_IF_MISS) |
348b2031 | 446 | fqdncache_nbgethostbyaddr(addr, dummy_handler, NULL); |
f88bb09c | 447 | return NULL; |
448 | } | |
449 | ||
450 | ||
451 | /* process objects list */ | |
b8d8561b | 452 | void |
453 | fqdnStats(StoreEntry * sentry) | |
f88bb09c | 454 | { |
455 | fqdncache_entry *f = NULL; | |
456 | int k; | |
457 | int ttl; | |
4bc76d59 | 458 | if (fqdn_table == NULL) |
f88bb09c | 459 | return; |
15576b6a | 460 | storeAppendPrintf(sentry, "FQDN Cache Statistics:\n"); |
461 | storeAppendPrintf(sentry, "FQDNcache Entries: %d\n", | |
59c4d35b | 462 | memInUse(MEM_FQDNCACHE_ENTRY)); |
15576b6a | 463 | storeAppendPrintf(sentry, "FQDNcache Requests: %d\n", |
f88bb09c | 464 | FqdncacheStats.requests); |
15576b6a | 465 | storeAppendPrintf(sentry, "FQDNcache Hits: %d\n", |
f88bb09c | 466 | FqdncacheStats.hits); |
15576b6a | 467 | storeAppendPrintf(sentry, "FQDNcache Negative Hits: %d\n", |
f88bb09c | 468 | FqdncacheStats.negative_hits); |
15576b6a | 469 | storeAppendPrintf(sentry, "FQDNcache Misses: %d\n", |
f88bb09c | 470 | FqdncacheStats.misses); |
15576b6a | 471 | storeAppendPrintf(sentry, "FQDN Cache Contents:\n\n"); |
0e70aa1e | 472 | storeAppendPrintf(sentry, "%-15.15s %3s %3s %3s %s\n", |
473 | "Address", "Flg", "TTL", "Cnt", "Hostnames"); | |
0f6bebac | 474 | hash_first(fqdn_table); |
475 | while ((f = (fqdncache_entry *) hash_next(fqdn_table))) { | |
0e70aa1e | 476 | ttl = (f->flags.fromhosts ? -1 : (f->expires - squid_curtime)); |
477 | storeAppendPrintf(sentry, "%-15.15s %c%c %3.3d % 3d", | |
186477c1 | 478 | hashKeyStr(&f->hash), |
add5d21f | 479 | f->flags.negcached ? 'N' : ' ', |
0e70aa1e | 480 | f->flags.fromhosts ? 'H' : ' ', |
f88bb09c | 481 | ttl, |
482 | (int) f->name_count); | |
483 | for (k = 0; k < (int) f->name_count; k++) | |
484 | storeAppendPrintf(sentry, " %s", f->names[k]); | |
22f3fd98 | 485 | storeAppendPrintf(sentry, "\n"); |
f88bb09c | 486 | } |
f88bb09c | 487 | } |
488 | ||
b8d8561b | 489 | static void |
79d39a72 | 490 | dummy_handler(const char *bufnotused, void *datanotused) |
f88bb09c | 491 | { |
492 | return; | |
493 | } | |
494 | ||
0ee4272b | 495 | const char * |
b8d8561b | 496 | fqdnFromAddr(struct in_addr addr) |
28ab0c0a | 497 | { |
0ee4272b | 498 | const char *n; |
39de381a | 499 | static char buf[32]; |
17a0a4ee | 500 | if (Config.onoff.log_fqdn && (n = fqdncache_gethostbyaddr(addr, 0))) |
28ab0c0a | 501 | return n; |
f2052513 | 502 | xstrncpy(buf, inet_ntoa(addr), 32); |
39de381a | 503 | return buf; |
28ab0c0a | 504 | } |
f201f309 | 505 | |
429fdbec | 506 | static void |
507 | fqdncacheLockEntry(fqdncache_entry * f) | |
508 | { | |
4bc76d59 | 509 | if (f->locks++ == 0) { |
510 | dlinkDelete(&f->lru, &lru_list); | |
511 | dlinkAdd(f, &f->lru, &lru_list); | |
512 | } | |
429fdbec | 513 | } |
514 | ||
515 | static void | |
516 | fqdncacheUnlockEntry(fqdncache_entry * f) | |
517 | { | |
ac06f720 | 518 | assert(f->locks > 0); |
429fdbec | 519 | f->locks--; |
520 | if (fqdncacheExpiredEntry(f)) | |
add5d21f | 521 | fqdncacheRelease(f); |
429fdbec | 522 | } |
523 | ||
ec878047 | 524 | static void |
525 | fqdncacheFreeEntry(void *data) | |
526 | { | |
e6ccf245 | 527 | fqdncache_entry *f = (fqdncache_entry *)data; |
ec878047 | 528 | int k; |
529 | for (k = 0; k < (int) f->name_count; k++) | |
530 | safe_free(f->names[k]); | |
186477c1 | 531 | safe_free(f->hash.key); |
ec878047 | 532 | safe_free(f->error_message); |
db1cd23c | 533 | memFree(f, MEM_FQDNCACHE_ENTRY); |
ec878047 | 534 | } |
535 | ||
56e15c50 | 536 | void |
537 | fqdncacheFreeMemory(void) | |
538 | { | |
ec878047 | 539 | hashFreeItems(fqdn_table, fqdncacheFreeEntry); |
56e15c50 | 540 | hashFreeMemory(fqdn_table); |
afe95a7e | 541 | fqdn_table = NULL; |
56e15c50 | 542 | } |
429fdbec | 543 | |
d20b1cd0 | 544 | /* Recalculate FQDN cache size upon reconfigure */ |
429fdbec | 545 | void |
546 | fqdncache_restart(void) | |
547 | { | |
e55650e3 | 548 | fqdncache_high = (long) (((float) Config.fqdncache.size * |
e144eae4 | 549 | (float) FQDN_HIGH_WATER) / (float) 100); |
e55650e3 | 550 | fqdncache_low = (long) (((float) Config.fqdncache.size * |
e144eae4 | 551 | (float) FQDN_LOW_WATER) / (float) 100); |
0e70aa1e | 552 | purge_entries_fromhosts(); |
553 | } | |
554 | ||
555 | /* | |
556 | * adds a "static" entry from /etc/hosts. the worldist is to be | |
557 | * managed by the caller, including pointed-to strings | |
558 | */ | |
559 | void | |
560 | fqdncacheAddEntryFromHosts(char *addr, wordlist * hostnames) | |
561 | { | |
562 | fqdncache_entry *fce; | |
563 | int j = 0; | |
564 | if ((fce = fqdncache_get(addr))) { | |
565 | if (1 == fce->flags.fromhosts) { | |
566 | fqdncacheUnlockEntry(fce); | |
567 | } else if (fce->locks > 0) { | |
568 | debug(35, 1) ("fqdncacheAddEntryFromHosts: can't add static entry for locked address '%s'\n", addr); | |
569 | return; | |
570 | } else { | |
571 | fqdncacheRelease(fce); | |
572 | } | |
573 | } | |
574 | fce = fqdncacheCreateEntry(addr); | |
575 | while (hostnames) { | |
576 | fce->names[j] = xstrdup(hostnames->key); | |
577 | j++; | |
578 | hostnames = hostnames->next; | |
579 | if (j >= FQDN_MAX_NAMES) | |
580 | break; | |
581 | } | |
582 | fce->name_count = j; | |
583 | fce->names[j] = NULL; /* it's safe */ | |
584 | fce->flags.fromhosts = 1; | |
585 | fqdncacheAddEntry(fce); | |
586 | fqdncacheLockEntry(fce); | |
429fdbec | 587 | } |
ce75f381 | 588 | |
0e70aa1e | 589 | |
ce75f381 | 590 | #ifdef SQUID_SNMP |
e7ef99a7 | 591 | /* |
135171fe | 592 | * The function to return the fqdn statistics via SNMP |
593 | */ | |
d60c11be | 594 | |
86115da5 | 595 | variable_list * |
e7ef99a7 | 596 | snmp_netFqdnFn(variable_list * Var, snint * ErrP) |
d60c11be | 597 | { |
736eb6ad | 598 | variable_list *Answer = NULL; |
38650cc8 | 599 | debug(49, 5) ("snmp_netFqdnFn: Processing request:\n"); |
e7ef99a7 | 600 | snmpDebugOid(5, Var->name, Var->name_length); |
86115da5 | 601 | *ErrP = SNMP_ERR_NOERROR; |
135171fe | 602 | switch (Var->name[LEN_SQ_NET + 1]) { |
e7ef99a7 | 603 | case FQDN_ENT: |
736eb6ad | 604 | Answer = snmp_var_new_integer(Var->name, Var->name_length, |
605 | memInUse(MEM_FQDNCACHE_ENTRY), | |
606 | SMI_GAUGE32); | |
135171fe | 607 | break; |
e7ef99a7 | 608 | case FQDN_REQ: |
736eb6ad | 609 | Answer = snmp_var_new_integer(Var->name, Var->name_length, |
610 | FqdncacheStats.requests, | |
611 | SMI_COUNTER32); | |
135171fe | 612 | break; |
e7ef99a7 | 613 | case FQDN_HITS: |
736eb6ad | 614 | Answer = snmp_var_new_integer(Var->name, Var->name_length, |
615 | FqdncacheStats.hits, | |
616 | SMI_COUNTER32); | |
135171fe | 617 | break; |
e7ef99a7 | 618 | case FQDN_PENDHIT: |
add5d21f | 619 | /* this is now worthless */ |
736eb6ad | 620 | Answer = snmp_var_new_integer(Var->name, Var->name_length, |
add5d21f | 621 | 0, |
736eb6ad | 622 | SMI_GAUGE32); |
135171fe | 623 | break; |
e7ef99a7 | 624 | case FQDN_NEGHIT: |
736eb6ad | 625 | Answer = snmp_var_new_integer(Var->name, Var->name_length, |
626 | FqdncacheStats.negative_hits, | |
627 | SMI_COUNTER32); | |
135171fe | 628 | break; |
e7ef99a7 | 629 | case FQDN_MISS: |
736eb6ad | 630 | Answer = snmp_var_new_integer(Var->name, Var->name_length, |
631 | FqdncacheStats.misses, | |
632 | SMI_COUNTER32); | |
135171fe | 633 | break; |
e7ef99a7 | 634 | case FQDN_GHBN: |
736eb6ad | 635 | Answer = snmp_var_new_integer(Var->name, Var->name_length, |
998adf71 | 636 | 0, /* deprecated */ |
736eb6ad | 637 | SMI_COUNTER32); |
135171fe | 638 | break; |
ce75f381 | 639 | default: |
135171fe | 640 | *ErrP = SNMP_ERR_NOSUCHNAME; |
736eb6ad | 641 | break; |
86115da5 | 642 | } |
643 | return Answer; | |
ce75f381 | 644 | } |
e7ef99a7 | 645 | |
135171fe | 646 | #endif /*SQUID_SNMP */ |