The Fork
http://the.fork.pl/code/saker/
 the.fork.pl
 Site
 Credits
 Contact
 Powered by
 The Story of Fork
 Words
 Sermon on the Hill
 Antybiografia
 Angel
 Devil
 Powrót z...
 Simon T.
 Favourite poems
 Roam
 Sounds
 The Lost Faith
 Atari Reloaded
 Players
 Code
 Saker
 Moon phase
 KB24
 Attic
 PLC
 33doi
 DemoScene
 Atari
 Logrus
 Cryogen
 Crew
 History
 Stuph
 Pictures
 Ascii Art
 Set One
 Set Two
 Set Three

Saker - Bandwidth stats per MAC

Introduction

This is little utility that gathers statistics for network bandwith. Tested on FreeBSD, probably won't work on Linux without changes. Needs FreeBSD 4.6 or later (because of poll(2) behavior on BPF devs).

Features

  • Layer 2 oriented
  • monitoring multiple interfaces
  • configurable output
  • DNS resolving (off by default)
  • pcap-style filter expressions

Download

download saker.cc 22.1K

Compile

$ c++ -o saker -lpcap -lthread saker.cc

Example output

# saker -iem0 -iem1 -iem2 -iem3 -b -n0 -c -t5 -p -m10 -l -X

saker v1.41
Listening on: em0 em1 em2 em3

Interfaces: em0 em1 em2 em3
Total packets: 22.29 KPkt (4.45 KPkts/s)
Total size: 15.07 MB (3.01 MB/s, 24.11 MBits/s)
SRC stats:
    4.07 MB  27.0 %   ckul-xchg
    3.47 MB  23.1 % * 00:0e:0c:59:77:72
    2.84 MB  18.9 % * xchg-3
    2.35 MB  15.6 %   shodan
    1.18 MB   7.8 % * xchg-2
  535.00 KB   3.5 %   k-antczak1
  201.57 KB   1.3 %   kolos
  129.90 KB   0.8 %   root
   82.76 KB   0.5 %   b203-asus
   68.38 KB   0.4 %   ping
DST stats:
    4.07 MB  27.0 % * 00:0e:0c:59:77:72
    3.47 MB  23.1 %   ckul-xchg
    2.75 MB  18.3 %   shodan
    2.42 MB  16.1 % * xchg-3
  849.05 KB   5.5 % * xchg-2
  758.70 KB   4.9 %   k-antczak1
  218.02 KB   1.4 %   k-rodak-1
  214.83 KB   1.4 %   root
  211.20 KB   1.4 % * xchg
   98.14 KB   0.6 %   ping
 

The code

  1. /**
  2. * Saker, local net (layer 2) stats for bsd
  3. * written by Jan Pustelnik, Marcin Gryszkalis
  4. * no license, grab the code and run.
  5. *
  6. * Requires FreeBSD 4.6 or later (because of poll(2) behavior on BPF devs)
  7. *
  8. * Compile with
  9. * $ c++ -o saker -lpcap saker.cc
  10. *
  11. * $Id: saker.cc,v 1.42 2006/04/19 22:15:02 mg Exp $
  12. */
  13.  
  14. // system and C includes
  15. #include <pcap.h>
  16. #include <cstdio>
  17.  
  18. #include <sys/types.h>
  19. #include <sys/sysctl.h>
  20. #include <unistd.h>
  21. #include <sys/socket.h>
  22. #include <ifaddrs.h>
  23. #include <stdio.h>
  24. #include <netdb.h>
  25. #include <net/if_dl.h>
  26. #include <net/route.h>
  27. #include <net/if_types.h>
  28. #include <netinet/in.h>
  29. #include <netinet/if_ether.h>
  30. #include <arpa/inet.h>
  31. #include <signal.h>
  32. #include <time.h>
  33. #include <poll.h>
  34. #include <errno.h>
  35.  
  36. #define SAKER_INT unsigned long long
  37.  
  38. // C++ includes
  39. #include <string>
  40. #include <iostream>
  41. #include <set>
  42. #include <map>
  43. #include <algorithm>
  44. #include <iterator>
  45.  
  46. using namespace std;
  47.  
  48. // container that keeps pairs (MAC, count) representing src
  49. // addresses of packets ordered by MAC adress
  50. map<string, SAKER_INT> src;
  51.  
  52. // same for dst addresses
  53. map<string, SAKER_INT> dst;
  54.  
  55. // container that keeps pairs (MAC, count)
  56. // representing src addresses of packets
  57. // ordered by count of packets (or count of bytes)
  58. multimap<SAKER_INT, string> src_score;
  59.  
  60. // same for dst addresses
  61. multimap<SAKER_INT, string> dst_score;
  62.  
  63. // keeps list of own macs (for -r/-l handling)
  64. set<string> ownmacs;
  65.  
  66. bool g_verbose = false;
  67. bool g_remote = false;
  68. bool g_bytemode = false;
  69. bool g_mark = false;
  70. bool g_debug = false;
  71. bool g_ascend = false;
  72. bool g_percent = false;
  73. bool g_only_dst = false;
  74. bool g_only_src = false;
  75. bool g_cont = false;
  76. bool g_bpf = false;
  77. bool g_promisc = true; // on by dafault!
  78. bool g_mac_cnt = false;
  79. bool g_pkt_cnt = false;
  80. bool g_resolve_arp = false;
  81. bool g_resolve_ip = false;
  82.  
  83. struct saker_device
  84. {
  85.     char *device;
  86.     pcap_t *pcap;
  87.     pollfd pfd;
  88. };
  89.  
  90. #define MAX_IFACES (16)
  91. saker_device dv[MAX_IFACES];
  92. pollfd pollfdtab[MAX_IFACES];
  93. int    pcap_dev_no = 0;
  94.  
  95. #define PCAP_MAX_PKT_PER_DISPATCH (256)
  96.  
  97. #define DEFAULT_PKT_CNT (100)
  98. #define DEFAULT_DELAY (10)
  99.  
  100. SAKER_INT pkt_cnt = DEFAULT_PKT_CNT;
  101. SAKER_INT mac_cnt = 0;
  102.  
  103. int time_delay = DEFAULT_DELAY;
  104.  
  105. SAKER_INT pkt_grb = 0; // number of packets actually grabbed
  106. SAKER_INT size_grb = 0;
  107.  
  108. time_t time_start = 0;
  109.  
  110. char *bpf;
  111. struct bpf_program bpff;
  112.  
  113. // PCAP callback function, grabs the packet
  114. void h(u_char * useless, const struct pcap_pkthdr * pkthdr, const u_char * pkt)
  115. {
  116.     char buf[50];
  117.     int  i;
  118.     bpf_u_int32 pkt_size = pkthdr->len;
  119.  
  120.     map<string, SAKER_INT>::iterator mit;
  121.  
  122.     pkt_grb++;
  123.     size_grb += pkt_size;
  124.  
  125.     for (i = 0; i < 6; i++)
  126.         sprintf(buf+3*i, "%02x:", pkt[i + 6]);
  127.     buf[17] = '\0';
  128.  
  129.     string s1(buf);
  130.     mit=src.find(s1);   // find element of src having MAC equal to s1
  131.     if (mit == src.end()) // not found, create
  132.     {
  133.         if (g_bytemode)
  134.             src.insert(make_pair(s1, pkt_size));
  135.         else
  136.            src.insert(make_pair(s1, 1));
  137.     }
  138.     else // found, increase count
  139.     {
  140.         if (g_bytemode)
  141.             mit->second += pkt_size;
  142.         else
  143.             ++(mit -> second);
  144.     }
  145.  
  146.     for (i = 0; i < 6; i++)
  147.         sprintf(buf+3*i, "%02x:", pkt[i]);
  148.     buf[17] = '\0';
  149.  
  150.     string s2(buf);
  151.     mit=dst.find(s2);   // same for dst
  152.     if (mit == dst.end())
  153.     {
  154.             if (g_bytemode)
  155.             dst.insert(make_pair(s2, pkt_size));
  156.         else
  157.            dst.insert(make_pair(s2, 1));
  158.  
  159.     }
  160.     else
  161.     {
  162.         if (g_bytemode)
  163.             mit->second += pkt_size;
  164.         else
  165.             ++(mit -> second);
  166.     }
  167.  
  168. //    if (g_debug)
  169. //        cout << s1 << " ->> " << s2 << endl;
  170. }
  171.  
  172.  
  173. // resolver stuff
  174.  
  175. typedef map<string, string> resolvermap;
  176. resolvermap resolver;
  177.  
  178. static char *resolveip(char *ipstr)
  179. {
  180.     struct in_addr ip;
  181.     inet_aton(ipstr, &ip);
  182.  
  183.     struct hostent *hp = gethostbyaddr((const char *)&ip, sizeof ip, AF_INET);
  184.  
  185.     if (hp)
  186.     {
  187.         // trim hostname
  188.         char * p = strchr(hp->h_name, '.');
  189.         if (p != NULL) *p = '\0';
  190.         return hp->h_name;
  191.     }
  192.  
  193.     return ipstr;
  194. }
  195.  
  196. #define ROUNDUP(a) \
  197.         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  198.  
  199. int prepare_arp()
  200. {
  201.     int mib[6];
  202.     size_t needed;
  203.     char *lim, *buf, *next;
  204.  
  205.     mib[0] = CTL_NET;
  206.     mib[1] = PF_ROUTE;
  207.     mib[2] = 0;
  208.     mib[3] = AF_INET;
  209.     mib[4] = NET_RT_FLAGS;
  210.     mib[5] = RTF_LLINFO;
  211.  
  212.     /* Retrieve routing table */
  213.  
  214.     if(sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
  215.     {
  216.         perror("Error: route-sysctl-estimate failed");
  217.         exit(1);
  218.     }
  219.  
  220.     if((buf = (char *)malloc(needed)) == NULL)
  221.     {
  222.         perror("Error: malloc failed");
  223.         exit(1);
  224.     }
  225.  
  226.     if(sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
  227.     {
  228.         perror("Error: retrieval of routing table failed");
  229.         exit(1);
  230.     }
  231.  
  232.     lim = buf + needed;
  233.  
  234.     struct rt_msghdr *rtm = NULL;
  235.     for (next = buf; next < lim; next += rtm->rtm_msglen)
  236.     {
  237.         rtm = (struct rt_msghdr *)next;
  238.         struct sockaddr_inarp *sinarp = (struct sockaddr_inarp *)(rtm + 1);
  239.         struct sockaddr_dl *sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
  240.  
  241.         if (
  242.             sdl->sdl_alen
  243.             && (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_L2VLAN)
  244.             && sdl->sdl_alen == ETHER_ADDR_LEN
  245.             )
  246.         {
  247.             char *thismac = ether_ntoa((struct ether_addr *)LLADDR(sdl));
  248.  
  249.             resolvermap::iterator hit = resolver.find(string(thismac));   // check if already in the cache
  250.             if (hit != resolver.end())
  251.                 continue;
  252.  
  253.             char *thisip = inet_ntoa(sinarp->sin_addr);
  254.  
  255.             char *thishost = NULL;
  256.             if (g_resolve_ip)
  257.                 thishost = resolveip(thisip);
  258.             else
  259.                 thishost = thisip;
  260.  
  261.             // save to cache
  262.             if (g_debug)
  263.                 cout << "MAC: " << string(thismac) << " -> " << string(thishost) << endl;
  264.  
  265.             resolver.insert(make_pair(string(thismac), string(thishost)));
  266.         }
  267.  
  268.     }
  269.  
  270.     free(buf);
  271.     return(0);
  272. }
  273.  
  274. string resolvemac(string mac)
  275. {
  276.     resolvermap::iterator hit;
  277.  
  278.     if (g_debug)
  279.            cout << "Resolve MAC: " << mac << endl;
  280.  
  281.     string h;
  282.     hit = resolver.find(mac);   // find in the cache
  283.     if (hit == resolver.end()) // not found, rebuild cache
  284.     {
  285.         prepare_arp();
  286.         hit = resolver.find(mac);
  287.  
  288.         if (hit == resolver.end()) // still not found
  289.             return mac;
  290.     }
  291.  
  292.     if (g_debug)
  293.            cout << "Resolve MAC (done): " << hit->first << endl;
  294.  
  295.     return hit->second;
  296. }
  297.  
  298.  
  299. template<class T> class uncount
  300. {
  301.     SAKER_INT* cnt_var;
  302. public:
  303.     uncount(SAKER_INT* cv) : cnt_var(cv) {}
  304.     void operator() (T x)
  305.     {
  306.         if (ownmacs.find(x.second) != ownmacs.end())
  307.         {
  308.             *cnt_var = *cnt_var - x.first;
  309.             if (g_debug)
  310.                 cout << "DEBUG uncount: " << x.first << " " << *cnt_var << endl;
  311.         }
  312.     }
  313. };
  314.  
  315. // utility for printing pairs to output stream
  316. template<class T> class print
  317. {
  318.     ostream &os;
  319.     SAKER_INT _cnt;
  320.     SAKER_INT _mac_cnt;
  321. //    bool g_mac_cnt;
  322. public:
  323.     print(ostream &out, SAKER_INT pc, SAKER_INT mc) : os(out), _cnt(pc), _mac_cnt(mc)
  324.     {
  325. /*        if (mc != DEFAULT_MAC_CNT)
  326.             g_mac_cnt = true;
  327.         else
  328.             g_mac_cnt = false; */
  329.     }
  330.  
  331.     void operator() (T x)
  332.     {
  333.         if (g_remote)
  334.         {
  335.             if (ownmacs.find(x.second) != ownmacs.end())
  336.             {
  337.                 if (g_debug)
  338.                     cout << "DEBUG: erased: " << x.second << endl;
  339.                 return;
  340.             }
  341.         }
  342. //cerr << "((" << g_mac_cnt << ":" << _mac_cnt << ":" << (_mac_cnt==0) << "))" << endl;
  343.  
  344.         if (g_mac_cnt && _mac_cnt==0)
  345.             return;
  346.  
  347.         _mac_cnt--;
  348.  
  349.         char f[1024];
  350.         char f1[1024];
  351.         human_size(x.first, f1);
  352.         if (g_bytemode)
  353.         {
  354.             sprintf(f, "%10sB", f1);
  355.         }
  356.         else
  357.         {
  358.             sprintf(f, "%10sPkt", f1);
  359.         }
  360.  
  361.         os <<  f << " ";
  362.  
  363.         if (g_percent)
  364.         {
  365.             char s[10];
  366.             sprintf(s, " %4.1f ", (static_cast<double>(x.first)/_cnt)*100.0);
  367.             cout << s << "%";
  368.         }
  369.  
  370.         if (g_mark)
  371.         {
  372.             if (ownmacs.find(x.second) != ownmacs.end())
  373.                 cout << " * ";
  374.             else
  375.                 cout << "   ";
  376.         }
  377.  
  378.  
  379.         if (g_resolve_arp) // resolve_ip is checked inside
  380.             cout << resolvemac(x.second);
  381.         else
  382.             cout << x.second;
  383.  
  384.         cout << endl;
  385.  
  386.     }
  387. };
  388.  
  389. // utility for reverting pairs
  390. template <class T, class S> class revert
  391. {
  392. // input:  pair (A, B)
  393. // output: pair (B, A)
  394. public:
  395.     revert() {}
  396.     pair<S, T> operator() (pair<T, S> x)
  397.     {
  398.         return make_pair(x.second, x.first);
  399.     }
  400. };
  401.  
  402. // Converts a size to a human readable format.
  403. void human_size(SAKER_INT _size, char *output)
  404. {
  405.     static const SAKER_INT KB = 1024;
  406.     static const SAKER_INT MB = 1024 * KB;
  407.     static const SAKER_INT GB = 1024 * MB;
  408.  
  409.     SAKER_INT number = 0, reminder = 0;
  410.     SAKER_INT size = _size;
  411.     if (size < KB)
  412.     {
  413.         sprintf(output, "%llu  ", size);
  414.     }
  415.     else
  416.     {
  417.         if (size < MB)
  418.         {
  419.             number = size / KB;
  420.             reminder = (size * 100 / KB) % 100;
  421.  
  422.             snprintf(output, 256, "%llu.%02llu K", number, reminder);
  423.         }
  424.         else
  425.         {
  426.             if (size < GB)
  427.             {
  428.                 number = size / MB;
  429.                 reminder = (size * 100 / MB) % 100;
  430.                 sprintf(output, "%llu.%02llu M", number, reminder);
  431.             }
  432.             else
  433.             {
  434.                 if (size >= GB)
  435.                 {
  436.                     number = size / GB;
  437.                     reminder = (size * 100 / GB) % 100;
  438.                     sprintf(output, "%llu.%02llu G", number, reminder);
  439.                 }
  440.             }
  441.         }
  442.     }
  443.  
  444. // cerr << "!" << size << "!" << number << "!" << output << "!" << endl;
  445. //  strNumber.Replace(".00", "");
  446. }
  447.  
  448. void report(void)
  449. {
  450. // container that keeps pairs (MAC, count)
  451. // representing src addresses of packets
  452. // ordered by count of packets
  453.     multimap<int, string> src_score;
  454.  
  455. // same for dst addresses
  456.     multimap<int, string> dst_score;
  457.  
  458.     // count the packets-per-second
  459.     SAKER_INT delta =  time(NULL) - time_start;
  460.     SAKER_INT pps = pkt_grb / (delta ? delta : 1);
  461.     SAKER_INT bps = size_grb / (delta ? delta : 1);
  462.  
  463.     char hbps[1024];
  464.     char hbbps[1024];
  465.     char hsize[1024];
  466.     char hpkt[1024];
  467.     char hpps[1024];
  468.     human_size(bps, hbps);
  469.     human_size(bps*8, hbbps);
  470.     human_size(size_grb, hsize);
  471.     human_size(pkt_grb, hpkt);
  472.     human_size(pps, hpps);
  473.  
  474.     cout << endl;
  475.     cout << "Interfaces: ";
  476.      for (int i=0; i<pcap_dev_no; i++)
  477.         cout << dv[i].device << " ";
  478.     cout << endl;
  479.  
  480.     cout << "Total packets: " << hpkt << "Pkt (" << hpps << "Pkts/s)" << endl;
  481.     cout << "Total size: " << hsize << "B (" << hbps << "B/s, " << hbbps << "Bits/s)" << endl;
  482. //    cout << "Macs: " << mac_cnt << endl;
  483.     if (!g_only_dst)
  484.     {
  485.         cout << "SRC stats:" << endl;
  486.         SAKER_INT srcv = g_bytemode ? size_grb : pkt_grb;
  487.  
  488.         // we have first to copy all stats from src, which is ordered by MAC to src_score
  489.         // which is ordered by count, making possible printing stats ordered by count
  490.         transform(src.begin(), src.end(), inserter(src_score, src_score.begin()), revert<string, SAKER_INT>());
  491.  
  492.         if (g_remote)
  493.             for_each(src_score.begin(), src_score.end(), uncount<pair<SAKER_INT, string> >(&srcv));
  494.  
  495.         // and now we simply print stats by count :)
  496.         if (g_ascend)
  497.             for_each(src_score.begin(), src_score.end(), print<pair<SAKER_INT, string> >(cout, srcv, mac_cnt));
  498.         else
  499.             for_each(src_score.rbegin(), src_score.rend(), print<pair<SAKER_INT, string> >(cout, srcv, mac_cnt));
  500.     }
  501.  
  502.     if (!g_only_src)
  503.     {
  504.         cout << "DST stats:" << endl;
  505.         SAKER_INT dstv = g_bytemode ? size_grb : pkt_grb;
  506.  
  507.         // same for dst
  508.         transform(dst.begin(), dst.end(), inserter(dst_score, dst_score.begin()), revert<string, SAKER_INT>());
  509.  
  510.         if (g_remote)
  511.             for_each(dst_score.begin(), dst_score.end(), uncount<pair<SAKER_INT, string> >(&dstv));
  512.  
  513.         if (g_ascend)
  514.             for_each(dst_score.begin(), dst_score.end(), print<pair<SAKER_INT, string> >(cout, dstv, mac_cnt));
  515.         else
  516.             for_each(dst_score.rbegin(), dst_score.rend(), print<pair<SAKER_INT, string> >(cout, dstv, mac_cnt));
  517.     }
  518. }
  519.  
  520. void sig_handler(int sig)
  521. {
  522.     cerr << endl << "saker: shutdown" << endl;
  523.     exit(127);
  524. }
  525.  
  526. int main(int argc, char *argv[])
  527. {
  528.     bpf_u_int32     net, mask;
  529.     int             opt;
  530.     bool            usage = false; // show usage
  531.     char            errbuff[PCAP_ERRBUF_SIZE];
  532.     int             i;
  533.  
  534.     char rev[255] = "$Revision: 1.42 $";
  535.     rev[strlen(rev)-2] = '\0';
  536.     char *revp = rev + 11; // skip prefix
  537.     cerr << "saker v" << revp << endl;
  538.  
  539.     signal(SIGINT, sig_handler);
  540.     signal(SIGTERM, sig_handler);
  541.  
  542.     for (i=0; i<MAX_IFACES; i++)
  543.     {
  544.         dv[i].pcap = NULL;
  545.         dv[i].device = NULL;
  546.         dv[i].pfd.fd = -1;
  547.     }
  548.  
  549.     while ((opt = getopt (argc, argv, "i:n:m:t:clapbhvorsdxXf:VD")) != -1)
  550.     {
  551.         switch (opt)
  552.         {
  553.         case 'i':
  554.             if (pcap_dev_no < MAX_IFACES)
  555.             {
  556.                 dv[pcap_dev_no++].device = (char *) strdup(optarg);
  557.             }
  558.             else
  559.             {
  560.                 cerr << "Error: too many interfaces specified" << endl;
  561.                 exit(2);
  562.             }
  563.             break;
  564.  
  565.         case 'n':
  566.             pkt_cnt = atoi(optarg);
  567.             g_pkt_cnt = true;
  568.             break;
  569.  
  570.         case 'm':
  571.             mac_cnt = atoi(optarg);
  572.             g_mac_cnt = true;
  573.             break;
  574.  
  575.         case 't':
  576.             time_delay = atoi(optarg);
  577.             if (time_delay < 1)
  578.                 time_delay = 1;
  579.             break;
  580.  
  581.         case 'a':
  582.             g_ascend = true;
  583.             break;
  584.  
  585.         case 'p':
  586.             g_percent = true;
  587.             break;
  588.  
  589.         case 'b':
  590.             g_bytemode = true;
  591.             break;
  592.  
  593.         case 'h':
  594.             usage = true;
  595.             break;
  596.  
  597.         case 'v':
  598.             g_verbose = true;
  599.             break;
  600.  
  601.         case 'r':
  602.             g_remote = true;
  603.             break;
  604.  
  605.         case 'l':
  606.             g_mark = true;
  607.             break;
  608.  
  609.         case 'o':
  610.             g_promisc = false;
  611.             break;
  612.  
  613.         case 'x':
  614.             g_resolve_arp = true;
  615.             break;
  616.  
  617.         case 'X':
  618.             g_resolve_arp = true;
  619.             g_resolve_ip = true;
  620.             break;
  621.  
  622.         case 'c':
  623.              g_cont = true;
  624.             pkt_cnt=0;
  625.             g_pkt_cnt = false;
  626.             break;
  627.  
  628.         case 'd':
  629.             g_only_dst = true;
  630.             if (g_only_src)
  631.             {
  632.                 cerr << "Error: You cannot have both -d and -s." << endl;
  633.                 usage = true;
  634.             }
  635.             break;
  636.  
  637.         case 's':
  638.             g_only_src = true;
  639.             if (g_only_dst)
  640.             {
  641.                 cerr << "Error: You cannot have both -d and -s." << endl;
  642.                 usage = true;
  643.             }
  644.             break;
  645.  
  646.         case 'f':
  647.             g_bpf = true;
  648.             bpf = (char *) strdup(optarg);
  649.             break;
  650.  
  651.         case 'V':
  652.             exit(0);
  653.             break;
  654.  
  655.         case 'D':
  656.             g_debug = true;
  657.             break;
  658.  
  659.         case '?':
  660.         default:
  661.             cerr << "Error: Unknown command line option." << endl;
  662.             usage = true;
  663.             break;
  664.         }
  665.     }
  666.  
  667.     if (usage == false && pcap_dev_no == 0)
  668.     {
  669.         cerr << "Error: Interface(s) not specified." << endl;
  670.         usage = true;
  671.     }
  672.  
  673.     if (usage)
  674.     {
  675.         cerr << endl
  676.             << "Usage: saker [-apbrmvhVD] [-n num] [-m num] [-s|-d] [-c -t num] [-f 'expr'] -i <if> [-i <if2> ... ]" << endl
  677.             << "  -i <if>   network interface (many interfaces can be specified)" << endl
  678.             << "  -h        show this info" << endl
  679.             << "  -n num    number of packets to capture (default " << DEFAULT_PKT_CNT << ", -1 for unlimited)" << endl
  680.             << "  -a        ascending sort (default descending)" << endl
  681.             << "  -m num    number of MACs to display in summary (all by default)" << endl
  682.             << "  -p        show percentage" << endl
  683.             << "  -b        count bytes (instead of packets)" << endl
  684.             << "  -r        count only remote ends (exclude own MACs)" << endl
  685.             << "  -l        mark local MACs with asterisk (see also -r)" << endl
  686.             << "  -s        show only source stats" << endl
  687.             << "  -d        show only destination stats" << endl
  688.             << "  -x        resolve MACs to IPs" << endl
  689.             << "  -X        resolve IPs to hostnames (implies -x)" << endl
  690.             << "  -c        continuous mode" << endl
  691.             << "  -o        turn off promiscuous mode" << endl
  692.             << "  -t num    time delay for continuous mode in seconds (default "<< DEFAULT_DELAY << ")" << endl
  693.             << "  -f 'expr' expr is a pcap-style BPF expression (man tcpdump)" << endl
  694.             << "  -v        be verbose (e.g. output each packet)" << endl
  695.             << "  -V        print version and exit" << endl
  696.             << "  -D        enable debug output (you are not supposed to understand it)" << endl;
  697.         exit(1);
  698.     }
  699.  
  700.     cerr << "Listening on: ";
  701.     for (i=0; i<pcap_dev_no; i++)
  702.         cerr << dv[i].device << " ";
  703.     cerr << endl;
  704.  
  705.     // get own mac's
  706.  
  707.     struct ifaddrs *ifap, *ifaphead;
  708.     int rtnerr;
  709.     const struct sockaddr_dl *sdl;
  710.     caddr_t ap;
  711.     int alen;
  712.     char ownmac[18] = "..:..:..:..:..:.."; // 6*2+5+1
  713.  
  714.     rtnerr = getifaddrs(&ifaphead);
  715.     if (rtnerr)
  716.     {
  717.         perror("Error: getifaddrs failed: ");
  718.         exit(2);
  719.     }
  720.  
  721.     if (g_verbose)
  722.         cout << "Own MAC adresses:" << endl;
  723.     for (ifap = ifaphead; ifap; ifap = ifap->ifa_next)
  724.     {
  725.         if (ifap->ifa_addr->sa_family == AF_LINK)
  726.         {
  727.             sdl = (const struct sockaddr_dl *) ifap->ifa_addr;
  728.             ap = ((caddr_t)((sdl)->sdl_data + (sdl)->sdl_nlen));
  729.             alen = sdl->sdl_alen;
  730.             if (ap && alen > 0)
  731.             {
  732.                 int i;
  733.                 for (i = 0; i < alen; i++, ap++)
  734.                 {
  735.                     if (i > 0)
  736.                         sprintf(ownmac+2+(i-1)*3,"%c%02x", ':' , 0xff&*ap);
  737.                     else
  738.                         sprintf(ownmac+i*3,"%02x", 0xff&*ap);
  739.                 }
  740.  
  741.                 if (g_verbose)
  742.                     cout << ownmac
  743.                         << " (" << ifap->ifa_name << ")"
  744.                         << endl;
  745.  
  746.                 string ownmacstr(ownmac);
  747.                 ownmacs.insert(ownmacstr);
  748.             }
  749.         }
  750.     }
  751.  
  752.  
  753.     if (g_debug)
  754.         copy(ownmacs.begin(), ownmacs.end(), ostream_iterator<string>(cout, "!\n"));
  755.  
  756.     freeifaddrs(ifaphead);
  757.  
  758.     time_start = time(NULL);
  759.  
  760.     //initialize pcap
  761.     for (i=0; i<pcap_dev_no; i++)
  762.     {
  763.         if (g_debug)
  764.             cerr << "PCAP init for " << dv[i].device << endl;
  765.  
  766.             int pcap_net = pcap_lookupnet(dv[i].device, &net, &mask, errbuff);
  767.             if (pcap_net == -1)
  768.             {
  769.                 cerr << "Error: pcap_lookupnet failed: "
  770.                     << errbuff
  771.                     << endl;
  772.                 exit(4);
  773.             }
  774.  
  775.             dv[i].pcap = pcap_open_live(dv[i].device, 100, g_promisc ? 1 : 0, 1000, errbuff);
  776.             if (dv[i].pcap == NULL)
  777.             {
  778.                 cerr << "Error: cannot open pcap live: "
  779.                     << errbuff
  780.                     << endl;
  781.                 exit(3);
  782.             }
  783.  
  784.             if (pcap_setnonblock(dv[i].pcap, 1, errbuff) < 0)
  785.             {
  786.                 cerr << "Error: cannot set nonblocking mode: "
  787.                     << errbuff
  788.                     << endl;
  789.                 exit(3);
  790.             }
  791.  
  792.             if (g_bpf)
  793.             {
  794.                     if (pcap_compile(dv[i].pcap, &bpff, bpf, 1, 0) < 0)
  795.                     {
  796.                         cerr << "Error: cannot compile BPF filter expression ("
  797.                             << pcap_geterr(dv[i].pcap)
  798.                             << ")"
  799.                             << endl;
  800.                         exit(6);
  801.                     }
  802.  
  803.                     if (pcap_setfilter(dv[i].pcap, &bpff))
  804.                     {
  805.                         cerr << "Error: cannot install BPF filter ("
  806.                             << pcap_geterr(dv[i].pcap)
  807.                             << ")"
  808.                             << endl;
  809.                         exit(5);
  810.                     }
  811.             }
  812.     }
  813.  
  814.     // init for poll(2)
  815.     for (i=0; i<pcap_dev_no; i++)
  816.     {
  817.         if ((dv[i].pfd.fd = pcap_get_selectable_fd(dv[i].pcap)) == -1)
  818.         {
  819.             perror("Error: pcap_get_selectable_fd failed");
  820.             exit(5);
  821.         }
  822.  
  823.         if (g_debug)
  824.             cerr << "pcap_selectable_fd: " << dv[i].device << "=" << dv[i].pfd.fd << endl;
  825.  
  826.         dv[i].pfd.events = POLLRDNORM;
  827.         pollfdtab[i] = dv[i].pfd;
  828.     }
  829.  
  830.     // the main loop
  831.     time_t last_report_time = time(NULL);
  832.     SAKER_INT poll_delay = time_delay*1000;
  833.     while (g_cont || pkt_grb < pkt_cnt)
  834.     {
  835.         int dispatched;
  836.         int pollret;
  837.         switch (pollret = poll(pollfdtab, pcap_dev_no, poll_delay))
  838.         {
  839.             case -1:
  840.                 if (errno != EINTR)
  841.                     perror("Error: poll failed");
  842.                 break;
  843.  
  844.             case 0:
  845.                 break;
  846.  
  847.             default:
  848. //                cerr << "POLL(" << pollret << ")" << endl;
  849.  
  850.                 for (i=0; i<pcap_dev_no; i++)
  851.                 {
  852.                     if (pollfdtab[i].revents)
  853.                     {
  854.                         if (dispatched = pcap_dispatch(dv[i].pcap, PCAP_MAX_PKT_PER_DISPATCH, h, NULL) < 0)
  855.                         {
  856.                             cerr << "Error: error during pcap dispatch ("
  857.                                 << pcap_geterr(dv[i].pcap)
  858.                                 << ")"
  859.                                 << endl;
  860.                             exit(5);
  861.                         }
  862.                     }
  863.                 }
  864.         }
  865.  
  866.         time_t now = time(NULL);
  867.         if (now - last_report_time >= time_delay)
  868.         {
  869.             report();
  870.             last_report_time = now;
  871.         }
  872.  
  873.     }
  874.  
  875.     report();
  876.  
  877.     return 0;
  878. }
  879.  
Last modified: 2006-11-04 01:40:44 (v423)   Valid XHTML 1.0

(c) 2009 Marcin Gryszkalis