summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2014-03-27 20:54:34 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2014-03-27 20:54:34 +0000
commitfec216df326b380fcf10e99c49251a45c3234ae4 (patch)
treea53c8dbc6183fb4a6b93b468d967efb6ded9af7b
parent4e1fe444285f11cf85a32b01f638fb6c102be4a0 (diff)
downloaddnsmasq-fec216df326b380fcf10e99c49251a45c3234ae4.tar.gz
Cache stats availble in CHAOS .bind domain.
-rw-r--r--man/dnsmasq.814
-rw-r--r--src/cache.c95
-rw-r--r--src/dnsmasq.h10
-rw-r--r--src/option.c35
-rw-r--r--src/rfc1035.c16
5 files changed, 155 insertions, 15 deletions
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index eaa0dc6..b339b79 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -1753,12 +1753,22 @@ When it receives a SIGUSR1,
writes statistics to the system log. It writes the cache size,
the number of names which have had to removed from the cache before
they expired in order to make room for new names and the total number
-of names that have been inserted into the cache. For each upstream
+of names that have been inserted into the cache. The number of cache hits and
+misses and the number of authoritative queries answered are also given. For each upstream
server it gives the number of queries sent, and the number which
resulted in an error. In
.B --no-daemon
mode or when full logging is enabled (-q), a complete dump of the
-contents of the cache is made.
+contents of the cache is made.
+
+The cache statistics are also available in the DNS as answers to
+queries of class CHAOS and type TXT in domain bind. The domain names are cachesize.bind, insertions.bind, evictions.bind,
+misses.bind, hits.bind, auth.bind and servers.bind. An example command to query this, using the
+.B dig
+utility would be
+
+dig +short chaos txt cachesize.bind
+
.PP
When it receives SIGUSR2 and it is logging direct to a file (see
.B --log-facility
diff --git a/src/cache.c b/src/cache.c
index ecc4a78..64cfeb1 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -1262,6 +1262,101 @@ void cache_add_dhcp_entry(char *host_name, int prot,
}
#endif
+int cache_make_stat(struct txt_record *t)
+{
+ static char *buff = NULL;
+ static int bufflen = 60;
+ int len;
+ struct server *serv, *serv1;
+ char *p;
+
+ if (!buff && !(buff = whine_malloc(60)))
+ return 0;
+
+ p = buff;
+
+ switch (t->stat)
+ {
+ case TXT_STAT_CACHESIZE:
+ sprintf(buff+1, "%d", daemon->cachesize);
+ break;
+
+ case TXT_STAT_INSERTS:
+ sprintf(buff+1, "%d", cache_inserted);
+ break;
+
+ case TXT_STAT_EVICTIONS:
+ sprintf(buff+1, "%d", cache_live_freed);
+ break;
+
+ case TXT_STAT_MISSES:
+ sprintf(buff+1, "%u", daemon->queries_forwarded);
+ break;
+
+ case TXT_STAT_HITS:
+ sprintf(buff+1, "%u", daemon->local_answer);
+ break;
+
+#ifdef HAVE_AUTH
+ case TXT_STAT_AUTH:
+ sprintf(buff+1, "%u", daemon->auth_answer);
+ break;
+#endif
+
+ case TXT_STAT_SERVERS:
+ /* sum counts from different records for same server */
+ for (serv = daemon->servers; serv; serv = serv->next)
+ serv->flags &= ~SERV_COUNTED;
+
+ for (serv = daemon->servers; serv; serv = serv->next)
+ if (!(serv->flags &
+ (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
+ {
+ char *new, *lenp;
+ int port, newlen, bytes_avail, bytes_needed;
+ unsigned int queries = 0, failed_queries = 0;
+ for (serv1 = serv; serv1; serv1 = serv1->next)
+ if (!(serv1->flags &
+ (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
+ sockaddr_isequal(&serv->addr, &serv1->addr))
+ {
+ serv1->flags |= SERV_COUNTED;
+ queries += serv1->queries;
+ failed_queries += serv1->failed_queries;
+ }
+ port = prettyprint_addr(&serv->addr, daemon->addrbuff);
+ lenp = p++; /* length */
+ bytes_avail = (p - buff) + bufflen;
+ bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
+ if (bytes_needed >= bytes_avail)
+ {
+ /* expand buffer if necessary */
+ newlen = bytes_needed + 1 + bufflen - bytes_avail;
+ if (!(new = whine_malloc(newlen)))
+ return 0;
+ memcpy(new, buff, bufflen);
+ free(buff);
+ p = new + (p - buff);
+ lenp = p - 1;
+ buff = new;
+ bufflen = newlen;
+ bytes_avail = (p - buff) + bufflen;
+ bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
+ }
+ *lenp = bytes_needed;
+ p += bytes_needed;
+ }
+ t->txt = (unsigned char *)buff;
+ t->len = p - buff;
+ return 1;
+ }
+
+ len = strlen(buff+1);
+ t->txt = (unsigned char *)buff;
+ t->len = len + 1;
+ *buff = len;
+ return 1;
+}
void dump_cache(time_t now)
{
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 4ee3c49..9c541eb 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -280,10 +280,19 @@ struct naptr {
struct naptr *next;
};
+#define TXT_STAT_CACHESIZE 1
+#define TXT_STAT_INSERTS 2
+#define TXT_STAT_EVICTIONS 3
+#define TXT_STAT_MISSES 4
+#define TXT_STAT_HITS 5
+#define TXT_STAT_AUTH 6
+#define TXT_STAT_SERVERS 7
+
struct txt_record {
char *name;
unsigned char *txt;
unsigned short class, len;
+ int stat;
struct txt_record *next;
};
@@ -1027,6 +1036,7 @@ void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_addre
struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
+int cache_make_stat(struct txt_record *t);
char *cache_get_name(struct crec *crecp);
char *cache_get_cname_target(struct crec *crecp);
struct crec *cache_enumerate(int init);
diff --git a/src/option.c b/src/option.c
index 8484513..049060b 100644
--- a/src/option.c
+++ b/src/option.c
@@ -615,19 +615,24 @@ static int atoi_check8(char *a, int *res)
}
#endif
-static void add_txt(char *name, char *txt)
+static void add_txt(char *name, char *txt, int stat)
{
- size_t len = strlen(txt);
struct txt_record *r = opt_malloc(sizeof(struct txt_record));
+
+ if (txt)
+ {
+ size_t len = strlen(txt);
+ r->txt = opt_malloc(len+1);
+ r->len = len+1;
+ *(r->txt) = len;
+ memcpy((r->txt)+1, txt, len);
+ }
+ r->stat = stat;
r->name = opt_string_alloc(name);
r->next = daemon->txt;
daemon->txt = r;
r->class = C_CHAOS;
- r->txt = opt_malloc(len+1);
- r->len = len+1;
- *(r->txt) = len;
- memcpy((r->txt)+1, txt, len);
}
static void do_usage(void)
@@ -3609,7 +3614,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->next = daemon->txt;
daemon->txt = new;
new->class = C_IN;
-
+ new->stat = 0;
+
if (!(new->name = canonicalise_opt(arg)))
ret_err(_("bad TXT record"));
@@ -4258,9 +4264,18 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->soa_refresh = SOA_REFRESH;
daemon->soa_retry = SOA_RETRY;
daemon->soa_expiry = SOA_EXPIRY;
- add_txt("version.bind", "dnsmasq-" VERSION );
- add_txt("authors.bind", "Simon Kelley");
- add_txt("copyright.bind", COPYRIGHT);
+ add_txt("version.bind", "dnsmasq-" VERSION, 0 );
+ add_txt("authors.bind", "Simon Kelley", 0);
+ add_txt("copyright.bind", COPYRIGHT, 0);
+ add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
+ add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
+ add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
+ add_txt("misses.bind", NULL, TXT_STAT_MISSES);
+ add_txt("hits.bind", NULL, TXT_STAT_HITS);
+#ifdef HAVE_AUTH
+ add_txt("auth.bind", NULL, TXT_STAT_AUTH);
+#endif
+ add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
while (1)
{
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 9f5570c..43a06b9 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1547,10 +1547,20 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
+ unsigned long ttl = daemon->local_ttl;
+ int ok = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
- if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
- daemon->local_ttl, NULL,
- T_TXT, t->class, "t", t->len, t->txt))
+ /* Dynamically generate stat record */
+ if (t->stat != 0)
+ {
+ ttl = 0;
+ if (!cache_make_stat(t))
+ ok = 0;
+ }
+
+ if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,
+ ttl, NULL,
+ T_TXT, t->class, "t", t->len, t->txt))
anscount++;
}