#include <sys/types.h>
#include <unistd.h>
-#include <hashvector.h>
+#include <HashVector.h>
+#include <stringitem.h>
// Seconds between outputs
static int DELAY = 5;
// Number of top usage to report
static int WORST = 20;
+// Drop-out age
+static int OLD = 600;
+
// Number of characters for text format IP holdings
#define IPBUFMAX 40
+// Count record for IP -> length mapping
typedef struct _Count {
- struct _Count *next;
- int ignore;
- int last;
- int accum;
- int total;
- char ip[ IPBUFMAX ];
+ struct _Count *next; // Next Count in time order
+ struct _Count *prev; // Previous Count in time order
+ struct timeval when; // Last update time for this Count record
+ int ignore; // Flag to leave out from reports
+ int last; // The saved accumulation from the last report period
+ int accum; // Current accumulation
+ int total; // The total accumulation (reduced by fading)
+ char ip[ IPBUFMAX ]; // The IP concerned, in ascii
} Count;
+// Print message and exit
static void die(char *m) {
fprintf( stderr, "%s\n", m );
exit( 1 );
}
-// Return pointer to the key for an item
-static void *Countp_itemkey(void *item) {
+// Returns the hashcode for a key
+static unsigned long Countp_hashcode(void *this,void *key) {
+ return HashVector_hashcode( key, IPBUFMAX );
+}
+
+// Return pointer a key for an item (could be temporary allocation)
+static void *Countp_itemkey(void *this,void *item) {
return ((Count*) item)->ip;
}
// Return 1 if the item has the key, or 0 otherwise.
-static int Countp_haskey(void *item,void *key) {
- return memcmp( key, Countp_itemkey( item ), IPBUFMAX ) == 0;
+static int Countp_haskey(void *this,void *item,void *key) {
+ return memcmp( key, Countp_itemkey( this, item ), IPBUFMAX ) == 0;
}
-// Returns the hashcode for a key
-static unsigned long Countp_hashcode(void *key) {
- return hashvector_hashcode( key, IPBUFMAX );
+#if 0
+// Releasing a key does nothing
+static void Countp_releasekey(void *this,void *item) {
}
+#endif
-static hashvector TBL = {
- .table = { 256, 0 },
+static ItemKeyFun Countp_itemkeyfun = {
+ .hashcode = Countp_hashcode,
+ .haskey = Countp_haskey,
+ .itemkey = Countp_itemkey,
+ //.releasekey = Countp_releasekey,
+ //.tostring = Countp_tostring
+};
+
+// The HashVector of seen IP
+static HashVector TBL = {
+ .table = { Nibble_index_levels, 16, 0 },
.fill = 0,
.holes = 0,
- .keyhashcode = Countp_hashcode,
- .itemkey = Countp_itemkey,
- .haskey = Countp_haskey
+ .type = &Countp_itemkeyfun,
};
+// The Count records in time order
+static struct {
+ Count *head;
+ Count *tail;
+} trail;
+
+// Temporary buffer for IP addresses in ascii
static char buffer[ IPBUFMAX ];
/*============================================================
* Reading ignore lines.
*/
+#if 0
// Return pointer to the key for an item
-static void *charp_itemkey(void *item) {
+static void *charp_itemkey(void *this,void *item) {
return item;
}
// Return 1 if the item has the key, or 0 otherwise.
-static int charp_haskey(void *item,void *key) {
+static int charp_haskey(void *this,void *item,void *key) {
return strcmp( key, item ) == 0;
}
// Returns the hashcode for a key
-static unsigned long charp_hashcode(void *key) {
- return hashvector_hashcode( key, strlen( (const char *) key ) );
+static unsigned long charp_hashcode(void *this,void *key) {
+ return HashVector_hashcode( key, strlen( (const char *) key ) );
}
+#endif
-static hashvector IGN = {
+static HashVector IGN = {
.table = { 256, 0 },
.fill = 0,
.holes = 0,
- .keyhashcode = charp_hashcode,
- .itemkey = charp_itemkey,
- .haskey = charp_haskey
+ .type = &stringitem
};
static void read_ignore_file(char *filename) {
char *ip = calloc( 1, p - cur + 1 );
memcpy( ip, cur, p - cur );
cur = p + 1;
- hashvector_add( &IGN, ip );
+ HashVector_add( &IGN, ip );
}
}
return a->last - b->last;
}
-static int Countp_fade_and_print(unsigned long index,void *x,void *d) {
+static int Countp_fade_and_print(VectorIndex index,void *x,void *d) {
if ( x ) {
Count *item = (Count *) x;
item->last = item->accum;
return 0;
}
-static int Countp_reclaim(pvector *pv,unsigned long ix,void *item,void *data) {
+static int Countp_reclaim(Vector *pv,unsigned long ix,void *item,void *data) {
return 0;
}
// ip points to [ IPBUFMAX ] of ip address in text
static void add_show_table(char *ip,size_t length) {
static time_t show = 0;
- Count *item;
- int i = hashvector_find( &TBL, ip, (void**) &item );
- if ( i == 0 ) {
+ Count *item = HashVector_find( &TBL, ip );
+ struct timeval now;
+ if ( gettimeofday( &now, 0 ) ) {
+ perror( "gettimeofday" );
+ exit( 1 );
+ }
+ if ( item == 0 ) {
item = (Count *) calloc( 1, sizeof( Count ) );
memcpy( item->ip, ip, strlen( ip ) );
- item->accum = length;
- hashvector_add( &TBL, item );
- item->ignore = hashvector_find( &IGN, ip, 0 );
+ HashVector_add( &TBL, item );
+ item->ignore = (HashVector_find( &IGN, ip ) != 0);
+ int i;
for ( i = strlen( ip )-1; i > 1; i-- ) {
if ( ip[i] == '.' || ip[i] == ':' ) {
- item->ignore |= hashvector_find( &IGN, ip, 0 );
+ item->ignore |= (HashVector_find( &IGN, ip ) != 0);
}
ip[i] = 0;
}
- //fprintf( stdout, "add %s\n", ip );
+ fprintf( stdout, "add %s\n", item->ip );
} else {
- item->accum += length;
+ // Unlink item from the trail
+ if ( item->next ) {
+ item->next->prev = item->prev;
+ }
+ if ( item->prev ) {
+ item->prev->next = item->next;
+ }
+ if ( trail.head == item ) {
+ trail.head = item->next;
+ }
+ if ( trail.tail == item ) {
+ trail.tail = item->prev;
+ }
+ item->prev = item->next = 0;
}
- struct timeval now;
- if ( gettimeofday( &now, 0 ) ) {
- perror( "gettimeofday" );
- exit( 1 );
+ item->accum += length;
+ item->when = now;
+ // Link in item to the trail end
+ if ( trail.head == 0 ) {
+ trail.head = item;
+ } else {
+ trail.tail->next = item;
+ item->prev = trail.tail;
+ }
+ trail.tail = item;
+ // Drop counters older than an hour
+ while ( trail.head->when.tv_sec + OLD < item->when.tv_sec ) {
+ Count *old = trail.head;
+ trail.head = old->next;
+ if ( trail.head ) {
+ trail.head->prev = 0;
+ }
+ fprintf( stdout, "drop %s\n", old->ip );
+ HashVector_delete( &TBL, old );
+ free( old );
}
if ( now.tv_sec < show ) {
return;
show = now.tv_sec;
}
show += DELAY; // Time for next output
- pvector ordered = { 0, 0 };
- hashvector_contents( &TBL, &ordered );
- pvector_qsort( &ordered, Countp_compare );
- pvector_iterate( &ordered, Countp_fade_and_print, 0 );
- pvector_resize( &ordered, 0, Countp_reclaim, 0 );
+ Vector ordered = { Nibble_index_levels, 0, 0 };
+ HashVector_contents( &TBL, Nibble_index_levels, &ordered );
+ Vector_qsort( &ordered, Countp_compare );
+ Vector_iterate( &ordered, 0, Countp_fade_and_print, 0 );
+ Vector_resize( &ordered, 0, Countp_reclaim, 0 );
fprintf( stdout, "==%ld/%ld/%ld\n", TBL.fill, TBL.holes, TBL.table.size );
}
fprintf( stdout, "Displaying at most %d lines in reports\n", WORST );
ARG++;
}
+ if ( ARG < argc && strncmp( argv[ ARG ], "-a", 2 ) == 0 ) {
+ if ( sscanf( argv[ ARG ]+2, "%d", &OLD ) != 1 ) {
+ die( "Missing/bad drop-out age (seconds)" );
+ }
+ fprintf( stdout, "Displaying at most %d lines in reports\n", WORST );
+ ARG++;
+ }
if ( ARG < argc && strncmp( argv[ ARG ], "-i", 2 ) == 0 ) {
char *filename = argv[ ARG ] + 2;
if ( (*filename) == 0 ) {
( strncmp( p, "0:0:0:0:0:0:0:1", 15 ) != 0 ) ) {
add_show_table( p, N );
}
- } else if ( code == 0x0800 ) {
- // ignore
} else if ( code == 0x8100 ) {
- // ignore
+ // ignore VLAN
} else {
// funny code
}