Added support for displaying ports.

This commit is contained in:
pdw
2002-10-10 08:59:14 +00:00
parent fb66807ab8
commit 803ee46de2
8 changed files with 155 additions and 47 deletions

View File

@@ -1,6 +1,10 @@
Change log for iftop Change log for iftop
$Id$ $Id$
0.8
Added support for displaying port numbers
0.7 02/10/02 0.7 02/10/02
Fixed missing sll.h file. Fixed missing sll.h file.

6
TODO
View File

@@ -1,12 +1,12 @@
Things to do for iftop Things to do for iftop
$Id$ $Id$
* Interface types other than ethernet? Should at least detect these.... * Include ports in display
- implement service name hash
- add key press for src/dest port aggregation
* IP types other than v4? * IP types other than v4?
* Include ports in display.
* Which average to use for the bar graph? Show several and peaks? Colours? * Which average to use for the bar graph? Show several and peaks? Colours?
* Single keypress firewalling of troublesome connections, a la top(1)'s K * Single keypress firewalling of troublesome connections, a la top(1)'s K

View File

@@ -12,7 +12,9 @@ int compare(void* a, void* b) {
addr_pair* aa = (addr_pair*)a; addr_pair* aa = (addr_pair*)a;
addr_pair* bb = (addr_pair*)b; addr_pair* bb = (addr_pair*)b;
return (aa->src.s_addr == bb->src.s_addr return (aa->src.s_addr == bb->src.s_addr
&& aa->dst.s_addr == bb->dst.s_addr); && aa->src_port == bb->src_port
&& aa->dst.s_addr == bb->dst.s_addr
&& aa->dst_port == bb->dst_port);
} }
int hash(void* key) { int hash(void* key) {
@@ -25,13 +27,15 @@ int hash(void* key) {
hash = ((addr & 0x000000FF) hash = ((addr & 0x000000FF)
+ (addr & 0x0000FF00 >> 8) + (addr & 0x0000FF00 >> 8)
+ (addr & 0x00FF0000 >> 16) + (addr & 0x00FF0000 >> 16)
+ (addr & 0xFF000000 >> 24)) % 0xFF; + (addr & 0xFF000000 >> 24)
+ ap->src_port) % 0xFF;
addr = (long)ap->dst.s_addr; addr = (long)ap->dst.s_addr;
hash = ( hash + (addr & 0x000000FF) hash = ( hash + (addr & 0x000000FF)
+ (addr & 0x0000FF00 >> 8) + (addr & 0x0000FF00 >> 8)
+ (addr & 0x00FF0000 >> 16) + (addr & 0x00FF0000 >> 16)
+ (addr & 0xFF000000 >> 24)) % 0xFF; + (addr & 0xFF000000 >> 24)
+ ap->dst_port) % 0xFF;
return hash; return hash;
} }

View File

@@ -12,7 +12,9 @@
#include "hash.h" #include "hash.h"
typedef struct { typedef struct {
unsigned short int src_port;
struct in_addr src; struct in_addr src;
unsigned short int dst_port;
struct in_addr dst; struct in_addr dst;
} addr_pair; } addr_pair;

71
iftop.c
View File

@@ -11,6 +11,8 @@
#include <net/if.h> #include <net/if.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <pthread.h> #include <pthread.h>
#include <curses.h> #include <curses.h>
#include <signal.h> #include <signal.h>
@@ -47,8 +49,8 @@ static void finish(int sig) {
/* Only need ethernet and IP headers. */ /* Only need ethernet and IP headers (48) + first 2 bytes of tcp/udp header */
#define CAPTURE_LENGTH 48 #define CAPTURE_LENGTH 68
void init_history() { void init_history() {
history = addr_hash_create(); history = addr_hash_create();
@@ -118,6 +120,39 @@ int in_filter_net(struct in_addr addr) {
return ret; return ret;
} }
/**
* Creates an addr_pair from an ip (and tcp/udp) header, swapping src and dst
* if required
*/
void assign_addr_pair(addr_pair* ap, struct ip* iptr, int flip) {
unsigned short int src_port = 0;
unsigned short int dst_port = 0;
/* Does this protocol use ports? */
if(iptr->ip_p == SOL_TCP || iptr->ip_p == SOL_UDP) {
/* We take a slight liberty here by treating UDP the same as TCP */
/* Find the TCP/UDP header */
struct tcphdr* thdr = ((void*)iptr) + iptr->ip_hl * 4;
src_port = ntohs(thdr->source);
dst_port = ntohs(thdr->dest);
}
if(flip == 0) {
ap->src = iptr->ip_src;
ap->src_port = src_port;
ap->dst = iptr->ip_dst;
ap->dst_port = dst_port;
}
else {
ap->src = iptr->ip_dst;
ap->src_port = dst_port;
ap->dst = iptr->ip_src;
ap->dst_port = src_port;
}
}
static void handle_ip_packet(struct ip* iptr, int hw_dir) static void handle_ip_packet(struct ip* iptr, int hw_dir)
{ {
int direction = 0; /* incoming */ int direction = 0; /* incoming */
@@ -131,28 +166,27 @@ static void handle_ip_packet(struct ip* iptr, int hw_dir)
*/ */
if(hw_dir == 1) { if(hw_dir == 1) {
/* Packet leaving this interface. */ /* Packet leaving this interface. */
ap.src = iptr->ip_src; assign_addr_pair(&ap, iptr, 0);
ap.dst = iptr->ip_dst;
direction = 1; direction = 1;
} }
else if(hw_dir == 0) { else if(hw_dir == 0) {
/* Packet incoming */ /* Packet incoming */
ap.src = iptr->ip_dst; assign_addr_pair(&ap, iptr, 1);
ap.dst = iptr->ip_src; direction = 0;
} }
/* /*
* This packet is not from or to this interface, or the h/ware * This packet is not from or to this interface, or the h/ware
* layer did not give the direction away. Therefore assume * layer did not give the direction away. Therefore assume
* it was picked up in promisc mode, and account it as incoming. * it was picked up in promisc mode, and account it as incoming.
*/ */
else if(iptr->ip_src.s_addr < iptr->ip_dst.s_addr) { else if(iptr->ip_src.s_addr < iptr->ip_dst.s_addr) {
ap.src = iptr->ip_src; assign_addr_pair(&ap, iptr, 0);
ap.dst = iptr->ip_dst; direction = 0;
} }
else { else {
ap.src = iptr->ip_dst; assign_addr_pair(&ap, iptr, 0);
ap.dst = iptr->ip_src; direction = 0;
} }
} }
else { else {
@@ -161,14 +195,13 @@ static void handle_ip_packet(struct ip* iptr, int hw_dir)
*/ */
if(in_filter_net(iptr->ip_src) & !in_filter_net(iptr->ip_dst)) { if(in_filter_net(iptr->ip_src) & !in_filter_net(iptr->ip_dst)) {
/* out of network */ /* out of network */
ap.src = iptr->ip_src; assign_addr_pair(&ap, iptr, 0);
ap.dst = iptr->ip_dst;
direction = 1; direction = 1;
} }
else if(in_filter_net(iptr->ip_dst) & !in_filter_net(iptr->ip_src)) { else if(in_filter_net(iptr->ip_dst) & !in_filter_net(iptr->ip_src)) {
/* into network */ /* into network */
ap.src = iptr->ip_dst; assign_addr_pair(&ap, iptr, 1);
ap.dst = iptr->ip_src; direction = 0;
} }
else { else {
/* drop packet */ /* drop packet */

View File

@@ -18,7 +18,7 @@
options_t options; options_t options;
char optstr[] = "+i:f:n:dhpb"; char optstr[] = "+i:f:n:dhpbP";
/* Global options. */ /* Global options. */
@@ -66,6 +66,7 @@ static void set_defaults() {
options.dnsresolution = 1; options.dnsresolution = 1;
options.promiscuous = 0; options.promiscuous = 0;
options.showbars = 1; options.showbars = 1;
options.showports = OPTION_PORTS_OFF;
options.aggregate = OPTION_AGGREGATE_OFF; options.aggregate = OPTION_AGGREGATE_OFF;
} }
@@ -120,6 +121,7 @@ static void usage(FILE *fp) {
" -f filter code use filter code to select packets to count\n" " -f filter code use filter code to select packets to count\n"
" (default: none, but only IP packets are counted)\n" " (default: none, but only IP packets are counted)\n"
" -n net/mask show traffic flows in/out of network\n" " -n net/mask show traffic flows in/out of network\n"
" -P show ports as well as hosts\n"
"\n" "\n"
"iftop, version " IFTOP_VERSION " copyright (c) 2002 Paul Warren <pdw@ex-parrot.com>\n" "iftop, version " IFTOP_VERSION " copyright (c) 2002 Paul Warren <pdw@ex-parrot.com>\n"
); );
@@ -153,6 +155,10 @@ void options_read(int argc, char **argv) {
options.promiscuous = 1; options.promiscuous = 1;
break; break;
case 'P':
options.showports = OPTION_PORTS_ON;
break;
case 'n': case 'n':
set_net_filter(optarg); set_net_filter(optarg);
break; break;

View File

@@ -16,6 +16,13 @@ typedef enum {
OPTION_AGGREGATE_DEST OPTION_AGGREGATE_DEST
} option_aggregate_t; } option_aggregate_t;
typedef enum {
OPTION_PORTS_OFF,
OPTION_PORTS_AGGSRC,
OPTION_PORTS_AGGDEST,
OPTION_PORTS_ON
} option_port_t;
typedef struct { typedef struct {
/* interface on which to listen */ /* interface on which to listen */
char *interface; char *interface;
@@ -30,6 +37,7 @@ typedef struct {
int dnsresolution; int dnsresolution;
int promiscuous; int promiscuous;
int showbars; int showbars;
option_port_t showports;
option_aggregate_t aggregate; option_aggregate_t aggregate;
} options_t; } options_t;

93
ui.c
View File

@@ -10,6 +10,7 @@
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <netdb.h>
#include "addr_hash.h" #include "addr_hash.h"
#include "iftop.h" #include "iftop.h"
@@ -199,15 +200,25 @@ void analyse_data() {
ap = *(addr_pair*)n->key; ap = *(addr_pair*)n->key;
/* Aggregate hosts, if required */
if(options.aggregate == OPTION_AGGREGATE_SRC) { if(options.aggregate == OPTION_AGGREGATE_SRC) {
ap.dst.s_addr = 0; ap.dst.s_addr = 0;
} }
else if(options.aggregate == OPTION_AGGREGATE_DEST) { else if(options.aggregate == OPTION_AGGREGATE_DEST) {
ap.src.s_addr = 0; ap.src.s_addr = 0;
} }
/* Aggregate ports, if required */
if(options.showports == OPTION_PORTS_AGGSRC || options.showports == OPTION_PORTS_OFF) {
ap.src_port = 0;
}
if(options.showports == OPTION_PORTS_AGGDEST || options.showports == OPTION_PORTS_OFF) {
ap.dst_port = 0;
}
if(hash_find(screen_hash, &ap, (void**)&screen_line) == HASH_STATUS_KEY_NOT_FOUND) { if(hash_find(screen_hash, &ap, (void**)&screen_line) == HASH_STATUS_KEY_NOT_FOUND) {
screen_line = xcalloc(1, sizeof *screen_line); screen_line = xcalloc(1, sizeof *screen_line);
hash_insert(screen_hash, &ap, screen_line); hash_insert(screen_hash, &ap, screen_line);
screen_line->ap = ap; screen_line->ap = ap;
} }
@@ -233,6 +244,9 @@ void analyse_data() {
} }
hash_delete_all(screen_hash); hash_delete_all(screen_hash);
/**
* Calculate peaks and totals
*/
for(i = 0; i < HISTORY_LENGTH; i++) { for(i = 0; i < HISTORY_LENGTH; i++) {
int j; int j;
int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH; int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
@@ -257,6 +271,48 @@ void analyse_data() {
} }
void sprint_host(char * line, struct in_addr* addr, unsigned int port, int L) {
char hostname[HOSTNAME_LENGTH];
char service[10];
struct servent* sent;
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);
//TODO: Replace this with in-memory hash for speed.
//sent = getservbyport(port, "tcp");
if(port != 0) {
sent = NULL;
if(sent == NULL) {
snprintf(service, 10, ":%d", port);
}
else {
snprintf(service, 10, ":%s", sent->s_name);
}
}
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 hostname[HOSTNAME_LENGTH]; char hostname[HOSTNAME_LENGTH];
@@ -313,22 +369,16 @@ void ui_print() {
host_pair_line* screen_line = (host_pair_line*)nn->data; host_pair_line* screen_line = (host_pair_line*)nn->data;
if(y < LINES - 4) { if(y < LINES - 4) {
fprintf(stderr, "Drawing at %d \r\n", y);
L = (COLS - 8 * HISTORY_DIVISIONS - 4) / 2; L = (COLS - 8 * HISTORY_DIVISIONS - 4) / 2;
if(L > sizeof hostname) { if(L > sizeof hostname) {
L = sizeof hostname; L = sizeof hostname;
} }
if(screen_line->ap.src.s_addr == 0) { sprint_host(line, &(screen_line->ap.src), screen_line->ap.src_port, L);
sprintf(hostname, " * ");
} //sprintf(line, "%-*s", L, hostname);
else {
if (options.dnsresolution)
resolve(&(screen_line->ap.src), hostname, L);
else
strcpy(hostname, inet_ntoa(screen_line->ap.src));
}
sprintf(line, "%-*s", L, hostname);
mvaddstr(y, x, line); mvaddstr(y, x, line);
x += L; x += L;
@@ -336,16 +386,9 @@ void ui_print() {
mvaddstr(y+1, x, " <= "); mvaddstr(y+1, x, " <= ");
x += 4; x += 4;
if(screen_line->ap.dst.s_addr == 0) {
sprintf(hostname, " * "); sprint_host(line, &(screen_line->ap.dst), screen_line->ap.dst_port, L);
}
else {
if (options.dnsresolution)
resolve(&screen_line->ap.dst, hostname, L);
else
strcpy(hostname, inet_ntoa(screen_line->ap.dst));
}
sprintf(line, "%-*s", L, hostname);
mvaddstr(y, x, line); mvaddstr(y, x, line);
draw_line_totals(y, screen_line); draw_line_totals(y, screen_line);
@@ -413,6 +456,7 @@ void ui_init() {
screen_list_init(); screen_list_init();
screen_hash = addr_hash_create(); screen_hash = addr_hash_create();
} }
void ui_loop() { void ui_loop() {
@@ -448,6 +492,13 @@ void ui_loop() {
? OPTION_AGGREGATE_OFF ? OPTION_AGGREGATE_OFF
: OPTION_AGGREGATE_DEST; : OPTION_AGGREGATE_DEST;
break; break;
case 'P':
options.showports =
(options.showports == OPTION_PORTS_OFF)
? OPTION_PORTS_ON
: OPTION_PORTS_OFF;
// Don't tick here, otherwise we get a bogus display
break;
} }
tick(0); tick(0);
} }