]> git.ipfire.org Git - thirdparty/squid.git/blob - src/fqdncache.cc
5c0c3a6e90b7b080d955b319244080b9ed225f5b
[thirdparty/squid.git] / src / fqdncache.cc
1 /*
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /* DEBUG: section 35 FQDN Cache */
10
11 #include "squid.h"
12 #include "cbdata.h"
13 #include "DnsLookupDetails.h"
14 #include "event.h"
15 #include "helper.h"
16 #include "Mem.h"
17 #include "mgr/Registration.h"
18 #include "SquidConfig.h"
19 #include "SquidDns.h"
20 #include "SquidTime.h"
21 #include "StatCounters.h"
22 #include "Store.h"
23 #include "wordlist.h"
24
25 #if SQUID_SNMP
26 #include "snmp_core.h"
27 #endif
28
29 /**
30 \defgroup FQDNCacheAPI FQDN Cache API
31 \ingroup Components
32 \section Introduction Introduction
33 \par
34 * The FQDN cache is a built-in component of squid providing
35 * Hostname to IP-Number translation functionality and managing
36 * the involved data-structures. Efficiency concerns require
37 * mechanisms that allow non-blocking access to these mappings.
38 * The FQDN cache usually doesn't block on a request except for
39 * special cases where this is desired (see below).
40 *
41 \todo FQDN Cache should have its own API *.h file.
42 */
43
44 /**
45 \defgroup FQDNCacheInternal FQDN Cache Internals
46 \ingroup FQDNCacheAPI
47 \par
48 * Internally, the execution flow is as follows:
49 * On a miss, fqdncache_nbgethostbyaddr() checks whether a request
50 * for this name is already pending, and if positive, it creates a
51 * new entry using fqdncacheAddEntry(). Then it calls
52 * fqdncacheAddPending() to add a request to the queue together
53 * with data and handler. Else, ifqdncache_dnsDispatch() is called
54 * to directly create a DNS query or to fqdncacheEnqueue() if all
55 * no DNS port is free.
56 *
57 \par
58 * fqdncacheCallback() is called regularly to walk down the pending
59 * list and call handlers.
60 *
61 \par
62 * LRU clean-up is performed through fqdncache_purgelru() according
63 * to the fqdncache_high threshold.
64 */
65
66 /// \ingroup FQDNCacheInternal
67 #define FQDN_LOW_WATER 90
68
69 /// \ingroup FQDNCacheInternal
70 #define FQDN_HIGH_WATER 95
71
72 /**
73 \ingroup FQDNCacheAPI
74 * The data structure used for storing name-address mappings
75 * is a small hashtable (static hash_table *fqdn_table),
76 * where structures of type fqdncache_entry whose most
77 * interesting members are:
78 */
79 class fqdncache_entry
80 {
81 public:
82 hash_link hash; /* must be first */
83 time_t lastref;
84 time_t expires;
85 unsigned char name_count;
86 char *names[FQDN_MAX_NAMES + 1];
87 FQDNH *handler;
88 void *handlerData;
89 char *error_message;
90
91 struct timeval request_time;
92 dlink_node lru;
93 unsigned short locks;
94
95 struct {
96 bool negcached;
97 bool fromhosts;
98 } flags;
99
100 int age() const; ///< time passed since request_time or -1 if unknown
101 };
102
103 /// \ingroup FQDNCacheInternal
104 static struct _fqdn_cache_stats {
105 int requests;
106 int replies;
107 int hits;
108 int misses;
109 int negative_hits;
110 } FqdncacheStats;
111
112 /// \ingroup FQDNCacheInternal
113 static dlink_list lru_list;
114
115 static IDNSCB fqdncacheHandleReply;
116 static int fqdncacheParse(fqdncache_entry *, const rfc1035_rr *, int, const char *error_message);
117 static void fqdncacheRelease(fqdncache_entry *);
118 static fqdncache_entry *fqdncacheCreateEntry(const char *name);
119 static void fqdncacheCallback(fqdncache_entry *, int wait);
120 static fqdncache_entry *fqdncache_get(const char *);
121 static int fqdncacheExpiredEntry(const fqdncache_entry *);
122 static void fqdncacheLockEntry(fqdncache_entry * f);
123 static void fqdncacheUnlockEntry(fqdncache_entry * f);
124 static FREE fqdncacheFreeEntry;
125 static void fqdncacheAddEntry(fqdncache_entry * f);
126
127 /// \ingroup FQDNCacheInternal
128 static hash_table *fqdn_table = NULL;
129
130 /// \ingroup FQDNCacheInternal
131 static long fqdncache_low = 180;
132
133 /// \ingroup FQDNCacheInternal
134 static long fqdncache_high = 200;
135
136 /// \ingroup FQDNCacheInternal
137 inline int fqdncacheCount() { return fqdn_table ? fqdn_table->count : 0; }
138
139 int
140 fqdncache_entry::age() const
141 {
142 return request_time.tv_sec ? tvSubMsec(request_time, current_time) : -1;
143 }
144
145 /**
146 \ingroup FQDNCacheInternal
147 * Removes the given fqdncache entry
148 */
149 static void
150 fqdncacheRelease(fqdncache_entry * f)
151 {
152 int k;
153 hash_remove_link(fqdn_table, (hash_link *) f);
154
155 for (k = 0; k < (int) f->name_count; ++k)
156 safe_free(f->names[k]);
157
158 debugs(35, 5, "fqdncacheRelease: Released FQDN record for '" << hashKeyStr(&f->hash) << "'.");
159
160 dlinkDelete(&f->lru, &lru_list);
161
162 safe_free(f->hash.key);
163
164 safe_free(f->error_message);
165
166 memFree(f, MEM_FQDNCACHE_ENTRY);
167 }
168
169 /**
170 \ingroup FQDNCacheInternal
171 \param name FQDN hash string.
172 \retval Match for given name
173 */
174 static fqdncache_entry *
175 fqdncache_get(const char *name)
176 {
177 hash_link *e;
178 static fqdncache_entry *f;
179 f = NULL;
180
181 if (fqdn_table) {
182 if ((e = (hash_link *)hash_lookup(fqdn_table, name)) != NULL)
183 f = (fqdncache_entry *) e;
184 }
185
186 return f;
187 }
188
189 /// \ingroup FQDNCacheInternal
190 static int
191 fqdncacheExpiredEntry(const fqdncache_entry * f)
192 {
193 /* all static entries are locked, so this takes care of them too */
194
195 if (f->locks != 0)
196 return 0;
197
198 if (f->expires > squid_curtime)
199 return 0;
200
201 return 1;
202 }
203
204 /// \ingroup FQDNCacheAPI
205 void
206 fqdncache_purgelru(void *notused)
207 {
208 dlink_node *m;
209 dlink_node *prev = NULL;
210 fqdncache_entry *f;
211 int removed = 0;
212 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 10.0, 1);
213
214 for (m = lru_list.tail; m; m = prev) {
215 if (fqdncacheCount() < fqdncache_low)
216 break;
217
218 prev = m->prev;
219
220 f = (fqdncache_entry *)m->data;
221
222 if (f->locks != 0)
223 continue;
224
225 fqdncacheRelease(f);
226
227 ++removed;
228 }
229
230 debugs(35, 9, "fqdncache_purgelru: removed " << removed << " entries");
231 }
232
233 /// \ingroup FQDNCacheAPI
234 static void
235 purge_entries_fromhosts(void)
236 {
237 dlink_node *m = lru_list.head;
238 fqdncache_entry *i = NULL;
239 fqdncache_entry *t;
240
241 while (m) {
242 if (i != NULL) { /* need to delay deletion */
243 fqdncacheRelease(i); /* we just override locks */
244 i = NULL;
245 }
246
247 t = (fqdncache_entry *)m->data;
248
249 if (t->flags.fromhosts)
250 i = t;
251
252 m = m->next;
253 }
254
255 if (i != NULL)
256 fqdncacheRelease(i);
257 }
258
259 /**
260 \ingroup FQDNCacheInternal
261 *
262 * Create blank fqdncache_entry
263 */
264 static fqdncache_entry *
265 fqdncacheCreateEntry(const char *name)
266 {
267 static fqdncache_entry *f;
268 f = (fqdncache_entry *)memAllocate(MEM_FQDNCACHE_ENTRY);
269 f->hash.key = xstrdup(name);
270 f->expires = squid_curtime + Config.negativeDnsTtl;
271 return f;
272 }
273
274 /// \ingroup FQDNCacheInternal
275 static void
276 fqdncacheAddEntry(fqdncache_entry * f)
277 {
278 hash_link *e = (hash_link *)hash_lookup(fqdn_table, f->hash.key);
279
280 if (NULL != e) {
281 /* avoid colission */
282 fqdncache_entry *q = (fqdncache_entry *) e;
283 fqdncacheRelease(q);
284 }
285
286 hash_join(fqdn_table, &f->hash);
287 dlinkAdd(f, &f->lru, &lru_list);
288 f->lastref = squid_curtime;
289 }
290
291 /**
292 \ingroup FQDNCacheInternal
293 *
294 * Walks down the pending list, calling handlers
295 */
296 static void
297 fqdncacheCallback(fqdncache_entry * f, int wait)
298 {
299 FQDNH *callback;
300 void *cbdata;
301 f->lastref = squid_curtime;
302
303 if (!f->handler)
304 return;
305
306 fqdncacheLockEntry(f);
307
308 callback = f->handler;
309
310 f->handler = NULL;
311
312 if (cbdataReferenceValidDone(f->handlerData, &cbdata)) {
313 const DnsLookupDetails details(f->error_message, wait);
314 callback(f->name_count ? f->names[0] : NULL, details, cbdata);
315 }
316
317 fqdncacheUnlockEntry(f);
318 }
319
320 /// \ingroup FQDNCacheInternal
321 static int
322 fqdncacheParse(fqdncache_entry *f, const rfc1035_rr * answers, int nr, const char *error_message)
323 {
324 int k;
325 int ttl = 0;
326 const char *name = (const char *)f->hash.key;
327 f->expires = squid_curtime + Config.negativeDnsTtl;
328 f->flags.negcached = true;
329
330 if (nr < 0) {
331 debugs(35, 3, "fqdncacheParse: Lookup of '" << name << "' failed (" << error_message << ")");
332 f->error_message = xstrdup(error_message);
333 return -1;
334 }
335
336 if (nr == 0) {
337 debugs(35, 3, "fqdncacheParse: No DNS records for '" << name << "'");
338 f->error_message = xstrdup("No DNS records");
339 return 0;
340 }
341
342 debugs(35, 3, "fqdncacheParse: " << nr << " answers for '" << name << "'");
343 assert(answers);
344
345 for (k = 0; k < nr; ++k) {
346 if (answers[k]._class != RFC1035_CLASS_IN)
347 continue;
348
349 if (answers[k].type == RFC1035_TYPE_PTR) {
350 if (!answers[k].rdata[0]) {
351 debugs(35, 2, "fqdncacheParse: blank PTR record for '" << name << "'");
352 continue;
353 }
354
355 if (strchr(answers[k].rdata, ' ')) {
356 debugs(35, 2, "fqdncacheParse: invalid PTR record '" << answers[k].rdata << "' for '" << name << "'");
357 continue;
358 }
359
360 f->names[f->name_count] = xstrdup(answers[k].rdata);
361 ++ f->name_count;
362 } else if (answers[k].type != RFC1035_TYPE_CNAME)
363 continue;
364
365 if (ttl == 0 || (int) answers[k].ttl < ttl)
366 ttl = answers[k].ttl;
367
368 if (f->name_count >= FQDN_MAX_NAMES)
369 break;
370 }
371
372 if (f->name_count == 0) {
373 debugs(35, DBG_IMPORTANT, "fqdncacheParse: No PTR record for '" << name << "'");
374 return 0;
375 }
376
377 if (ttl > Config.positiveDnsTtl)
378 ttl = Config.positiveDnsTtl;
379
380 if (ttl < Config.negativeDnsTtl)
381 ttl = Config.negativeDnsTtl;
382
383 f->expires = squid_curtime + ttl;
384
385 f->flags.negcached = false;
386
387 return f->name_count;
388 }
389
390 /**
391 \ingroup FQDNCacheAPI
392 *
393 * Callback for handling DNS results.
394 */
395 static void
396 fqdncacheHandleReply(void *data, const rfc1035_rr * answers, int na, const char *error_message)
397 {
398 fqdncache_entry *f;
399 static_cast<generic_cbdata *>(data)->unwrap(&f);
400 ++FqdncacheStats.replies;
401 const int age = f->age();
402 statCounter.dns.svcTime.count(age);
403 fqdncacheParse(f, answers, na, error_message);
404 fqdncacheAddEntry(f);
405 fqdncacheCallback(f, age);
406 }
407
408 /**
409 \ingroup FQDNCacheAPI
410 *
411 \param addr IP address of domain to resolve.
412 \param handler A pointer to the function to be called when
413 * the reply from the FQDN cache
414 * (or the DNS if the FQDN cache misses)
415 \param handlerData Information that is passed to the handler
416 * and does not affect the FQDN cache.
417 */
418 void
419 fqdncache_nbgethostbyaddr(const Ip::Address &addr, FQDNH * handler, void *handlerData)
420 {
421 fqdncache_entry *f = NULL;
422 char name[MAX_IPSTRLEN];
423 generic_cbdata *c;
424 addr.toStr(name,MAX_IPSTRLEN);
425 debugs(35, 4, "fqdncache_nbgethostbyaddr: Name '" << name << "'.");
426 ++FqdncacheStats.requests;
427
428 if (name[0] == '\0') {
429 debugs(35, 4, "fqdncache_nbgethostbyaddr: Invalid name!");
430 const DnsLookupDetails details("Invalid hostname", -1); // error, no lookup
431 if (handler)
432 handler(NULL, details, handlerData);
433 return;
434 }
435
436 f = fqdncache_get(name);
437
438 if (NULL == f) {
439 /* miss */
440 (void) 0;
441 } else if (fqdncacheExpiredEntry(f)) {
442 /* hit, but expired -- bummer */
443 fqdncacheRelease(f);
444 f = NULL;
445 } else {
446 /* hit */
447 debugs(35, 4, "fqdncache_nbgethostbyaddr: HIT for '" << name << "'");
448
449 if (f->flags.negcached)
450 ++ FqdncacheStats.negative_hits;
451 else
452 ++ FqdncacheStats.hits;
453
454 f->handler = handler;
455
456 f->handlerData = cbdataReference(handlerData);
457
458 fqdncacheCallback(f, -1); // no lookup
459
460 return;
461 }
462
463 debugs(35, 5, "fqdncache_nbgethostbyaddr: MISS for '" << name << "'");
464 ++ FqdncacheStats.misses;
465 f = fqdncacheCreateEntry(name);
466 f->handler = handler;
467 f->handlerData = cbdataReference(handlerData);
468 f->request_time = current_time;
469 c = new generic_cbdata(f);
470 idnsPTRLookup(addr, fqdncacheHandleReply, c);
471 }
472
473 /**
474 \ingroup FQDNCacheAPI
475 *
476 * Is different in that it only checks if an entry exists in
477 * it's data-structures and does not by default contact the
478 * DNS, unless this is requested, by setting the flags
479 * to FQDN_LOOKUP_IF_MISS.
480 *
481 \param addr address of the FQDN being resolved
482 \param flags values are NULL or FQDN_LOOKUP_IF_MISS. default is NULL.
483 *
484 */
485 const char *
486 fqdncache_gethostbyaddr(const Ip::Address &addr, int flags)
487 {
488 char name[MAX_IPSTRLEN];
489 fqdncache_entry *f = NULL;
490
491 if (addr.isAnyAddr() || addr.isNoAddr()) {
492 return NULL;
493 }
494
495 addr.toStr(name,MAX_IPSTRLEN);
496 ++ FqdncacheStats.requests;
497 f = fqdncache_get(name);
498
499 if (NULL == f) {
500 (void) 0;
501 } else if (fqdncacheExpiredEntry(f)) {
502 fqdncacheRelease(f);
503 f = NULL;
504 } else if (f->flags.negcached) {
505 ++ FqdncacheStats.negative_hits;
506 // ignore f->error_message: the caller just checks FQDN cache presence
507 return NULL;
508 } else {
509 ++ FqdncacheStats.hits;
510 f->lastref = squid_curtime;
511 // ignore f->error_message: the caller just checks FQDN cache presence
512 return f->names[0];
513 }
514
515 /* no entry [any more] */
516
517 ++ FqdncacheStats.misses;
518
519 if (flags & FQDN_LOOKUP_IF_MISS) {
520 fqdncache_nbgethostbyaddr(addr, NULL, NULL);
521 }
522
523 return NULL;
524 }
525
526 /**
527 \ingroup FQDNCacheInternal
528 *
529 * Process objects list
530 */
531 void
532 fqdnStats(StoreEntry * sentry)
533 {
534 fqdncache_entry *f = NULL;
535 int k;
536 int ttl;
537
538 if (fqdn_table == NULL)
539 return;
540
541 storeAppendPrintf(sentry, "FQDN Cache Statistics:\n");
542
543 storeAppendPrintf(sentry, "FQDNcache Entries In Use: %d\n",
544 memInUse(MEM_FQDNCACHE_ENTRY));
545
546 storeAppendPrintf(sentry, "FQDNcache Entries Cached: %d\n",
547 fqdncacheCount());
548
549 storeAppendPrintf(sentry, "FQDNcache Requests: %d\n",
550 FqdncacheStats.requests);
551
552 storeAppendPrintf(sentry, "FQDNcache Hits: %d\n",
553 FqdncacheStats.hits);
554
555 storeAppendPrintf(sentry, "FQDNcache Negative Hits: %d\n",
556 FqdncacheStats.negative_hits);
557
558 storeAppendPrintf(sentry, "FQDNcache Misses: %d\n",
559 FqdncacheStats.misses);
560
561 storeAppendPrintf(sentry, "FQDN Cache Contents:\n\n");
562
563 storeAppendPrintf(sentry, "%-45.45s %3s %3s %3s %s\n",
564 "Address", "Flg", "TTL", "Cnt", "Hostnames");
565
566 hash_first(fqdn_table);
567
568 while ((f = (fqdncache_entry *) hash_next(fqdn_table))) {
569 ttl = (f->flags.fromhosts ? -1 : (f->expires - squid_curtime));
570 storeAppendPrintf(sentry, "%-45.45s %c%c %3.3d % 3d",
571 hashKeyStr(&f->hash),
572 f->flags.negcached ? 'N' : ' ',
573 f->flags.fromhosts ? 'H' : ' ',
574 ttl,
575 (int) f->name_count);
576
577 for (k = 0; k < (int) f->name_count; ++k)
578 storeAppendPrintf(sentry, " %s", f->names[k]);
579
580 storeAppendPrintf(sentry, "\n");
581 }
582 }
583
584 /// \ingroup FQDNCacheInternal
585 static void
586 fqdncacheLockEntry(fqdncache_entry * f)
587 {
588 if (f->locks++ == 0) {
589 dlinkDelete(&f->lru, &lru_list);
590 dlinkAdd(f, &f->lru, &lru_list);
591 }
592 }
593
594 /// \ingroup FQDNCacheInternal
595 static void
596 fqdncacheUnlockEntry(fqdncache_entry * f)
597 {
598 assert(f->locks > 0);
599 -- f->locks;
600
601 if (fqdncacheExpiredEntry(f))
602 fqdncacheRelease(f);
603 }
604
605 /// \ingroup FQDNCacheInternal
606 static void
607 fqdncacheFreeEntry(void *data)
608 {
609 fqdncache_entry *f = (fqdncache_entry *)data;
610 int k;
611
612 for (k = 0; k < (int) f->name_count; ++k)
613 safe_free(f->names[k]);
614
615 safe_free(f->hash.key);
616
617 safe_free(f->error_message);
618
619 memFree(f, MEM_FQDNCACHE_ENTRY);
620 }
621
622 /// \ingroup FQDNCacheAPI
623 void
624 fqdncacheFreeMemory(void)
625 {
626 hashFreeItems(fqdn_table, fqdncacheFreeEntry);
627 hashFreeMemory(fqdn_table);
628 fqdn_table = NULL;
629 }
630
631 /**
632 \ingroup FQDNCacheAPI
633 *
634 * Recalculate FQDN cache size upon reconfigure.
635 * Is called to clear the FQDN cache's data structures,
636 * cancel all pending requests.
637 */
638 void
639 fqdncache_restart(void)
640 {
641 fqdncache_high = (long) (((float) Config.fqdncache.size *
642 (float) FQDN_HIGH_WATER) / (float) 100);
643 fqdncache_low = (long) (((float) Config.fqdncache.size *
644 (float) FQDN_LOW_WATER) / (float) 100);
645 purge_entries_fromhosts();
646 }
647
648 /**
649 \ingroup FQDNCacheAPI
650 *
651 * Adds a "static" entry from /etc/hosts.
652 \par
653 * The worldist is to be managed by the caller,
654 * including pointed-to strings
655 *
656 \param addr FQDN name to be added.
657 \param hostnames ??
658 */
659 void
660 fqdncacheAddEntryFromHosts(char *addr, wordlist * hostnames)
661 {
662 fqdncache_entry *fce;
663 int j = 0;
664
665 if ((fce = fqdncache_get(addr))) {
666 if (1 == fce->flags.fromhosts) {
667 fqdncacheUnlockEntry(fce);
668 } else if (fce->locks > 0) {
669 debugs(35, DBG_IMPORTANT, "fqdncacheAddEntryFromHosts: can't add static entry for locked address '" << addr << "'");
670 return;
671 } else {
672 fqdncacheRelease(fce);
673 }
674 }
675
676 fce = fqdncacheCreateEntry(addr);
677
678 while (hostnames) {
679 fce->names[j] = xstrdup(hostnames->key);
680 Tolower(fce->names[j]);
681 ++j;
682 hostnames = hostnames->next;
683
684 if (j >= FQDN_MAX_NAMES)
685 break;
686 }
687
688 fce->name_count = j;
689 fce->names[j] = NULL; /* it's safe */
690 fce->flags.fromhosts = true;
691 fqdncacheAddEntry(fce);
692 fqdncacheLockEntry(fce);
693 }
694
695 /// \ingroup FQDNCacheInternal
696 static void
697 fqdncacheRegisterWithCacheManager(void)
698 {
699 Mgr::RegisterAction("fqdncache", "FQDN Cache Stats and Contents",
700 fqdnStats, 0, 1);
701
702 }
703
704 /**
705 \ingroup FQDNCacheAPI
706 *
707 * Initialize the fqdncache.
708 * Called after IP cache initialization.
709 */
710 void
711 fqdncache_init(void)
712 {
713 int n;
714
715 fqdncacheRegisterWithCacheManager();
716
717 if (fqdn_table)
718 return;
719
720 debugs(35, 3, "Initializing FQDN Cache...");
721
722 memset(&FqdncacheStats, '\0', sizeof(FqdncacheStats));
723
724 memset(&lru_list, '\0', sizeof(lru_list));
725
726 fqdncache_high = (long) (((float) Config.fqdncache.size *
727 (float) FQDN_HIGH_WATER) / (float) 100);
728
729 fqdncache_low = (long) (((float) Config.fqdncache.size *
730 (float) FQDN_LOW_WATER) / (float) 100);
731
732 n = hashPrime(fqdncache_high / 4);
733
734 fqdn_table = hash_create((HASHCMP *) strcmp, n, hash4);
735
736 memDataInit(MEM_FQDNCACHE_ENTRY, "fqdncache_entry",
737 sizeof(fqdncache_entry), 0);
738 }
739
740 #if SQUID_SNMP
741 /**
742 * \ingroup FQDNCacheAPI
743 * The function to return the FQDN statistics via SNMP
744 */
745 variable_list *
746 snmp_netFqdnFn(variable_list * Var, snint * ErrP)
747 {
748 variable_list *Answer = NULL;
749 MemBuf tmp;
750 debugs(49, 5, "snmp_netFqdnFn: Processing request:" << snmpDebugOid(Var->name, Var->name_length, tmp));
751 *ErrP = SNMP_ERR_NOERROR;
752
753 switch (Var->name[LEN_SQ_NET + 1]) {
754
755 case FQDN_ENT:
756 Answer = snmp_var_new_integer(Var->name, Var->name_length,
757 fqdncacheCount(),
758 SMI_GAUGE32);
759 break;
760
761 case FQDN_REQ:
762 Answer = snmp_var_new_integer(Var->name, Var->name_length,
763 FqdncacheStats.requests,
764 SMI_COUNTER32);
765 break;
766
767 case FQDN_HITS:
768 Answer = snmp_var_new_integer(Var->name, Var->name_length,
769 FqdncacheStats.hits,
770 SMI_COUNTER32);
771 break;
772
773 case FQDN_PENDHIT:
774 /* this is now worthless */
775 Answer = snmp_var_new_integer(Var->name, Var->name_length,
776 0,
777 SMI_GAUGE32);
778 break;
779
780 case FQDN_NEGHIT:
781 Answer = snmp_var_new_integer(Var->name, Var->name_length,
782 FqdncacheStats.negative_hits,
783 SMI_COUNTER32);
784 break;
785
786 case FQDN_MISS:
787 Answer = snmp_var_new_integer(Var->name, Var->name_length,
788 FqdncacheStats.misses,
789 SMI_COUNTER32);
790 break;
791
792 case FQDN_GHBN:
793 Answer = snmp_var_new_integer(Var->name, Var->name_length,
794 0, /* deprecated */
795 SMI_COUNTER32);
796 break;
797
798 default:
799 *ErrP = SNMP_ERR_NOSUCHNAME;
800 break;
801 }
802
803 return Answer;
804 }
805
806 #endif /*SQUID_SNMP */