version 1.1, 2012/02/21 16:57:34
|
version 1.1.1.2, 2016/10/18 14:04:50
|
Line 3
|
Line 3
|
* |
* |
*/ |
*/ |
|
|
|
#include "config.h" |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
|
#include <ctype.h> |
#include <ctype.h> |
#include <curses.h> | #include <ncurses.h> |
#include <errno.h> |
#include <errno.h> |
#include <string.h> |
#include <string.h> |
#include <math.h> |
#include <math.h> |
Line 26
|
Line 28
|
#include "options.h" |
#include "options.h" |
#include "screenfilter.h" |
#include "screenfilter.h" |
|
|
#define HOSTNAME_LENGTH 256 | #include "ui_common.h" |
|
|
#define HISTORY_DIVISIONS 3 |
|
|
|
#define HELP_TIME 2 |
#define HELP_TIME 2 |
|
|
#define HELP_MESSAGE \ |
#define HELP_MESSAGE \ |
Line 38
|
Line 38
|
" s - toggle show source host h - toggle this help display\n"\ |
" s - toggle show source host h - toggle this help display\n"\ |
" d - toggle show destination host b - toggle bar graph display\n"\ |
" d - toggle show destination host b - toggle bar graph display\n"\ |
" t - cycle line display mode B - cycle bar graph average\n"\ |
" t - cycle line display mode B - cycle bar graph average\n"\ |
" T - toggle cummulative line totals\n"\ | " T - toggle cumulative line totals\n"\ |
"Port display: j/k - scroll display\n"\ |
"Port display: j/k - scroll display\n"\ |
" N - toggle service resolution f - edit filter code\n"\ |
" N - toggle service resolution f - edit filter code\n"\ |
" S - toggle show source port l - set screen filter\n"\ |
" S - toggle show source port l - set screen filter\n"\ |
Line 51
|
Line 51
|
" > - sort by dest name\n"\ |
" > - sort by dest name\n"\ |
" o - freeze current order\n"\ |
" o - freeze current order\n"\ |
"\n"\ |
"\n"\ |
"iftop, version " IFTOP_VERSION | "iftop, version " PACKAGE_VERSION |
|
|
|
|
/* 2, 10 and 40 seconds */ |
|
int history_divs[HISTORY_DIVISIONS] = {1, 5, 20}; |
|
|
|
#define UNIT_DIVISIONS 4 |
|
char* unit_bits[UNIT_DIVISIONS] = { "b", "Kb", "Mb", "Gb"}; |
|
char* unit_bytes[UNIT_DIVISIONS] = { "B", "KB", "MB", "GB"}; |
|
|
|
typedef struct host_pair_line_tag { |
|
addr_pair ap; |
|
double long total_recv; |
|
double long total_sent; |
|
double long recv[HISTORY_DIVISIONS]; |
|
double long sent[HISTORY_DIVISIONS]; |
|
} host_pair_line; |
|
|
|
|
|
extern hash_type* history; |
extern hash_type* history; |
extern int history_pos; |
extern int history_pos; |
extern int history_len; |
extern int history_len; |
Line 78 extern options_t options ;
|
Line 62 extern options_t options ;
|
|
|
void ui_finish(); |
void ui_finish(); |
|
|
hash_type* screen_hash; |
|
hash_type* service_hash; |
|
sorted_list_type screen_list; |
|
host_pair_line totals; |
|
int peaksent, peakrecv, peaktotal; |
|
|
|
#define HELP_MSG_SIZE 80 |
#define HELP_MSG_SIZE 80 |
int showhelphint = 0; |
int showhelphint = 0; |
int persistenthelp = 0; |
int persistenthelp = 0; |
Line 91 time_t helptimer = 0;
|
Line 69 time_t helptimer = 0;
|
char helpmsg[HELP_MSG_SIZE]; |
char helpmsg[HELP_MSG_SIZE]; |
int dontshowdisplay = 0; |
int dontshowdisplay = 0; |
|
|
/* |
|
* Compare two screen lines based on bandwidth. Start comparing from the |
|
* specified column |
|
*/ |
|
int screen_line_bandwidth_compare(host_pair_line* aa, host_pair_line* bb, int start_div) { |
|
int i; |
|
for(i = start_div; i < HISTORY_DIVISIONS; i++) { |
|
if(aa->recv[i] + aa->sent[i] != bb->recv[i] + bb->sent[i]) { |
|
return(aa->recv[i] + aa->sent[i] < bb->recv[i] + bb->sent[i]); |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
/* |
|
* Compare two screen lines based on hostname / IP. Fall over to compare by |
|
* bandwidth. |
|
*/ |
|
int screen_line_host_compare(struct in_addr* a, struct in_addr* b, host_pair_line* aa, host_pair_line* bb) { |
|
char hosta[HOSTNAME_LENGTH], hostb[HOSTNAME_LENGTH]; |
|
int r; |
|
|
|
/* This isn't overly efficient because we resolve again before |
|
display. */ |
|
if (options.dnsresolution) { |
|
resolve(a, hosta, HOSTNAME_LENGTH); |
|
resolve(b, hostb, HOSTNAME_LENGTH); |
|
} |
|
else { |
|
strcpy(hosta, inet_ntoa(*a)); |
|
strcpy(hostb, inet_ntoa(*b)); |
|
} |
|
|
|
r = strcmp(hosta, hostb); |
|
|
|
if(r == 0) { |
|
return screen_line_bandwidth_compare(aa, bb, 2); |
|
} |
|
else { |
|
return (r > 0); |
|
} |
|
|
|
|
|
} |
|
|
|
int screen_line_compare(void* a, void* b) { |
|
host_pair_line* aa = (host_pair_line*)a; |
|
host_pair_line* bb = (host_pair_line*)b; |
|
if(options.sort == OPTION_SORT_DIV1) { |
|
return screen_line_bandwidth_compare(aa, bb, 0); |
|
} |
|
else if(options.sort == OPTION_SORT_DIV2) { |
|
return screen_line_bandwidth_compare(aa, bb, 1); |
|
} |
|
else if(options.sort == OPTION_SORT_DIV3) { |
|
return screen_line_bandwidth_compare(aa, bb, 2); |
|
} |
|
else if(options.sort == OPTION_SORT_SRC) { |
|
return screen_line_host_compare(&(aa->ap.src), &(bb->ap.src), aa, bb); |
|
} |
|
else if(options.sort == OPTION_SORT_DEST) { |
|
return screen_line_host_compare(&(aa->ap.dst), &(bb->ap.dst), aa, bb); |
|
} |
|
|
|
return 1; |
|
} |
|
|
|
void readable_size(float n, char* buf, int bsize, int ksize, int bytes) { |
|
|
|
int i = 0; |
|
float size = 1; |
|
|
|
/* Convert to bits? */ |
|
if(bytes == 0) { |
|
n *= 8; |
|
} |
|
|
|
while(1) { |
|
if(n < size * 1000 || i >= UNIT_DIVISIONS - 1) { |
|
snprintf(buf, bsize, " %4.0f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); |
|
break; |
|
} |
|
i++; |
|
size *= ksize; |
|
if(n < size * 10) { |
|
snprintf(buf, bsize, " %4.2f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); |
|
break; |
|
} |
|
else if(n < size * 100) { |
|
snprintf(buf, bsize, " %4.1f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
/* Barchart scales. */ |
/* Barchart scales. */ |
static struct { |
static struct { |
int max, interval; |
int max, interval; |
Line 201 static struct {
|
Line 83 static struct {
|
}; |
}; |
static int rateidx = 0, wantbiggerrate; |
static int rateidx = 0, wantbiggerrate; |
|
|
|
static int rateidx_init = 0; |
|
|
static int get_bar_interval(float bandwidth) { |
static int get_bar_interval(float bandwidth) { |
int i = 10; |
int i = 10; |
if(bandwidth > 100000000) { |
if(bandwidth > 100000000) { |
Line 225 static int get_bar_length(const int rate) {
|
Line 109 static int get_bar_length(const int rate) {
|
float l; |
float l; |
if (rate <= 0) |
if (rate <= 0) |
return 0; |
return 0; |
if (rate > scale[rateidx].max) | if (rate > scale[rateidx].max) { |
wantbiggerrate = 1; | wantbiggerrate = 1; |
| if(! rateidx_init) { |
| while(rate > scale[rateidx_init++].max) { |
| } |
| rateidx = rateidx_init; |
| } |
| } |
if(options.log_scale) { |
if(options.log_scale) { |
l = log(rate) / log(get_max_bandwidth()); |
l = log(rate) / log(get_max_bandwidth()); |
} |
} |
Line 263 static void draw_bar_scale(int* y) {
|
Line 153 static void draw_bar_scale(int* y) {
|
char s[40], *p; |
char s[40], *p; |
int x; |
int x; |
/* This 1024 vs 1000 stuff is just plain evil */ |
/* This 1024 vs 1000 stuff is just plain evil */ |
readable_size(i, s, sizeof s, options.log_scale ? 1000 : 1024, 0); | readable_size(i, s, sizeof s, options.log_scale ? 1000 : 1024, options.bandwidth_in_bytes); |
p = s + strspn(s, " "); |
p = s + strspn(s, " "); |
x = get_bar_length(i * 8); |
x = get_bar_length(i * 8); |
mvaddch(*y + 1, x, ACS_BTEE); |
mvaddch(*y + 1, x, ACS_BTEE); |
Line 287 static void draw_bar_scale(int* y) {
|
Line 177 static void draw_bar_scale(int* y) {
|
} |
} |
} |
} |
|
|
int history_length(const int d) { |
|
if (history_len < history_divs[d]) |
|
return history_len * RESOLUTION; |
|
else |
|
return history_divs[d] * RESOLUTION; |
|
} |
|
|
|
void draw_line_total(float sent, float recv, int y, int x, option_linedisplay_t linedisplay, int bytes) { |
void draw_line_total(float sent, float recv, int y, int x, option_linedisplay_t linedisplay, int bytes) { |
char buf[10]; |
char buf[10]; |
float n; | float n = 0; |
switch(linedisplay) { |
switch(linedisplay) { |
case OPTION_LINEDISPLAY_TWO_LINE: |
case OPTION_LINEDISPLAY_TWO_LINE: |
draw_line_total(sent, recv, y, x, OPTION_LINEDISPLAY_ONE_LINE_SENT, bytes); |
draw_line_total(sent, recv, y, x, OPTION_LINEDISPLAY_ONE_LINE_SENT, bytes); |
Line 372 void draw_totals(host_pair_line* totals) {
|
Line 255 void draw_totals(host_pair_line* totals) {
|
|
|
extern history_type history_totals; |
extern history_type history_totals; |
|
|
void screen_list_init() { |
|
screen_list.compare = &screen_line_compare; |
|
sorted_list_initialise(&screen_list); |
|
} |
|
|
|
void screen_list_clear() { |
|
sorted_list_node* nn = NULL; |
|
peaksent = peakrecv = peaktotal = 0; |
|
while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) { |
|
free(nn->data); |
|
} |
|
sorted_list_destroy(&screen_list); |
|
} |
|
|
|
void calculate_totals() { |
|
int i; |
|
|
|
/** |
|
* Calculate peaks and totals |
|
*/ |
|
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]) { |
|
totals.recv[j] += history_totals.recv[ii]; |
|
totals.sent[j] += history_totals.sent[ii]; |
|
} |
|
} |
|
|
|
if(history_totals.recv[i] > peakrecv) { |
|
peakrecv = history_totals.recv[i]; |
|
} |
|
if(history_totals.sent[i] > peaksent) { |
|
peaksent = history_totals.sent[i]; |
|
} |
|
if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) { |
|
peaktotal = history_totals.recv[i] + history_totals.sent[i]; |
|
} |
|
} |
|
for(i = 0; i < HISTORY_DIVISIONS; i++) { |
|
int t = history_length(i); |
|
totals.recv[i] /= t; |
|
totals.sent[i] /= t; |
|
} |
|
} |
|
|
|
void make_screen_list() { |
|
hash_node_type* n = NULL; |
|
while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) { |
|
host_pair_line* line = (host_pair_line*)n->rec; |
|
int i; |
|
for(i = 0; i < HISTORY_DIVISIONS; i++) { |
|
line->recv[i] /= history_length(i); |
|
line->sent[i] /= history_length(i); |
|
} |
|
|
|
/* Don't make a new, sorted screen list if order is frozen |
|
*/ |
|
if(!options.freezeorder) { |
|
sorted_list_insert(&screen_list, line); |
|
} |
|
|
|
} |
|
} |
|
|
|
/* |
|
* Zeros all data in the screen hash, but does not remove items. |
|
*/ |
|
void screen_hash_clear() { |
|
hash_node_type* n = NULL; |
|
while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) { |
|
host_pair_line* hpl = (host_pair_line*)n->rec; |
|
memset(hpl->recv, 0, sizeof(hpl->recv)); |
|
memset(hpl->sent, 0, sizeof(hpl->sent)); |
|
} |
|
} |
|
|
|
void analyse_data() { |
|
hash_node_type* n = NULL; |
|
|
|
if(options.paused == 1) { |
|
return; |
|
} |
|
|
|
// Zero totals |
|
memset(&totals, 0, sizeof totals); |
|
|
|
if(options.freezeorder) { |
|
screen_hash_clear(); |
|
} |
|
else { |
|
screen_list_clear(); |
|
hash_delete_all(screen_hash); |
|
} |
|
|
|
while(hash_next_item(history, &n) == HASH_STATUS_OK) { |
|
history_type* d = (history_type*)n->rec; |
|
host_pair_line* screen_line; |
|
union { |
|
host_pair_line **h_p_l_pp; |
|
void **void_pp; |
|
} u_screen_line = { &screen_line }; |
|
addr_pair ap; |
|
int i; |
|
int tsent, trecv; |
|
tsent = trecv = 0; |
|
|
|
|
|
ap = *(addr_pair*)n->key; |
|
|
|
/* Aggregate hosts, if required */ |
|
if(options.aggregate_src) { |
|
ap.src.s_addr = 0; |
|
} |
|
if(options.aggregate_dest) { |
|
ap.dst.s_addr = 0; |
|
} |
|
|
|
/* Aggregate ports, if required */ |
|
if(options.showports == OPTION_PORTS_DEST || options.showports == OPTION_PORTS_OFF) { |
|
ap.src_port = 0; |
|
} |
|
if(options.showports == OPTION_PORTS_SRC || options.showports == OPTION_PORTS_OFF) { |
|
ap.dst_port = 0; |
|
} |
|
if(options.showports == OPTION_PORTS_OFF) { |
|
ap.protocol = 0; |
|
} |
|
|
|
|
|
if(hash_find(screen_hash, &ap, u_screen_line.void_pp) == HASH_STATUS_KEY_NOT_FOUND) { |
|
screen_line = xcalloc(1, sizeof *screen_line); |
|
hash_insert(screen_hash, &ap, screen_line); |
|
screen_line->ap = ap; |
|
} |
|
|
|
screen_line->total_sent += d->total_sent; |
|
screen_line->total_recv += d->total_recv; |
|
|
|
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]; |
|
} |
|
} |
|
} |
|
|
|
} |
|
|
|
make_screen_list(); |
|
|
|
|
|
calculate_totals(); |
|
|
|
} |
|
|
|
void sprint_host(char * line, struct in_addr* addr, unsigned int port, unsigned int protocol, int L) { |
|
char hostname[HOSTNAME_LENGTH]; |
|
char service[HOSTNAME_LENGTH]; |
|
char* s_name; |
|
union { |
|
char **ch_pp; |
|
void **void_pp; |
|
} u_s_name = { &s_name }; |
|
|
|
ip_service skey; |
|
int left; |
|
if(addr->s_addr == 0) { |
|
sprintf(hostname, " * "); |
|
} |
|
else { |
|
if (options.dnsresolution) |
|
resolve(addr, hostname, L); |
|
else |
|
strcpy(hostname, inet_ntoa(*addr)); |
|
} |
|
left = strlen(hostname); |
|
|
|
if(port != 0) { |
|
skey.port = port; |
|
skey.protocol = protocol; |
|
if(options.portresolution && hash_find(service_hash, &skey, u_s_name.void_pp) == HASH_STATUS_OK) { |
|
snprintf(service, HOSTNAME_LENGTH, ":%s", s_name); |
|
} |
|
else { |
|
snprintf(service, HOSTNAME_LENGTH, ":%d", port); |
|
} |
|
} |
|
else { |
|
service[0] = '\0'; |
|
} |
|
|
|
|
|
sprintf(line, "%-*s", L, hostname); |
|
if(left > (L - strlen(service))) { |
|
left = L - strlen(service); |
|
if(left < 0) { |
|
left = 0; |
|
} |
|
} |
|
sprintf(line + left, "%-*s", L-left, service); |
|
} |
|
|
|
|
|
|
|
void ui_print() { |
void ui_print() { |
sorted_list_node* nn = NULL; |
sorted_list_node* nn = NULL; |
char host1[HOSTNAME_LENGTH], host2[HOSTNAME_LENGTH]; |
char host1[HOSTNAME_LENGTH], host2[HOSTNAME_LENGTH]; |
Line 636 void ui_print() {
|
Line 309 void ui_print() {
|
L = HOSTNAME_LENGTH; |
L = HOSTNAME_LENGTH; |
} |
} |
|
|
sprint_host(host1, &(screen_line->ap.src), screen_line->ap.src_port, screen_line->ap.protocol, L); | sprint_host(host1, screen_line->ap.af, |
sprint_host(host2, &(screen_line->ap.dst), screen_line->ap.dst_port, screen_line->ap.protocol, L); | &(screen_line->ap.src6), |
| screen_line->ap.src_port, |
| screen_line->ap.protocol, L, options.aggregate_src); |
| sprint_host(host2, screen_line->ap.af, |
| &(screen_line->ap.dst6), |
| screen_line->ap.dst_port, |
| screen_line->ap.protocol, L, options.aggregate_dest); |
| |
if(!screen_filter_match(host1) && !screen_filter_match(host2)) { |
if(!screen_filter_match(host1) && !screen_filter_match(host2)) { |
continue; |
continue; |
} |
} |
Line 693 void ui_print() {
|
Line 373 void ui_print() {
|
mvaddstr(y+2, 0, "TOTAL: "); |
mvaddstr(y+2, 0, "TOTAL: "); |
|
|
/* Cummulative totals */ |
/* Cummulative totals */ |
mvaddstr(y, 16, "cumm: "); | mvaddstr(y, 16, "cum: "); |
|
|
readable_size(history_totals.total_sent, line, 10, 1024, 1); |
readable_size(history_totals.total_sent, line, 10, 1024, 1); |
mvaddstr(y, 22, line); |
mvaddstr(y, 22, line); |
Line 733 void ui_print() {
|
Line 413 void ui_print() {
|
|
|
/* Bar chart auto scale */ |
/* Bar chart auto scale */ |
if (wantbiggerrate && options.max_bandwidth == 0) { |
if (wantbiggerrate && options.max_bandwidth == 0) { |
++rateidx; | ++rateidx; |
wantbiggerrate = 0; | wantbiggerrate = 0; |
} |
} |
} |
} |
|
|
Line 754 void ui_curses_init() {
|
Line 434 void ui_curses_init() {
|
(void) nonl(); /* tell curses not to do NL->CR/NL on output */ |
(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) cbreak(); /* take input chars one at a time, no wait for \n */ |
(void) noecho(); /* don't echo input */ |
(void) noecho(); /* don't echo input */ |
|
(void) curs_set(0); /* hide blinking cursor in ui */ |
halfdelay(2); |
halfdelay(2); |
} |
} |
|
|
Line 1045 void ui_loop() {
|
Line 726 void ui_loop() {
|
break; |
break; |
} |
} |
case '!': { |
case '!': { |
#ifndef NO_SYSTEM | #ifdef ALLOW_SUBSHELL |
char *s; |
char *s; |
dontshowdisplay = 1; |
dontshowdisplay = 1; |
if ((s = edline(0, "Command", "")) && s[strspn(s, " \t")]) { |
if ((s = edline(0, "Command", "")) && s[strspn(s, " \t")]) { |
Line 1082 void ui_loop() {
|
Line 763 void ui_loop() {
|
case 'T': |
case 'T': |
options.show_totals = !options.show_totals; |
options.show_totals = !options.show_totals; |
if(options.show_totals) { |
if(options.show_totals) { |
showhelp("Show cummulative totals"); | showhelp("Show cumulative totals"); |
} |
} |
else { |
else { |
showhelp("Hide cummulative totals"); | showhelp("Hide cumulative totals"); |
} |
} |
ui_print(); |
ui_print(); |
break; |
break; |