2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2009, 2010 Daniel Borkmann.
5 * Subject to the GPL, version 2.
7 * A tiny tool to provide top-like reliable networking statistics.
8 * Why? Well, some time ago I used iptraf to display network traffic
9 * statistics. During that time and probably also today, they are
10 * using libpcap to collect statistics. Well, bad idea since this
11 * will give you false statistics on high I/O load. Therefore, ifpps
12 * reads out the 'real' kernel statistics, so things your NIC sees
13 * and not some userland library.
15 * He had all the injured air of a liar suspected when for once he
16 * has told the truth, or part of it.
18 * -- The Lord of the Rings, On Gollum,
19 * Chapter 'The Black Gate is Closed'.
26 ifpps - fetch and format kernel network statistics
30 ifpps -d|--dev <netdev> [-t|--interval <sec>][-p|--promisc][-c|--term]
31 [-C|--csv][-H|--csv-tablehead][-l|--loop][-v|--version][-h|--help]
35 A tiny tool to provide top-like reliable networking statistics.
36 ifpps reads out the 'real' kernel statistics, so it does not give erroneous
37 statistics on high I/O load.
43 =item ifpps --dev eth0
45 Fetch eth0 interface statistics.
47 =item ifpps --dev eth0 --interval 60 --csv
49 Output eth0 interface statistics every minute in CSV format.
59 Print help text and lists all options.
65 =item -d|--dev <netdev>
67 Device to fetch statistics for i.e., eth0.
71 Put the device in promiscuous mode
73 =item -t|--interval <time>
75 Refresh time in sec (default 1 sec)
84 E.g. post-processing with Gnuplot et al.
86 =item -H|--csv-tablehead
98 Written by Daniel Borkmann <daniel@netsniff-ng.org>
102 Documentation by Emmanuel Roullit <emmanuel@netsniff-ng.org>
106 Please report bugs to <bugs@netsniff-ng.org>
117 #include <sys/socket.h>
126 #include "built_in.h"
129 * TODO: Cleanups, this got quite a hack over time.
132 #define TERM_MODE_NORMAL 1
133 #define TERM_MODE_CSV 2
134 #define TERM_MODE_CSV_HDR 4
136 #define USER_HZ sysconf(_SC_CLK_TCK)
139 unsigned long rx_bytes
;
140 unsigned long rx_packets
;
141 unsigned long rx_drops
;
142 unsigned long rx_errors
;
143 unsigned long rx_fifo
;
144 unsigned long rx_frame
;
145 unsigned long rx_multi
;
146 unsigned long tx_bytes
;
147 unsigned long tx_packets
;
148 unsigned long tx_drops
;
149 unsigned long tx_errors
;
150 unsigned long tx_fifo
;
151 unsigned long tx_colls
;
152 unsigned long tx_carrier
;
153 unsigned long irq_nr
;
155 unsigned long *irqs_srx
;
156 unsigned long *irqs_stx
;
157 unsigned long *cpu_user
;
158 unsigned long *cpu_nice
;
159 unsigned long *cpu_sys
;
160 unsigned long *cpu_idle
;
161 unsigned long *cpu_iow
;
164 unsigned long procs_run
;
165 unsigned long procs_iow
;
170 int wifi_link_qual_max
;
171 int wifi_signal_level
;
172 int wifi_noise_level
;
178 volatile sig_atomic_t sigint
= 0;
180 static const char *short_options
= "d:t:vhcCHlp";
182 static struct option long_options
[] = {
183 {"dev", required_argument
, 0, 'd'},
184 {"interval", required_argument
, 0, 't'},
185 {"loop", no_argument
, 0, 'l'},
186 {"term", no_argument
, 0, 'c'},
187 {"promisc", no_argument
, 0, 'p'},
188 {"csv", no_argument
, 0, 'C'},
189 {"csv-tablehead", no_argument
, 0, 'H'},
190 {"version", no_argument
, 0, 'v'},
191 {"help", no_argument
, 0, 'h'},
195 static void signal_handler(int number
)
208 static int rxtx_stats(const char *ifname
, struct ifstat
*s
)
214 FILE *fp
= fopen("/proc/net/dev", "r");
216 whine("Cannot open /proc/net/dev!\n");
221 ptr
= fgets(buf
, sizeof(buf
), fp
);
222 ptr
= fgets(buf
, sizeof(buf
), fp
);
224 memset(buf
, 0, sizeof(buf
));
225 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
226 buf
[sizeof(buf
) -1] = 0;
228 if (strstr(buf
, ifname
) == NULL
)
236 ret
= sscanf(ptr
, "%lu%lu%lu%lu%lu%lu%lu%*u%lu%lu%lu%lu%lu%lu%lu",
237 &s
->rx_bytes
, &s
->rx_packets
, &s
->rx_errors
,
238 &s
->rx_drops
, &s
->rx_fifo
, &s
->rx_frame
,
240 &s
->tx_bytes
, &s
->tx_packets
, &s
->tx_errors
,
241 &s
->tx_drops
, &s
->tx_fifo
, &s
->tx_colls
,
248 memset(buf
, 0, sizeof(buf
));
256 static int wifi_stats(const char *ifname
, struct ifstat
*s
)
259 struct iw_statistics ws
;
261 ret
= wireless_sigqual(ifname
, &ws
);
263 /* We don't want to trouble in case of eth* */
268 s
->wifi_bitrate
= wireless_bitrate(ifname
);
269 s
->wifi_signal_level
= adjust_dbm_level(ws
.qual
.level
);
270 s
->wifi_noise_level
= adjust_dbm_level(ws
.qual
.noise
);
271 s
->wifi_link_qual
= ws
.qual
.qual
;
272 s
->wifi_link_qual_max
= wireless_rangemax_sigqual(ifname
);
277 static void stats_check_alloc(struct ifstat
*s
)
279 int cpus
= get_number_cpus();
281 if (s
->irqs_len
!= get_number_cpus()) {
282 if (s
->irqs
) xfree(s
->irqs
);
283 if (s
->irqs_srx
) xfree(s
->irqs_srx
);
284 if (s
->irqs_stx
) xfree(s
->irqs_stx
);
285 if (s
->cpu_user
) xfree(s
->cpu_user
);
286 if (s
->cpu_nice
) xfree(s
->cpu_nice
);
287 if (s
->cpu_sys
) xfree(s
->cpu_sys
);
288 if (s
->cpu_idle
) xfree(s
->cpu_idle
);
289 if (s
->cpu_iow
) xfree(s
->cpu_iow
);
291 s
->irqs_srx
= xzmalloc(sizeof(*(s
->irqs_srx
)) * cpus
);
292 s
->irqs_stx
= xzmalloc(sizeof(*(s
->irqs_stx
)) * cpus
);
293 s
->irqs
= xzmalloc(sizeof(*(s
->irqs
)) * cpus
);
294 s
->cpu_user
= xzmalloc(sizeof(*(s
->cpu_user
)) * cpus
);
295 s
->cpu_nice
= xzmalloc(sizeof(*(s
->cpu_nice
)) * cpus
);
296 s
->cpu_sys
= xzmalloc(sizeof(*(s
->cpu_sys
)) * cpus
);
297 s
->cpu_idle
= xzmalloc(sizeof(*(s
->cpu_idle
)) * cpus
);
298 s
->cpu_iow
= xzmalloc(sizeof(*(s
->cpu_iow
)) * cpus
);
303 static int irq_sstats(struct ifstat
*s
)
309 FILE *fp
= fopen("/proc/softirqs", "r");
311 whine("Cannot open /proc/softirqs!\n");
315 stats_check_alloc(s
);
317 memset(buff
, 0, sizeof(buff
));
318 while (fgets(buff
, sizeof(buff
), fp
) != NULL
) {
319 buff
[sizeof(buff
) - 1] = 0;
321 if ((ptr
= strstr(buff
, "NET_TX:")) == NULL
) {
322 ptr
= strstr(buff
, "NET_RX:");
331 ptr
+= strlen("NET_TX:");
333 for (i
= 0; i
< s
->irqs_len
; ++i
) {
338 while (*ptr
!= ' ' && *ptr
!= 0)
342 s
->irqs_srx
[i
] = atoi(ptr2
);
344 s
->irqs_stx
[i
] = atoi(ptr2
);
347 memset(buff
, 0, sizeof(buff
));
355 static int mem_stats(struct ifstat
*s
)
358 unsigned long total
, free
;
362 FILE *fp
= fopen("/proc/meminfo", "r");
364 whine("Cannot open /proc/meminfo!\n");
368 memset(buff
, 0, sizeof(buff
));
369 while (fgets(buff
, sizeof(buff
), fp
) != NULL
) {
370 buff
[sizeof(buff
) - 1] = 0;
372 if ((ptr
= strstr(buff
, "MemTotal:")) != NULL
) {
373 ptr
+= strlen("MemTotal:");
379 ret
= sscanf(ptr
, "%lu", &total
);
382 } else if ((ptr
= strstr(buff
, "MemFree:")) != NULL
) {
383 ptr
+= strlen("MemFree:");
389 ret
= sscanf(ptr
, "%lu", &free
);
394 memset(buff
, 0, sizeof(buff
));
398 s
->mem_used
= 100.f
* (total
- free
) / total
;
407 static int sys_stats(struct ifstat
*s
)
413 FILE *fp
= fopen("/proc/stat", "r");
415 whine("Cannot open /proc/stat!\n");
419 stats_check_alloc(s
);
421 memset(buff
, 0, sizeof(buff
));
422 while (fgets(buff
, sizeof(buff
), fp
) != NULL
) {
423 buff
[sizeof(buff
) - 1] = 0;
425 if ((ptr
= strstr(buff
, "cpu")) != NULL
) {
426 ptr
+= strlen("cpu");
431 while (*ptr
!= ' ' && *ptr
!= 0)
436 if (cpu
< 0 || cpu
>= s
->irqs_len
)
440 ret
= sscanf(ptr
, "%lu%lu%lu%lu%lu", &s
->cpu_user
[cpu
],
441 &s
->cpu_nice
[cpu
], &s
->cpu_sys
[cpu
],
442 &s
->cpu_idle
[cpu
], &s
->cpu_iow
[cpu
]);
445 } else if ((ptr
= strstr(buff
, "ctxt")) != NULL
) {
446 ptr
+= strlen("ctxt");
452 ret
= sscanf(ptr
, "%lu", &s
->ctxt
);
455 } else if ((ptr
= strstr(buff
, "processes")) != NULL
) {
456 ptr
+= strlen("processes");
462 ret
= sscanf(ptr
, "%lu", &s
->forks
);
465 } else if ((ptr
= strstr(buff
, "procs_running")) != NULL
) {
466 ptr
+= strlen("procs_running");
472 ret
= sscanf(ptr
, "%lu", &s
->procs_run
);
475 } else if ((ptr
= strstr(buff
, "procs_blocked")) != NULL
) {
476 ptr
+= strlen("procs_blocked");
482 ret
= sscanf(ptr
, "%lu", &s
->procs_iow
);
487 memset(buff
, 0, sizeof(buff
));
495 static int irq_stats(const char *ifname
, struct ifstat
*s
)
502 if (!strncmp("lo", ifname
, strlen("lo")))
505 FILE *fp
= fopen("/proc/interrupts", "r");
507 whine("Cannot open /proc/interrupts!\n");
511 stats_check_alloc(s
);
513 memset(buff
, 0, sizeof(buff
));
514 while (fgets(buff
, sizeof(buff
), fp
) != NULL
) {
515 buff
[sizeof(buff
) - 1] = 0;
517 if (strstr(buff
, ifname
) == NULL
)
524 s
->irq_nr
= atoi(buff
);
526 bug_on(s
->irq_nr
== 0);
528 for (i
= 0; i
< s
->irqs_len
; ++i
) {
533 while (*ptr
!= ' ' && *ptr
!= 0)
536 s
->irqs
[i
] = atoi(ptr2
);
539 memset(buff
, 0, sizeof(buff
));
547 static void diff_stats(struct ifstat
*old
, struct ifstat
*new,
552 if(old
->irqs_len
!= new->irqs_len
)
553 return; /* Refetch stats and take old diff! */
555 diff
->rx_bytes
= new->rx_bytes
- old
->rx_bytes
;
556 diff
->rx_packets
= new->rx_packets
- old
->rx_packets
;
557 diff
->rx_drops
= new->rx_drops
- old
->rx_drops
;
558 diff
->rx_errors
= new->rx_errors
- old
->rx_errors
;
559 diff
->rx_fifo
= new->rx_fifo
- old
->rx_fifo
;
560 diff
->rx_frame
= new->rx_frame
- old
->rx_frame
;
561 diff
->rx_multi
= new->rx_multi
- old
->rx_multi
;
562 diff
->tx_bytes
= new->tx_bytes
- old
->tx_bytes
;
563 diff
->tx_packets
= new->tx_packets
- old
->tx_packets
;
564 diff
->tx_drops
= new->tx_drops
- old
->tx_drops
;
565 diff
->tx_errors
= new->tx_errors
- old
->tx_errors
;
566 diff
->tx_fifo
= new->tx_fifo
- old
->tx_fifo
;
567 diff
->tx_colls
= new->tx_colls
- old
->tx_colls
;
568 diff
->tx_carrier
= new->tx_carrier
- old
->tx_carrier
;
569 diff
->wifi_signal_level
= new->wifi_signal_level
- old
->wifi_signal_level
;
570 diff
->wifi_noise_level
= new->wifi_noise_level
- old
->wifi_noise_level
;
571 diff
->wifi_link_qual
= new->wifi_link_qual
- old
->wifi_link_qual
;
572 diff
->ctxt
= new->ctxt
- old
->ctxt
;
573 diff
->forks
= new->forks
- old
->forks
;
574 diff
->procs_run
= new->procs_run
- old
->procs_run
;
575 diff
->procs_iow
= new->procs_iow
- old
->procs_iow
;
577 stats_check_alloc(diff
);
579 diff
->irq_nr
= new->irq_nr
;
581 for (i
= 0; i
< diff
->irqs_len
; ++i
) {
582 diff
->irqs
[i
] = new->irqs
[i
] - old
->irqs
[i
];
583 diff
->irqs_srx
[i
] = new->irqs_srx
[i
] - old
->irqs_srx
[i
];
584 diff
->irqs_stx
[i
] = new->irqs_stx
[i
] - old
->irqs_stx
[i
];
585 diff
->cpu_user
[i
] = new->cpu_user
[i
] - old
->cpu_user
[i
];
586 diff
->cpu_nice
[i
] = new->cpu_nice
[i
] - old
->cpu_nice
[i
];
587 diff
->cpu_sys
[i
] = new->cpu_sys
[i
] - old
->cpu_sys
[i
];
588 diff
->cpu_idle
[i
] = new->cpu_idle
[i
] - old
->cpu_idle
[i
];
589 diff
->cpu_iow
[i
] = new->cpu_iow
[i
] - old
->cpu_iow
[i
];
593 static void screen_init(WINDOW
**screen
)
595 (*screen
) = initscr();
598 nodelay((*screen
), TRUE
);
603 static void screen_update(WINDOW
*screen
, const char *ifname
,
604 struct ifstat
*s
, struct ifstat
*t
,
605 int *first
, double interval
)
610 mvwprintw(screen
, 1, 2, "Kernel net/sys statistics for %s, t=%.2lfs",
613 mvwprintw(screen
, 3, 0,
614 " RX: %16.3f MiB/t %10lu pkts/t %10lu drops/t %10lu errors/t ",
615 1.f
* s
->rx_bytes
/ (1 << 20), s
->rx_packets
, s
->rx_drops
,
617 mvwprintw(screen
, 4, 0,
618 " TX: %16.3f MiB/t %10lu pkts/t %10lu drops/t %10lu errors/t ",
619 1.f
* s
->tx_bytes
/ (1 << 20), s
->tx_packets
, s
->tx_drops
,
622 mvwprintw(screen
, 6, 2,
623 "RX: %16.3f MiB %10lu pkts %10lu drops %10lu errors",
624 1.f
* t
->rx_bytes
/ (1 << 20), t
->rx_packets
, t
->rx_drops
,
626 mvwprintw(screen
, 7, 2,
627 "TX: %16.3f MiB %10lu pkts %10lu drops %10lu errors",
628 1.f
* t
->tx_bytes
/ (1 << 20), t
->tx_packets
, t
->tx_drops
,
631 mvwprintw(screen
, j
++, 2, "SYS: %14ld cs/t %10.1f%% mem "
632 "%13ld running %10ld iowait",
633 s
->ctxt
, t
->mem_used
, t
->procs_run
, t
->procs_iow
);
635 if (s
->irq_nr
!= 0) {
636 for(i
= 0; i
< s
->irqs_len
; ++i
) {
637 unsigned long all
= s
->cpu_user
[i
] + s
->cpu_nice
[i
] +
638 s
->cpu_sys
[i
] + s
->cpu_idle
[i
] +
640 mvwprintw(screen
, j
++, 2, "CPU%d: %13.1f%% usr/t "
641 "%9.1f%% sys/t %10.1f%% idl/t %11.1f%% iow/t ",
643 100.f
* (s
->cpu_user
[i
] + s
->cpu_nice
[i
]) / all
,
644 100.f
* s
->cpu_sys
[i
] / all
,
645 100.f
* s
->cpu_idle
[i
] /all
,
646 100.f
* s
->cpu_iow
[i
] / all
);
649 for(i
= 0; i
< s
->irqs_len
; ++i
)
650 mvwprintw(screen
, j
++, 2, "CPU%d: %14ld irqs/t "
651 "%15ld soirq RX/t %15ld soirq TX/t ",
652 i
, s
->irqs
[i
], s
->irqs_srx
[i
], s
->irqs_stx
[i
]);
654 for(i
= 0; i
< s
->irqs_len
; ++i
)
655 mvwprintw(screen
, j
++, 2, "CPU%d: %14ld irqs",
659 if (t
->wifi_bitrate
> 0) {
660 mvwprintw(screen
, j
++, 2, "LinkQual: %7d/%d (%d/t) ",
661 t
->wifi_link_qual
, t
->wifi_link_qual_max
,
663 mvwprintw(screen
, j
++, 2, "Signal: %8d dBm (%d dBm/t) ",
664 t
->wifi_signal_level
, s
->wifi_signal_level
);
665 mvwprintw(screen
, j
++, 2, "Noise: %8d dBm (%d dBm/t) ",
666 t
->wifi_noise_level
, s
->wifi_noise_level
);
670 mvwprintw(screen
, 2, 2, "Collecting data ...");
673 mvwprintw(screen
, 2, 2, " ");
679 static void screen_end(void)
684 static void print_update(const char *ifname
, struct ifstat
*s
,
685 struct ifstat
*t
, double interval
)
689 printf("RX: %16.3f MiB/t %10lu Pkts/t %10lu Drops/t %10lu Errors/t\n",
690 1.f
* s
->rx_bytes
/ (1 << 20), s
->rx_packets
, s
->rx_drops
,
692 printf("TX: %16.3f MiB/t %10lu Pkts/t %10lu Drops/t %10lu Errors/t\n",
693 1.f
* s
->tx_bytes
/ (1 << 20), s
->tx_packets
, s
->tx_drops
,
696 for(i
= 0; i
< s
->irqs_len
; ++i
)
697 printf("CPU%d: %10ld IRQs/t "
699 "%10ld SoIRQ TX/t\n", i
,
700 s
->irqs
[i
], s
->irqs_srx
[i
], s
->irqs_stx
[i
]);
701 if (t
->wifi_bitrate
> 0) {
702 printf("LinkQual: %6d/%d (%d/t)\n", t
->wifi_link_qual
,
703 t
->wifi_link_qual_max
, s
->wifi_link_qual
);
704 printf("Signal: %8d dBm (%d dBm/t)\n", t
->wifi_signal_level
,
705 s
->wifi_signal_level
);
706 printf("Noise: %8d dBm (%d dBm/t)\n", t
->wifi_noise_level
,
707 s
->wifi_noise_level
);
711 static void print_update_csv(const char *ifname
, struct ifstat
*s
,
712 struct ifstat
*t
, double interval
)
716 printf("%lu,%lu,%lu,%lu,", s
->rx_bytes
, s
->rx_packets
, s
->rx_drops
,
718 printf("%lu,%lu,%lu,%lu", s
->tx_bytes
, s
->tx_packets
, s
->tx_drops
,
721 for(i
= 0; i
< s
->irqs_len
; ++i
)
722 printf(",%ld,%ld,%ld", s
->irqs
[i
], s
->irqs_srx
[i
],
724 if (t
->wifi_bitrate
> 0) {
725 printf(",%d,%d", t
->wifi_link_qual
, t
->wifi_link_qual_max
);
726 printf(",%d", t
->wifi_signal_level
);
727 printf(",%d", t
->wifi_noise_level
);
732 static void print_update_csv_hdr(const char *ifname
, struct ifstat
*s
,
733 struct ifstat
*t
, double interval
)
737 printf("RX Byte/t,RX Pkts/t,RX Drops/t,RX Errors/t,");
738 printf("TX Byte/t,TX Pkts/t,TX Drops/t,TX Errors/t");
740 for(i
= 0; i
< s
->irqs_len
; ++i
)
741 printf(",CPU%d IRQs/t,CPU%d SoIRQ RX/t,"
742 "CPU%d SoIRQ TX/t", i
, i
, i
);
743 if (t
->wifi_bitrate
> 0)
744 printf(",LinkQual,LinkQualMax,Signal Level,Noise Level");
748 static inline int do_stats(const char *ifname
, struct ifstat
*s
)
752 ret
+= rxtx_stats(ifname
, s
);
753 ret
+= irq_stats(ifname
, s
);
754 ret
+= irq_sstats(s
);
757 ret
+= wifi_stats(ifname
, s
);
762 static int screen_loop(const char *ifname
, uint32_t interval
)
764 int ret
= 0, first
= 1;
765 struct ifstat old
, new, curr
;
766 WINDOW
*screen
= NULL
;
768 memset(&old
, 0, sizeof(old
));
769 memset(&new, 0, sizeof(new));
770 memset(&curr
, 0, sizeof(curr
));
772 screen_init(&screen
);
778 screen_update(screen
, ifname
, &curr
, &new, &first
, interval
);
780 ret
= do_stats(ifname
, &old
);
786 ret
= do_stats(ifname
, &new);
790 diff_stats(&old
, &new, &curr
);
796 whine("Error fetching stats!\n");
807 static int print_loop(const char *ifname
, uint32_t interval
)
810 struct ifstat old
, new, curr
;
812 memset(&old
, 0, sizeof(old
));
813 memset(&new, 0, sizeof(new));
814 memset(&curr
, 0, sizeof(curr
));
816 ret
= do_stats(ifname
, &old
);
822 ret
= do_stats(ifname
, &new);
826 diff_stats(&old
, &new, &curr
);
828 if (first
&& (mode
& TERM_MODE_CSV_HDR
) ==
830 print_update_csv_hdr(ifname
, &curr
, &new, interval
);
834 if ((mode
& TERM_MODE_CSV
) == TERM_MODE_CSV
)
835 print_update_csv(ifname
, &curr
, &new, interval
);
836 else if ((mode
& TERM_MODE_NORMAL
) == TERM_MODE_NORMAL
)
837 print_update(ifname
, &curr
, &new, interval
);
838 } while (loop
&& !sigint
);
841 whine("Error fetching stats!\n");
852 static void help(void)
854 printf("\nifpps %s, kernel networking and system statistics\n",
856 printf("http://www.netsniff-ng.org\n\n");
857 printf("Usage: ifpps [options] || ifpps <netdev>\n");
858 printf("Options:\n");
859 printf(" -d|--dev <netdev> Device to fetch statistics for i.e., eth0\n");
860 printf(" -p|--promisc Promiscuous mode\n");
861 printf(" -t|--interval <time> Refresh time in sec (default 1 s)\n");
862 printf(" -c|--term Output to terminal\n");
863 printf(" -C|--csv Output to terminal as CSV\n");
864 printf(" E.g. post-processing with Gnuplot et al.\n");
865 printf(" -H|--csv-tablehead Print CSV table head\n");
866 printf(" -l|--loop Loop terminal output\n");
867 printf(" -v|--version Print version\n");
868 printf(" -h|--help Print this help\n");
870 printf("Examples:\n");
871 printf(" ifpps --dev eth0\n");
872 printf(" ifpps --dev eth0 --interval 60 --csv\n\n");
873 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
874 printf("Copyright (C) 2009-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n");
875 printf("License: GNU GPL version 2\n");
876 printf("This is free software: you are free to change and redistribute it.\n");
877 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
881 static void version(void)
883 printf("\nifpps %s, kernel networking statistics per sec\n",
885 printf("http://www.netsniff-ng.org\n\n");
886 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
887 printf("Copyright (C) 2009-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n");
888 printf("License: GNU GPL version 2\n");
889 printf("This is free software: you are free to change and redistribute it.\n");
890 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
894 int main(int argc
, char **argv
)
897 int c
, opt_index
, ret
;
898 unsigned int promisc
= 0;
900 uint32_t interval
= 1;
901 int (*main_loop
)(const char *ifname
, uint32_t interval
) = screen_loop
;
903 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
904 &opt_index
)) != EOF
) {
913 ifname
= xstrndup(optarg
, IFNAMSIZ
);
916 interval
= atoi(optarg
);
919 mode
|= TERM_MODE_NORMAL
;
920 main_loop
= print_loop
;
929 mode
|= TERM_MODE_CSV
;
930 main_loop
= print_loop
;
933 mode
|= TERM_MODE_CSV_HDR
;
934 main_loop
= print_loop
;
940 panic("Option -%c requires an argument!\n",
944 whine("Unknown option character "
945 "`0x%X\'!\n", optopt
);
956 ifname
= xstrndup(argv
[1], IFNAMSIZ
);
958 panic("No networking device given!\n");
959 if (!strncmp("lo", ifname
, IFNAMSIZ
))
960 panic("lo is not supported!\n");
961 if (device_mtu(ifname
) == 0)
962 panic("This is no networking device!\n");
963 register_signal(SIGINT
, signal_handler
);
964 register_signal(SIGHUP
, signal_handler
);
966 check_for_root_maybe_die();
967 ifflags
= enter_promiscuous_mode(ifname
);
969 ret
= main_loop(ifname
, interval
);
971 leave_promiscuous_mode(ifname
, ifflags
);