4 * DEBUG: section 35 FQDN Cache
5 * AUTHOR: Harvest Derived
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37 #include "DnsLookupDetails.h"
39 #include "mgr/Registration.h"
40 #include "SquidTime.h"
45 \defgroup FQDNCacheAPI FQDN Cache API
47 \section Introduction Introduction
49 * The FQDN cache is a built-in component of squid providing
50 * Hostname to IP-Number translation functionality and managing
51 * the involved data-structures. Efficiency concerns require
52 * mechanisms that allow non-blocking access to these mappings.
53 * The FQDN cache usually doesn't block on a request except for
54 * special cases where this is desired (see below).
56 \todo FQDN Cache should have its own API *.h file.
60 \defgroup FQDNCacheInternal FQDN Cache Internals
63 * Internally, the execution flow is as follows:
64 * On a miss, fqdncache_nbgethostbyaddr() checks whether a request
65 * for this name is already pending, and if positive, it creates a
66 * new entry using fqdncacheAddEntry(). Then it calls
67 * fqdncacheAddPending() to add a request to the queue together
68 * with data and handler. Else, ifqdncache_dnsDispatch() is called
69 * to directly create a DNS query or to fqdncacheEnqueue() if all
70 * no DNS port is free.
73 * fqdncacheCallback() is called regularly to walk down the pending
74 * list and call handlers.
77 * LRU clean-up is performed through fqdncache_purgelru() according
78 * to the fqdncache_high threshold.
81 /// \ingroup FQDNCacheInternal
82 #define FQDN_LOW_WATER 90
84 /// \ingroup FQDNCacheInternal
85 #define FQDN_HIGH_WATER 95
89 * The data structure used for storing name-address mappings
90 * is a small hashtable (static hash_table *fqdn_table),
91 * where structures of type fqdncache_entry whose most
92 * interesting members are:
97 hash_link hash
; /* must be first */
100 unsigned char name_count
;
101 char *names
[FQDN_MAX_NAMES
+ 1];
106 struct timeval request_time
;
108 unsigned short locks
;
111 unsigned int negcached
:1;
112 unsigned int fromhosts
:1;
115 int age() const; ///< time passed since request_time or -1 if unknown
118 /// \ingroup FQDNCacheInternal
119 static struct _fqdn_cache_stats
{
127 /// \ingroup FQDNCacheInternal
128 static dlink_list lru_list
;
131 static HLPCB fqdncacheHandleReply
;
132 static int fqdncacheParse(fqdncache_entry
*, const char *buf
);
134 static IDNSCB fqdncacheHandleReply
;
135 static int fqdncacheParse(fqdncache_entry
*, rfc1035_rr
*, int, const char *error_message
);
137 static void fqdncacheRelease(fqdncache_entry
*);
138 static fqdncache_entry
*fqdncacheCreateEntry(const char *name
);
139 static void fqdncacheCallback(fqdncache_entry
*, int wait
);
140 static fqdncache_entry
*fqdncache_get(const char *);
141 static int fqdncacheExpiredEntry(const fqdncache_entry
*);
142 static void fqdncacheLockEntry(fqdncache_entry
* f
);
143 static void fqdncacheUnlockEntry(fqdncache_entry
* f
);
144 static FREE fqdncacheFreeEntry
;
145 static void fqdncacheAddEntry(fqdncache_entry
* f
);
147 /// \ingroup FQDNCacheInternal
148 static hash_table
*fqdn_table
= NULL
;
150 /// \ingroup FQDNCacheInternal
151 static long fqdncache_low
= 180;
153 /// \ingroup FQDNCacheInternal
154 static long fqdncache_high
= 200;
156 /// \ingroup FQDNCacheInternal
157 inline int fqdncacheCount() { return fqdn_table
? fqdn_table
->count
: 0; }
160 fqdncache_entry::age() const
162 return request_time
.tv_sec
? tvSubMsec(request_time
, current_time
) : -1;
167 \ingroup FQDNCacheInternal
168 * Removes the given fqdncache entry
171 fqdncacheRelease(fqdncache_entry
* f
)
174 hash_remove_link(fqdn_table
, (hash_link
*) f
);
176 for (k
= 0; k
< (int) f
->name_count
; k
++)
177 safe_free(f
->names
[k
]);
179 debugs(35, 5, "fqdncacheRelease: Released FQDN record for '" << hashKeyStr(&f
->hash
) << "'.");
181 dlinkDelete(&f
->lru
, &lru_list
);
183 safe_free(f
->hash
.key
);
185 safe_free(f
->error_message
);
187 memFree(f
, MEM_FQDNCACHE_ENTRY
);
191 \ingroup FQDNCacheInternal
192 \param name FQDN hash string.
193 \retval Match for given name
195 static fqdncache_entry
*
196 fqdncache_get(const char *name
)
199 static fqdncache_entry
*f
;
203 if ((e
= (hash_link
*)hash_lookup(fqdn_table
, name
)) != NULL
)
204 f
= (fqdncache_entry
*) e
;
210 /// \ingroup FQDNCacheInternal
212 fqdncacheExpiredEntry(const fqdncache_entry
* f
)
214 /* all static entries are locked, so this takes care of them too */
219 if (f
->expires
> squid_curtime
)
225 /// \ingroup FQDNCacheAPI
227 fqdncache_purgelru(void *notused
)
230 dlink_node
*prev
= NULL
;
233 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 10.0, 1);
235 for (m
= lru_list
.tail
; m
; m
= prev
) {
236 if (fqdncacheCount() < fqdncache_low
)
241 f
= (fqdncache_entry
*)m
->data
;
251 debugs(35, 9, "fqdncache_purgelru: removed " << removed
<< " entries");
254 /// \ingroup FQDNCacheAPI
256 purge_entries_fromhosts(void)
258 dlink_node
*m
= lru_list
.head
;
259 fqdncache_entry
*i
= NULL
;
263 if (i
!= NULL
) { /* need to delay deletion */
264 fqdncacheRelease(i
); /* we just override locks */
268 t
= (fqdncache_entry
*)m
->data
;
270 if (t
->flags
.fromhosts
)
281 \ingroup FQDNCacheInternal
283 * Create blank fqdncache_entry
285 static fqdncache_entry
*
286 fqdncacheCreateEntry(const char *name
)
288 static fqdncache_entry
*f
;
289 f
= (fqdncache_entry
*)memAllocate(MEM_FQDNCACHE_ENTRY
);
290 f
->hash
.key
= xstrdup(name
);
291 f
->expires
= squid_curtime
+ Config
.negativeDnsTtl
;
295 /// \ingroup FQDNCacheInternal
297 fqdncacheAddEntry(fqdncache_entry
* f
)
299 hash_link
*e
= (hash_link
*)hash_lookup(fqdn_table
, f
->hash
.key
);
302 /* avoid colission */
303 fqdncache_entry
*q
= (fqdncache_entry
*) e
;
307 hash_join(fqdn_table
, &f
->hash
);
308 dlinkAdd(f
, &f
->lru
, &lru_list
);
309 f
->lastref
= squid_curtime
;
313 \ingroup FQDNCacheInternal
315 * Walks down the pending list, calling handlers
318 fqdncacheCallback(fqdncache_entry
* f
, int wait
)
322 f
->lastref
= squid_curtime
;
327 fqdncacheLockEntry(f
);
329 callback
= f
->handler
;
333 if (cbdataReferenceValidDone(f
->handlerData
, &cbdata
)) {
334 const DnsLookupDetails
details(f
->error_message
, wait
);
335 callback(f
->name_count
? f
->names
[0] : NULL
, details
, cbdata
);
338 fqdncacheUnlockEntry(f
);
341 /// \ingroup FQDNCacheInternal
344 fqdncacheParse(fqdncache_entry
*f
, const char *inbuf
)
346 LOCAL_ARRAY(char, buf
, DNS_INBUF_SZ
);
349 const char *name
= (const char *)f
->hash
.key
;
350 f
->expires
= squid_curtime
+ Config
.negativeDnsTtl
;
351 f
->flags
.negcached
= 1;
354 debugs(35, 1, "fqdncacheParse: Got <NULL> reply in response to '" << name
<< "'");
355 f
->error_message
= xstrdup("Internal Error");
359 xstrncpy(buf
, inbuf
, DNS_INBUF_SZ
);
360 debugs(35, 5, "fqdncacheParse: parsing: {" << buf
<< "}");
361 token
= strtok(buf
, w_space
);
364 debugs(35, 1, "fqdncacheParse: Got <NULL>, expecting '$name' in response to '" << name
<< "'");
365 f
->error_message
= xstrdup("Internal Error");
369 if (0 == strcmp(token
, "$fail")) {
370 token
= strtok(NULL
, "\n");
371 assert(NULL
!= token
);
372 f
->error_message
= xstrdup(token
);
376 if (0 != strcmp(token
, "$name")) {
377 debugs(35, 1, "fqdncacheParse: Got '" << inbuf
<< "', expecting '$name' in response to '" << name
<< "'");
378 f
->error_message
= xstrdup("Internal Error");
382 token
= strtok(NULL
, w_space
);
385 debugs(35, 1, "fqdncacheParse: Got '" << inbuf
<< "', expecting TTL in response to '" << name
<< "'");
386 f
->error_message
= xstrdup("Internal Error");
392 token
= strtok(NULL
, w_space
);
395 debugs(35, 1, "fqdncacheParse: Got '" << inbuf
<< "', expecting hostname in response to '" << name
<< "'");
396 f
->error_message
= xstrdup("Internal Error");
400 f
->names
[0] = xstrdup(token
);
403 if (ttl
== 0 || ttl
> Config
.positiveDnsTtl
)
404 ttl
= Config
.positiveDnsTtl
;
406 if (ttl
< Config
.negativeDnsTtl
)
407 ttl
= Config
.negativeDnsTtl
;
409 f
->expires
= squid_curtime
+ ttl
;
411 f
->flags
.negcached
= 0;
413 return f
->name_count
;
418 fqdncacheParse(fqdncache_entry
*f
, rfc1035_rr
* answers
, int nr
, const char *error_message
)
422 const char *name
= (const char *)f
->hash
.key
;
423 f
->expires
= squid_curtime
+ Config
.negativeDnsTtl
;
424 f
->flags
.negcached
= 1;
427 debugs(35, 3, "fqdncacheParse: Lookup of '" << name
<< "' failed (" << error_message
<< ")");
428 f
->error_message
= xstrdup(error_message
);
433 debugs(35, 3, "fqdncacheParse: No DNS records for '" << name
<< "'");
434 f
->error_message
= xstrdup("No DNS records");
438 debugs(35, 3, "fqdncacheParse: " << nr
<< " answers for '" << name
<< "'");
441 for (k
= 0; k
< nr
; k
++) {
442 if (answers
[k
]._class
!= RFC1035_CLASS_IN
)
445 if (answers
[k
].type
== RFC1035_TYPE_PTR
) {
446 if (!answers
[k
].rdata
[0]) {
447 debugs(35, 2, "fqdncacheParse: blank PTR record for '" << name
<< "'");
451 if (strchr(answers
[k
].rdata
, ' ')) {
452 debugs(35, 2, "fqdncacheParse: invalid PTR record '" << answers
[k
].rdata
<< "' for '" << name
<< "'");
456 f
->names
[f
->name_count
++] = xstrdup(answers
[k
].rdata
);
457 } else if (answers
[k
].type
!= RFC1035_TYPE_CNAME
)
460 if (ttl
== 0 || (int) answers
[k
].ttl
< ttl
)
461 ttl
= answers
[k
].ttl
;
463 if (f
->name_count
>= FQDN_MAX_NAMES
)
467 if (f
->name_count
== 0) {
468 debugs(35, 1, "fqdncacheParse: No PTR record for '" << name
<< "'");
472 if (ttl
> Config
.positiveDnsTtl
)
473 ttl
= Config
.positiveDnsTtl
;
475 if (ttl
< Config
.negativeDnsTtl
)
476 ttl
= Config
.negativeDnsTtl
;
478 f
->expires
= squid_curtime
+ ttl
;
480 f
->flags
.negcached
= 0;
482 return f
->name_count
;
489 \ingroup FQDNCacheAPI
491 * Callback for handling DNS results.
495 fqdncacheHandleReply(void *data
, char *reply
)
497 fqdncacheHandleReply(void *data
, rfc1035_rr
* answers
, int na
, const char *error_message
)
501 static_cast<generic_cbdata
*>(data
)->unwrap(&f
);
502 ++FqdncacheStats
.replies
;
503 const int age
= f
->age();
504 statHistCount(&statCounter
.dns
.svc_time
, age
);
507 fqdncacheParse(f
, reply
);
510 fqdncacheParse(f
, answers
, na
, error_message
);
513 fqdncacheAddEntry(f
);
515 fqdncacheCallback(f
, age
);
519 \ingroup FQDNCacheAPI
521 \param addr IP address of domain to resolve.
522 \param handler A pointer to the function to be called when
523 * the reply from the FQDN cache
524 * (or the DNS if the FQDN cache misses)
525 \param handlerData Information that is passed to the handler
526 * and does not affect the FQDN cache.
529 fqdncache_nbgethostbyaddr(const Ip::Address
&addr
, FQDNH
* handler
, void *handlerData
)
531 fqdncache_entry
*f
= NULL
;
532 char name
[MAX_IPSTRLEN
];
534 addr
.NtoA(name
,MAX_IPSTRLEN
);
535 debugs(35, 4, "fqdncache_nbgethostbyaddr: Name '" << name
<< "'.");
536 FqdncacheStats
.requests
++;
538 if (name
[0] == '\0') {
539 debugs(35, 4, "fqdncache_nbgethostbyaddr: Invalid name!");
540 const DnsLookupDetails
details("Invalid hostname", -1); // error, no lookup
542 handler(NULL
, details
, handlerData
);
546 f
= fqdncache_get(name
);
551 } else if (fqdncacheExpiredEntry(f
)) {
552 /* hit, but expired -- bummer */
557 debugs(35, 4, "fqdncache_nbgethostbyaddr: HIT for '" << name
<< "'");
559 if (f
->flags
.negcached
)
560 FqdncacheStats
.negative_hits
++;
562 FqdncacheStats
.hits
++;
564 f
->handler
= handler
;
566 f
->handlerData
= cbdataReference(handlerData
);
568 fqdncacheCallback(f
, -1); // no lookup
573 debugs(35, 5, "fqdncache_nbgethostbyaddr: MISS for '" << name
<< "'");
574 FqdncacheStats
.misses
++;
575 f
= fqdncacheCreateEntry(name
);
576 f
->handler
= handler
;
577 f
->handlerData
= cbdataReference(handlerData
);
578 f
->request_time
= current_time
;
579 c
= new generic_cbdata(f
);
582 dnsSubmit(hashKeyStr(&f
->hash
), fqdncacheHandleReply
, c
);
584 idnsPTRLookup(addr
, fqdncacheHandleReply
, c
);
588 /// \ingroup FQDNCacheInternal
590 fqdncacheRegisterWithCacheManager(void)
592 Mgr::RegisterAction("fqdncache", "FQDN Cache Stats and Contents",
598 \ingroup FQDNCacheAPI
600 * Initialize the fqdncache.
601 * Called after IP cache initialization.
608 fqdncacheRegisterWithCacheManager();
613 debugs(35, 3, "Initializing FQDN Cache...");
615 memset(&FqdncacheStats
, '\0', sizeof(FqdncacheStats
));
617 memset(&lru_list
, '\0', sizeof(lru_list
));
619 fqdncache_high
= (long) (((float) Config
.fqdncache
.size
*
620 (float) FQDN_HIGH_WATER
) / (float) 100);
622 fqdncache_low
= (long) (((float) Config
.fqdncache
.size
*
623 (float) FQDN_LOW_WATER
) / (float) 100);
625 n
= hashPrime(fqdncache_high
/ 4);
627 fqdn_table
= hash_create((HASHCMP
*) strcmp
, n
, hash4
);
629 memDataInit(MEM_FQDNCACHE_ENTRY
, "fqdncache_entry",
630 sizeof(fqdncache_entry
), 0);
634 \ingroup FQDNCacheAPI
636 * Is different in that it only checks if an entry exists in
637 * it's data-structures and does not by default contact the
638 * DNS, unless this is requested, by setting the flags
639 * to FQDN_LOOKUP_IF_MISS.
641 \param addr address of the FQDN being resolved
642 \param flags values are NULL or FQDN_LOOKUP_IF_MISS. default is NULL.
646 fqdncache_gethostbyaddr(const Ip::Address
&addr
, int flags
)
648 char name
[MAX_IPSTRLEN
];
649 fqdncache_entry
*f
= NULL
;
651 if (addr
.IsAnyAddr() || addr
.IsNoAddr()) {
655 addr
.NtoA(name
,MAX_IPSTRLEN
);
656 FqdncacheStats
.requests
++;
657 f
= fqdncache_get(name
);
661 } else if (fqdncacheExpiredEntry(f
)) {
664 } else if (f
->flags
.negcached
) {
665 FqdncacheStats
.negative_hits
++;
666 // ignore f->error_message: the caller just checks FQDN cache presence
669 FqdncacheStats
.hits
++;
670 f
->lastref
= squid_curtime
;
671 // ignore f->error_message: the caller just checks FQDN cache presence
675 /* no entry [any more] */
677 FqdncacheStats
.misses
++;
679 if (flags
& FQDN_LOOKUP_IF_MISS
) {
680 fqdncache_nbgethostbyaddr(addr
, NULL
, NULL
);
688 \ingroup FQDNCacheInternal
690 * Process objects list
693 fqdnStats(StoreEntry
* sentry
)
695 fqdncache_entry
*f
= NULL
;
699 if (fqdn_table
== NULL
)
702 storeAppendPrintf(sentry
, "FQDN Cache Statistics:\n");
704 storeAppendPrintf(sentry
, "FQDNcache Entries In Use: %d\n",
705 memInUse(MEM_FQDNCACHE_ENTRY
));
707 storeAppendPrintf(sentry
, "FQDNcache Entries Cached: %d\n",
710 storeAppendPrintf(sentry
, "FQDNcache Requests: %d\n",
711 FqdncacheStats
.requests
);
713 storeAppendPrintf(sentry
, "FQDNcache Hits: %d\n",
714 FqdncacheStats
.hits
);
716 storeAppendPrintf(sentry
, "FQDNcache Negative Hits: %d\n",
717 FqdncacheStats
.negative_hits
);
719 storeAppendPrintf(sentry
, "FQDNcache Misses: %d\n",
720 FqdncacheStats
.misses
);
722 storeAppendPrintf(sentry
, "FQDN Cache Contents:\n\n");
724 storeAppendPrintf(sentry
, "%-45.45s %3s %3s %3s %s\n",
725 "Address", "Flg", "TTL", "Cnt", "Hostnames");
727 hash_first(fqdn_table
);
729 while ((f
= (fqdncache_entry
*) hash_next(fqdn_table
))) {
730 ttl
= (f
->flags
.fromhosts
? -1 : (f
->expires
- squid_curtime
));
731 storeAppendPrintf(sentry
, "%-45.45s %c%c %3.3d % 3d",
732 hashKeyStr(&f
->hash
),
733 f
->flags
.negcached
? 'N' : ' ',
734 f
->flags
.fromhosts
? 'H' : ' ',
736 (int) f
->name_count
);
738 for (k
= 0; k
< (int) f
->name_count
; k
++)
739 storeAppendPrintf(sentry
, " %s", f
->names
[k
]);
741 storeAppendPrintf(sentry
, "\n");
745 /// \ingroup FQDNCacheAPI
747 fqdnFromAddr(const Ip::Address
&addr
)
750 static char buf
[MAX_IPSTRLEN
];
752 if (Config
.onoff
.log_fqdn
&& (n
= fqdncache_gethostbyaddr(addr
, 0)))
755 /// \todo Perhapse this should use toHostname() instead of straight NtoA.
756 /// that would wrap the IPv6 properly when raw.
757 addr
.NtoA(buf
, MAX_IPSTRLEN
);
762 /// \ingroup FQDNCacheInternal
764 fqdncacheLockEntry(fqdncache_entry
* f
)
766 if (f
->locks
++ == 0) {
767 dlinkDelete(&f
->lru
, &lru_list
);
768 dlinkAdd(f
, &f
->lru
, &lru_list
);
772 /// \ingroup FQDNCacheInternal
774 fqdncacheUnlockEntry(fqdncache_entry
* f
)
776 assert(f
->locks
> 0);
779 if (fqdncacheExpiredEntry(f
))
783 /// \ingroup FQDNCacheInternal
785 fqdncacheFreeEntry(void *data
)
787 fqdncache_entry
*f
= (fqdncache_entry
*)data
;
790 for (k
= 0; k
< (int) f
->name_count
; k
++)
791 safe_free(f
->names
[k
]);
793 safe_free(f
->hash
.key
);
795 safe_free(f
->error_message
);
797 memFree(f
, MEM_FQDNCACHE_ENTRY
);
800 /// \ingroup FQDNCacheAPI
802 fqdncacheFreeMemory(void)
804 hashFreeItems(fqdn_table
, fqdncacheFreeEntry
);
805 hashFreeMemory(fqdn_table
);
810 \ingroup FQDNCacheAPI
812 * Recalculate FQDN cache size upon reconfigure.
813 * Is called to clear the FQDN cache's data structures,
814 * cancel all pending requests.
817 fqdncache_restart(void)
819 fqdncache_high
= (long) (((float) Config
.fqdncache
.size
*
820 (float) FQDN_HIGH_WATER
) / (float) 100);
821 fqdncache_low
= (long) (((float) Config
.fqdncache
.size
*
822 (float) FQDN_LOW_WATER
) / (float) 100);
823 purge_entries_fromhosts();
827 \ingroup FQDNCacheAPI
829 * Adds a "static" entry from /etc/hosts.
831 * The worldist is to be managed by the caller,
832 * including pointed-to strings
834 \param addr FQDN name to be added.
838 fqdncacheAddEntryFromHosts(char *addr
, wordlist
* hostnames
)
840 fqdncache_entry
*fce
;
843 if ((fce
= fqdncache_get(addr
))) {
844 if (1 == fce
->flags
.fromhosts
) {
845 fqdncacheUnlockEntry(fce
);
846 } else if (fce
->locks
> 0) {
847 debugs(35, 1, "fqdncacheAddEntryFromHosts: can't add static entry for locked address '" << addr
<< "'");
850 fqdncacheRelease(fce
);
854 fce
= fqdncacheCreateEntry(addr
);
857 fce
->names
[j
] = xstrdup(hostnames
->key
);
858 Tolower(fce
->names
[j
]);
860 hostnames
= hostnames
->next
;
862 if (j
>= FQDN_MAX_NAMES
)
867 fce
->names
[j
] = NULL
; /* it's safe */
868 fce
->flags
.fromhosts
= 1;
869 fqdncacheAddEntry(fce
);
870 fqdncacheLockEntry(fce
);
876 * \ingroup FQDNCacheAPI
877 * The function to return the FQDN statistics via SNMP
880 snmp_netFqdnFn(variable_list
* Var
, snint
* ErrP
)
882 variable_list
*Answer
= NULL
;
884 debugs(49, 5, "snmp_netFqdnFn: Processing request:" << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
885 *ErrP
= SNMP_ERR_NOERROR
;
887 switch (Var
->name
[LEN_SQ_NET
+ 1]) {
890 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
896 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
897 FqdncacheStats
.requests
,
902 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
908 /* this is now worthless */
909 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
915 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
916 FqdncacheStats
.negative_hits
,
921 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
922 FqdncacheStats
.misses
,
927 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
933 *ErrP
= SNMP_ERR_NOSUCHNAME
;
940 #endif /*SQUID_SNMP */