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 },

Reply via email to