]> gitweb.fperrin.net Git - iftop.git/blobdiff - iftop.c
Import iftop-1.0pre4
[iftop.git] / iftop.c
diff --git a/iftop.c b/iftop.c
index 97020ea3f2fae72786bde4a3f7438039571ac76e..a090dcf84a18e63b7b4f74f9a1e6c6268753d7e2 100644 (file)
--- a/iftop.c
+++ b/iftop.c
@@ -5,13 +5,6 @@
 
 #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/ioctl.h>
 #include <sys/socket.h>
 #include <net/if.h>
-#include <net/bpf.h>
+/* include <net/bpf.h> -- this was added by the PFLOG patch but seems
+ * superfluous and breaks on Slackware */
+#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 <pthread.h>
 #include <curses.h>
 #include <signal.h>
 #include <string.h>
 #include <unistd.h>
+#include <locale.h>
 
 #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"
 #include "ethertype.h"
 #include "cfgfile.h"
 #include "ppp.h"
+#include "addrs_ioctl.h"
 
 #include <netinet/ip6.h>
 
 /* 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;
@@ -63,6 +68,7 @@ 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;
@@ -80,9 +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 */
+/* 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.  */
-#define CAPTURE_LENGTH 92
+/* 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();
@@ -133,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);
@@ -152,11 +177,11 @@ int in_filter_net(struct in_addr addr) {
     return ret;
 }
 
-int __inline__ 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;
 }
 
-int __inline__ ip6_addr_match(struct in6_addr *addr) {
+static int __inline__ ip6_addr_match(struct in6_addr *addr) {
     return IN6_ARE_ADDR_EQUAL(addr, &if_ip6_addr);
 }
 
@@ -229,8 +254,8 @@ static void handle_ip_packet(struct ip* iptr, int hw_dir)
     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;
     unsigned int len = 0;
@@ -241,6 +266,8 @@ static void handle_ip_packet(struct ip* iptr, int hw_dir)
 
     memset(&ap, '\0', sizeof(ap));
 
+    tick(0);
+
     if( (IP_V(iptr) ==4 && options.netfilter == 0)
             || (IP_V(iptr) == 6 && options.netfilter6 == 0) ) { 
         /*
@@ -279,6 +306,14 @@ static void handle_ip_packet(struct ip* iptr, int hw_dir)
             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
@@ -297,6 +332,8 @@ static void handle_ip_packet(struct ip* iptr, int hw_dir)
             direction = 0;
         }
         /* Drop other uncertain packages. */
+        else
+            return;
     }
 
     if(IP_V(iptr) == 4 && options.netfilter != 0) {
@@ -328,11 +365,11 @@ static void handle_ip_packet(struct ip* iptr, int hw_dir)
         /* First reduce the participating addresses using the netfilter prefix.
          * We need scratch pads to do this.
          */
-        for (j=0; j < 4; ++j) {
-            scribdst.s6_addr32[j] = ip6tr->ip6_dst.s6_addr32[j]
-                                        & options.netfilter6mask.s6_addr32[j];
-            scribsrc.s6_addr32[j] = ip6tr->ip6_src.s6_addr32[j]
-                                        & options.netfilter6mask.s6_addr32[j];
+        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];
         }
 
         /* Now look for any hits. */
@@ -445,10 +482,15 @@ static void handle_pflog_packet(unsigned char* args, const struct pcap_pkthdr* p
        hdrlen = BPF_WORDALIGN(hdr->length);
        length -= hdrlen;
        packet += hdrlen;
-       handle_ip_packet((struct ip*)packet, length);
+       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));
@@ -457,9 +499,9 @@ static void handle_llc_packet(const struct llc* llc, int dir) {
     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:
@@ -559,12 +601,10 @@ static void handle_eth_packet(unsigned char* args, const struct pcap_pkthdr* pkt
     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);
     }
 
@@ -580,11 +620,11 @@ static void handle_eth_packet(unsigned char* args, const struct pcap_pkthdr* pkt
             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;
         }
 
@@ -594,6 +634,20 @@ static void handle_eth_packet(unsigned char* args, const struct pcap_pkthdr* pkt
     }
 }
 
+#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
@@ -626,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;
@@ -682,9 +735,22 @@ void packet_init() {
                packet_handler = handle_pflog_packet;
     }
 #endif
-    else if(dlt == DLT_RAW || dlt == DLT_NULL) {
+    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;
     }
@@ -726,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();
@@ -744,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);