#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;
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;
-/* 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();
void history_rotate() {
hash_node_type* n = NULL;
+ struct pcap_stat ps;
+
history_pos = (history_pos + 1) % HISTORY_LENGTH;
hash_next_item(history, &n);
while(n != NULL) {
if(history_len < HISTORY_LENGTH) {
history_len++;
}
+
+ pcap_stats(pd, &ps);
+ history_totals.lost_packets = ps.ps_drop + ps.ps_ifdrop;
}
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);
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);
}
}
}
-static void handle_ip_packet(struct ip* iptr, int hw_dir)
+static void handle_ip_packet(struct ip* iptr, int hw_dir, int pld_len)
{
int direction = 0; /* incoming */
+ int len;
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;
struct in6_addr scribdst; /* Scratch pad. */
struct in6_addr scribsrc; /* Scratch pad. */
/* Reinterpret packet type. */
memset(&ap, '\0', sizeof(ap));
- if( (IP_V(iptr) ==4 && options.netfilter == 0)
+ tick(0);
+
+ /*
+ * Sanity check: drop obviously short packets.
+ * pld_len comes from pcaphdr->len - sizeof(struct l2_header).
+ *
+ * It is assumed that the snaplen (currently hard-coded to 1000) is
+ * big enough to always capture the IP header past the L2 encap, and
+ * that pcap never truncates the packet to less than snaplen; in
+ * other words, that pcaphdr->caplen = MIN(pcaphdr->len, snaplen).
+ */
+ if (pld_len < sizeof (struct ip))
+ return;
+ if (IP_V(iptr) == 6 && pld_len < sizeof (struct ip6_hdr))
+ return;
+
+ 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
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
direction = 0;
}
/* Drop other uncertain packages. */
+ else
+ return;
}
if(IP_V(iptr) == 4 && options.netfilter != 0) {
/* 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. */
break;
}
-
if(hash_find(history, &ap, u_ht.void_pp) == HASH_STATUS_KEY_NOT_FOUND) {
ht = history_create();
hash_insert(history, &ap, ht);
}
/* Do accounting. */
- switch (IP_V(iptr)) {
- case 4:
- len = ntohs(iptr->ip_len);
- break;
- case 6:
- len = ntohs(ip6tr->ip6_plen) + 40;
+ switch (options.bandwidth_unit) {
+ case OPTION_BW_BITS:
+ case OPTION_BW_BYTES:
+ len = pld_len;
+ break;
+ case OPTION_BW_PKTS:
+ len = 1;
+ break;
default:
- break;
+ return;
}
/* Update record */
static void handle_raw_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
{
- handle_ip_packet((struct ip*)packet, -1);
+ handle_ip_packet((struct ip*)packet, -1, pkthdr->len);
}
#ifdef DLT_PFLOG
hdrlen = BPF_WORDALIGN(hdr->length);
length -= hdrlen;
packet += hdrlen;
- handle_ip_packet((struct ip*)packet, length);
+ handle_ip_packet((struct ip*)packet, -1, length);
}
#endif
-static void handle_llc_packet(const struct llc* llc, int dir) {
+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, pkthdr->len);
+}
- struct ip* ip = (struct ip*)((void*)llc + sizeof(struct llc));
+static void handle_llc_packet(const struct llc* llc, int dir, int llclen) {
+ int hdrlen = sizeof(struct llc);
+ int pldlen = llclen - hdrlen;
+ struct ip* ip = (struct ip*)((void*)llc + hdrlen);
/* 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;
+ 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:
- handle_ip_packet(ip, dir);
+ handle_ip_packet(ip, dir, pldlen);
break;
case OUI_APPLETALK:
if(et == ETHERTYPE_ATALK) {
- handle_ip_packet(ip, dir);
+ handle_ip_packet(ip, dir, pldlen);
}
break;
default:;
static void handle_tokenring_packet(unsigned char* args, const struct pcap_pkthdr* pkthdr, const unsigned char* packet)
{
struct token_header *trp;
+ int hdrlen = 0;
int dir = -1;
trp = (struct token_header *)packet;
if(IS_SOURCE_ROUTED(trp)) {
- packet += RIF_LENGTH(trp);
+ hdrlen += RIF_LENGTH(trp);
}
- packet += TOKEN_HDRLEN;
+ hdrlen += TOKEN_HDRLEN;
+ packet += 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) {
+ }
+ 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);
+ handle_llc_packet((struct llc*)packet, dir, pkthdr->len - hdrlen);
}
}
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;
+ register u_int length = pkthdr->len;
+ register u_int caplen = pkthdr->caplen;
+ u_int proto;
- if (caplen < 2)
- return;
+ if (caplen < 2)
+ return;
- if(packet[0] == PPP_ADDRESS) {
- if (caplen < 4)
- return;
+ if(packet[0] == PPP_ADDRESS) {
+ if (caplen < 4)
+ return;
- packet += 2;
- length -= 2;
+ packet += 2;
+ length -= 2;
- proto = EXTRACT_16BITS(packet);
- packet += 2;
- length -= 2;
+ proto = EXTRACT_16BITS(packet);
+ packet += 2;
+ length -= 2;
- if(proto == PPP_IP || proto == ETHERTYPE_IP || proto == ETHERTYPE_IPV6) {
- handle_ip_packet((struct ip*)packet, -1);
- }
+ if(proto == PPP_IP || proto == ETHERTYPE_IP
+ || proto == ETHERTYPE_IPV6) {
+ handle_ip_packet((struct ip*)packet, -1, length);
+ }
}
}
dir=1;
break;
}
- handle_ip_packet((struct ip*)(packet+SLL_HDR_LEN), dir);
+ handle_ip_packet((struct ip*)(packet+SLL_HDR_LEN), dir,
+ thdr->len - SLL_HDR_LEN);
}
#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;
+ int ether_type, hdrlen;
+
eptr = (struct ether_header*)packet;
ether_type = ntohs(eptr->ether_type);
- payload = packet + sizeof(struct ether_header);
-
- tick(0);
+ hdrlen = sizeof(struct ether_header);
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);
+ struct vlan_8021q_header* vptr;
+ vptr = (struct vlan_8021q_header*) (packet + hdrlen);
+ ether_type = ntohs(vptr->ether_type);
+ hdrlen += sizeof(struct vlan_8021q_header);
}
if(ether_type == ETHERTYPE_IP || ether_type == ETHERTYPE_IPV6) {
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);
+ iptr = (struct ip*) (packet + hdrlen); /* alignment? */
+ handle_ip_packet(iptr, dir, pkthdr->len - hdrlen);
}
}
+#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 */
+ int hdrlen = ((struct radiotap_header *)packet)->it_len + 34;
+ handle_ip_packet((struct ip*)(packet + hdrlen), -1, pkthdr->len - hdrlen);
+}
+
+
+#endif
/* set_filter_code:
* Install some filter code. Returns NULL on success or an error message on
void packet_init() {
char errbuf[PCAP_ERRBUF_SIZE];
char *m;
- int s;
- int i;
int dlt;
int result;
}
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");
+ fprintf(stderr, "MAC address is: %s\n", ether_ntoa(if_hw_addr));
}
// exit(0);
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;
}
pthread_t thread;
struct sigaction sa = {};
+ setlocale(LC_ALL, "");
+
/* TODO: tidy this up */
/* read command line options and config file */
config_init();
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);