--- embedaddon/iftop/iftop.c 2012/02/21 16:57:34 1.1.1.1 +++ embedaddon/iftop/iftop.c 2016/10/18 14:04:50 1.1.1.2 @@ -5,13 +5,6 @@ #include "integers.h" -#if defined(HAVE_PCAP_H) -# include -#elif defined(HAVE_PCAP_PCAP_H) -# include -#else -# error No pcap.h -#endif #include #include #include @@ -19,17 +12,29 @@ #include #include #include +/* include -- this was added by the PFLOG patch but seems + * superfluous and breaks on Slackware */ +#if defined(HAVE_PCAP_H) +# include +#elif defined(HAVE_PCAP_PCAP_H) +# include +#else +# error No pcap.h +#endif #include #include #include #include #include +#include #include "iftop.h" #include "addr_hash.h" #include "resolver.h" +#include "ui_common.h" #include "ui.h" +#include "tui.h" #include "options.h" #ifdef DLT_LINUX_SLL #include "sll.h" @@ -44,21 +49,26 @@ #include "ethertype.h" #include "cfgfile.h" #include "ppp.h" +#include "addrs_ioctl.h" +#include /* ethernet address of interface. */ int have_hw_addr = 0; -unsigned char if_hw_addr[6]; +char if_hw_addr[6]; /* IP address of interface */ int have_ip_addr = 0; +int have_ip6_addr = 0; struct in_addr if_ip_addr; +struct in6_addr if_ip6_addr; extern options_t options; hash_type* history; history_type history_totals; time_t last_timestamp; +time_t first_timestamp; int history_pos = 0; int history_len = 1; pthread_mutex_t tick_mutex; @@ -76,8 +86,14 @@ static void finish(int sig) { -/* Only need ethernet (plus optional 4 byte VLAN) and IP headers (48) + first 2 bytes of tcp/udp header */ -#define CAPTURE_LENGTH 72 +/* Only need ethernet (plus optional 4 byte VLAN) and IP headers (48) + first 2 + * bytes of tcp/udp header */ +/* Increase with a further 20 to account for IPv6 header length. */ +/* IEEE 802.11 radiotap throws in a variable length header plus 8 (radiotap + * header header) plus 34 (802.11 MAC) plus 40 (IPv6) = 78, plus whatever's in + * the radiotap payload */ +/*#define CAPTURE_LENGTH 92 */ +#define CAPTURE_LENGTH 256 void init_history() { history = addr_hash_create(); @@ -128,14 +144,28 @@ void tick(int print) { t = time(NULL); if(t - last_timestamp >= RESOLUTION) { - //printf("TICKING\n"); analyse_data(); - ui_print(); + if (options.no_curses) { + if (!options.timed_output || (options.timed_output && t - first_timestamp >= options.timed_output)) { + tui_print(); + if (options.timed_output) { + finish(SIGINT); + } + } + } + else { + ui_print(); + } history_rotate(); last_timestamp = t; } else { - ui_tick(print); + if (options.no_curses) { + tui_tick(print); + } + else { + ui_tick(print); + } } pthread_mutex_unlock(&tick_mutex); @@ -147,10 +177,14 @@ int in_filter_net(struct in_addr addr) { return ret; } -int ip_addr_match(struct in_addr addr) { +static int __inline__ ip_addr_match(struct in_addr addr) { return addr.s_addr == if_ip_addr.s_addr; } +static int __inline__ ip6_addr_match(struct in6_addr *addr) { + return IN6_ARE_ADDR_EQUAL(addr, &if_ip6_addr); +} + /** * Creates an addr_pair from an ip (and tcp/udp) header, swapping src and dst * if required @@ -159,6 +193,11 @@ void assign_addr_pair(addr_pair* ap, struct ip* iptr, unsigned short int src_port = 0; unsigned short int dst_port = 0; + /* Arrange for predictable values. */ + memset(ap, '\0', sizeof(*ap)); + + if(IP_V(iptr) == 4) { + ap->af = AF_INET; /* Does this protocol use ports? */ if(iptr->ip_p == IPPROTO_TCP || iptr->ip_p == IPPROTO_UDP) { /* We take a slight liberty here by treating UDP the same as TCP */ @@ -181,7 +220,33 @@ void assign_addr_pair(addr_pair* ap, struct ip* iptr, ap->dst = iptr->ip_src; ap->dst_port = src_port; } + } /* IPv4 */ + else if (IP_V(iptr) == 6) { + /* IPv6 packet seen. */ + struct ip6_hdr *ip6tr = (struct ip6_hdr *) iptr; + ap->af = AF_INET6; + + if( (ip6tr->ip6_nxt == IPPROTO_TCP) || (ip6tr->ip6_nxt == IPPROTO_UDP) ) { + struct tcphdr *thdr = ((void *) ip6tr) + 40; + + src_port = ntohs(thdr->th_sport); + dst_port = ntohs(thdr->th_dport); + } + + if(flip == 0) { + memcpy(&ap->src6, &ip6tr->ip6_src, sizeof(ap->src6)); + ap->src_port = src_port; + memcpy(&ap->dst6, &ip6tr->ip6_dst, sizeof(ap->dst6)); + ap->dst_port = dst_port; + } + else { + memcpy(&ap->src6, &ip6tr->ip6_dst, sizeof(ap->src6)); + ap->src_port = dst_port; + memcpy(&ap->dst6, &ip6tr->ip6_src, sizeof(ap->dst6)); + ap->dst_port = src_port; + } + } } static void handle_ip_packet(struct ip* iptr, int hw_dir) @@ -189,13 +254,22 @@ static void handle_ip_packet(struct ip* iptr, int hw_d int direction = 0; /* incoming */ history_type* ht; union { - history_type **ht_pp; - void **void_pp; + history_type **ht_pp; + void **void_pp; } u_ht = { &ht }; addr_pair ap; - int len; + unsigned int len = 0; + struct in6_addr scribdst; /* Scratch pad. */ + struct in6_addr scribsrc; /* Scratch pad. */ + /* Reinterpret packet type. */ + struct ip6_hdr* ip6tr = (struct ip6_hdr *) iptr; - if(options.netfilter == 0) { + memset(&ap, '\0', sizeof(ap)); + + tick(0); + + if( (IP_V(iptr) ==4 && options.netfilter == 0) + || (IP_V(iptr) == 6 && options.netfilter6 == 0) ) { /* * Net filter is off, so assign direction based on MAC address */ @@ -212,16 +286,34 @@ static void handle_ip_packet(struct ip* iptr, int hw_d /* Packet direction is not given away by h/ware layer. Try IP * layer */ - else if(have_ip_addr && ip_addr_match(iptr->ip_src)) { + else if((IP_V(iptr) == 4) && have_ip_addr && ip_addr_match(iptr->ip_src)) { /* outgoing */ assign_addr_pair(&ap, iptr, 0); direction = 1; } - else if(have_ip_addr && ip_addr_match(iptr->ip_dst)) { + else if((IP_V(iptr) == 4) && have_ip_addr && ip_addr_match(iptr->ip_dst)) { /* incoming */ assign_addr_pair(&ap, iptr, 1); direction = 0; } + else if((IP_V(iptr) == 6) && have_ip6_addr && ip6_addr_match(&ip6tr->ip6_src)) { + /* outgoing */ + assign_addr_pair(&ap, iptr, 0); + direction = 1; + } + else if((IP_V(iptr) == 6) && have_ip6_addr && ip6_addr_match(&ip6tr->ip6_dst)) { + /* incoming */ + assign_addr_pair(&ap, iptr, 1); + direction = 0; + } + else if (IP_V(iptr) == 4 && IN_MULTICAST(iptr->ip_dst.s_addr)) { + assign_addr_pair(&ap, iptr, 1); + direction = 0; + } + else if (IP_V(iptr) == 6 && IN6_IS_ADDR_MULTICAST(&ip6tr->ip6_dst)) { + assign_addr_pair(&ap, iptr, 1); + direction = 0; + } /* * Cannot determine direction from hardware or IP levels. Therefore * assume that it was a packet between two other machines, assign @@ -231,16 +323,20 @@ static void handle_ip_packet(struct ip* iptr, int hw_d else if (options.promiscuous_but_choosy) { return; /* junk it */ } - else if(iptr->ip_src.s_addr < iptr->ip_dst.s_addr) { + else if((IP_V(iptr) == 4) && (iptr->ip_src.s_addr < iptr->ip_dst.s_addr)) { assign_addr_pair(&ap, iptr, 1); direction = 0; } - else { + else if(IP_V(iptr) == 4) { assign_addr_pair(&ap, iptr, 0); direction = 0; } + /* Drop other uncertain packages. */ + else + return; } - else { + + if(IP_V(iptr) == 4 && options.netfilter != 0) { /* * Net filter on, assign direction according to netmask */ @@ -260,22 +356,96 @@ static void handle_ip_packet(struct ip* iptr, int hw_d } } - ap.protocol = iptr->ip_p; + if(IP_V(iptr) == 6 && options.netfilter6 != 0) { + /* + * Net filter IPv6 active. + */ + int j; + //else if((IP_V(iptr) == 6) && have_ip6_addr && ip6_addr_match(&ip6tr->ip6_dst)) { + /* First reduce the participating addresses using the netfilter prefix. + * We need scratch pads to do this. + */ + for (j=0; j < 16; ++j) { + scribdst.s6_addr[j] = ip6tr->ip6_dst.s6_addr[j] + & options.netfilter6mask.s6_addr[j]; + scribsrc.s6_addr[j] = ip6tr->ip6_src.s6_addr[j] + & options.netfilter6mask.s6_addr[j]; + } - /* Add the addresses to be resolved */ - resolve(&iptr->ip_dst, NULL, 0); - resolve(&iptr->ip_src, NULL, 0); + /* Now look for any hits. */ + //if(in_filter_net(iptr->ip_src) && !in_filter_net(iptr->ip_dst)) { + if (IN6_ARE_ADDR_EQUAL(&scribsrc, &options.netfilter6net) + && ! IN6_ARE_ADDR_EQUAL(&scribdst, &options.netfilter6net)) { + /* out of network */ + assign_addr_pair(&ap, iptr, 0); + direction = 1; + } + //else if(in_filter_net(iptr->ip_dst) && !in_filter_net(iptr->ip_src)) { + else if (! IN6_ARE_ADDR_EQUAL(&scribsrc, &options.netfilter6net) + && IN6_ARE_ADDR_EQUAL(&scribdst, &options.netfilter6net)) { + /* into network */ + assign_addr_pair(&ap, iptr, 1); + direction = 0; + } + else { + /* drop packet */ + return ; + } + } +#if 1 + /* Test if link-local IPv6 packets should be dropped. */ + if( IP_V(iptr) == 6 && !options.link_local + && (IN6_IS_ADDR_LINKLOCAL(&ip6tr->ip6_dst) + || IN6_IS_ADDR_LINKLOCAL(&ip6tr->ip6_src)) ) + return; +#endif + + /* Do address resolving. */ + switch (IP_V(iptr)) { + case 4: + ap.protocol = iptr->ip_p; + /* Add the addresses to be resolved */ + /* The IPv4 address is embedded in a in6_addr structure, + * so it need be copied, and delivered to resolve(). */ + memset(&scribdst, '\0', sizeof(scribdst)); + memcpy(&scribdst, &iptr->ip_dst, sizeof(struct in_addr)); + resolve(ap.af, &scribdst, NULL, 0); + memset(&scribsrc, '\0', sizeof(scribsrc)); + memcpy(&scribsrc, &iptr->ip_src, sizeof(struct in_addr)); + resolve(ap.af, &scribsrc, NULL, 0); + break; + case 6: + ap.protocol = ip6tr->ip6_nxt; + /* Add the addresses to be resolved */ + resolve(ap.af, &ip6tr->ip6_dst, NULL, 0); + resolve(ap.af, &ip6tr->ip6_src, NULL, 0); + default: + break; + } + + if(hash_find(history, &ap, u_ht.void_pp) == HASH_STATUS_KEY_NOT_FOUND) { ht = history_create(); hash_insert(history, &ap, ht); } - len = ntohs(iptr->ip_len); + /* Do accounting. */ + switch (IP_V(iptr)) { + case 4: + len = ntohs(iptr->ip_len); + break; + case 6: + len = ntohs(ip6tr->ip6_plen) + 40; + default: + break; + } /* Update record */ ht->last_write = history_pos; - if(iptr->ip_src.s_addr == ap.src.s_addr) { + if( ((IP_V(iptr) == 4) && (iptr->ip_src.s_addr == ap.src.s_addr)) + || ((IP_V(iptr) == 6) && !memcmp(&ip6tr->ip6_src, &ap.src6, sizeof(ap.src6))) ) + { ht->sent[history_pos] += len; ht->total_sent += len; } @@ -301,6 +471,26 @@ static void handle_raw_packet(unsigned char* args, con handle_ip_packet((struct ip*)packet, -1); } +#ifdef DLT_PFLOG +static void handle_pflog_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet) +{ + register u_int length = pkthdr->len; + u_int hdrlen; + const struct pfloghdr *hdr; + + hdr = (struct pfloghdr *)packet; + hdrlen = BPF_WORDALIGN(hdr->length); + length -= hdrlen; + packet += hdrlen; + handle_ip_packet((struct ip*)packet, -1); +} +#endif + +static void handle_null_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet) +{ + handle_ip_packet((struct ip*)(packet + 4), -1); +} + static void handle_llc_packet(const struct llc* llc, int dir) { struct ip* ip = (struct ip*)((void*)llc + sizeof(struct llc)); @@ -309,9 +499,9 @@ static void handle_llc_packet(const struct llc* llc, i if(llc->ssap == LLCSAP_SNAP && llc->dsap == LLCSAP_SNAP && llc->llcui == LLC_UI) { u_int32_t orgcode; - register u_short et; + u_int16_t et; orgcode = EXTRACT_24BITS(&llc->llc_orgcode[0]); - et = EXTRACT_16BITS(&llc->llc_ethertype[0]); + et = (llc->llc_ethertype[0] << 8) + llc->llc_ethertype[1]; switch(orgcode) { case OUI_ENCAP_ETHER: case OUI_CISCO_90: @@ -374,7 +564,7 @@ static void handle_ppp_packet(unsigned char* args, con packet += 2; length -= 2; - if(proto == PPP_IP || proto == ETHERTYPE_IP) { + if(proto == PPP_IP || proto == ETHERTYPE_IP || proto == ETHERTYPE_IPV6) { handle_ip_packet((struct ip*)packet, -1); } } @@ -411,16 +601,14 @@ static void handle_eth_packet(unsigned char* args, con 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); + 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) { + if(ether_type == ETHERTYPE_IP || ether_type == ETHERTYPE_IPV6) { struct ip* iptr; int dir = -1; @@ -432,30 +620,45 @@ static void handle_eth_packet(unsigned char* args, con 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 */ + /* 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; + } + /* Distinguishing ip_hdr and ip6_hdr will be done later. */ iptr = (struct ip*)(payload); /* alignment? */ handle_ip_packet(iptr, dir); } } +#ifdef DLT_IEEE802_11_RADIO +/* + * Packets with a bonus radiotap header. + * See http://www.gsp.com/cgi-bin/man.cgi?section=9&topic=ieee80211_radiotap + */ +static void handle_radiotap_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet) +{ + /* 802.11 MAC header is = 34 bytes (not sure if that's universally true) */ + /* We could try harder to figure out hardware direction from the MAC header */ + handle_ip_packet((struct ip*)(packet + ((struct radiotap_header *)packet)->it_len + 34),-1); +} + +#endif + /* 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); + x = xmalloc(strlen(filter) + sizeof "() and (ip or ip6)"); + sprintf(x, "(%s) and (ip or ip6)", filter); } else - x = xstrdup("ip"); + x = xstrdup("ip or ip6"); if (pcap_compile(pd, &pcap_filter, x, 1, 0) == -1) { xfree(x); return pcap_geterr(pd); @@ -477,7 +680,6 @@ char *set_filter_code(const char *filter) { void packet_init() { char errbuf[PCAP_ERRBUF_SIZE]; char *m; - int s; int i; int dlt; int result; @@ -485,20 +687,29 @@ void packet_init() { #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); + result = get_addrs_ioctl(options.interface, if_hw_addr, + &if_ip_addr, &if_ip6_addr); #endif if (result < 0) { exit(1); } - have_hw_addr = result & 1; - have_ip_addr = result & 2; + have_hw_addr = result & 0x01; + have_ip_addr = result & 0x02; + have_ip6_addr = result & 0x04; if(have_ip_addr) { fprintf(stderr, "IP address is: %s\n", inet_ntoa(if_ip_addr)); } + if(have_ip6_addr) { + char ip6str[INET6_ADDRSTRLEN]; + ip6str[0] = '\0'; + inet_ntop(AF_INET6, &if_ip6_addr, ip6str, sizeof(ip6str)); + fprintf(stderr, "IPv6 address is: %s\n", ip6str); + } + if(have_hw_addr) { fprintf(stderr, "MAC address is:"); for (i = 0; i < 6; ++i) @@ -519,9 +730,27 @@ void packet_init() { if(dlt == DLT_EN10MB) { packet_handler = handle_eth_packet; } - else if(dlt == DLT_RAW || dlt == DLT_NULL) { +#ifdef DLT_PFLOG + else if (dlt == DLT_PFLOG) { + packet_handler = handle_pflog_packet; + } +#endif + else if(dlt == DLT_RAW) { packet_handler = handle_raw_packet; } + else if(dlt == DLT_NULL) { + packet_handler = handle_null_packet; + } +#ifdef DLT_LOOP + else if(dlt == DLT_LOOP) { + packet_handler = handle_null_packet; + } +#endif +#ifdef DLT_IEEE802_11_RADIO + else if(dlt == DLT_IEEE802_11_RADIO) { + packet_handler = handle_radiotap_packet; + } +#endif else if(dlt == DLT_IEEE802) { packet_handler = handle_tokenring_packet; } @@ -563,6 +792,8 @@ int main(int argc, char **argv) { pthread_t thread; struct sigaction sa = {}; + setlocale(LC_ALL, ""); + /* TODO: tidy this up */ /* read command line options and config file */ config_init(); @@ -581,11 +812,31 @@ int main(int argc, char **argv) { init_history(); - ui_init(); + if (options.no_curses) { + tui_init(); + } + else { + ui_init(); + } pthread_create(&thread, NULL, (void*)&packet_loop, NULL); - ui_loop(); + /* Keep the starting time (used for timed termination) */ + first_timestamp = time(NULL); + + if (options.no_curses) { + if (options.timed_output) { + while(!foad) { + sleep(1); + } + } + else { + tui_loop(); + } + } + else { + ui_loop(); + } pthread_cancel(thread);