/**
* Saker, local net (layer 2) stats for bsd
* written by Jan Pustelnik, Marcin Gryszkalis
* no license, grab the code and run.
*
* Requires FreeBSD 4.6 or later (because of poll(2) behavior on BPF devs)
*
* Compile with
* $ c++ -o saker -lpcap saker.cc
*
* $Id: saker.cc,v 1.42 2006/04/19 22:15:02 mg Exp $
*/
// system and C includes
#include <pcap.h>
#include <cstdio>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <netdb.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <signal.h>
#include <time.h>
#include <poll.h>
#include <errno.h>
#define SAKER_INT unsigned long long
// C++ includes
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <algorithm>
#include <iterator>
// container that keeps pairs (MAC, count) representing src
// addresses of packets ordered by MAC adress
// same for dst addresses
// container that keeps pairs (MAC, count)
// representing src addresses of packets
// ordered by count of packets (or count of bytes)
// same for dst addresses
// keeps list of own macs (for -r/-l handling)
// on by dafault!
#define MAX_IFACES (16)
#define PCAP_MAX_PKT_PER_DISPATCH (256)
#define DEFAULT_PKT_CNT (100)
#define DEFAULT_DELAY (10)
// number of packets actually grabbed
// PCAP callback function, grabs the packet
"%02x:", pkt[i + 6]);
buf[17] = '\0';
string s1(buf);
mit=src.find(s1); // find element of src having MAC equal to s1
// not found, create
// found, increase count
"%02x:", pkt[i]);
buf[17] = '\0';
string s2(buf);
mit=dst.find(s2); // same for dst
// if (g_debug)
// cout << s1 << " ->> " << s2 << endl;
}
// resolver stuff
// trim hostname
'.''\0'#define ROUNDUP(a) \
/* Retrieve routing table */"Error: route-sysctl-estimate failed""Error: malloc failed""Error: retrieval of routing table failed"// check if already in the cache
// save to cache
"MAC: "" -> ""Resolve MAC: " << mac << endl;
string h;
hit = resolver.find(mac); // find in the cache
// not found, rebuild cache
// still not found
"Resolve MAC (done): ""DEBUG uncount: " << x.first << " " << *cnt_var << endl;
}
}
};
// utility for printing pairs to output stream
// bool g_mac_cnt;
/* if (mc != DEFAULT_MAC_CNT)
g_mac_cnt = true;
else
g_mac_cnt = false; */"DEBUG: erased: "//cerr << "((" << g_mac_cnt << ":" << _mac_cnt << ":" << (_mac_cnt==0) << "))" << endl;
"%10sB""%10sPkt", f1);
}
os << f << " "" %4.1f ""%"" * "" "// resolve_ip is checked inside
// utility for reverting pairs
// input: pair (A, B)
// output: pair (B, A)
// Converts a size to a human readable format.
"%llu ""%llu.%02llu K""%llu.%02llu M""%llu.%02llu G", number, reminder);
}
}
}
}
// cerr << "!" << size << "!" << number << "!" << output << "!" << endl;
// strNumber.Replace(".00", "");
// container that keeps pairs (MAC, count)
// representing src addresses of packets
// ordered by count of packets
// same for dst addresses
// count the packets-per-second
"Interfaces: "" ""Total packets: " << hpkt << "Pkt (" << hpps << "Pkts/s)""Total size: " << hsize << "B (" << hbps << "B/s, " << hbbps << "Bits/s)" << endl;
// cout << "Macs: " << mac_cnt << endl;
"SRC stats:"// we have first to copy all stats from src, which is ordered by MAC to src_score
// which is ordered by count, making possible printing stats ordered by count
// and now we simply print stats by count :)
"DST stats:"// same for dst
"saker: shutdown"// show usage
"$Revision: 1.42 $"'\0'// skip prefix
"saker v""i:n:m:t:clapbhvorsdxXf:VD"'i'"Error: too many interfaces specified"'n''m''t''a''p''b''h''v''r''l''o''x''X''c''d'"Error: You cannot have both -d and -s."'s'"Error: You cannot have both -d and -s."'f''V''D''?'"Error: Unknown command line option.""Error: Interface(s) not specified.""Usage: saker [-apbrmvhVD] [-n num] [-m num] [-s|-d] [-c -t num] [-f 'expr'] -i <if> [-i <if2> ... ]" << endl
<< " -i <if> network interface (many interfaces can be specified)" << endl
<< " -h show this info" << endl
<< " -n num number of packets to capture (default "", -1 for unlimited)" << endl
<< " -a ascending sort (default descending)" << endl
<< " -m num number of MACs to display in summary (all by default)" << endl
<< " -p show percentage" << endl
<< " -b count bytes (instead of packets)" << endl
<< " -r count only remote ends (exclude own MACs)" << endl
<< " -l mark local MACs with asterisk (see also -r)" << endl
<< " -s show only source stats" << endl
<< " -d show only destination stats" << endl
<< " -x resolve MACs to IPs" << endl
<< " -X resolve IPs to hostnames (implies -x)" << endl
<< " -c continuous mode" << endl
<< " -o turn off promiscuous mode" << endl
<< " -t num time delay for continuous mode in seconds (default "")" << endl
<< " -f 'expr' expr is a pcap-style BPF expression (man tcpdump)" << endl
<< " -v be verbose (e.g. output each packet)" << endl
<< " -V print version and exit" << endl
<< " -D enable debug output (you are not supposed to understand it)""Listening on: "" "// get own mac's
"..:..:..:..:..:.."; // 6*2+5+1
"Error: getifaddrs failed: ""Own MAC adresses:""%c%02x", ':'"%02x"" ("")""!\n"//initialize pcap
"PCAP init for ""Error: pcap_lookupnet failed: ""Error: cannot open pcap live: ""Error: cannot set nonblocking mode: ""Error: cannot compile BPF filter expression ("
<< pcap_geterr(dv[i].pcap)
<< ")""Error: cannot install BPF filter ("
<< pcap_geterr(dv[i].pcap)
<< ")"// init for poll(2)
"Error: pcap_get_selectable_fd failed""pcap_selectable_fd: " << dv[i].device << "=" << dv[i].pfd.fd << endl;
dv[i].pfd.events = POLLRDNORM;
pollfdtab[i] = dv[i].pfd;
}
// the main loop
"Error: poll failed"// cerr << "POLL(" << pollret << ")" << endl;
"Error: error during pcap dispatch ("
<< pcap_geterr(dv[i].pcap)
<< ")"