3 #include <linux/if_ether.h>
9 #include <sys/socket.h>
12 #include <sys/types.h>
15 #include <hashvector.h>
17 // Seconds between outputs
20 // Byte count fade-out between displays
21 static int FADE = 10000;
23 // Number of top usage to report
24 static int WORST = 20;
26 // Number of characters for text format IP holdings
29 typedef struct _Count {
38 static void die(char *m) {
39 fprintf( stderr, "%s\n", m );
43 // Return pointer to the key for an item
44 static void *Countp_itemkey(void *item) {
45 return ((Count*) item)->ip;
48 // Return 1 if the item has the key, or 0 otherwise.
49 static int Countp_haskey(void *item,void *key) {
50 return memcmp( key, Countp_itemkey( item ), IPBUFMAX ) == 0;
53 // Returns the hashcode for a key
54 static unsigned long Countp_hashcode(void *key) {
55 return hashvector_hashcode( key, IPBUFMAX );
58 static hashvector TBL = {
62 .keyhashcode = Countp_hashcode,
63 .itemkey = Countp_itemkey,
64 .haskey = Countp_haskey
67 static char buffer[ IPBUFMAX ];
69 /*============================================================
70 * Reading ignore lines.
72 // Return pointer to the key for an item
73 static void *charp_itemkey(void *item) {
77 // Return 1 if the item has the key, or 0 otherwise.
78 static int charp_haskey(void *item,void *key) {
79 return strcmp( key, item ) == 0;
82 // Returns the hashcode for a key
83 static unsigned long charp_hashcode(void *key) {
84 return hashvector_hashcode( key, strlen( (const char *) key ) );
87 static hashvector IGN = {
91 .keyhashcode = charp_hashcode,
92 .itemkey = charp_itemkey,
93 .haskey = charp_haskey
96 static void read_ignore_file(char *filename) {
97 #define RDBLKSZ 1000000
98 static char block[ RDBLKSZ ];
99 static char *cur = block;
100 static char *end = block;
101 int fd = open( filename, O_RDONLY );
103 die( "Cannot load the ignare file." );
108 for ( ;; ) { // move p to end of line
109 while ( p < end && *p != '\n' ) {
115 if ( cur != block && cur != end ) {
116 memmove( cur, block, end - cur );
121 n = RDBLKSZ - ( end - cur );
122 n = read( fd, end, n );
128 // Line from cur to '\n' at p < end.
129 char *ip = calloc( 1, p - cur + 1 );
130 memcpy( ip, cur, p - cur );
132 hashvector_add( &IGN, ip );
136 /*============================================================*/
138 static int Countp_compare(const void *ax, const void *bx) {
139 Count *a = (Count*) ax;
140 Count *b = (Count*) bx;
147 int x = a->total - b->total;
151 return a->last - b->last;
154 static int Countp_fade_and_print(unsigned long index,void *x,void *d) {
156 Count *item = (Count *) x;
157 item->last = item->accum;
158 item->total += item->last - FADE;
160 if ( item->total <= 0 ) {
162 } else if ( index < WORST && item->ignore == 0 ) {
163 fprintf( stdout, "... %s %d %d\n",
164 item->ip, item->total, item->last );
170 static int Countp_reclaim(pvector *pv,unsigned long ix,void *item,void *data) {
175 // ip points to [ IPBUFMAX ] of ip address in text
176 static void add_show_table(char *ip,size_t length) {
177 static time_t show = 0;
179 int i = hashvector_find( &TBL, ip, (void**) &item );
181 item = (Count *) calloc( 1, sizeof( Count ) );
182 memcpy( item->ip, ip, strlen( ip ) );
183 item->accum = length;
184 hashvector_add( &TBL, item );
185 item->ignore = hashvector_find( &IGN, ip, 0 );
186 for ( i = strlen( ip )-1; i > 1; i-- ) {
187 if ( ip[i] == '.' || ip[i] == ':' ) {
188 item->ignore |= hashvector_find( &IGN, ip, 0 );
192 //fprintf( stdout, "add %s\n", ip );
194 item->accum += length;
197 if ( gettimeofday( &now, 0 ) ) {
198 perror( "gettimeofday" );
201 if ( now.tv_sec < show ) {
204 if ( now.tv_sec - show > DELAY ) {
207 show += DELAY; // Time for next output
208 pvector ordered = { 0, 0 };
209 hashvector_contents( &TBL, &ordered );
210 pvector_qsort( &ordered, Countp_compare );
211 pvector_iterate( &ordered, Countp_fade_and_print, 0 );
212 pvector_resize( &ordered, 0, Countp_reclaim, 0 );
213 fprintf( stdout, "==%ld/%ld/%ld\n", TBL.fill, TBL.holes, TBL.table.size );
216 static char *ipv4_address(char *b) {
217 memset( buffer, 0, sizeof( buffer ) );
218 sprintf( buffer, "%hhu.%hhu.%hhu.%hhu", b[0], b[1], b[2], b[3] );
222 static char *ipv6_address(short *b) {
223 memset( buffer, 0, sizeof( buffer ) );
224 sprintf( buffer, "%x:%x:%x:%x:%x:%x:%x:%x",
225 ntohs(b[0]), ntohs(b[1]), ntohs(b[2]), ntohs(b[3]),
226 ntohs(b[4]), ntohs(b[5]), ntohs(b[6]), ntohs(b[7]) );
230 int main(int argc,char **argv) {
231 static char packet[ 2048 ];
233 // Check for -fN to set FADE
234 if ( ARG < argc && strncmp( argv[ ARG ], "-d", 2 ) == 0 ) {
235 if ( sscanf( argv[ ARG ]+2, "%d", &DELAY ) != 1 ) {
236 die( "Missing/bad delay value" );
238 fprintf( stdout, "Delay is %d seconds between reports\n", DELAY );
241 if ( ARG < argc && strncmp( argv[ ARG ], "-f", 2 ) == 0 ) {
242 if ( sscanf( argv[ ARG ]+2, "%d", &FADE ) != 1 ) {
243 die( "Missing/bad fade value" );
245 fprintf( stdout, "Fading %d bytes before reports\n", FADE );
248 if ( ARG < argc && strncmp( argv[ ARG ], "-n", 2 ) == 0 ) {
249 if ( sscanf( argv[ ARG ]+2, "%d", &WORST ) != 1 ) {
250 die( "Missing/bad number to display" );
252 fprintf( stdout, "Displaying at most %d lines in reports\n", WORST );
255 if ( ARG < argc && strncmp( argv[ ARG ], "-i", 2 ) == 0 ) {
256 char *filename = argv[ ARG ] + 2;
257 if ( (*filename) == 0 ) {
258 die( "Missing/bad ignore filename" );
260 read_ignore_file( filename );
261 fprintf( stdout, "ignoring ip prefixes from %s\n", filename );
265 die( "Please tell which interface to sniff" );
269 char *iface = argv[ ARG ];
270 int fd = socket( AF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) );
271 char flags[4] = { 1,0,0,0 };
280 if ( setsockopt( fd, SOL_SOCKET, SO_BINDTODEVICE, iface, N ) ) {
281 die( "setsockopt bind to device" );
283 if ( setsockopt( fd, SOL_SOCKET, SO_BROADCAST, &flags, 4 ) ) {
284 die( "setsockopt broadcast" );
286 while ( ( N = read( fd, packet, 2048 ) ) > 0 ) {
290 int code = ntohs( *((short*)(packet+12)) );
291 if ( code == 0x0800 ) {
292 // 14+12=src 14+16=dst
293 char *p = ipv4_address( packet+30 );
294 if ( ( strncmp( p, "127.", 4 ) != 0 ) ) {
295 add_show_table( p, N );
297 } else if ( code == 0x86dd ) {
298 // 14+8=src 14+24=dst
299 char *p = ipv6_address( (short*)(packet+38) );
300 if ( ( strncmp( p, "ff02:0:0:0:0:", 13 ) != 0 ) &&
301 ( strncmp( p, "0:0:0:0:0:0:0:1", 15 ) != 0 ) ) {
302 add_show_table( p, N );
304 } else if ( code == 0x0800 ) {
306 } else if ( code == 0x8100 ) {