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 */
11 /* gethostbyname(3) */
15 #include <sys/types.h>
16 #include <sys/socket.h>
18 #include <net/route.h>
19 #include <net/if_dl.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <netinet/if_ether.h>
34 #include <sys/ioctl.h>
40 #define APP_NAME "snifstat"
41 #define APP_VERSION 0.2
43 unsigned int calc_traf_io(char *, struct ether_header *);
44 int ethaddrsncmp(const char *, const char *, size_t);
45 void reset_count(int);
46 unsigned short get_windowsize(void);
47 void usage(const char *);
49 unsigned int reset = 0;
51 int main(int argc, char **argv) {
54 unsigned int show_in_bits = 0;
55 char bits_prefix[] = "Kbps";
56 char bytes_prefix[] = "KB/s";
57 unsigned int max_iteration = 0;
59 char errbuf[PCAP_ERRBUF_SIZE];
61 struct bpf_program filterd;
62 bpf_u_int32 netp, netmask;
64 const u_char *packet = NULL;
65 struct pcap_pkthdr header;
67 unsigned char *ether_addrs = NULL;
68 struct ifaddrs *ifa = NULL;
69 struct sockaddr_dl *sdl = NULL;
71 struct itimerval itv, oitv;
72 struct itimerval *itvp = &itv;
75 struct ether_header *ethernet = NULL;
77 unsigned int iteration = 0, total_iteration = 0;
78 double cur_in, cur_out;
79 unsigned short cur_ws = 0, new_ws, old_ws, ws_change;
80 unsigned int traf_io = 2;
82 unsigned int *resetp = &reset;
89 while((argch = getopt(argc, argv, "i:bc:hv")) != -1) {
92 if(strlen(optarg) < 16) {
105 max_iteration = (unsigned int)atoi(optarg);
110 case 'v': /* LOL WUT?! */
111 printf("%s v%.1f by nocturnal [at] swehack [dot] se\n", APP_NAME, APP_VERSION);
116 if(argc - optind < 1) {
121 filter = argv[optind];
123 if(pcap_lookupnet(ifname, &netp, &netmask, errbuf) == -1) {
124 fprintf(stderr, "pcap_lookupnet: %s\n", errbuf);
128 if((pcap = pcap_open_live(ifname, 65535, 1, 10, errbuf)) == NULL) {
129 fprintf(stderr, "pcap_open_live: %s\n", errbuf);
133 if(pcap_compile(pcap, &filterd, filter, 1, netmask) == -1) {
134 fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(pcap));
138 if(pcap_setfilter(pcap, &filterd) == -1) {
139 fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(pcap));
143 if(signal(SIGALRM, reset_count) == SIG_ERR) {
148 if(getifaddrs(&ifa) == -1) {
149 perror("getifaddrs: ");
153 for(;ifa;ifa = ifa->ifa_next) {
154 if(strncmp(ifname, ifa->ifa_name, sizeof(ifa->ifa_name)) == 0) {
155 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
156 if((ether_addrs = malloc(sdl->sdl_alen)) == NULL) {
160 memcpy(ether_addrs, LLADDR(sdl), sdl->sdl_alen);
165 timerclear(&itvp->it_interval);
166 itvp->it_value.tv_sec = 1;
167 itvp->it_value.tv_usec = 0;
173 new_ws = get_windowsize();
174 if(new_ws != old_ws) {
177 ws_change = cur_ws-2;
179 if(setitimer(ITIMER_REAL, itvp, &oitv) < 0) {
180 fprintf(stderr, "setitimer: \n");
186 while(*resetp == 0) {
187 if((packet = pcap_next(pcap, &header)) != NULL) {
188 ethernet = (struct ether_header *)packet;
190 if(header.len == 671429858) {
194 traf_io = calc_traf_io(ether_addrs, ethernet);
196 cur_in += header.len;
197 } else if(traf_io == 1) {
198 cur_out += header.len;
208 if(show_in_bits == 1) {
213 if(iteration >= ws_change || total_iteration == 0) {
214 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);
220 if(total_iteration > 0) {
221 printf("%8.2lf %9.2lf\n", cur_in, cur_out);
224 if(max_iteration > 0 && max_iteration == total_iteration) {
237 /* calculate if the packet is going in or out */
238 unsigned int calc_traf_io(char *ether_addrs, struct ether_header *ethernet) {
242 * GET IT!? GET IT?!?!??!!? :/ */
243 if(ethaddrsncmp(ether_addrs, ethernet->ether_shost, sizeof(ether_addrs)) == 0) {
246 if(ethaddrsncmp(ether_addrs, ethernet->ether_dhost, sizeof(ether_addrs)) == 0) {
252 /* compare ethernet addresses */
253 int ethaddrsncmp(const char *s1, const char *s2, size_t len) {
260 return(*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
267 /* resets a global value */
268 void reset_count(int signal) {
278 unsigned short get_windowsize(void) {
281 if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0) {
288 void usage(const char *appname) {
289 printf("Usage: %s -i <interface> [-bhv] <filter>\n", appname);
290 printf("\t-i <interface>\t Specify interface to capture from\n"
291 "\t-b\t\t Show values in bits instead of bytes\n"
292 "\t-h\t\t Show this help text\n"
293 "\t-v\t\t Show version\n");