|
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; |