+#include <arpa/inet.h>
+#include <linux/if_ether.h>
+#include <linux/in.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <htable.h>
+
+// Seconds between outputs
+#define DELAY 5
+
+// Byte count fade-out between displays
+#define FADE 10000
+
+// Number of top usage to report
+#define WORST 20
+
+// Number of characters for text format IP holdings
+#define IPBUFMAX 40
+
+typedef struct _Count {
+ struct _Count *next;
+ int ignore;
+ int last;
+ int accum;
+ int total;
+ char ip[ IPBUFMAX ];
+} Count;
+
+static void die(char *m) {
+ fprintf( stderr, "%s\n", m );
+ exit( 1 );
+}
+
+static int Count_hashcode(htable *table,unsigned char *key) {
+ int value = 0;
+ int i = 0;
+ while ( *key ) {
+ value += *(key++) + (i++);
+ value += i;
+ }
+ return value;
+}
+
+static htable TBL = HTABLEINIT( Count, ip, Count_hashcode );
+static Count *last_add;
+static char buffer[ IPBUFMAX ];
+
+#include "ignores.i"
+
+static struct {
+ Count *table[ WORST ];
+ int fill;
+ int lowest;
+} worst;
+
+static int Countp_compare(const void *ax, const void *bx) {
+ Count *a = *(Count**) ax;
+ Count *b = *(Count**) bx;
+ int x = b->total - a->total;
+ if ( x != 0 ) {
+ if ( a->last == 0 ) {
+ return ( b->last == 0 )? x : -1;
+ }
+ }
+ x = b->last - a->last;
+ return x;
+}
+
+static void add_worst_ordered(Count *item) {
+ if ( worst.fill < WORST ) {
+ worst.table[ worst.fill++ ] = item;
+ if ( worst.fill == WORST ) {
+ qsort( worst.table, worst.fill, sizeof( Count* ), Countp_compare );
+ }
+ return;
+ }
+ Count **repl = bsearch(
+ &item, worst.table, worst.fill, sizeof( Count* ), Countp_compare );
+ if ( repl == 0 ) {
+ return;
+ }
+ int size = (char*) &worst.table[ worst.fill - 1 ] - (char*) repl;
+ if ( size > 0 ) {
+ memmove( repl + 1, repl, size );
+ }
+ *repl = item;
+}
+
+static void add_show_table(char *ip,size_t length) {
+ static time_t show = 0;
+ Count *item;
+ int i = htfind( &TBL, ip, (unsigned char **) &item );
+ if ( i == 0 ) {
+ item = (Count *) calloc( 1, sizeof( Count ) );
+ memcpy( item->ip, ip, strlen( ip ) );
+ item->accum = length;
+ item->ignore = ignored( ip );
+ htadd( &TBL, (unsigned char *) item );
+ item->next = last_add;
+ last_add = item;
+ } else {
+ item->accum += length;
+ }
+ struct timeval now;
+ if ( gettimeofday( &now, 0 ) ) {
+ perror( "gettimeofday" );
+ exit( 1 );
+ }
+ if ( now.tv_sec < show ) {
+ return;
+ }
+ if ( now.tv_sec - show > DELAY ) {
+ show = now.tv_sec;
+ }
+ show += 5; // Time for next output
+ // collate entries; Keep the X worst entries, but reduce all a bit
+ worst.fill = 0;
+ item = last_add;
+ for ( ; item; item = item->next ) {
+ item->last = item->accum;
+ item->total += item->last - FADE;
+ if ( item->total < 0 ) {
+ item->total = 0;
+ }
+ item->accum = 0;
+ if ( item->ignore == 0 ) {
+ add_worst_ordered( item );
+ }
+ }
+ fprintf( stdout, "\e[2J" );
+ for ( i = 0; i < worst.fill; i++ ) {
+ item = worst.table[ i ];
+ if ( item->total && item->last ) {
+ fprintf( stdout, "... %s %d %d\n",
+ item->ip, item->total, item->last );
+ }
+ }
+ fprintf( stdout, "==%d/%d/%d\n", TBL.fill, TBL.holes,TBL.size );
+}
+
+static char *ipv4_address(char *b) {
+ memset( buffer, 0, sizeof( buffer ) );
+ sprintf( buffer, "%hhu.%hhu.%hhu.%hhu", b[0], b[1], b[2], b[3] );
+ return buffer;
+}
+
+static char *ipv6_address(short *b) {
+ memset( buffer, 0, sizeof( buffer ) );
+ sprintf( buffer, "%x:%x:%x:%x:%x:%x:%x:%x",
+ ntohs(b[0]), ntohs(b[1]), ntohs(b[2]), ntohs(b[3]),
+ ntohs(b[4]), ntohs(b[5]), ntohs(b[6]), ntohs(b[7]) );
+ return buffer;
+}
+
+int main(int argc,char **argv) {
+ static char packet[ 2048 ];
+ if ( argc != 2 ) {
+ die( "Please tell which interface to sniff" );
+ }
+ setbuf( stdout, 0 );
+ int N;
+ char *iface = argv[ argc - 1 ];
+ int fd = socket( AF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) );
+ char flags[4] = { 1,0,0,0 };
+ if ( fd < 0 ) {
+ perror( "what?" );
+ die( "socket" );
+ }
+ if ( fd < 0 ) {
+ die( "socket" );
+ }
+ N = strlen(iface);
+ if ( setsockopt( fd, SOL_SOCKET, SO_BINDTODEVICE, iface, N ) ) {
+ die( "setsockopt bind to device" );
+ }
+ if ( setsockopt( fd, SOL_SOCKET, SO_BROADCAST, &flags, 4 ) ) {
+ die( "setsockopt broadcast" );
+ }
+ while ( ( N = read( fd, packet, 2048 ) ) > 0 ) {
+ if ( N < 54 ) {
+ continue;
+ }
+ int code = ntohs( *((short*)(packet+12)) );
+ if ( code == 0x0800 ) {
+ // 14+12=src 14+16=dst
+ add_show_table( ipv4_address( packet+30 ), N );
+ } else if ( code == 0x86dd ) {
+ // 14+8=src 14+24=dst
+ add_show_table( ipv6_address( (short*)(packet+38) ), N );
+ } else if ( code == 0x0800 ) {
+ // ignore
+ } else if ( code == 0x8100 ) {
+ // ignore
+ } else {
+ // funny code
+ }
+ }
+ return 0;
+}