diff options
author | pdw <> | 2007-03-03 16:01:48 +0000 |
---|---|---|
committer | pdw <> | 2007-03-03 16:01:48 +0000 |
commit | 6458ed04f5ce51a4b0dc9059e8ddeff05e56a721 (patch) | |
tree | bd99c53cb248642b18075154baae4f3d4ff28722 | |
parent | 86013fabd68b173dc9021829913ebcc9ce6e9722 (diff) | |
download | iftop-6458ed04f5ce51a4b0dc9059e8ddeff05e56a721.zip |
Created iftop-dump
-rw-r--r-- | Makefile.OLD | 33 | ||||
-rw-r--r-- | Makefile.am | 10 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | counter_hash.c | 56 | ||||
-rw-r--r-- | counter_hash.h | 23 | ||||
-rw-r--r-- | iftop-dump.c | 466 | ||||
-rw-r--r-- | iftop.h | 5 | ||||
-rw-r--r-- | ui.h | 2 |
8 files changed, 579 insertions, 18 deletions
diff --git a/Makefile.OLD b/Makefile.OLD index 2855d1c..e965a0c 100644 --- a/Makefile.OLD +++ b/Makefile.OLD @@ -22,8 +22,8 @@ CFLAGS += -I/usr/include/pcap -g # Do you want to use curses or ncurses? Probably ncurses, unless curses # is ncurses on your machine. -CURSES = ncurses -#CURSES = curses +# CURSES = -lncurses +#CURSES = -lcurses # # Name resolution. Sensible systems have gethostbyaddr_r, which is reentrant @@ -66,7 +66,7 @@ CFLAGS += -DUSE_GETHOSTBYADDR_R # # Solaris needs a library to make sockets go and lacks inet_aton. # -LDLIBS += -lsocket -lnsl +#LDLIBS += -lsocket -lnsl CFLAGS += -DFAKE_INET_ATON # PREFIX specifies the base directory for the installation. @@ -83,23 +83,32 @@ MANDIR = man # You shouldn't need to change anything below this point. CFLAGS += -g -Wall "-DIFTOP_VERSION=\"$(VERSION)\"" LDFLAGS += -g #-pthread -LDLIBS += -lpcap -l$(CURSES) -lm -lpthread - -SRCS = iftop.c addr_hash.c hash.c ns_hash.c resolver.c ui.c util.c sorted_list.c\ - options.c serv_hash.c threadprof.c edline.c screenfilter.c +LDLIBS += -lpcap $(CURSES) -lm -lpthread + +COMMON_SRCS = addr_hash.c hash.c ns_hash.c util.c sorted_list.c\ + options.c serv_hash.c threadprof.c screenfilter.c cfgfile.c stringmap.c addrs_ioctl.c +IFTOP_ONLY_SRCS = iftop.c ui.c stringmap.c +IFTOPDUMP_ONLY_SRCS = iftop-dump.c counter_hash.c +SRCS = $(COMMON_SRCS) $(IFTOPDUMP_ONLY_SRCS) $(IFTOP_ONLY_SRCS) +IFTOP_SRCS = $(IFTOP_ONLY_SRCS) $(COMMON_SRCS) +IFTOPDUMP_SRCS = $(IFTOPDUMP_ONLY_SRCS) $(COMMON_SRCS) HDRS = addr_hash.h hash.h iftop.h ns_hash.h resolver.h sorted_list.h ui.h options.h sll.h\ serv_hash.h threadprof.h ether.h ip.h tcp.h screenfilter.h token.h llc.h \ extract.h ethertype.h TXTS = README CHANGES INSTALL TODO iftop.8 COPYING SPECFILE = iftop.spec iftop.spec.in -OBJS = $(SRCS:.c=.o) +IFTOP_OBJS = $(IFTOP_SRCS:.c=.o) +IFTOPDUMP_OBJS = $(IFTOPDUMP_SRCS:.c=.o) + +iftop: $(IFTOP_OBJS) Makefile + $(CC) $(LDFLAGS) -o $@ $(IFTOP_OBJS) $(LDLIBS) -iftop: $(OBJS) Makefile - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) +iftop-dump: $(IFTOPDUMP_OBJS) Makefile + $(CC) $(LDFLAGS) -o $@ $(IFTOPDUMP_OBJS) $(LDLIBS) -integers.h: integers - ./integers +#integers.h: integers +# ./integers install: iftop install -D iftop $(PREFIX)/$(BINDIR)/iftop diff --git a/Makefile.am b/Makefile.am index 9459c3c..2eeb45c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,7 +10,7 @@ # $Id$ # -sbin_PROGRAMS = iftop +sbin_PROGRAMS = iftop iftop-dump iftop_SOURCES = addr_hash.c edline.c hash.c iftop.c ns_hash.c \ options.c resolver.c screenfilter.c serv_hash.c \ @@ -18,6 +18,14 @@ iftop_SOURCES = addr_hash.c edline.c hash.c iftop.c ns_hash.c \ addrs_ioctl.c addrs_dlpi.c dlcommon.c \ stringmap.c cfgfile.c vector.c +iftop_dump_SOURCES = counter_hash.c hash.c iftop-dump.c \ + options.c \ + util.c \ + addrs_ioctl.c addrs_dlpi.c dlcommon.c \ + stringmap.c cfgfile.c + + + noinst_HEADERS = addr_hash.h ether.h ethertype.h extract.h hash.h iftop.h \ integers.h ip.h llc.h ns_hash.h options.h resolver.h \ screenfilter.h serv_hash.h sll.h sorted_list.h tcp.h \ diff --git a/configure.in b/configure.in index 128d4c6..ec0416d 100644 --- a/configure.in +++ b/configure.in @@ -29,7 +29,7 @@ AC_CONFIG_AUX_DIR(config) AC_CANONICAL_SYSTEM AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(iftop, "0.17pre3") +AM_INIT_AUTOMAKE(iftop, "0.17") AC_DEFINE_UNQUOTED(IFTOP_VERSION, "$VERSION", [The iftop version number]) diff --git a/counter_hash.c b/counter_hash.c new file mode 100644 index 0000000..d0a275b --- /dev/null +++ b/counter_hash.c @@ -0,0 +1,56 @@ +/* hash table */ + +#include <stdio.h> +#include <stdlib.h> +#include <netinet/in.h> +#include "counter_hash.h" +#include "hash.h" +#include "iftop.h" + +#define hash_table_size 256 + +int counter_hash_compare(void* a, void* b) { + return *(long*)a == *(long*)b; +} + +int counter_hash_hash(void* key) { + int hash; + long addr; + + addr = *(long*)key; + + hash = ((addr & 0x000000FF) + + (addr & 0x0000FF00 >> 8) + + (addr & 0x00FF0000 >> 16) + + (addr & 0xFF000000 >> 24) + ) % 0xFF; + + return hash; +} + +void* counter_hash_copy_key(void* orig) { + struct in_addr* copy; + copy = xmalloc(sizeof *copy); + *copy = *(struct in_addr*)orig; + return copy; +} + +void counter_hash_delete_key(void* key) { + free(key); +} + +/* + * Allocate and return a hash + */ +hash_type* counter_hash_create() { + hash_type* hash_table; + hash_table = xcalloc(hash_table_size, sizeof *hash_table); + hash_table->size = hash_table_size; + hash_table->compare = &counter_hash_compare; + hash_table->hash = &counter_hash_hash; + hash_table->delete_key = &counter_hash_delete_key; + hash_table->copy_key = &counter_hash_copy_key; + hash_initialise(hash_table); + return hash_table; +} + diff --git a/counter_hash.h b/counter_hash.h new file mode 100644 index 0000000..9041238 --- /dev/null +++ b/counter_hash.h @@ -0,0 +1,23 @@ +/* + * addr_hash.h: + * + */ + +#ifndef __ADDR_HASH_H_ /* include guard */ +#define __ADDR_HASH_H_ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include "hash.h" + +typedef struct { + unsigned long long sent; + unsigned long long recv; +} counter_type; + +typedef counter_type key_type; /* index into hash table */ + +hash_type* counter_hash_create(void); + +#endif /* __ADDR_HASH_H_ */ diff --git a/iftop-dump.c b/iftop-dump.c new file mode 100644 index 0000000..c8a9fff --- /dev/null +++ b/iftop-dump.c @@ -0,0 +1,466 @@ +/* + * iftop.c: + * + */ + +#include "integers.h" + +#if defined(HAVE_PCAP_H) +# include <pcap.h> +#elif defined(HAVE_PCAP_PCAP_H) +# include <pcap/pcap.h> +#else +# error No pcap.h +#endif +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> + +#include <pthread.h> +#include <curses.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> + +#include "iftop.h" +#include "counter_hash.h" +#include "resolver.h" +#include "options.h" +#ifdef DLT_LINUX_SLL +#include "sll.h" +#endif /* DLT_LINUX_SLL */ +#include "threadprof.h" +#include "ether.h" +#include "ip.h" +#include "tcp.h" +#include "token.h" +#include "llc.h" +#include "extract.h" +#include "ethertype.h" +#include "cfgfile.h" +#include "ppp.h" + + +/* ethernet address of interface. */ +int have_hw_addr = 0; +unsigned char if_hw_addr[6]; + +/* IP address of interface */ +int have_ip_addr = 0; +struct in_addr if_ip_addr; + +extern options_t options; + +hash_type* counters; +time_t last_timestamp; +pthread_mutex_t tick_mutex; + +pcap_t* pd; /* pcap descriptor */ +struct bpf_program pcap_filter; +pcap_handler packet_handler; + + + +sig_atomic_t foad; + +static void finish(int sig) { + foad = sig; +} + + + + + +/* Only need ethernet (plus optional 4 byte VLAN) and IP headers (48) + first 2 bytes of tcp/udp header */ +#define CAPTURE_LENGTH 72 + +void init_counters() { + counters = counter_hash_create(); + last_timestamp = time(NULL); +} + +counter_type* counter_create() { + counter_type* c; + c = xcalloc(1, sizeof *c); + return c; +} + +void tick(int print) { + time_t t; + hash_node_type * hn = NULL; + counter_type* n; + + pthread_mutex_lock(&tick_mutex); + + t = time(NULL); + if(t - last_timestamp >= DUMP_RESOLUTION) { + last_timestamp = t; + while(hash_next_item(counters, &hn) == HASH_STATUS_OK) { + n = (counter_type*)hn->rec; + printf("%s %lld %lld\n",inet_ntoa(*(struct in_addr*)hn->key),n->sent,n->recv); + } + } + else { + } + + pthread_mutex_unlock(&tick_mutex); +} + +int in_filter_net(struct in_addr addr) { + int ret; + ret = ((addr.s_addr & options.netfiltermask.s_addr) == options.netfilternet.s_addr); + return ret; +} + +int ip_addr_match(struct in_addr addr) { + return addr.s_addr == if_ip_addr.s_addr; +} + + +static void handle_ip_packet(struct ip* iptr, int hw_dir) +{ + int direction = 0; /* incoming */ + /* + union { + void **void_pp; + } u_ht = { &ht }; + */ + counter_type * counter; + int len; + struct in_addr local_addr; + + if(options.netfilter == 0) { + fprintf(stderr, "netfilter option must be specified for iftop-dump\n"); + } + else { + /* + * Net filter on, assign direction according to netmask + */ + if(in_filter_net(iptr->ip_src) && !in_filter_net(iptr->ip_dst)) { + /* out of network */ + local_addr = iptr->ip_src; + direction = 1; + } + else if(in_filter_net(iptr->ip_dst) && !in_filter_net(iptr->ip_src)) { + /* into network */ + local_addr = iptr->ip_dst; + direction = 0; + } + else { + /* drop packet */ + return ; + } + } + + if(hash_find(counters, &local_addr, (void**)&counter) == HASH_STATUS_KEY_NOT_FOUND) { + counter = counter_create(); + hash_insert(counters, &local_addr, counter); + } + + len = ntohs(iptr->ip_len); + + if(direction == 0) { + /* incoming */ + counter->recv += len; + } + else { + counter->sent += len; + } + +} + +static void handle_raw_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet) +{ + handle_ip_packet((struct ip*)packet, -1); +} + +static void handle_llc_packet(const struct llc* llc, int dir) { + + struct ip* ip = (struct ip*)((void*)llc + sizeof(struct llc)); + + /* Taken from tcpdump/print-llc.c */ + if(llc->ssap == LLCSAP_SNAP && llc->dsap == LLCSAP_SNAP + && llc->llcui == LLC_UI) { + u_int32_t orgcode; + register u_short et; + orgcode = EXTRACT_24BITS(&llc->llc_orgcode[0]); + et = EXTRACT_16BITS(&llc->llc_ethertype[0]); + switch(orgcode) { + case OUI_ENCAP_ETHER: + case OUI_CISCO_90: + handle_ip_packet(ip, dir); + break; + case OUI_APPLETALK: + if(et == ETHERTYPE_ATALK) { + handle_ip_packet(ip, dir); + } + break; + default:; + /* Not a lot we can do */ + } + } +} + +static void handle_tokenring_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet) +{ + struct token_header *trp; + int dir = -1; + trp = (struct token_header *)packet; + + if(IS_SOURCE_ROUTED(trp)) { + packet += RIF_LENGTH(trp); + } + packet += TOKEN_HDRLEN; + + if(memcmp(trp->token_shost, if_hw_addr, 6) == 0 ) { + /* packet leaving this i/f */ + dir = 1; + } + else if(memcmp(trp->token_dhost, if_hw_addr, 6) == 0 || memcmp("\xFF\xFF\xFF\xFF\xFF\xFF", trp->token_dhost, 6) == 0) { + /* packet entering this i/f */ + dir = 0; + } + + /* Only know how to deal with LLC encapsulated packets */ + if(FRAME_TYPE(trp) == TOKEN_FC_LLC) { + handle_llc_packet((struct llc*)packet, dir); + } +} + +static void handle_ppp_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet) +{ + register u_int length = pkthdr->len; + register u_int caplen = pkthdr->caplen; + u_int proto; + + if (caplen < 2) + return; + + if(packet[0] == PPP_ADDRESS) { + if (caplen < 4) + return; + + packet += 2; + length -= 2; + + proto = EXTRACT_16BITS(packet); + packet += 2; + length -= 2; + + if(proto == PPP_IP || proto == ETHERTYPE_IP) { + handle_ip_packet((struct ip*)packet, -1); + } + } +} + +#ifdef DLT_LINUX_SLL +static void handle_cooked_packet(unsigned char *args, const struct pcap_pkthdr * thdr, const unsigned char * packet) +{ + struct sll_header *sptr; + int dir = -1; + sptr = (struct sll_header *) packet; + + switch (ntohs(sptr->sll_pkttype)) + { + case LINUX_SLL_HOST: + /*entering this interface*/ + dir = 0; + break; + case LINUX_SLL_OUTGOING: + /*leaving this interface */ + dir=1; + break; + } + handle_ip_packet((struct ip*)(packet+SLL_HDR_LEN), dir); +} +#endif /* DLT_LINUX_SLL */ + +static void handle_eth_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet) +{ + struct ether_header *eptr; + int ether_type; + const unsigned char *payload; + eptr = (struct ether_header*)packet; + ether_type = ntohs(eptr->ether_type); + payload = packet + sizeof(struct ether_header); + + tick(0); + + if(ether_type == ETHERTYPE_8021Q) { + struct vlan_8021q_header* vptr; + vptr = (struct vlan_8021q_header*)payload; + ether_type = ntohs(vptr->ether_type); + payload += sizeof(struct vlan_8021q_header); + } + + if(ether_type == ETHERTYPE_IP) { + struct ip* iptr; + int dir = -1; + + /* + * Is a direction implied by the MAC addresses? + */ + if(have_hw_addr && memcmp(eptr->ether_shost, if_hw_addr, 6) == 0 ) { + /* packet leaving this i/f */ + dir = 1; + } + else if(have_hw_addr && memcmp(eptr->ether_dhost, if_hw_addr, 6) == 0 ) { + /* packet entering this i/f */ + dir = 0; + } + else if (memcmp("\xFF\xFF\xFF\xFF\xFF\xFF", eptr->ether_dhost, 6) == 0) { + /* broadcast packet, count as incoming */ + dir = 0; + } + + iptr = (struct ip*)(payload); /* alignment? */ + handle_ip_packet(iptr, dir); + } +} + + +/* set_filter_code: + * Install some filter code. Returns NULL on success or an error message on + * failure. */ +char *set_filter_code(const char *filter) { + char *x; + if (filter) { + x = xmalloc(strlen(filter) + sizeof "() and ip"); + sprintf(x, "(%s) and ip", filter); + } else + x = xstrdup("ip"); + if (pcap_compile(pd, &pcap_filter, x, 1, 0) == -1) { + xfree(x); + return pcap_geterr(pd); + } + xfree(x); + if (pcap_setfilter(pd, &pcap_filter) == -1) + return pcap_geterr(pd); + else + return NULL; +} + + + +/* + * packet_init: + * + * performs pcap initialisation, called before ui is initialised + */ +void packet_init() { + char errbuf[PCAP_ERRBUF_SIZE]; + char *m; + int s; + int i; + int dlt; + int result; + +#ifdef HAVE_DLPI + result = get_addrs_dlpi(options.interface, if_hw_addr, &if_ip_addr); +#else + result = get_addrs_ioctl(options.interface, if_hw_addr, &if_ip_addr); +#endif + + if (result < 0) { + exit(1); + } + + have_hw_addr = result & 1; + have_ip_addr = result & 2; + + if(have_ip_addr) { + fprintf(stderr, "IP address is: %s\n", inet_ntoa(if_ip_addr)); + } + + if(have_hw_addr) { + fprintf(stderr, "MAC address is:"); + for (i = 0; i < 6; ++i) + fprintf(stderr, "%c%02x", i ? ':' : ' ', (unsigned int)if_hw_addr[i]); + fprintf(stderr, "\n"); + } + + // exit(0); + /* resolver_initialise(); */ + + pd = pcap_open_live(options.interface, CAPTURE_LENGTH, options.promiscuous, 1000, errbuf); + // DEBUG: pd = pcap_open_offline("tcpdump.out", errbuf); + if(pd == NULL) { + fprintf(stderr, "pcap_open_live(%s): %s\n", options.interface, errbuf); + exit(1); + } + dlt = pcap_datalink(pd); + if(dlt == DLT_EN10MB) { + packet_handler = handle_eth_packet; + } + else if(dlt == DLT_RAW || dlt == DLT_NULL) { + packet_handler = handle_raw_packet; + } + else if(dlt == DLT_IEEE802) { + packet_handler = handle_tokenring_packet; + } + else if(dlt == DLT_PPP) { + packet_handler = handle_ppp_packet; + } +/* + * SLL support not available in older libpcaps + */ +#ifdef DLT_LINUX_SLL + else if(dlt == DLT_LINUX_SLL) { + packet_handler = handle_cooked_packet; + } +#endif + else { + fprintf(stderr, "Unsupported datalink type: %d\n" + "Please email pdw@ex-parrot.com, quoting the datalink type and what you were\n" + "trying to do at the time\n.", dlt); + exit(1); + } + + if ((m = set_filter_code(options.filtercode))) { + fprintf(stderr, "set_filter_code: %s\n", m); + exit(1); + return; + } +} + +/* packet_loop: */ +void packet_loop() { + pcap_loop(pd,-1,(pcap_handler)packet_handler,NULL); +} + + +/* main: + * Entry point. See usage(). */ +int main(int argc, char **argv) { + pthread_t thread; + struct sigaction sa = {}; + + /* TODO: tidy this up */ + /* read command line options and config file */ + config_init(); + options_set_defaults(); + options_read_args(argc, argv); + /* If a config was explicitly specified, whinge if it can't be found */ + read_config(options.config_file, options.config_file_specified); + options_make(); + + /* + sa.sa_handler = finish; + sigaction(SIGINT, &sa, NULL); + */ + + pthread_mutex_init(&tick_mutex, NULL); + + packet_init(); + + init_counters(); + + packet_loop(); + + return 0; +} @@ -11,6 +11,7 @@ /* 40 / 2 */ #define HISTORY_LENGTH 20 #define RESOLUTION 2 +#define DUMP_RESOLUTION 15 typedef struct { long recv[HISTORY_LENGTH]; @@ -28,10 +29,6 @@ void *xrealloc(void *w, size_t n); char *xstrdup(const char *s); void xfree(void *v); -/* ui.c */ -void analyse_data(void); -void ui_init(void); - /* options.c */ void options_read(int argc, char **argv); @@ -11,5 +11,7 @@ void ui_print(void); void ui_loop(void); void ui_finish(void); void ui_tick(int); +void analyse_data(void); +void ui_init(void); #endif /* __UI_H_ */ |