initial
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Wed, 15 Jun 2022 00:05:51 +0000 (10:05 +1000)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Wed, 15 Jun 2022 00:05:51 +0000 (10:05 +1000)
socket-sniff/Makefile [new file with mode: 0644]
socket-sniff/ignores.i [new file with mode: 0644]
socket-sniff/socket-sniff.c [new file with mode: 0644]

diff --git a/socket-sniff/Makefile b/socket-sniff/Makefile
new file mode 100644 (file)
index 0000000..e90a6de
--- /dev/null
@@ -0,0 +1,11 @@
+default: socket-sniff
+
+.INTERMEDIATE: socket-sniff.o
+socket-sniff.o: CFLAGS = -Wall -I../htable -g
+socket-sniff.o: socket-sniff.c | ignores.i
+
+socket-sniff: LDLIBS = -L../htable -lhtable
+socket-sniff: socket-sniff.o
+
+clean:
+       rm -f socket-sniff
diff --git a/socket-sniff/ignores.i b/socket-sniff/ignores.i
new file mode 100644 (file)
index 0000000..79728bb
--- /dev/null
@@ -0,0 +1,113 @@
+static char *IGNORES[] = {
+    "10.0.99.",         // ganetinet
+    "127.",             // localhost
+    "152.228.204.144",  // VM via nardoo
+    "152.228.204.145",
+    "152.228.204.146",
+    "152.228.204.147",
+    "152.228.204.148",
+    "152.228.204.149",
+    "152.228.204.150",
+    "152.228.204.151",
+    "152.228.204.152",
+    "152.228.204.153",
+    "152.228.204.154",
+    "152.228.204.155",
+    "152.228.204.156",
+    "152.228.204.157",
+    "152.228.204.158",
+    "152.228.204.159",
+    "2001:41d0:2:1f68:" // (via) nash
+    "2001:41d0:2:d06e:" // (via) newtonia
+    "2001:41d0:8:732b:" // (via) napier
+    "2001:41d0:a:511b:" // (via) nardoo
+    "37.187.145.27",    // nardoo
+    "37.59.56.43",      // napier
+    "46.105.97.110",    // newtonia
+    "5.135.82.176",     // VM via napier
+    "5.135.82.177",
+    "5.135.82.178",
+    "5.135.82.179",
+    "5.135.82.180",
+    "5.135.82.181",
+    "5.135.82.182",
+    "5.135.82.183",
+    "5.135.82.184",
+    "5.135.82.185",
+    "5.135.82.186",
+    "5.135.82.187",
+    "5.135.82.188",
+    "5.135.82.189",
+    "5.135.82.190",
+    "5.135.82.191",
+    "5.196.38.16",      // VM via newtonia
+    "5.196.38.17",
+    "5.196.38.18",
+    "5.196.38.19",
+    "5.196.38.20",
+    "5.196.38.21",
+    "5.196.38.22",
+    "5.196.38.23",
+    "5.196.38.24",
+    "5.196.38.25",
+    "5.196.38.26",
+    "5.196.38.27",
+    "5.196.38.28",
+    "5.196.38.29",
+    "5.196.38.30",
+    "5.196.38.31",
+    "54.36.142.176",    // VM via nash
+    "54.36.142.177",
+    "54.36.142.178",
+    "54.36.142.179",
+    "54.36.142.180",
+    "54.36.142.181",
+    "54.36.142.182",
+    "54.36.142.183",
+    "54.36.142.184",
+    "54.36.142.185",
+    "54.36.142.186",
+    "54.36.142.187",
+    "54.36.142.188",
+    "54.36.142.189",
+    "54.36.142.190",
+    "54.36.142.191",
+    "94.23.30.104",     // nash
+    (char*)0
+};
+
+// Return the size of the IGN table
+static int IGN_count() {
+    int i = 0;
+    while ( IGNORES[ i ] != 0 ) {
+       i++;
+    }
+    return i;
+}
+
+/**
+ * Compare an IP against an ignore entry of width w.
+ * return 0 if ip starts with ign, <0 if ip < ign, and >0 if ip > ign
+ */
+static int IGN_cmp(const void *ipx, const void *ignx) {
+    char *ip = (char *) ipx;
+    char *ign = *(char**) ignx;
+    while ( *ign ) {
+       if ( *ip == 0 ) {
+           return -1;
+       }
+       int c = *(ip++) - *(ign++);
+       if ( c ) {
+           return c;
+       }
+    }
+    return 0;
+}
+
+static int ignored(char *ip) {
+    static int IGN_size = -1;
+    if ( IGN_size == -1 ) {
+       IGN_size = IGN_count();
+    }
+    return bsearch( ip, IGNORES, IGN_size, sizeof( char* ), IGN_cmp )? 1 : 0;
+}
diff --git a/socket-sniff/socket-sniff.c b/socket-sniff/socket-sniff.c
new file mode 100644 (file)
index 0000000..6844359
--- /dev/null
@@ -0,0 +1,205 @@
+#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;
+}