[PATCH] host-statistics for bind9

Shapor Naghibzadeh shapor at shapor.com
Wed Aug 20 21:45:06 UTC 2008


Hi list,

I've heard a few people asking about host-statistics support in bind9,
so I thought I'd share the patch I recently coded to implement it. It is
far less memory intensive than the bind8 implementation, as it only
tracks a single "question count" per host.  For more information see:
http://shapor.com/bind9_host-statistics/

Regards,
Shapor

Patch follows:
diff -rup bind-9.4.2-P1/bin/named/include/named/server.h bind-9.4.2-P1.shapor/bin/named/include/named/server.h
--- bind-9.4.2-P1/bin/named/include/named/server.h	2006-03-09 15:46:20.000000000 -0800
+++ bind-9.4.2-P1.shapor/bin/named/include/named/server.h	2008-08-20 02:54:11.162565000 -0700
@@ -37,6 +37,16 @@
 #define NS_EVENT_RELOAD		(NS_EVENTCLASS + 0)
 #define NS_EVENT_CLIENTCONTROL	(NS_EVENTCLASS + 1)
 
+#define HOSTSTAT_HASHSIZE	1024
+
+typedef struct host_stat	host_stat_t;
+
+struct host_stat {
+	isc_uint32_t	ip; /* only support IPv4, 128 bit addresses are ridiculous */
+	isc_uint32_t	counter;
+	host_stat_t	*next;
+};
+
 /*%
  * Name server state.  Better here than in lots of separate global variables.
  */
@@ -92,6 +102,11 @@ struct ns_server {
 
 	isc_uint64_t *		querystats;	/*%< Query statistics counters */
 
+	isc_boolean_t		host_stats_on;
+	isc_uint32_t		host_stats_max;
+	isc_uint32_t		host_stats_count;
+	struct host_stat	*host_stats[HOSTSTAT_HASHSIZE];
+
 	ns_controls_t *		controls;	/*%< Control channels */
 	unsigned int		dispatchgen;
 	ns_dispatchlist_t	dispatches;
diff -rup bind-9.4.2-P1/bin/named/query.c bind-9.4.2-P1.shapor/bin/named/query.c
--- bind-9.4.2-P1/bin/named/query.c	2007-09-25 20:08:14.000000000 -0700
+++ bind-9.4.2-P1.shapor/bin/named/query.c	2008-08-20 02:48:00.912193000 -0700
@@ -126,6 +126,8 @@ validate(ns_client_t *client, dns_db_t *
  */
 static inline void
 inc_stats(ns_client_t *client, dns_statscounter_t counter) {
+	unsigned int peer = 0;
+	host_stat_t *hst;
 	dns_zone_t *zone = client->query.authzone;
 
 	REQUIRE(counter < DNS_STATS_NCOUNTERS);
@@ -137,6 +139,28 @@ inc_stats(ns_client_t *client, dns_stats
 		if (zonestats != NULL)
 			zonestats[counter]++;
 	}
+
+	if (ns_g_server->host_stats_on != ISC_TRUE)
+		return;
+
+	if (client->peeraddr.type.sa.sa_family == AF_INET)
+		peer = ntohl(client->peeraddr.type.sin.sin_addr.s_addr);
+
+	hst = ns_g_server->host_stats[peer % HOSTSTAT_HASHSIZE];
+	while(hst && hst->ip != peer)
+		hst = hst->next;
+	if (!hst) { /* insert */
+		if (ns_g_server->host_stats_count++ >= ns_g_server->host_stats_max)
+			return;
+		if (!(hst = isc_mem_get(ns_g_mctx, sizeof(host_stat_t))))
+			return;
+		hst->counter = 1;
+		hst->ip = peer;
+		hst->next = ns_g_server->host_stats[peer % HOSTSTAT_HASHSIZE];
+		ns_g_server->host_stats[peer % HOSTSTAT_HASHSIZE] = hst;
+	} else {
+		hst->counter++;
+	}
 }
 
 static void
diff -rup bind-9.4.2-P1/bin/named/server.c bind-9.4.2-P1.shapor/bin/named/server.c
--- bind-9.4.2-P1/bin/named/server.c	2008-05-22 14:28:04.000000000 -0700
+++ bind-9.4.2-P1.shapor/bin/named/server.c	2008-08-20 02:40:29.306977000 -0700
@@ -2853,6 +2853,15 @@ load_configuration(const char *filename,
 	ns_g_udpsize = (isc_uint16_t)udpsize;
 
 	/*
+	 * Configure host-statistics
+	 */
+	obj = NULL;
+	if (ns_config_get(maps, "host-statistics", &obj) == ISC_R_SUCCESS)
+		server->host_stats_on = cfg_obj_asboolean(obj);
+	obj = NULL;
+	if (ns_config_get(maps, "host-statistics-max", &obj) == ISC_R_SUCCESS)
+		server->host_stats_max = cfg_obj_asuint32(obj);
+	/*
 	 * Configure the zone manager.
 	 */
 	obj = NULL;
@@ -3609,6 +3618,11 @@ ns_server_create(isc_mem_t *mctx, ns_ser
 		   "isc_mem_strdup");
 	server->querystats = NULL;
 
+	server->host_stats_on = ISC_FALSE;
+	server->host_stats_max = -1;
+	server->host_stats_count = 0;
+	memset(server->host_stats, 0, sizeof(host_stat_t*) * HOSTSTAT_HASHSIZE);
+
 	server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
 	CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
 		   "isc_mem_strdup");
@@ -3643,11 +3657,21 @@ ns_server_create(isc_mem_t *mctx, ns_ser
 void
 ns_server_destroy(ns_server_t **serverp) {
 	ns_server_t *server = *serverp;
+	int i;
+	host_stat_t *hst, *next;
 	REQUIRE(NS_SERVER_VALID(server));
 
 	ns_controls_destroy(&server->controls);
 
 	dns_stats_freecounters(server->mctx, &server->querystats);
+	for (i = 0; i < HOSTSTAT_HASHSIZE; i++) {
+		hst = server->host_stats[i];
+		while (hst) {
+			next = hst->next;
+			isc_mem_put(ns_g_mctx, hst, sizeof(host_stat_t));
+			hst = next;
+		}
+	}
 
 	isc_mem_free(server->mctx, server->statsfile);
 	isc_mem_free(server->mctx, server->dumpfile);
@@ -4195,6 +4219,7 @@ ns_server_dumpstats(ns_server_t *server)
 	FILE *fp = NULL;
 	int i;
 	int ncounters;
+	host_stat_t *hst;
 
 	isc_stdtime_get(&now);
 
@@ -4236,6 +4261,16 @@ ns_server_dumpstats(ns_server_t *server)
 			}
 		}
 	}
+	if (server->host_stats_on == ISC_TRUE) {
+		fprintf(fp, "++ Name Server Statistics ++\n(Legend)\n      TotalQ\n");
+		for (i = 0; i < HOSTSTAT_HASHSIZE; i++) {
+			hst = server->host_stats[i];
+			while (hst) {
+				fprintf(fp, "[%s]\n   %u\n", inet_ntoa((struct in_addr){ .s_addr = htonl(hst->ip)}), hst->counter);
+				hst = hst->next;
+			}
+		}
+	}
 	if (result == ISC_R_NOMORE)
 		result = ISC_R_SUCCESS;
 	CHECK(result);
diff -rup bind-9.4.2-P1/lib/isccfg/namedconf.c bind-9.4.2-P1.shapor/lib/isccfg/namedconf.c
--- bind-9.4.2-P1/lib/isccfg/namedconf.c	2006-05-02 18:46:40.000000000 -0700
+++ bind-9.4.2-P1.shapor/lib/isccfg/namedconf.c	2008-08-19 15:46:29.667198000 -0700
@@ -618,8 +618,8 @@ options_clauses[] = {
 	{ "files", &cfg_type_size, 0 },
 	{ "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
 	{ "heartbeat-interval", &cfg_type_uint32, 0 },
-	{ "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
-	{ "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
+	{ "host-statistics", &cfg_type_boolean, 0 },
+	{ "host-statistics-max", &cfg_type_uint32, 0 },
 	{ "hostname", &cfg_type_qstringornone, 0 },
 	{ "interface-interval", &cfg_type_uint32, 0 },
 	{ "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },


More information about the bind-users mailing list