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