snifstat.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /* this application captures packets destined to and from
  2. * a specified host, it then tries to calculate in and out
  3. * traffic statistics and display it like ifstat
  4. * by nocturnal [at] swehack [dot] se */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <string.h>
  9. /* gethostbyname(3) */
  10. #include <netdb.h>
  11. /* networking(4) */
  12. #include <sys/types.h>
  13. #include <sys/socket.h>
  14. #include <net/if.h>
  15. #include <net/route.h>
  16. #include <net/if_dl.h>
  17. #include <netinet/in.h>
  18. #include <arpa/inet.h>
  19. #include <netinet/if_ether.h>
  20. #include <ifaddrs.h>
  21. /* setitimer(2) */
  22. #include <sys/time.h>
  23. /* signal(3) */
  24. #include <signal.h>
  25. /* get_windowsize */
  26. #include <termios.h>
  27. #ifndef TIOCGWINSZ
  28. #include <sys/ioctl.h>
  29. #endif
  30. /* duh -lpcap */
  31. #include <pcap.h>
  32. #define APP_NAME "snifstat"
  33. #define APP_VERSION 0.2
  34. unsigned int calc_traf_io(char *, struct ether_header *);
  35. int ethaddrsncmp(const char *, const char *, size_t);
  36. void reset_count(int);
  37. unsigned short get_windowsize(void);
  38. void usage(const char *);
  39. unsigned int reset = 0;
  40. int main(int argc, char **argv) {
  41. char *ifname = NULL;
  42. int argch;
  43. unsigned int show_in_bits = 0;
  44. char bits_prefix[] = "Kbps";
  45. char bytes_prefix[] = "KB/s";
  46. unsigned int max_iteration = 0;
  47. char errbuf[PCAP_ERRBUF_SIZE];
  48. pcap_t *pcap = NULL;
  49. struct bpf_program filterd;
  50. bpf_u_int32 netp, netmask;
  51. char *filter = NULL;
  52. const u_char *packet = NULL;
  53. struct pcap_pkthdr header;
  54. unsigned char *ether_addrs = NULL;
  55. struct ifaddrs *ifa = NULL;
  56. struct sockaddr_dl *sdl = NULL;
  57. struct itimerval itv, oitv;
  58. struct itimerval *itvp = &itv;
  59. struct ether_header *ethernet = NULL;
  60. unsigned int iteration = 0, total_iteration = 0;
  61. double cur_in, cur_out;
  62. unsigned short cur_ws = 0, new_ws, old_ws, ws_change;
  63. unsigned int traf_io = 2;
  64. unsigned int *resetp = &reset;
  65. if(argc < 4) {
  66. usage(argv[0]);
  67. exit(-1);
  68. }
  69. while((argch = getopt(argc, argv, "i:bc:hv")) != -1) {
  70. switch(argch) {
  71. case 'i':
  72. if(strlen(optarg) < 16) {
  73. ifname = optarg;
  74. optreset = 1;
  75. } else {
  76. usage(argv[0]);
  77. exit(-1);
  78. }
  79. break;
  80. case 'b':
  81. show_in_bits = 1;
  82. optreset = 1;
  83. break;
  84. case 'c':
  85. max_iteration = (unsigned int)atoi(optarg);
  86. break;
  87. case 'h':
  88. usage(argv[0]);
  89. exit(-1);
  90. case 'v': /* LOL WUT?! */
  91. printf("%s v%.1f by nocturnal [at] swehack [dot] se\n", APP_NAME, APP_VERSION);
  92. exit(-1);
  93. }
  94. }
  95. if(argc - optind < 1) {
  96. usage(argv[0]);
  97. exit(-1);
  98. }
  99. filter = argv[optind];
  100. if(pcap_lookupnet(ifname, &netp, &netmask, errbuf) == -1) {
  101. fprintf(stderr, "pcap_lookupnet: %s\n", errbuf);
  102. exit(-1);
  103. }
  104. if((pcap = pcap_open_live(ifname, 65535, 1, 10, errbuf)) == NULL) {
  105. fprintf(stderr, "pcap_open_live: %s\n", errbuf);
  106. exit(-1);
  107. }
  108. if(pcap_compile(pcap, &filterd, filter, 1, netmask) == -1) {
  109. fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(pcap));
  110. exit(-1);
  111. }
  112. if(pcap_setfilter(pcap, &filterd) == -1) {
  113. fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(pcap));
  114. exit(-1);
  115. }
  116. if(signal(SIGALRM, reset_count) == SIG_ERR) {
  117. perror("signal: ");
  118. exit(-1);
  119. }
  120. if(getifaddrs(&ifa) == -1) {
  121. perror("getifaddrs: ");
  122. exit(-1);
  123. }
  124. for(;ifa;ifa = ifa->ifa_next) {
  125. if(strncmp(ifname, ifa->ifa_name, sizeof(ifa->ifa_name)) == 0) {
  126. sdl = (struct sockaddr_dl *)ifa->ifa_addr;
  127. if((ether_addrs = malloc(sdl->sdl_alen)) == NULL) {
  128. perror("malloc: ");
  129. exit(-1);
  130. }
  131. memcpy(ether_addrs, LLADDR(sdl), sdl->sdl_alen);
  132. break;
  133. }
  134. }
  135. timerclear(&itvp->it_interval);
  136. itvp->it_value.tv_sec = 1;
  137. itvp->it_value.tv_usec = 0;
  138. while(1) {
  139. *resetp = 0;
  140. old_ws = cur_ws;
  141. new_ws = get_windowsize();
  142. if(new_ws != old_ws) {
  143. cur_ws = new_ws;
  144. }
  145. ws_change = cur_ws-2;
  146. if(setitimer(ITIMER_REAL, itvp, &oitv) < 0) {
  147. fprintf(stderr, "setitimer: \n");
  148. exit(-1);
  149. }
  150. cur_in = 0.0;
  151. cur_out = 0.0;
  152. while(*resetp == 0) {
  153. if((packet = pcap_next(pcap, &header)) != NULL) {
  154. ethernet = (struct ether_header *)packet;
  155. if(header.len == 671429858) {
  156. cur_in += 0.0;
  157. cur_out += 0.0;
  158. } else {
  159. traf_io = calc_traf_io(ether_addrs, ethernet);
  160. if(traf_io == 0) {
  161. cur_in += header.len;
  162. } else if(traf_io == 1) {
  163. cur_out += header.len;
  164. }
  165. traf_io = 2;
  166. }
  167. }
  168. }
  169. cur_in /= 1024;
  170. cur_out /= 1024;
  171. if(show_in_bits == 1) {
  172. cur_in *= 8;
  173. cur_out *= 8;
  174. }
  175. if(iteration >= ws_change || total_iteration == 0) {
  176. printf("%11s\n%5s in %5s out\n", ifname, (show_in_bits == 1) ? bits_prefix : bytes_prefix, (show_in_bits == 1) ? bits_prefix : bytes_prefix);
  177. if(iteration > 1) {
  178. iteration = 1;
  179. }
  180. }
  181. if(total_iteration > 0) {
  182. printf("%8.2lf %9.2lf\n", cur_in, cur_out);
  183. }
  184. if(max_iteration > 0 && max_iteration == total_iteration) {
  185. break;
  186. }
  187. iteration++;
  188. total_iteration++;
  189. }
  190. pcap_close(pcap);
  191. exit(0);
  192. }
  193. /* calculate if the packet is going in or out */
  194. unsigned int calc_traf_io(char *ether_addrs, struct ether_header *ethernet) {
  195. /* 0 = in
  196. * 1 = out
  197. * 2 = error
  198. * GET IT!? GET IT?!?!??!!? :/ */
  199. if(ethaddrsncmp(ether_addrs, ethernet->ether_shost, sizeof(ether_addrs)) == 0) {
  200. return(1);
  201. }
  202. if(ethaddrsncmp(ether_addrs, ethernet->ether_dhost, sizeof(ether_addrs)) == 0) {
  203. return(0);
  204. }
  205. return(2);
  206. }
  207. /* compare ethernet addresses */
  208. int ethaddrsncmp(const char *s1, const char *s2, size_t len) {
  209. if(len == 0) {
  210. return(0);
  211. }
  212. do {
  213. if(*s1++ != *s2++) {
  214. return(*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
  215. }
  216. } while(--len != 0);
  217. return(0);
  218. }
  219. /* resets a global value */
  220. void reset_count(int signal) {
  221. int *resetp = NULL;
  222. resetp = &reset;
  223. *resetp = 1;
  224. return;
  225. }
  226. /* get windowsize */
  227. unsigned short get_windowsize(void) {
  228. struct winsize ws;
  229. if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) {
  230. return(-1);
  231. }
  232. return(ws.ws_row);
  233. }
  234. void usage(const char *appname) {
  235. printf("Usage: %s -i <interface> [-bhv] <filter>\n", appname);
  236. printf("\t-i <interface>\t Specify interface to capture from\n"
  237. "\t-b\t\t Show values in bits instead of bytes\n"
  238. "\t-h\t\t Show this help text\n"
  239. "\t-v\t\t Show version\n");
  240. return;
  241. }