]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ipcache.cc
A modified / unified cbdata and mempool implementation. cbdata
[thirdparty/squid.git] / src / ipcache.cc
1
2 /*
3 * $Id: ipcache.cc,v 1.231 2001/01/05 09:51:38 adrian Exp $
4 *
5 * DEBUG: section 14 IP Cache
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
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 the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * the Regents of the University of California. Please see the
16 * COPYRIGHT file for full details. Squid incorporates software
17 * developed and/or copyrighted by other sources. Please see the
18 * CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37
38 typedef struct _ipcache_entry ipcache_entry;
39
40 struct _ipcache_entry {
41 hash_link hash; /* must be first */
42 time_t lastref;
43 time_t expires;
44 ipcache_addrs addrs;
45 IPH *handler;
46 void *handlerData;
47 char *error_message;
48 struct timeval request_time;
49 dlink_node lru;
50 unsigned short locks;
51 struct {
52 unsigned int negcached:1;
53 unsigned int fromhosts:1;
54 } flags;
55 };
56
57 static struct {
58 int requests;
59 int replies;
60 int hits;
61 int misses;
62 int negative_hits;
63 int errors;
64 int ghbn_calls; /* # calls to blocking gethostbyname() */
65 int release_locked;
66 } IpcacheStats;
67
68 static dlink_list lru_list;
69
70 static FREE ipcacheFreeEntry;
71 #if USE_DNSSERVERS
72 static HLPCB ipcacheHandleReply;
73 #else
74 static IDNSCB ipcacheHandleReply;
75 #endif
76 static IPH dummy_handler;
77 static int ipcacheExpiredEntry(ipcache_entry *);
78 static int ipcache_testname(void);
79 #if USE_DNSSERVERS
80 static ipcache_entry *ipcacheParse(const char *buf);
81 #else
82 static ipcache_entry *ipcacheParse(rfc1035_rr *, int);
83 #endif
84 static ipcache_entry *ipcache_get(const char *);
85 static void ipcacheLockEntry(ipcache_entry *);
86 static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
87 static void ipcacheUnlockEntry(ipcache_entry *);
88 static void ipcacheRelease(ipcache_entry *);
89
90 static ipcache_addrs static_addrs;
91 static hash_table *ip_table = NULL;
92
93 static long ipcache_low = 180;
94 static long ipcache_high = 200;
95
96 #if LIBRESOLV_DNS_TTL_HACK
97 extern int _dns_ttl_;
98 #endif
99
100 static int
101 ipcache_testname(void)
102 {
103 wordlist *w = NULL;
104 debug(14, 1) ("Performing DNS Tests...\n");
105 if ((w = Config.dns_testname_list) == NULL)
106 return 1;
107 for (; w; w = w->next) {
108 IpcacheStats.ghbn_calls++;
109 if (gethostbyname(w->key) != NULL)
110 return 1;
111 }
112 return 0;
113 }
114
115 /* removes the given ipcache entry */
116 static void
117 ipcacheRelease(ipcache_entry * i)
118 {
119 hash_remove_link(ip_table, (hash_link *) i);
120 dlinkDelete(&i->lru, &lru_list);
121 ipcacheFreeEntry(i);
122 }
123
124 static ipcache_entry *
125 ipcache_get(const char *name)
126 {
127 if (ip_table != NULL)
128 return (ipcache_entry *) hash_lookup(ip_table, name);
129 else
130 return NULL;
131 }
132
133 static int
134 ipcacheExpiredEntry(ipcache_entry * i)
135 {
136 /* all static entries are locked, so this takes care of them too */
137 if (i->locks != 0)
138 return 0;
139 if (i->addrs.count == 0)
140 if (0 == i->flags.negcached)
141 return 1;
142 if (i->expires > squid_curtime)
143 return 0;
144 return 1;
145 }
146
147 void
148 ipcache_purgelru(void *voidnotused)
149 {
150 dlink_node *m;
151 dlink_node *prev = NULL;
152 ipcache_entry *i;
153 int removed = 0;
154 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
155 for (m = lru_list.tail; m; m = prev) {
156 if (memInUse(MEM_IPCACHE_ENTRY) < ipcache_low)
157 break;
158 prev = m->prev;
159 i = m->data;
160 if (i->locks != 0)
161 continue;
162 ipcacheRelease(i);
163 removed++;
164 }
165 debug(14, 9) ("ipcache_purgelru: removed %d entries\n", removed);
166 }
167
168 /* purges entries added from /etc/hosts (or whatever). */
169 static void
170 purge_entries_fromhosts(void)
171 {
172 dlink_node *m = lru_list.head;
173 ipcache_entry *i = NULL, *t;
174 while (m) {
175 if (i != NULL) { /* need to delay deletion */
176 ipcacheRelease(i); /* we just override locks */
177 i = NULL;
178 }
179 t = m->data;
180 if (t->flags.fromhosts)
181 i = t;
182 m = m->next;
183 }
184 if (i != NULL)
185 ipcacheRelease(i);
186 }
187
188 /* create blank ipcache_entry */
189 static ipcache_entry *
190 ipcacheCreateEntry(const char *name)
191 {
192 static ipcache_entry *i;
193 i = memAllocate(MEM_IPCACHE_ENTRY);
194 i->hash.key = xstrdup(name);
195 i->expires = squid_curtime + Config.negativeDnsTtl;
196 return i;
197 }
198
199 static void
200 ipcacheAddEntry(ipcache_entry * i)
201 {
202 hash_link *e = hash_lookup(ip_table, i->hash.key);
203 if (NULL != e) {
204 /* avoid colission */
205 ipcache_entry *q = (ipcache_entry *) e;
206 ipcacheRelease(q);
207 }
208 hash_join(ip_table, &i->hash);
209 dlinkAdd(i, &i->lru, &lru_list);
210 i->lastref = squid_curtime;
211 }
212
213 /* walks down the pending list, calling handlers */
214 static void
215 ipcacheCallback(ipcache_entry * i)
216 {
217 IPH *handler = i->handler;
218 void *handlerData = i->handlerData;
219 i->lastref = squid_curtime;
220 ipcacheLockEntry(i);
221 if (NULL == handler)
222 return;
223 i->handler = NULL;
224 i->handlerData = NULL;
225 if (cbdataValid(handlerData)) {
226 dns_error_message = i->error_message;
227 handler(i->flags.negcached ? NULL : &i->addrs, handlerData);
228 }
229 cbdataUnlock(handlerData);
230 ipcacheUnlockEntry(i);
231 }
232
233 static ipcache_entry *
234 #if USE_DNSSERVERS
235 ipcacheParse(const char *inbuf)
236 {
237 LOCAL_ARRAY(char, buf, DNS_INBUF_SZ);
238 char *token;
239 static ipcache_entry i;
240 int j;
241 int k;
242 int ipcount = 0;
243 int ttl;
244 char A[32][16];
245 memset(&i, '\0', sizeof(i));
246 i.expires = squid_curtime;
247 i.flags.negcached = 1;
248 if (inbuf == NULL) {
249 debug(14, 1) ("ipcacheParse: Got <NULL> reply\n");
250 i.error_message = xstrdup("Internal Squid Error");
251 return &i;
252 }
253 xstrncpy(buf, inbuf, DNS_INBUF_SZ);
254 debug(14, 5) ("ipcacheParse: parsing: {%s}\n", buf);
255 token = strtok(buf, w_space);
256 if (NULL == token) {
257 debug(14, 1) ("ipcacheParse: Got <NULL>, expecting '$addr'\n");
258 return &i;
259 }
260 if (0 == strcmp(token, "$fail")) {
261 i.expires = squid_curtime + Config.negativeDnsTtl;
262 token = strtok(NULL, "\n");
263 assert(NULL != token);
264 i.error_message = xstrdup(token);
265 return &i;
266 }
267 if (0 != strcmp(token, "$addr")) {
268 debug(14, 1) ("ipcacheParse: Got '%s', expecting '$addr'\n", token);
269 return &i;
270 }
271 token = strtok(NULL, w_space);
272 if (NULL == token) {
273 debug(14, 1) ("ipcacheParse: Got <NULL>, expecting TTL\n");
274 return &i;
275 }
276 i.flags.negcached = 0;
277 ttl = atoi(token);
278 if (ttl > 0)
279 i.expires = squid_curtime + ttl;
280 else
281 i.expires = squid_curtime + Config.positiveDnsTtl;
282 while (NULL != (token = strtok(NULL, w_space))) {
283 xstrncpy(A[ipcount], token, 16);
284 if (++ipcount == 32)
285 break;
286 }
287 if (0 == ipcount) {
288 i.addrs.in_addrs = NULL;
289 i.addrs.bad_mask = NULL;
290 } else {
291 i.addrs.in_addrs = xcalloc(ipcount, sizeof(struct in_addr));
292 i.addrs.bad_mask = xcalloc(ipcount, sizeof(unsigned char));
293 }
294 for (j = 0, k = 0; k < ipcount; k++) {
295 if (safe_inet_addr(A[k], &i.addrs.in_addrs[j]))
296 j++;
297 else
298 debug(14, 1) ("ipcacheParse: Invalid IP address '%s'\n", A[k]);
299 }
300 i.addrs.count = (unsigned char) j;
301 return &i;
302 }
303 #else
304 ipcacheParse(rfc1035_rr * answers, int nr)
305 {
306 static ipcache_entry i;
307 int k;
308 int j;
309 int na = 0;
310 memset(&i, '\0', sizeof(i));
311 i.expires = squid_curtime + Config.negativeDnsTtl;
312 i.flags.negcached = 1;
313 if (nr < 0) {
314 debug(14, 3) ("ipcacheParse: Lookup failed (error %d)\n",
315 rfc1035_errno);
316 assert(rfc1035_error_message);
317 i.error_message = xstrdup(rfc1035_error_message);
318 return &i;
319 }
320 if (nr == 0) {
321 debug(14, 3) ("ipcacheParse: No DNS records\n");
322 i.error_message = xstrdup("No DNS records");
323 return &i;
324 }
325 assert(answers);
326 for (j = 0, k = 0; k < nr; k++) {
327 if (answers[k].type != RFC1035_TYPE_A)
328 continue;
329 if (answers[k].class != RFC1035_CLASS_IN)
330 continue;
331 na++;
332 }
333 if (na == 0) {
334 debug(14, 1) ("ipcacheParse: No Address records\n");
335 i.error_message = xstrdup("No Address records");
336 return &i;
337 }
338 i.flags.negcached = 0;
339 i.addrs.in_addrs = xcalloc(na, sizeof(struct in_addr));
340 i.addrs.bad_mask = xcalloc(na, sizeof(unsigned char));
341 i.addrs.count = (unsigned char) na;
342 for (j = 0, k = 0; k < nr; k++) {
343 if (answers[k].type != RFC1035_TYPE_A)
344 continue;
345 if (answers[k].class != RFC1035_CLASS_IN)
346 continue;
347 if (j == 0)
348 i.expires = squid_curtime + answers[k].ttl;
349 assert(answers[k].rdlength == 4);
350 xmemcpy(&i.addrs.in_addrs[j++], answers[k].rdata, 4);
351 debug(14, 3) ("ipcacheParse: #%d %s\n",
352 j - 1,
353 inet_ntoa(i.addrs.in_addrs[j - 1]));
354 }
355 assert(j == na);
356 return &i;
357 }
358 #endif
359
360 static void
361 #if USE_DNSSERVERS
362 ipcacheHandleReply(void *data, char *reply)
363 #else
364 ipcacheHandleReply(void *data, rfc1035_rr * answers, int na)
365 #endif
366 {
367 int n;
368 generic_cbdata *c = data;
369 ipcache_entry *i = c->data;
370 ipcache_entry *x = NULL;
371 cbdataFree(c);
372 c = NULL;
373 n = ++IpcacheStats.replies;
374 statHistCount(&statCounter.dns.svc_time,
375 tvSubMsec(i->request_time, current_time));
376 #if USE_DNSSERVERS
377 x = ipcacheParse(reply);
378 #else
379 x = ipcacheParse(answers, na);
380 #endif
381 assert(x);
382 i->addrs = x->addrs;
383 i->error_message = x->error_message;
384 i->expires = x->expires;
385 i->flags = x->flags;
386 ipcacheAddEntry(i);
387 ipcacheCallback(i);
388 }
389
390 void
391 ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
392 {
393 ipcache_entry *i = NULL;
394 const ipcache_addrs *addrs = NULL;
395 generic_cbdata *c;
396 assert(handler != NULL);
397 debug(14, 4) ("ipcache_nbgethostbyname: Name '%s'.\n", name);
398 IpcacheStats.requests++;
399 if (name == NULL || name[0] == '\0') {
400 debug(14, 4) ("ipcache_nbgethostbyname: Invalid name!\n");
401 handler(NULL, handlerData);
402 return;
403 }
404 if ((addrs = ipcacheCheckNumeric(name))) {
405 handler(addrs, handlerData);
406 return;
407 }
408 i = ipcache_get(name);
409 if (NULL == i) {
410 /* miss */
411 (void) 0;
412 } else if (ipcacheExpiredEntry(i)) {
413 /* hit, but expired -- bummer */
414 ipcacheRelease(i);
415 i = NULL;
416 } else {
417 /* hit */
418 debug(14, 4) ("ipcache_nbgethostbyname: HIT for '%s'\n", name);
419 if (i->flags.negcached)
420 IpcacheStats.negative_hits++;
421 else
422 IpcacheStats.hits++;
423 i->handler = handler;
424 i->handlerData = handlerData;
425 cbdataLock(handlerData);
426 ipcacheCallback(i);
427 return;
428 }
429 debug(14, 5) ("ipcache_nbgethostbyname: MISS for '%s'\n", name);
430 IpcacheStats.misses++;
431 i = ipcacheCreateEntry(name);
432 i->handler = handler;
433 i->handlerData = handlerData;
434 cbdataLock(handlerData);
435 i->request_time = current_time;
436 c = CBDATA_ALLOC(generic_cbdata, NULL);
437 c->data = i;
438 #if USE_DNSSERVERS
439 dnsSubmit(hashKeyStr(&i->hash), ipcacheHandleReply, c);
440 #else
441 idnsALookup(hashKeyStr(&i->hash), ipcacheHandleReply, c);
442 #endif
443 }
444
445 /* initialize the ipcache */
446 void
447 ipcache_init(void)
448 {
449 int n;
450 debug(14, 3) ("Initializing IP Cache...\n");
451 memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
452 memset(&lru_list, '\0', sizeof(lru_list));
453 /* test naming lookup */
454 if (!opt_dns_tests) {
455 debug(14, 4) ("ipcache_init: Skipping DNS name lookup tests.\n");
456 } else if (!ipcache_testname()) {
457 fatal("ipcache_init: DNS name lookup tests failed.");
458 } else {
459 debug(14, 1) ("Successful DNS name lookup tests...\n");
460 }
461 memset(&static_addrs, '\0', sizeof(ipcache_addrs));
462 static_addrs.in_addrs = xcalloc(1, sizeof(struct in_addr));
463 static_addrs.bad_mask = xcalloc(1, sizeof(unsigned char));
464 ipcache_high = (long) (((float) Config.ipcache.size *
465 (float) Config.ipcache.high) / (float) 100);
466 ipcache_low = (long) (((float) Config.ipcache.size *
467 (float) Config.ipcache.low) / (float) 100);
468 n = hashPrime(ipcache_high / 4);
469 ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
470 cachemgrRegister("ipcache",
471 "IP Cache Stats and Contents",
472 stat_ipcache_get, 0, 1);
473 memDataInit(MEM_IPCACHE_ENTRY, "ipcache_entry", sizeof(ipcache_entry), 0);
474 }
475
476 const ipcache_addrs *
477 ipcache_gethostbyname(const char *name, int flags)
478 {
479 ipcache_entry *i = NULL;
480 ipcache_addrs *addrs;
481 assert(name);
482 debug(14, 3) ("ipcache_gethostbyname: '%s', flags=%x\n", name, flags);
483 IpcacheStats.requests++;
484 i = ipcache_get(name);
485 if (NULL == i) {
486 (void) 0;
487 } else if (ipcacheExpiredEntry(i)) {
488 ipcacheRelease(i);
489 i = NULL;
490 } else if (i->flags.negcached) {
491 IpcacheStats.negative_hits++;
492 dns_error_message = i->error_message;
493 return NULL;
494 } else {
495 IpcacheStats.hits++;
496 i->lastref = squid_curtime;
497 return &i->addrs;
498 }
499 if ((addrs = ipcacheCheckNumeric(name)))
500 return addrs;
501 IpcacheStats.misses++;
502 if (flags & IP_LOOKUP_IF_MISS)
503 ipcache_nbgethostbyname(name, dummy_handler, NULL);
504 return NULL;
505 }
506
507 static void
508 ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
509 {
510 int k;
511 storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)",
512 hashKeyStr(&i->hash),
513 i->flags.fromhosts ? 'H' : ' ',
514 i->flags.negcached ? 'N' : ' ',
515 (int) (squid_curtime - i->lastref),
516 (int) ((i->flags.fromhosts ? -1 : i->expires - squid_curtime)),
517 (int) i->addrs.count,
518 (int) i->addrs.badcount);
519 for (k = 0; k < (int) i->addrs.count; k++) {
520 storeAppendPrintf(sentry, " %15s-%3s", inet_ntoa(i->addrs.in_addrs[k]),
521 i->addrs.bad_mask[k] ? "BAD" : "OK ");
522 }
523 storeAppendPrintf(sentry, "\n");
524 }
525
526 /* process objects list */
527 void
528 stat_ipcache_get(StoreEntry * sentry)
529 {
530 dlink_node *m;
531 assert(ip_table != NULL);
532 storeAppendPrintf(sentry, "IP Cache Statistics:\n");
533 storeAppendPrintf(sentry, "IPcache Entries: %d\n",
534 memInUse(MEM_IPCACHE_ENTRY));
535 storeAppendPrintf(sentry, "IPcache Requests: %d\n",
536 IpcacheStats.requests);
537 storeAppendPrintf(sentry, "IPcache Hits: %d\n",
538 IpcacheStats.hits);
539 storeAppendPrintf(sentry, "IPcache Negative Hits: %d\n",
540 IpcacheStats.negative_hits);
541 storeAppendPrintf(sentry, "IPcache Misses: %d\n",
542 IpcacheStats.misses);
543 storeAppendPrintf(sentry, "Blocking calls to gethostbyname(): %d\n",
544 IpcacheStats.ghbn_calls);
545 storeAppendPrintf(sentry, "Attempts to release locked entries: %d\n",
546 IpcacheStats.release_locked);
547 storeAppendPrintf(sentry, "\n\n");
548 storeAppendPrintf(sentry, "IP Cache Contents:\n\n");
549 storeAppendPrintf(sentry, " %-29.29s %3s %6s %6s %1s\n",
550 "Hostname",
551 "Flg",
552 "lstref",
553 "TTL",
554 "N");
555 for (m = lru_list.head; m; m = m->next)
556 ipcacheStatPrint(m->data, sentry);
557 }
558
559 static void
560 dummy_handler(const ipcache_addrs * addrsnotused, void *datanotused)
561 {
562 return;
563 }
564
565 void
566 ipcacheInvalidate(const char *name)
567 {
568 ipcache_entry *i;
569 if ((i = ipcache_get(name)) == NULL)
570 return;
571 i->expires = squid_curtime;
572 /*
573 * NOTE, don't call ipcacheRelease here becuase we might be here due
574 * to a thread started from a callback.
575 */
576 }
577
578 ipcache_addrs *
579 ipcacheCheckNumeric(const char *name)
580 {
581 struct in_addr ip;
582 /* check if it's already a IP address in text form. */
583 if (!safe_inet_addr(name, &ip))
584 return NULL;
585 static_addrs.count = 1;
586 static_addrs.cur = 0;
587 static_addrs.in_addrs[0].s_addr = ip.s_addr;
588 static_addrs.bad_mask[0] = FALSE;
589 static_addrs.badcount = 0;
590 return &static_addrs;
591 }
592
593 static void
594 ipcacheLockEntry(ipcache_entry * i)
595 {
596 if (i->locks++ == 0) {
597 dlinkDelete(&i->lru, &lru_list);
598 dlinkAdd(i, &i->lru, &lru_list);
599 }
600 }
601
602 static void
603 ipcacheUnlockEntry(ipcache_entry * i)
604 {
605 assert(i->locks > 0);
606 i->locks--;
607 if (ipcacheExpiredEntry(i))
608 ipcacheRelease(i);
609 }
610
611 void
612 ipcacheCycleAddr(const char *name, ipcache_addrs * ia)
613 {
614 ipcache_entry *i;
615 unsigned char k;
616 assert(name || ia);
617 if (NULL == ia) {
618 if ((i = ipcache_get(name)) == NULL)
619 return;
620 if (i->flags.negcached)
621 return;
622 ia = &i->addrs;
623 }
624 for (k = 0; k < ia->count; k++) {
625 if (++ia->cur == ia->count)
626 ia->cur = 0;
627 if (!ia->bad_mask[ia->cur])
628 break;
629 }
630 if (k == ia->count) {
631 /* All bad, reset to All good */
632 debug(14, 3) ("ipcacheCycleAddr: Changing ALL %s addrs from BAD to OK\n",
633 name);
634 for (k = 0; k < ia->count; k++)
635 ia->bad_mask[k] = 0;
636 ia->badcount = 0;
637 ia->cur = 0;
638 }
639 debug(14, 3) ("ipcacheCycleAddr: %s now at %s\n", name,
640 inet_ntoa(ia->in_addrs[ia->cur]));
641 }
642
643 /*
644 * Marks the given address as BAD and calls ipcacheCycleAddr to
645 * advance the current pointer to the next OK address.
646 */
647 void
648 ipcacheMarkBadAddr(const char *name, struct in_addr addr)
649 {
650 ipcache_entry *i;
651 ipcache_addrs *ia;
652 int k;
653 if ((i = ipcache_get(name)) == NULL)
654 return;
655 ia = &i->addrs;
656 for (k = 0; k < (int) ia->count; k++) {
657 if (ia->in_addrs[k].s_addr == addr.s_addr)
658 break;
659 }
660 if (k == (int) ia->count) /* not found */
661 return;
662 if (!ia->bad_mask[k]) {
663 ia->bad_mask[k] = TRUE;
664 ia->badcount++;
665 debug(14, 2) ("ipcacheMarkBadAddr: %s [%s]\n", name, inet_ntoa(addr));
666 }
667 ipcacheCycleAddr(name, ia);
668 }
669
670 void
671 ipcacheMarkGoodAddr(const char *name, struct in_addr addr)
672 {
673 ipcache_entry *i;
674 ipcache_addrs *ia;
675 int k;
676 if ((i = ipcache_get(name)) == NULL)
677 return;
678 ia = &i->addrs;
679 for (k = 0; k < (int) ia->count; k++) {
680 if (ia->in_addrs[k].s_addr == addr.s_addr)
681 break;
682 }
683 if (k == (int) ia->count) /* not found */
684 return;
685 if (!ia->bad_mask[k]) /* already OK */
686 return;
687 ia->bad_mask[k] = FALSE;
688 ia->badcount--;
689 debug(14, 2) ("ipcacheMarkGoodAddr: %s [%s]\n", name, inet_ntoa(addr));
690 }
691
692 static void
693 ipcacheFreeEntry(void *data)
694 {
695 ipcache_entry *i = data;
696 safe_free(i->addrs.in_addrs);
697 safe_free(i->addrs.bad_mask);
698 safe_free(i->hash.key);
699 safe_free(i->error_message);
700 memFree(i, MEM_IPCACHE_ENTRY);
701 }
702
703 void
704 ipcacheFreeMemory(void)
705 {
706 hashFreeItems(ip_table, ipcacheFreeEntry);
707 hashFreeMemory(ip_table);
708 ip_table = NULL;
709 }
710
711 /* Recalculate IP cache size upon reconfigure */
712 void
713 ipcache_restart(void)
714 {
715 ipcache_high = (long) (((float) Config.ipcache.size *
716 (float) Config.ipcache.high) / (float) 100);
717 ipcache_low = (long) (((float) Config.ipcache.size *
718 (float) Config.ipcache.low) / (float) 100);
719 purge_entries_fromhosts();
720 }
721
722 /*
723 * adds a "static" entry from /etc/hosts.
724 * returns 0 upon success, 1 if the ip address is invalid
725 */
726 int
727 ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
728 {
729 ipcache_entry *i;
730 struct in_addr ip;
731 if (!safe_inet_addr(ipaddr, &ip)) {
732 debug(14, 1) ("ipcacheAddEntryFromHosts: bad IP address '%s'\n",
733 ipaddr);
734 return 1;
735 }
736 if ((i = ipcache_get(name))) {
737 if (1 == i->flags.fromhosts) {
738 ipcacheUnlockEntry(i);
739 } else if (i->locks > 0) {
740 debug(14, 1) ("ipcacheAddEntryFromHosts: can't add static entry"
741 " for locked name '%s'\n", name);
742 return 1;
743 } else {
744 ipcacheRelease(i);
745 }
746 }
747 i = ipcacheCreateEntry(name);
748 i->addrs.count = 1;
749 i->addrs.cur = 0;
750 i->addrs.badcount = 0;
751 i->addrs.in_addrs = xcalloc(1, sizeof(struct in_addr));
752 i->addrs.bad_mask = xcalloc(1, sizeof(unsigned char));
753 i->addrs.in_addrs[0].s_addr = ip.s_addr;
754 i->addrs.bad_mask[0] = FALSE;
755 i->flags.fromhosts = 1;
756 ipcacheAddEntry(i);
757 ipcacheLockEntry(i);
758 return 0;
759 }
760
761 #ifdef SQUID_SNMP
762 /*
763 * The function to return the ip cache statistics to via SNMP
764 */
765
766 variable_list *
767 snmp_netIpFn(variable_list * Var, snint * ErrP)
768 {
769 variable_list *Answer = NULL;
770 debug(49, 5) ("snmp_netIpFn: Processing request:\n", Var->name[LEN_SQ_NET + 1]);
771 snmpDebugOid(5, Var->name, Var->name_length);
772 *ErrP = SNMP_ERR_NOERROR;
773 switch (Var->name[LEN_SQ_NET + 1]) {
774 case IP_ENT:
775 Answer = snmp_var_new_integer(Var->name, Var->name_length,
776 memInUse(MEM_IPCACHE_ENTRY),
777 SMI_GAUGE32);
778 break;
779 case IP_REQ:
780 Answer = snmp_var_new_integer(Var->name, Var->name_length,
781 IpcacheStats.requests,
782 SMI_COUNTER32);
783 break;
784 case IP_HITS:
785 Answer = snmp_var_new_integer(Var->name, Var->name_length,
786 IpcacheStats.hits,
787 SMI_COUNTER32);
788 break;
789 case IP_PENDHIT:
790 Answer = snmp_var_new_integer(Var->name, Var->name_length,
791 0,
792 SMI_GAUGE32);
793 break;
794 case IP_NEGHIT:
795 Answer = snmp_var_new_integer(Var->name, Var->name_length,
796 IpcacheStats.negative_hits,
797 SMI_COUNTER32);
798 break;
799 case IP_MISS:
800 Answer = snmp_var_new_integer(Var->name, Var->name_length,
801 IpcacheStats.misses,
802 SMI_COUNTER32);
803 break;
804 case IP_GHBN:
805 Answer = snmp_var_new_integer(Var->name, Var->name_length,
806 IpcacheStats.ghbn_calls,
807 SMI_COUNTER32);
808 break;
809 case IP_LOC:
810 Answer = snmp_var_new_integer(Var->name, Var->name_length,
811 IpcacheStats.release_locked,
812 SMI_COUNTER32);
813 break;
814 default:
815 *ErrP = SNMP_ERR_NOSUCHNAME;
816 snmp_var_free(Answer);
817 return (NULL);
818 }
819 return Answer;
820 }
821
822 #endif /*SQUID_SNMP */