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