major reorganisation
[rrq/rrqmisc.git] / socket-sniff / socket-sniff.c
index e939712b3d8a2935096c86edf2ec4200e2639d32..4bcc8a254c42d438fe254902f2b6d9734fab9a98 100644 (file)
@@ -12,7 +12,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <hashvector.h>
+#include <HashVector.h>
+#include <stringitem.h>
 
 // Seconds between outputs
 static int DELAY = 5;
@@ -23,74 +24,101 @@ static int FADE = 10000;
 // 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) {
@@ -129,7 +157,7 @@ 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 );
     }
 }
 
@@ -151,7 +179,7 @@ static int Countp_compare(const void *ax, const void *bx) {
     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;
@@ -167,7 +195,7 @@ static int Countp_fade_and_print(unsigned long index,void *x,void *d) {
     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;
 }
 
@@ -175,28 +203,61 @@ static int Countp_reclaim(pvector *pv,unsigned long ix,void *item,void *data) {
 // 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;
@@ -205,11 +266,11 @@ static void add_show_table(char *ip,size_t length) {
        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 );
 }
 
@@ -252,6 +313,13 @@ int main(int argc,char **argv) {
        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 ) {
@@ -301,10 +369,8 @@ int main(int argc,char **argv) {
                 ( 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
        }