/* * $Id: ipcache.c,v 1.245.2.3 2007/11/26 10:59:09 adrian Exp $ * * DEBUG: section 14 IP Cache * AUTHOR: Harvest Derived * * SQUID Web Proxy Cache http://www.squid-cache.org/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from * the Internet community; see the CONTRIBUTORS file for full * details. Many organizations have provided support for Squid's * development; see the SPONSORS file for full details. Squid is * Copyrighted (C) 2001 by the Regents of the University of * California; see the COPYRIGHT file for full details. Squid * incorporates software developed and/or copyrighted by other * sources; see the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" typedef struct _ipcache_entry ipcache_entry; struct _ipcache_entry { hash_link hash; /* must be first */ time_t lastref; time_t expires; ipcache_addrs addrs; IPH *handler; void *handlerData; char *error_message; struct timeval request_time; dlink_node lru; unsigned short locks; struct { unsigned int negcached:1; unsigned int fromhosts:1; } flags; }; static struct { int requests; int replies; int hits; int misses; int negative_hits; int numeric_hits; int invalid; } IpcacheStats; static dlink_list lru_list; static FREE ipcacheFreeEntry; #if USE_DNSSERVERS static HLPCB ipcacheHandleReply; #else static IDNSCB ipcacheHandleReply; #endif static IPH dummy_handler; static int ipcacheExpiredEntry(ipcache_entry *); static int ipcache_testname(void); #if USE_DNSSERVERS static ipcache_entry *ipcacheParse(ipcache_entry *, const char *buf); #else static ipcache_entry *ipcacheParse(ipcache_entry *, rfc1035_rr *, int, const char *error); #endif static ipcache_entry *ipcache_get(const char *); static void ipcacheLockEntry(ipcache_entry *); static void ipcacheStatPrint(ipcache_entry *, StoreEntry *); static void ipcacheUnlockEntry(ipcache_entry *); static void ipcacheRelease(ipcache_entry *); static ipcache_addrs static_addrs; static hash_table *ip_table = NULL; static long ipcache_low = 180; static long ipcache_high = 200; #if LIBRESOLV_DNS_TTL_HACK extern int _dns_ttl_; #endif static int ipcache_testname(void) { wordlist *w = NULL; debug(14, 1) ("Performing DNS Tests...\n"); if ((w = Config.dns_testname_list) == NULL) return 1; for (; w; w = w->next) { if (gethostbyname(w->key) != NULL) return 1; } return 0; } /* removes the given ipcache entry */ static void ipcacheRelease(ipcache_entry * i) { debug(14, 3) ("ipcacheRelease: Releasing entry for '%s'\n", (const char *) i->hash.key); hash_remove_link(ip_table, (hash_link *) i); dlinkDelete(&i->lru, &lru_list); ipcacheFreeEntry(i); } static ipcache_entry * ipcache_get(const char *name) { if (ip_table != NULL) return (ipcache_entry *) hash_lookup(ip_table, name); else return NULL; } static int ipcacheExpiredEntry(ipcache_entry * i) { /* all static entries are locked, so this takes care of them too */ if (i->locks != 0) return 0; if (i->addrs.count == 0) if (0 == i->flags.negcached) return 1; if (i->expires > squid_curtime) return 0; return 1; } void ipcache_purgelru(void *voidnotused) { dlink_node *m; dlink_node *prev = NULL; ipcache_entry *i; int removed = 0; eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1); for (m = lru_list.tail; m; m = prev) { if (memInUse(MEM_IPCACHE_ENTRY) < ipcache_low) break; prev = m->prev; i = m->data; if (i->locks != 0) continue; ipcacheRelease(i); removed++; } debug(14, 9) ("ipcache_purgelru: removed %d entries\n", removed); } /* purges entries added from /etc/hosts (or whatever). */ static void purge_entries_fromhosts(void) { dlink_node *m = lru_list.head; ipcache_entry *i = NULL, *t; while (m) { if (i != NULL) { /* need to delay deletion */ ipcacheRelease(i); /* we just override locks */ i = NULL; } t = m->data; if (t->flags.fromhosts) i = t; m = m->next; } if (i != NULL) ipcacheRelease(i); } /* create blank ipcache_entry */ static ipcache_entry * ipcacheCreateEntry(const char *name) { static ipcache_entry *i; i = memAllocate(MEM_IPCACHE_ENTRY); i->hash.key = xstrdup(name); i->expires = squid_curtime + Config.negativeDnsTtl; return i; } static void ipcacheAddEntry(ipcache_entry * i) { hash_link *e = hash_lookup(ip_table, i->hash.key); if (NULL != e) { /* avoid colission */ ipcache_entry *q = (ipcache_entry *) e; ipcacheRelease(q); } hash_join(ip_table, &i->hash); dlinkAdd(i, &i->lru, &lru_list); i->lastref = squid_curtime; } /* walks down the pending list, calling handlers */ static void ipcacheCallback(ipcache_entry * i) { IPH *handler = i->handler; void *handlerData = i->handlerData; i->lastref = squid_curtime; ipcacheLockEntry(i); if (NULL == handler) return; i->handler = NULL; i->handlerData = NULL; if (cbdataValid(handlerData)) { dns_error_message = i->error_message; handler(i->addrs.count ? &i->addrs : NULL, handlerData); } cbdataUnlock(handlerData); ipcacheUnlockEntry(i); } #if USE_DNSSERVERS static ipcache_entry * ipcacheParse(ipcache_entry * i, const char *inbuf) { LOCAL_ARRAY(char, buf, DNS_INBUF_SZ); char *token; int j = 0; int k; int ipcount = 0; int ttl; char A[32][16]; const char *name = (const char *) i->hash.key; i->expires = squid_curtime + Config.negativeDnsTtl; i->flags.negcached = 1; safe_free(i->addrs.in_addrs); safe_free(i->addrs.bad_mask); safe_free(i->error_message); i->addrs.count = 0; if (inbuf == NULL) { debug(14, 1) ("ipcacheParse: Got reply\n"); i->error_message = xstrdup("Internal Squid Error"); return i; } xstrncpy(buf, inbuf, DNS_INBUF_SZ); debug(14, 5) ("ipcacheParse: parsing: {%s}\n", buf); token = strtok(buf, w_space); if (NULL == token) { debug(14, 1) ("ipcacheParse: expecting result, got '%s'\n", inbuf); i->error_message = xstrdup("Internal Squid Error"); return NULL; } if (0 == strcmp(token, "$fail")) { token = strtok(NULL, "\n"); assert(NULL != token); i->error_message = xstrdup(token); return i; } if (0 != strcmp(token, "$addr")) { debug(14, 1) ("ipcacheParse: expecting '$addr', got '%s' in response to '%s'\n", inbuf, name); i->error_message = xstrdup("Internal Squid Error"); return NULL; } token = strtok(NULL, w_space); if (NULL == token) { debug(14, 1) ("ipcacheParse: expecting data, got '%s' in response to '%s'\n", inbuf, name); i->error_message = xstrdup("Internal Squid Error"); return NULL; } i->flags.negcached = 0; ttl = atoi(token); while (NULL != (token = strtok(NULL, w_space))) { xstrncpy(A[ipcount], token, 16); if (++ipcount == 32) break; } if (ipcount <= 0) { debug(14, 1) ("ipcacheParse: No addresses in response to '%s'\n", name); } else { i->addrs.in_addrs = xcalloc(ipcount, sizeof(struct in_addr)); i->addrs.bad_mask = xcalloc(ipcount, sizeof(unsigned char)); for (j = 0, k = 0; k < ipcount; k++) { if (safe_inet_addr(A[k], &i->addrs.in_addrs[j])) j++; else debug(14, 1) ("ipcacheParse: Invalid IP address '%s' in response to '%s'\n", A[k], name); } } i->addrs.count = (unsigned char) j; if (ttl == 0 || ttl > Config.positiveDnsTtl) ttl = Config.positiveDnsTtl; if (ttl < Config.negativeDnsTtl) ttl = Config.negativeDnsTtl; i->expires = squid_curtime + ttl; return i; } #else static ipcache_entry * ipcacheParse(ipcache_entry * i, rfc1035_rr * answers, int nr, const char *error_message) { int k; int j; int na = 0; int ttl = 0; const char *name = (const char *) i->hash.key; i->expires = squid_curtime + Config.negativeDnsTtl; i->flags.negcached = 1; safe_free(i->addrs.in_addrs); safe_free(i->addrs.bad_mask); safe_free(i->error_message); i->addrs.count = 0; if (nr < 0) { debug(14, 3) ("ipcacheParse: Lookup failed '%s' for '%s'\n", error_message, (const char *) i->hash.key); i->error_message = xstrdup(error_message); return i; } if (nr == 0) { debug(14, 3) ("ipcacheParse: No DNS records in response to '%s'\n", name); i->error_message = xstrdup("No DNS records"); return i; } assert(answers); for (k = 0; k < nr; k++) { if (answers[k].type != RFC1035_TYPE_A) continue; if (answers[k].class != RFC1035_CLASS_IN) continue; if (answers[k].rdlength != 4) { debug(14, 1) ("ipcacheParse: Invalid IP address in response to '%s'\n", name); continue; } na++; } if (na == 0) { debug(14, 1) ("ipcacheParse: No Address records in response to '%s'\n", name); i->error_message = xstrdup("No Address records"); return i; } i->flags.negcached = 0; i->addrs.in_addrs = xcalloc(na, sizeof(struct in_addr)); i->addrs.bad_mask = xcalloc(na, sizeof(unsigned char)); for (j = 0, k = 0; k < nr; k++) { if (answers[k].class != RFC1035_CLASS_IN) continue; if (answers[k].type == RFC1035_TYPE_A) { if (answers[k].rdlength != 4) continue; xmemcpy(&i->addrs.in_addrs[j++], answers[k].rdata, 4); debug(14, 3) ("ipcacheParse: #%d %s\n", j - 1, inet_ntoa(i->addrs.in_addrs[j - 1])); } else if (answers[k].type != RFC1035_TYPE_CNAME) continue; if (ttl == 0 || ttl > answers[k].ttl) ttl = answers[k].ttl; } if (na < 256) i->addrs.count = (unsigned char) na; else i->addrs.count = 255; if (ttl > Config.positiveDnsTtl) ttl = Config.positiveDnsTtl; if (ttl < Config.negativeDnsTtl) ttl = Config.negativeDnsTtl; i->expires = squid_curtime + ttl; assert(j == na); return i; } #endif static void #if USE_DNSSERVERS ipcacheHandleReply(void *data, char *reply) #else ipcacheHandleReply(void *data, rfc1035_rr * answers, int na, const char *error_message) #endif { generic_cbdata *c = data; ipcache_entry *i = c->data; cbdataFree(c); c = NULL; IpcacheStats.replies++; statHistCount(&statCounter.dns.svc_time, tvSubMsec(i->request_time, current_time)); #if USE_DNSSERVERS ipcacheParse(i, reply); #else ipcacheParse(i, answers, na, error_message); #endif ipcacheAddEntry(i); ipcacheCallback(i); } void ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData) { ipcache_entry *i = NULL; const ipcache_addrs *addrs = NULL; generic_cbdata *c; assert(handler != NULL); debug(14, 4) ("ipcache_nbgethostbyname: Name '%s'.\n", name); IpcacheStats.requests++; if (name == NULL || name[0] == '\0') { debug(14, 4) ("ipcache_nbgethostbyname: Invalid name!\n"); IpcacheStats.invalid++; dns_error_message = "Invalid hostname"; handler(NULL, handlerData); return; } if ((addrs = ipcacheCheckNumeric(name))) { dns_error_message = NULL; IpcacheStats.numeric_hits++; handler(addrs, handlerData); return; } i = ipcache_get(name); if (NULL == i) { /* miss */ (void) 0; } else if (ipcacheExpiredEntry(i)) { /* hit, but expired -- bummer */ ipcacheRelease(i); i = NULL; } else { /* hit */ debug(14, 4) ("ipcache_nbgethostbyname: HIT for '%s'\n", name); if (i->flags.negcached) IpcacheStats.negative_hits++; else IpcacheStats.hits++; i->handler = handler; i->handlerData = handlerData; cbdataLock(handlerData); ipcacheCallback(i); return; } debug(14, 5) ("ipcache_nbgethostbyname: MISS for '%s'\n", name); IpcacheStats.misses++; i = ipcacheCreateEntry(name); i->handler = handler; i->handlerData = handlerData; cbdataLock(handlerData); i->request_time = current_time; c = cbdataAlloc(generic_cbdata); c->data = i; #if USE_DNSSERVERS dnsSubmit(hashKeyStr(&i->hash), ipcacheHandleReply, c); #else idnsALookup(hashKeyStr(&i->hash), ipcacheHandleReply, c); #endif } /* initialize the ipcache */ void ipcache_init(void) { int n; debug(14, 3) ("Initializing IP Cache...\n"); memset(&IpcacheStats, '\0', sizeof(IpcacheStats)); memset(&lru_list, '\0', sizeof(lru_list)); /* test naming lookup */ if (!opt_dns_tests) { debug(14, 4) ("ipcache_init: Skipping DNS name lookup tests.\n"); } else if (!ipcache_testname()) { fatal("ipcache_init: DNS name lookup tests failed."); } else { debug(14, 1) ("Successful DNS name lookup tests...\n"); } memset(&static_addrs, '\0', sizeof(ipcache_addrs)); static_addrs.in_addrs = xcalloc(1, sizeof(struct in_addr)); static_addrs.bad_mask = xcalloc(1, sizeof(unsigned char)); ipcache_high = (long) (((float) Config.ipcache.size * (float) Config.ipcache.high) / (float) 100); ipcache_low = (long) (((float) Config.ipcache.size * (float) Config.ipcache.low) / (float) 100); n = hashPrime(ipcache_high / 4); ip_table = hash_create((HASHCMP *) strcmp, n, hash4); cachemgrRegister("ipcache", "IP Cache Stats and Contents", stat_ipcache_get, 0, 1); memDataInit(MEM_IPCACHE_ENTRY, "ipcache_entry", sizeof(ipcache_entry), 0); } const ipcache_addrs * ipcache_gethostbyname(const char *name, int flags) { ipcache_entry *i = NULL; ipcache_addrs *addrs; assert(name); debug(14, 3) ("ipcache_gethostbyname: '%s', flags=%x\n", name, flags); IpcacheStats.requests++; i = ipcache_get(name); if (NULL == i) { (void) 0; } else if (ipcacheExpiredEntry(i)) { ipcacheRelease(i); i = NULL; } else if (i->flags.negcached) { IpcacheStats.negative_hits++; dns_error_message = i->error_message; return NULL; } else { IpcacheStats.hits++; i->lastref = squid_curtime; dns_error_message = i->error_message; return &i->addrs; } dns_error_message = NULL; if ((addrs = ipcacheCheckNumeric(name))) { IpcacheStats.numeric_hits++; return addrs; } IpcacheStats.misses++; if (flags & IP_LOOKUP_IF_MISS) ipcache_nbgethostbyname(name, dummy_handler, NULL); return NULL; } static void ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry) { int k; storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)", hashKeyStr(&i->hash), i->flags.fromhosts ? 'H' : ' ', i->flags.negcached ? 'N' : ' ', (int) (squid_curtime - i->lastref), (int) ((i->flags.fromhosts ? -1 : i->expires - squid_curtime)), (int) i->addrs.count, (int) i->addrs.badcount); for (k = 0; k < (int) i->addrs.count; k++) { storeAppendPrintf(sentry, " %15s-%3s", inet_ntoa(i->addrs.in_addrs[k]), i->addrs.bad_mask[k] ? "BAD" : "OK "); } storeAppendPrintf(sentry, "\n"); } /* process objects list */ void stat_ipcache_get(StoreEntry * sentry) { dlink_node *m; assert(ip_table != NULL); storeAppendPrintf(sentry, "IP Cache Statistics:\n"); storeAppendPrintf(sentry, "IPcache Entries: %d\n", memInUse(MEM_IPCACHE_ENTRY)); storeAppendPrintf(sentry, "IPcache Requests: %d\n", IpcacheStats.requests); storeAppendPrintf(sentry, "IPcache Hits: %d\n", IpcacheStats.hits); storeAppendPrintf(sentry, "IPcache Negative Hits: %d\n", IpcacheStats.negative_hits); storeAppendPrintf(sentry, "IPcache Numeric Hits: %d\n", IpcacheStats.numeric_hits); storeAppendPrintf(sentry, "IPcache Misses: %d\n", IpcacheStats.misses); storeAppendPrintf(sentry, "IPcache Invalid Requests: %d\n", IpcacheStats.invalid); storeAppendPrintf(sentry, "\n\n"); storeAppendPrintf(sentry, "IP Cache Contents:\n\n"); storeAppendPrintf(sentry, " %-29.29s %3s %6s %6s %1s\n", "Hostname", "Flg", "lstref", "TTL", "N"); for (m = lru_list.head; m; m = m->next) ipcacheStatPrint(m->data, sentry); } static void dummy_handler(const ipcache_addrs * addrsnotused, void *datanotused) { return; } void ipcacheInvalidate(const char *name) { ipcache_entry *i; if ((i = ipcache_get(name)) == NULL) return; i->expires = squid_curtime; /* * NOTE, don't call ipcacheRelease here becuase we might be here due * to a thread started from a callback. */ } void ipcacheInvalidateNegative(const char *name) { ipcache_entry *i; if ((i = ipcache_get(name)) == NULL) return; if (i->flags.negcached) i->expires = squid_curtime; /* * NOTE, don't call ipcacheRelease here becuase we might be here due * to a thread started from a callback. */ } ipcache_addrs * ipcacheCheckNumeric(const char *name) { struct in_addr ip; /* check if it's already a IP address in text form. */ if (!safe_inet_addr(name, &ip)) return NULL; static_addrs.count = 1; static_addrs.cur = 0; static_addrs.in_addrs[0].s_addr = ip.s_addr; static_addrs.bad_mask[0] = FALSE; static_addrs.badcount = 0; return &static_addrs; } static void ipcacheLockEntry(ipcache_entry * i) { if (i->locks++ == 0) { dlinkDelete(&i->lru, &lru_list); dlinkAdd(i, &i->lru, &lru_list); } } static void ipcacheUnlockEntry(ipcache_entry * i) { assert(i->locks > 0); i->locks--; if (ipcacheExpiredEntry(i)) ipcacheRelease(i); } void ipcacheCycleAddr(const char *name, ipcache_addrs * ia) { ipcache_entry *i; unsigned char k; assert(name || ia); if (NULL == ia) { if ((i = ipcache_get(name)) == NULL) return; if (i->flags.negcached) return; ia = &i->addrs; } for (k = 0; k < ia->count; k++) { if (++ia->cur == ia->count) ia->cur = 0; if (!ia->bad_mask[ia->cur]) break; } if (k == ia->count) { /* All bad, reset to All good */ debug(14, 3) ("ipcacheCycleAddr: Changing ALL %s addrs from BAD to OK\n", name); for (k = 0; k < ia->count; k++) ia->bad_mask[k] = 0; ia->badcount = 0; ia->cur = 0; } debug(14, 3) ("ipcacheCycleAddr: %s now at %s\n", name, inet_ntoa(ia->in_addrs[ia->cur])); } /* * Marks the given address as BAD and calls ipcacheCycleAddr to * advance the current pointer to the next OK address. */ void ipcacheMarkBadAddr(const char *name, struct in_addr addr) { ipcache_entry *i; ipcache_addrs *ia; int k; if ((i = ipcache_get(name)) == NULL) return; ia = &i->addrs; for (k = 0; k < (int) ia->count; k++) { if (ia->in_addrs[k].s_addr == addr.s_addr) break; } if (k == (int) ia->count) /* not found */ return; if (!ia->bad_mask[k]) { ia->bad_mask[k] = TRUE; ia->badcount++; i->expires = XMIN(squid_curtime + XMAX(60, Config.negativeDnsTtl), i->expires); debug(14, 2) ("ipcacheMarkBadAddr: %s [%s]\n", name, inet_ntoa(addr)); } ipcacheCycleAddr(name, ia); } void ipcacheMarkGoodAddr(const char *name, struct in_addr addr) { ipcache_entry *i; ipcache_addrs *ia; int k; if ((i = ipcache_get(name)) == NULL) return; ia = &i->addrs; for (k = 0; k < (int) ia->count; k++) { if (ia->in_addrs[k].s_addr == addr.s_addr) break; } if (k == (int) ia->count) /* not found */ return; if (!ia->bad_mask[k]) /* already OK */ return; ia->bad_mask[k] = FALSE; ia->badcount--; debug(14, 2) ("ipcacheMarkGoodAddr: %s [%s]\n", name, inet_ntoa(addr)); } static void ipcacheFreeEntry(void *data) { ipcache_entry *i = data; safe_free(i->addrs.in_addrs); safe_free(i->addrs.bad_mask); safe_free(i->hash.key); safe_free(i->error_message); memFree(i, MEM_IPCACHE_ENTRY); } void ipcacheFreeMemory(void) { hashFreeItems(ip_table, ipcacheFreeEntry); hashFreeMemory(ip_table); ip_table = NULL; } /* Recalculate IP cache size upon reconfigure */ void ipcache_restart(void) { ipcache_high = (long) (((float) Config.ipcache.size * (float) Config.ipcache.high) / (float) 100); ipcache_low = (long) (((float) Config.ipcache.size * (float) Config.ipcache.low) / (float) 100); purge_entries_fromhosts(); } /* * adds a "static" entry from /etc/hosts. * returns 0 upon success, 1 if the ip address is invalid */ int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr) { ipcache_entry *i; struct in_addr ip; if (!safe_inet_addr(ipaddr, &ip)) { if (strchr(ipaddr, ':') && strspn(ipaddr, "0123456789abcdefABCDEF:") == strlen(ipaddr)) { debug(14, 3) ("ipcacheAddEntryFromHosts: Skipping IPv6 address '%s'\n", ipaddr); } else { debug(14, 1) ("ipcacheAddEntryFromHosts: Bad IP address '%s'\n", ipaddr); } return 1; } if ((i = ipcache_get(name))) { if (1 == i->flags.fromhosts) { ipcacheUnlockEntry(i); } else if (i->locks > 0) { debug(14, 1) ("ipcacheAddEntryFromHosts: can't add static entry" " for locked name '%s'\n", name); return 1; } else { ipcacheRelease(i); } } i = ipcacheCreateEntry(name); i->addrs.count = 1; i->addrs.cur = 0; i->addrs.badcount = 0; i->addrs.in_addrs = xcalloc(1, sizeof(struct in_addr)); i->addrs.bad_mask = xcalloc(1, sizeof(unsigned char)); i->addrs.in_addrs[0].s_addr = ip.s_addr; i->addrs.bad_mask[0] = FALSE; i->flags.fromhosts = 1; ipcacheAddEntry(i); ipcacheLockEntry(i); return 0; } #ifdef SQUID_SNMP /* * The function to return the ip cache statistics to via SNMP */ variable_list * snmp_netIpFn(variable_list * Var, snint * ErrP) { variable_list *Answer = NULL; debug(49, 5) ("snmp_netIpFn: Processing request:\n"); snmpDebugOid(5, Var->name, Var->name_length); *ErrP = SNMP_ERR_NOERROR; switch (Var->name[LEN_SQ_NET + 1]) { case IP_ENT: Answer = snmp_var_new_integer(Var->name, Var->name_length, memInUse(MEM_IPCACHE_ENTRY), SMI_GAUGE32); break; case IP_REQ: Answer = snmp_var_new_integer(Var->name, Var->name_length, IpcacheStats.requests, SMI_COUNTER32); break; case IP_HITS: Answer = snmp_var_new_integer(Var->name, Var->name_length, IpcacheStats.hits, SMI_COUNTER32); break; case IP_PENDHIT: Answer = snmp_var_new_integer(Var->name, Var->name_length, 0, /* deprecated */ SMI_GAUGE32); break; case IP_NEGHIT: Answer = snmp_var_new_integer(Var->name, Var->name_length, IpcacheStats.negative_hits, SMI_COUNTER32); break; case IP_MISS: Answer = snmp_var_new_integer(Var->name, Var->name_length, IpcacheStats.misses, SMI_COUNTER32); break; case IP_GHBN: Answer = snmp_var_new_integer(Var->name, Var->name_length, 0, /* deprecated */ SMI_COUNTER32); break; case IP_LOC: Answer = snmp_var_new_integer(Var->name, Var->name_length, 0, /* deprecated */ SMI_COUNTER32); break; default: *ErrP = SNMP_ERR_NOSUCHNAME; snmp_var_free(Answer); return (NULL); } return Answer; } #endif /*SQUID_SNMP */