iftop
This commit is contained in:
BIN
.iftop.h.swp
Normal file
BIN
.iftop.h.swp
Normal file
Binary file not shown.
46
Makefile
Normal file
46
Makefile
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Makefile:
|
||||||
|
|
||||||
|
#CC = gcc
|
||||||
|
|
||||||
|
CFLAGS += -g -Wall -I/usr/local/include
|
||||||
|
LDFLAGS += -g
|
||||||
|
|
||||||
|
LDLIBS += -L/usr/local/lib -lpcap -lpthread -lcurses
|
||||||
|
|
||||||
|
SRCS = iftop.c \
|
||||||
|
addr_hash.c \
|
||||||
|
hash.c \
|
||||||
|
ns_hash.c \
|
||||||
|
resolver.c \
|
||||||
|
ui.c \
|
||||||
|
sorted_list.c
|
||||||
|
|
||||||
|
OBJS = $(SRCS:.c=.o)
|
||||||
|
|
||||||
|
HDRS = addr_hash.h
|
||||||
|
|
||||||
|
# If you do not have makedepend, you will need to remove references to depend
|
||||||
|
# and nodepend below.
|
||||||
|
iftop: depend $(OBJS) Makefile
|
||||||
|
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
|
||||||
|
|
||||||
|
%.o: %.c Makefile
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean: nodepend
|
||||||
|
rm -f *~ *.o core iftop
|
||||||
|
|
||||||
|
tags :
|
||||||
|
etags *.c *.h
|
||||||
|
|
||||||
|
depend:
|
||||||
|
makedepend -- $(CFLAGS) -- $(SRCS)
|
||||||
|
touch depend
|
||||||
|
|
||||||
|
nodepend:
|
||||||
|
makedepend -- --
|
||||||
|
rm -f depend
|
||||||
|
|
||||||
|
# DO NOT DELETE
|
||||||
|
|
||||||
|
|
||||||
69
addr_hash.c
Normal file
69
addr_hash.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/* hash table */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "addr_hash.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
#define hash_table_size 256
|
||||||
|
|
||||||
|
int compare(void* a, void* b) {
|
||||||
|
addr_pair* aa = (addr_pair*)a;
|
||||||
|
addr_pair* bb = (addr_pair*)b;
|
||||||
|
return (aa->src.s_addr == bb->src.s_addr
|
||||||
|
&& aa->dst.s_addr == bb->dst.s_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hash(void* key) {
|
||||||
|
int hash;
|
||||||
|
long addr;
|
||||||
|
addr_pair* ap = (addr_pair*)key;
|
||||||
|
|
||||||
|
addr = (long)ap->src.s_addr;
|
||||||
|
|
||||||
|
hash = ((addr & 0x000000FF)
|
||||||
|
+ (addr & 0x0000FF00 >> 8)
|
||||||
|
+ (addr & 0x00FF0000 >> 16)
|
||||||
|
+ (addr & 0xFF000000 >> 24)) % 0xFF;
|
||||||
|
|
||||||
|
addr = (long)ap->dst.s_addr;
|
||||||
|
hash += ((addr & 0x000000FF)
|
||||||
|
+ (addr & 0x0000FF00 >> 8)
|
||||||
|
+ (addr & 0x00FF0000 >> 16)
|
||||||
|
+ (addr & 0xFF000000 >> 24)) % 0xFF;
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* copy_key(void* orig) {
|
||||||
|
addr_pair* copy = malloc(sizeof(addr_pair));
|
||||||
|
if(copy == NULL) {
|
||||||
|
printf("Out of memory\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
*copy = *(addr_pair*)orig;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_key(void* key) {
|
||||||
|
free(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a hash
|
||||||
|
*/
|
||||||
|
hash_type* addr_hash_create() {
|
||||||
|
hash_type* hash_table;
|
||||||
|
if ((hash_table = calloc(hash_table_size, sizeof(hash_type*))) == 0) {
|
||||||
|
fprintf (stderr, "out of memory (hashTable)\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
hash_table->size = hash_table_size;
|
||||||
|
hash_table->compare = &compare;
|
||||||
|
hash_table->hash = &hash;
|
||||||
|
hash_table->delete_key = &delete_key;
|
||||||
|
hash_table->copy_key = ©_key;
|
||||||
|
hash_initialise(hash_table);
|
||||||
|
return hash_table;
|
||||||
|
}
|
||||||
|
|
||||||
23
addr_hash.h
Normal file
23
addr_hash.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* addr_hash.h:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ADDR_HASH_H_ /* include guard */
|
||||||
|
#define __ADDR_HASH_H_
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct in_addr src;
|
||||||
|
struct in_addr dst;
|
||||||
|
} addr_pair;
|
||||||
|
|
||||||
|
typedef addr_pair key_type; /* index into hash table */
|
||||||
|
|
||||||
|
hash_type* addr_hash_create();
|
||||||
|
|
||||||
|
#endif /* __ADDR_HASH_H_ */
|
||||||
112
hash.c
Normal file
112
hash.c
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/* hash table */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
hash_status_enum hash_insert(hash_type* hash_table, void* key, void* rec) {
|
||||||
|
hash_node_type *p, *p0;
|
||||||
|
int bucket;
|
||||||
|
|
||||||
|
/************************************************
|
||||||
|
* allocate node for data and insert in table *
|
||||||
|
************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* insert node at beginning of list */
|
||||||
|
bucket = hash_table->hash(key);
|
||||||
|
if ((p = malloc(sizeof(hash_node_type))) == 0)
|
||||||
|
return HASH_STATUS_MEM_EXHAUSTED;
|
||||||
|
p0 = hash_table->table[bucket];
|
||||||
|
hash_table->table[bucket] = p;
|
||||||
|
p->next = p0;
|
||||||
|
p->key = hash_table->copy_key(key);
|
||||||
|
p->rec = rec;
|
||||||
|
return HASH_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_status_enum hash_delete(hash_type* hash_table, void* key) {
|
||||||
|
hash_node_type *p0, *p;
|
||||||
|
int bucket;
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* delete node containing data from table *
|
||||||
|
********************************************/
|
||||||
|
|
||||||
|
/* find node */
|
||||||
|
p0 = 0;
|
||||||
|
bucket = hash_table->hash(key);
|
||||||
|
p = hash_table->table[bucket];
|
||||||
|
while (p && !hash_table->compare(p->key, key)) {
|
||||||
|
p0 = p;
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
if (!p) return HASH_STATUS_KEY_NOT_FOUND;
|
||||||
|
|
||||||
|
/* p designates node to delete, remove it from list */
|
||||||
|
if (p0)
|
||||||
|
/* not first node, p0 points to previous node */
|
||||||
|
p0->next = p->next;
|
||||||
|
else
|
||||||
|
/* first node on chain */
|
||||||
|
hash_table->table[bucket] = p->next;
|
||||||
|
|
||||||
|
hash_table->delete_key(p->key);
|
||||||
|
free (p);
|
||||||
|
return HASH_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_status_enum hash_find(hash_type* hash_table, void* key, void **rec) {
|
||||||
|
hash_node_type *p;
|
||||||
|
|
||||||
|
/*******************************
|
||||||
|
* find node containing data *
|
||||||
|
*******************************/
|
||||||
|
p = hash_table->table[hash_table->hash(key)];
|
||||||
|
while (p && !hash_table->compare(p->key, key))
|
||||||
|
p = p->next;
|
||||||
|
if (!p) return HASH_STATUS_KEY_NOT_FOUND;
|
||||||
|
*rec = p->rec;
|
||||||
|
return HASH_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_status_enum hash_next_item(hash_type* hash_table, hash_node_type** ppnode) {
|
||||||
|
int i;
|
||||||
|
if(*ppnode != NULL) {
|
||||||
|
if((*ppnode)->next != NULL) {
|
||||||
|
*ppnode = (*ppnode)->next;
|
||||||
|
return HASH_STATUS_OK;
|
||||||
|
}
|
||||||
|
i = hash_table->hash((*ppnode)->key) + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* first node */
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
while(i < hash_table->size && hash_table->table[i] == NULL) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if(i == hash_table->size) {
|
||||||
|
*ppnode = NULL;
|
||||||
|
return HASH_STATUS_KEY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*ppnode = hash_table->table[i];
|
||||||
|
return HASH_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a hash
|
||||||
|
*/
|
||||||
|
hash_status_enum hash_initialise(hash_type* hash_table) {
|
||||||
|
if ((hash_table->table = calloc(hash_table->size, sizeof(hash_node_type *))) == 0) {
|
||||||
|
fprintf (stderr, "out of memory (hash_table)\n");
|
||||||
|
return HASH_STATUS_MEM_EXHAUSTED;
|
||||||
|
}
|
||||||
|
return HASH_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_status_enum hash_destroy(hash_type* hash_table) {
|
||||||
|
free(hash_table->table);
|
||||||
|
return HASH_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
39
hash.h
Normal file
39
hash.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* addr_hash.h:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HASH_H_ /* include guard */
|
||||||
|
#define __HASH_H_
|
||||||
|
|
||||||
|
/* implementation independent declarations */
|
||||||
|
typedef enum {
|
||||||
|
HASH_STATUS_OK,
|
||||||
|
HASH_STATUS_MEM_EXHAUSTED,
|
||||||
|
HASH_STATUS_KEY_NOT_FOUND
|
||||||
|
} hash_status_enum;
|
||||||
|
|
||||||
|
typedef struct node_tag {
|
||||||
|
struct node_tag *next; /* next node */
|
||||||
|
void* key; /* key */
|
||||||
|
void* rec; /* user data */
|
||||||
|
} hash_node_type;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int (*compare) (void*, void*);
|
||||||
|
int (*hash) (void*);
|
||||||
|
void* (*copy_key) (void*);
|
||||||
|
void (*delete_key) (void*);
|
||||||
|
hash_node_type** table;
|
||||||
|
int size;
|
||||||
|
} hash_type;
|
||||||
|
|
||||||
|
|
||||||
|
hash_status_enum hash_initialise(hash_type*);
|
||||||
|
hash_status_enum hash_destroy(hash_type*);
|
||||||
|
hash_status_enum hash_insert(hash_type*, void* key, void *rec);
|
||||||
|
hash_status_enum hash_delete(hash_type* hash_table, void* key);
|
||||||
|
hash_status_enum hash_find(hash_type* hash_table, void* key, void** rec);
|
||||||
|
hash_status_enum hash_next_item(hash_type* hash_table, hash_node_type** ppnode);
|
||||||
|
|
||||||
|
#endif /* __HASH_H_ */
|
||||||
172
iftop.c
Normal file
172
iftop.c
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* iftop.c:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pcap.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <curses.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "iftop.h"
|
||||||
|
#include "addr_hash.h"
|
||||||
|
#include "resolver.h"
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
hash_type* history;
|
||||||
|
time_t last_timestamp;
|
||||||
|
int history_pos = 0;
|
||||||
|
int history_len = 1;
|
||||||
|
pthread_mutex_t tick_mutex;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define CAPTURE_LENGTH 512
|
||||||
|
|
||||||
|
void init_history() {
|
||||||
|
history = addr_hash_create();
|
||||||
|
last_timestamp = time(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
history_type* history_create() {
|
||||||
|
history_type* h;
|
||||||
|
if ((h = calloc(1, sizeof(history_type))) == 0) {
|
||||||
|
fprintf (stderr, "out of memory (history_type)\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void history_rotate() {
|
||||||
|
hash_node_type* n = NULL;
|
||||||
|
history_pos = (history_pos + 1) % HISTORY_LENGTH;
|
||||||
|
hash_next_item(history, &n);
|
||||||
|
while(n != NULL) {
|
||||||
|
hash_node_type* next = n;
|
||||||
|
history_type* d = (history_type*)n->rec;
|
||||||
|
hash_next_item(history, &next);
|
||||||
|
|
||||||
|
if(d->last_write == history_pos) {
|
||||||
|
addr_pair key = *(addr_pair*)(n->key);
|
||||||
|
hash_delete(history, &key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->recv[history_pos] = 0;
|
||||||
|
d->sent[history_pos] = 0;
|
||||||
|
}
|
||||||
|
n = next;
|
||||||
|
}
|
||||||
|
if(history_len < HISTORY_LENGTH) {
|
||||||
|
history_len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tick() {
|
||||||
|
time_t t;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&tick_mutex);
|
||||||
|
|
||||||
|
t = time(NULL);
|
||||||
|
if(t - last_timestamp >= RESOLUTION) {
|
||||||
|
//printf("TICKING\n");
|
||||||
|
ui_print();
|
||||||
|
history_rotate();
|
||||||
|
last_timestamp = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&tick_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_packet(char* args, const struct pcap_pkthdr* pkthdr,const char* packet)
|
||||||
|
{
|
||||||
|
struct ether_header *eptr;
|
||||||
|
eptr = (struct ether_header*)packet;
|
||||||
|
|
||||||
|
tick();
|
||||||
|
|
||||||
|
if(ntohs(eptr->ether_type) == ETHERTYPE_IP) {
|
||||||
|
struct ip* iptr = (struct ip*)(packet + sizeof(struct ether_header));
|
||||||
|
history_type* ht;
|
||||||
|
addr_pair ap;
|
||||||
|
|
||||||
|
if(iptr->ip_src.s_addr < iptr->ip_dst.s_addr) {
|
||||||
|
ap.src = iptr->ip_src;
|
||||||
|
ap.dst = iptr->ip_dst;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ap.src = iptr->ip_dst;
|
||||||
|
ap.dst = iptr->ip_src;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the address to be resolved */
|
||||||
|
resolve(&iptr->ip_dst, NULL, 0);
|
||||||
|
|
||||||
|
if(hash_find(history, &ap, (void**)&ht) == HASH_STATUS_KEY_NOT_FOUND) {
|
||||||
|
ht = history_create();
|
||||||
|
hash_insert(history, &ap, ht);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update record */
|
||||||
|
ht->last_write = history_pos;
|
||||||
|
if(iptr->ip_src.s_addr < iptr->ip_dst.s_addr) {
|
||||||
|
ht->recv[history_pos] += ntohs(iptr->ip_len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ht->sent[history_pos] += ntohs(iptr->ip_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* packet capture thread
|
||||||
|
*/
|
||||||
|
void packet_loop(void* ptr) {
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
|
char* device;
|
||||||
|
pcap_t* pd;
|
||||||
|
|
||||||
|
resolver_initialise();
|
||||||
|
|
||||||
|
device = pcap_lookupdev(errbuf);
|
||||||
|
printf("Device: %s\n",device);
|
||||||
|
pd = pcap_open_live(device,CAPTURE_LENGTH,1,1000,errbuf);
|
||||||
|
if(pd == NULL) {
|
||||||
|
printf("pcap_open_live(): %s\n",errbuf);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("Begin loop\n");
|
||||||
|
init_history();
|
||||||
|
pcap_loop(pd,0,(pcap_handler)handle_packet,NULL);
|
||||||
|
printf("end loop\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void finish(int sig)
|
||||||
|
{
|
||||||
|
ui_finish();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
pthread_t thread;
|
||||||
|
|
||||||
|
(void) signal(SIGINT, finish); /* arrange interrupts to terminate */
|
||||||
|
|
||||||
|
pthread_mutex_init(&tick_mutex, NULL);
|
||||||
|
|
||||||
|
pthread_create(&thread, NULL, (void*)&packet_loop, NULL);
|
||||||
|
|
||||||
|
ui_loop();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
21
iftop.h
Normal file
21
iftop.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* iftop.h:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __IFTOP_H_ /* include guard */
|
||||||
|
#define __IFTOP_H_
|
||||||
|
|
||||||
|
/* 5 * 60 / 3 */
|
||||||
|
#define HISTORY_LENGTH 100
|
||||||
|
#define RESOLUTION 3
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long recv[HISTORY_LENGTH];
|
||||||
|
long sent[HISTORY_LENGTH];
|
||||||
|
int last_write;
|
||||||
|
} history_type;
|
||||||
|
|
||||||
|
void tick();
|
||||||
|
|
||||||
|
#endif /* __IFTOP_H_ */
|
||||||
64
ns_hash.c
Normal file
64
ns_hash.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/* hash table */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include "ns_hash.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
#define hash_table_size 256
|
||||||
|
|
||||||
|
int ns_hash_compare(void* a, void* b) {
|
||||||
|
struct in_addr* aa = (struct in_addr*)a;
|
||||||
|
struct in_addr* bb = (struct in_addr*)b;
|
||||||
|
return (aa->s_addr == bb->s_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ns_hash_hash(void* key) {
|
||||||
|
int hash;
|
||||||
|
long addr;
|
||||||
|
|
||||||
|
addr = (long)((struct in_addr*)key)->s_addr;
|
||||||
|
|
||||||
|
hash = ((addr & 0x000000FF)
|
||||||
|
+ (addr & 0x0000FF00 >> 8)
|
||||||
|
+ (addr & 0x00FF0000 >> 16)
|
||||||
|
+ (addr & 0xFF000000 >> 24)) % 0xFF;
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ns_hash_copy_key(void* orig) {
|
||||||
|
struct in_addr* copy = malloc(sizeof(struct in_addr));
|
||||||
|
if(copy == NULL) {
|
||||||
|
printf("Out of memory\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
*copy = *(struct in_addr*)orig;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ns_hash_delete_key(void* key) {
|
||||||
|
free(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a hash
|
||||||
|
*/
|
||||||
|
hash_type* ns_hash_create() {
|
||||||
|
hash_type* hash_table;
|
||||||
|
if ((hash_table = calloc(hash_table_size, sizeof(hash_type*))) == 0) {
|
||||||
|
fprintf (stderr, "out of memory (hashTable)\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
hash_table->size = hash_table_size;
|
||||||
|
hash_table->compare = &ns_hash_compare;
|
||||||
|
hash_table->hash = &ns_hash_hash;
|
||||||
|
hash_table->delete_key = &ns_hash_delete_key;
|
||||||
|
hash_table->copy_key = &ns_hash_copy_key;
|
||||||
|
hash_initialise(hash_table);
|
||||||
|
return hash_table;
|
||||||
|
}
|
||||||
|
|
||||||
18
ns_hash.h
Normal file
18
ns_hash.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* ns_hash.h:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 DecisionSoft Ltd.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NS_HASH_H_ /* include guard */
|
||||||
|
#define __NS_HASH_H_
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
hash_type* ns_hash_create();
|
||||||
|
|
||||||
|
#endif /* __NS_HASH_H_ */
|
||||||
143
resolver.c
Normal file
143
resolver.c
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* resolver.c:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ns_hash.h"
|
||||||
|
|
||||||
|
#define RESOLVE_QUEUE_LENGTH 20
|
||||||
|
|
||||||
|
struct in_addr resolve_queue[RESOLVE_QUEUE_LENGTH];
|
||||||
|
|
||||||
|
pthread_cond_t resolver_queue_cond;
|
||||||
|
pthread_mutex_t resolver_queue_mutex;
|
||||||
|
pthread_mutex_t resolver_queue_access_mutex;
|
||||||
|
|
||||||
|
hash_type* ns_hash;
|
||||||
|
|
||||||
|
int head;
|
||||||
|
int tail;
|
||||||
|
|
||||||
|
void resolver_worker(void* ptr) {
|
||||||
|
struct timespec delay;
|
||||||
|
delay.tv_sec = 0;
|
||||||
|
delay.tv_nsec = 500;
|
||||||
|
while(1) {
|
||||||
|
/* Wait until we are told that an address has been added to the
|
||||||
|
* queue
|
||||||
|
*/
|
||||||
|
pthread_cond_wait(&resolver_queue_cond, &resolver_queue_mutex);
|
||||||
|
|
||||||
|
/* Keep resolving until the queue is empty */
|
||||||
|
pthread_mutex_lock(&resolver_queue_access_mutex);
|
||||||
|
while(head != tail) {
|
||||||
|
struct in_addr addr = resolve_queue[tail];
|
||||||
|
struct hostent hostbuf, *hp;
|
||||||
|
size_t hstbuflen;
|
||||||
|
char *tmphstbuf;
|
||||||
|
int res;
|
||||||
|
int herr;
|
||||||
|
|
||||||
|
/* mutex always locked at this point */
|
||||||
|
|
||||||
|
tail = (tail + 1) % RESOLVE_QUEUE_LENGTH;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&resolver_queue_access_mutex);
|
||||||
|
|
||||||
|
|
||||||
|
hstbuflen = 1024;
|
||||||
|
/* Allocate buffer, remember to free it to avoid memory leakage. */
|
||||||
|
tmphstbuf = malloc (hstbuflen);
|
||||||
|
|
||||||
|
while ((res = gethostbyaddr_r (&addr, sizeof(addr), AF_INET,
|
||||||
|
&hostbuf, tmphstbuf, hstbuflen,
|
||||||
|
&hp, &herr)) == ERANGE) {
|
||||||
|
/* Enlarge the buffer. */
|
||||||
|
hstbuflen *= 2;
|
||||||
|
tmphstbuf = realloc (tmphstbuf, hstbuflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store the result in ns_hash
|
||||||
|
*/
|
||||||
|
pthread_mutex_lock(&resolver_queue_access_mutex);
|
||||||
|
|
||||||
|
/* Check for errors. */
|
||||||
|
if (res || hp == NULL) {
|
||||||
|
/* failed */
|
||||||
|
//printf("[ Did not resolve %s ]\n", inet_ntoa(addr));
|
||||||
|
/* Leave the unresolved IP in the hash */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* success */
|
||||||
|
char* hostname;
|
||||||
|
//printf("[ Resolved: %s ]\n", hp->h_name);
|
||||||
|
if(hash_find(ns_hash, &addr, (void**)&hostname) == HASH_STATUS_OK) {
|
||||||
|
hash_delete(ns_hash, &addr);
|
||||||
|
free(hostname);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//printf("[ Warning: Could not find hash entry for key: %s ]\n", inet_ntoa(addr));
|
||||||
|
}
|
||||||
|
hostname = strdup(hp->h_name);
|
||||||
|
hash_insert(ns_hash, &addr, (void*)hostname);
|
||||||
|
|
||||||
|
}
|
||||||
|
free(tmphstbuf);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&resolver_queue_access_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolver_initialise() {
|
||||||
|
pthread_t thread;
|
||||||
|
head = tail = 0;
|
||||||
|
|
||||||
|
ns_hash = ns_hash_create();
|
||||||
|
|
||||||
|
pthread_mutex_init(&resolver_queue_mutex, NULL);
|
||||||
|
pthread_mutex_init(&resolver_queue_access_mutex, NULL);
|
||||||
|
pthread_cond_init(&resolver_queue_cond, NULL);
|
||||||
|
|
||||||
|
pthread_create(&thread, NULL, (void*)&resolver_worker, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolve(struct in_addr* addr, char* result, int buflen) {
|
||||||
|
char* hostname;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&resolver_queue_access_mutex);
|
||||||
|
|
||||||
|
if(hash_find(ns_hash, addr, (void**)&hostname) == HASH_STATUS_OK) {
|
||||||
|
/* Found => already resolved, or on the queue */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hostname = strdup(inet_ntoa(*addr));
|
||||||
|
hash_insert(ns_hash, addr, hostname);
|
||||||
|
|
||||||
|
if(((head + 1) % RESOLVE_QUEUE_LENGTH) == tail) {
|
||||||
|
/* queue full */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve_queue[head] = *addr;
|
||||||
|
head = (head + 1) % RESOLVE_QUEUE_LENGTH;
|
||||||
|
pthread_cond_signal(&resolver_queue_cond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&resolver_queue_access_mutex);
|
||||||
|
|
||||||
|
if(result != NULL && buflen > 1) {
|
||||||
|
strncpy(result, hostname, buflen - 1);
|
||||||
|
result[buflen - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
15
resolver.h
Normal file
15
resolver.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* resolver.h:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RESOLVER_H_ /* include guard */
|
||||||
|
#define __RESOLVER_H_
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
void resolver_initialise();
|
||||||
|
|
||||||
|
void resolve(struct in_addr* addr, char* result, int buflen);
|
||||||
|
|
||||||
|
#endif /* __RESOLVER_H_ */
|
||||||
59
sorted_list.c
Normal file
59
sorted_list.c
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* sorted_list.c:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "sorted_list.h"
|
||||||
|
|
||||||
|
|
||||||
|
void sorted_list_insert(sorted_list_type* list, void* item) {
|
||||||
|
sorted_list_node *node, *p;
|
||||||
|
|
||||||
|
p = &(list->root);
|
||||||
|
|
||||||
|
while(p->next != NULL && list->compare(item, p->next->data) > 0) {
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = (sorted_list_node*)malloc(sizeof(sorted_list_node));
|
||||||
|
if(node == NULL) {
|
||||||
|
fprintf(stderr,"Out of memory\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->next = p->next;
|
||||||
|
node->data = item;
|
||||||
|
p->next = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sorted_list_node* sorted_list_next_item(sorted_list_type* list, sorted_list_node* prev) {
|
||||||
|
if(prev == NULL) {
|
||||||
|
return list->root.next;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return prev->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sorted_list_destroy(sorted_list_type* list) {
|
||||||
|
sorted_list_node *p, *n;
|
||||||
|
p = list->root.next;
|
||||||
|
|
||||||
|
while(p != NULL) {
|
||||||
|
n = p->next;
|
||||||
|
free(p);
|
||||||
|
p = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->root.next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sorted_list_initialise(sorted_list_type* list) {
|
||||||
|
list->root.next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
25
sorted_list.h
Normal file
25
sorted_list.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* sorted_list.h:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SORTED_LIST_H_ /* include guard */
|
||||||
|
#define __SORTED_LIST_H_
|
||||||
|
|
||||||
|
typedef struct sorted_list_node_tag {
|
||||||
|
struct sorted_list_node_tag* next;
|
||||||
|
void* data;
|
||||||
|
} sorted_list_node;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
sorted_list_node root;
|
||||||
|
int (*compare)(void*, void*);
|
||||||
|
} sorted_list_type;
|
||||||
|
|
||||||
|
void sorted_list_initialise(sorted_list_type* list);
|
||||||
|
void sorted_list_insert(sorted_list_type* list, void* item);
|
||||||
|
sorted_list_node* sorted_list_next_item(sorted_list_type* list, sorted_list_node* prev);
|
||||||
|
void sorted_list_destroy(sorted_list_type* list);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __SORTED_LIST_H_ */
|
||||||
153
ui.c
Normal file
153
ui.c
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* ui.c:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <curses.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "addr_hash.h"
|
||||||
|
#include "iftop.h"
|
||||||
|
#include "resolver.h"
|
||||||
|
#include "sorted_list.h"
|
||||||
|
|
||||||
|
#define HOSTNAME_LENGTH 20
|
||||||
|
|
||||||
|
#define HISTORY_DIVISIONS 3
|
||||||
|
|
||||||
|
int history_divs[HISTORY_DIVISIONS] = {3, 20, 40};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct host_pair_line_tag {
|
||||||
|
addr_pair* ap;
|
||||||
|
long recv[HISTORY_DIVISIONS];
|
||||||
|
long sent[HISTORY_DIVISIONS];
|
||||||
|
} host_pair_line;
|
||||||
|
|
||||||
|
|
||||||
|
extern hash_type* history;
|
||||||
|
extern int history_pos;
|
||||||
|
extern int history_len;
|
||||||
|
|
||||||
|
int screen_line_compare(void* a, void* b) {
|
||||||
|
host_pair_line* aa = (host_pair_line*)a;
|
||||||
|
host_pair_line* bb = (host_pair_line*)b;
|
||||||
|
return(aa->recv[0] + aa->sent[0] < bb->recv[0] + bb->sent[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readable_size(float n, char* buf, int bsize) {
|
||||||
|
if(n >= 102400) {
|
||||||
|
snprintf(buf, bsize, " %4.1fM", n / (1024 * 1024));
|
||||||
|
}
|
||||||
|
else if(n >= 1024) {
|
||||||
|
snprintf(buf, bsize, " %4.1fK", n / 1024);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
snprintf(buf, bsize, " %4.0fb", n );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_print() {
|
||||||
|
hash_node_type* n = NULL;
|
||||||
|
sorted_list_node* nn = NULL;
|
||||||
|
char hostname[HOSTNAME_LENGTH];
|
||||||
|
char line[80]; // FIXME
|
||||||
|
int y = 2;
|
||||||
|
sorted_list_type screen_list;
|
||||||
|
|
||||||
|
screen_list.compare = &screen_line_compare;
|
||||||
|
sorted_list_initialise(&screen_list);
|
||||||
|
|
||||||
|
erase();
|
||||||
|
|
||||||
|
while(hash_next_item(history, &n) == HASH_STATUS_OK) {
|
||||||
|
history_type* d = (history_type*)n->rec;
|
||||||
|
host_pair_line* screen_line;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
screen_line = (host_pair_line*)calloc(1,sizeof(host_pair_line));
|
||||||
|
screen_line->ap = (addr_pair*)n->key;
|
||||||
|
|
||||||
|
for(i = 0; i < HISTORY_LENGTH; i++) {
|
||||||
|
int j;
|
||||||
|
int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
|
||||||
|
for(j = 0; j < HISTORY_DIVISIONS; j++) {
|
||||||
|
if(i < history_divs[j]) {
|
||||||
|
screen_line->recv[j] += d->recv[ii];
|
||||||
|
screen_line->sent[j] += d->sent[ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sorted_list_insert(&screen_list, screen_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) {
|
||||||
|
int x = 0;
|
||||||
|
int j;
|
||||||
|
host_pair_line* screen_line = (host_pair_line*)nn->data;
|
||||||
|
|
||||||
|
resolve(&screen_line->ap->src, hostname, HOSTNAME_LENGTH);
|
||||||
|
sprintf(line, "%s ", hostname);
|
||||||
|
mvaddstr(y, x, line);
|
||||||
|
x += 20;
|
||||||
|
|
||||||
|
resolve(&screen_line->ap->dst, hostname, HOSTNAME_LENGTH);
|
||||||
|
sprintf(line ,"=> %10s ", hostname);
|
||||||
|
mvaddstr(y, x, line);
|
||||||
|
x += 24;
|
||||||
|
|
||||||
|
for(j = 0; j < HISTORY_DIVISIONS; j++) {
|
||||||
|
int t;
|
||||||
|
if(history_len < history_divs[j]) {
|
||||||
|
t = history_len * RESOLUTION;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t = history_divs[j] * RESOLUTION;
|
||||||
|
}
|
||||||
|
readable_size(screen_line->sent[j] / t, line, 10);
|
||||||
|
mvaddstr(y, x, line);
|
||||||
|
x += strlen(line);
|
||||||
|
|
||||||
|
readable_size(screen_line->recv[j] / t, line, 10);
|
||||||
|
mvaddstr(y, x, line);
|
||||||
|
x += strlen(line);
|
||||||
|
}
|
||||||
|
y++;
|
||||||
|
free(screen_line);
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
sorted_list_destroy(&screen_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_loop() {
|
||||||
|
pthread_mutex_t tick_wait_mutex;
|
||||||
|
pthread_cond_t tick_wait_cond;
|
||||||
|
|
||||||
|
|
||||||
|
(void) initscr(); /* initialize the curses library */
|
||||||
|
keypad(stdscr, TRUE); /* enable keyboard mapping */
|
||||||
|
(void) nonl(); /* tell curses not to do NL->CR/NL on output */
|
||||||
|
(void) cbreak(); /* take input chars one at a time, no wait for \n */
|
||||||
|
(void) noecho(); /* don't echo input */
|
||||||
|
|
||||||
|
|
||||||
|
pthread_mutex_init(&tick_wait_mutex, NULL);
|
||||||
|
pthread_cond_init(&tick_wait_cond, NULL);
|
||||||
|
while(1) {
|
||||||
|
struct timespec t;
|
||||||
|
t.tv_sec = time(NULL) + 1;
|
||||||
|
t.tv_nsec = 0;
|
||||||
|
|
||||||
|
pthread_cond_timedwait(&tick_wait_cond, &tick_wait_mutex, &t);
|
||||||
|
//fprintf(stderr,"timeout tick\n");
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_finish() {
|
||||||
|
endwin();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user