1 /* XXX: Coding Style - use the tool indent with the following (Linux kernel
4 * indent -nbad -bap -nbc -bbo -hnl -br -brs -c33 -cd33 -ncdb -ce -ci4 \
5 * -cli0 -d0 -di1 -nfc1 -i8 -ip0 -l120 -lp -npcs -nprs -npsl -sai \
6 * -saf -saw -ncs -nsc -sob -nfca -cp33 -ss -ts8 -il1
11 * High performance network sniffer for packet inspection
13 * Copyright (C) 2009, 2010 Daniel Borkmann <danborkmann@googlemail.com> and
14 * Emmanuel Roullit <emmanuel.roullit@googlemail.com>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or (at
19 * your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
30 * Note: Your kernel has to be compiled with CONFIG_PACKET_MMAP=y option in
49 #include <netsniff-ng.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
55 #include <sys/ioctl.h>
57 #include <sys/types.h>
60 #include <netsniff-ng/misc.h>
61 #include <netsniff-ng/system.h>
62 #include <netsniff-ng/rx_ring.h>
63 #include <netsniff-ng/signal.h>
64 #include <netsniff-ng/macros.h>
65 #include <netsniff-ng/types.h>
66 #include <netsniff-ng/print.h>
67 #include <netsniff-ng/dump.h>
68 #include <netsniff-ng/netdev.h>
69 #include <netsniff-ng/bpf.h>
75 volatile sig_atomic_t sigint
= 0;
76 volatile sig_atomic_t sigusr2
= 0;
78 ring_buff_stat_t netstat
;
79 pthread_mutex_t gs_loc_mutex
;
81 print_packet_buff_t print_packet_buffer
= versatile_print
;
88 * refresh_counters - Refreshes global packet counters
90 static inline void refresh_counters(void)
92 float curr_weight
= 0.68f
;
94 netstat
.per_min
.frames
+= netstat
.per_sec
.frames
;
95 netstat
.per_min
.bytes
+= netstat
.per_sec
.bytes
;
99 if (unlikely(netstat
.t_elapsed
% 60 == 0)) {
100 netstat
.s_per_min
.frames
=
101 curr_weight
* netstat
.per_min
.frames
+ (1.f
- curr_weight
) * netstat
.s_per_min
.frames
;
102 netstat
.s_per_min
.bytes
=
103 curr_weight
* netstat
.per_min
.bytes
+ (1.f
- curr_weight
) * netstat
.s_per_min
.bytes
;
105 netstat
.per_min
.frames
= netstat
.per_min
.bytes
= 0;
108 netstat
.s_per_sec
.frames
=
109 curr_weight
* netstat
.per_sec
.frames
+ (1.f
- curr_weight
) * netstat
.s_per_sec
.frames
;
110 netstat
.s_per_sec
.bytes
= curr_weight
* netstat
.per_sec
.bytes
+ (1.f
- curr_weight
) * netstat
.s_per_sec
.bytes
;
112 netstat
.per_sec
.frames
= netstat
.per_sec
.bytes
= 0;
116 * print_counters - Prints global counters to terminal
118 static inline void print_counters(void)
120 uint64_t d_day
, d_h
, d_min
, d_sec
, d_nsec
;
122 struct timespec t_curr
, diff
;
124 clock_gettime(CLOCK_REALTIME
, &t_curr
);
126 timespec_subtract(&diff
, &t_curr
, &netstat
.m_start
);
128 d_day
= DIV_S2DAYS(diff
.tv_sec
);
129 diff
.tv_sec
= MOD_DAYS2S(diff
.tv_sec
);
130 d_h
= DIV_S2HOURS(diff
.tv_sec
);
131 diff
.tv_sec
= MOD_HOURS2S(diff
.tv_sec
);
132 d_min
= DIV_S2MINUT(diff
.tv_sec
);
133 diff
.tv_sec
= MOD_MINUT2S(diff
.tv_sec
);
135 d_nsec
= diff
.tv_nsec
;
138 * FIXME Find a way to print a uint64_t
139 * on 32 and 64 bit arch w/o gcc warnings
141 info("stats summary:\n");
142 info("--------------------------------------------------------------------------------------------\n");
143 info("elapsed time: %llu d, %llu h, %llu min, %llu s, %llu ns\n", d_day
, d_h
, d_min
, d_sec
, d_nsec
);
144 info("-----------+--------------------------+--------------------------+--------------------------\n");
145 info(" | per sec | per min | total \n");
146 info("-----------+--------------------------+--------------------------+--------------------------\n");
147 info(" frames | %24llu | %24llu | %24llu \n",
148 netstat
.s_per_sec
.frames
, netstat
.s_per_min
.frames
, netstat
.total
.frames
);
149 info("-----------+--------------------------+--------------------------+--------------------------\n");
150 info(" in B | %24llu | %24llu | %24llu \n",
151 netstat
.s_per_sec
.bytes
, netstat
.s_per_min
.bytes
, netstat
.total
.bytes
);
152 info(" in KB | %24llu | %24llu | %24llu \n",
153 DIV_KBYTES(netstat
.s_per_sec
.bytes
), DIV_KBYTES(netstat
.s_per_min
.bytes
), DIV_KBYTES(netstat
.total
.bytes
));
154 info(" in MB | %24llu | %24llu | %24llu \n",
155 DIV_MBYTES(netstat
.s_per_sec
.bytes
), DIV_MBYTES(netstat
.s_per_min
.bytes
), DIV_MBYTES(netstat
.total
.bytes
));
156 info(" in GB | %24llu | %24llu | %24llu \n",
157 DIV_GBYTES(netstat
.s_per_sec
.bytes
), DIV_GBYTES(netstat
.s_per_min
.bytes
), DIV_GBYTES(netstat
.total
.bytes
));
158 info("-----------+--------------------------+--------------------------+--------------------------\n");
162 * uds_thread - Unix Domain Socket thread for sending internal counter states
163 * @psock: socket pointer
165 static void *uds_thread(void *psock
)
172 /* Signalmask is per thread. we don't want to interrupt the
174 hold_softirq_pthread(2, SIGUSR1
, SIGALRM
);
176 info("unix domain socket server: entering thread\n");
177 sock
= *((int *)psock
);
179 pthread_mutex_lock(&gs_loc_mutex
);
181 ret
= send(sock
, &netstat
, sizeof(netstat
), 0);
183 perr("cannot send ring buffer stats - ");
186 pthread_mutex_unlock(&gs_loc_mutex
);
190 info("unix domain socket server: quitting thread\n");
195 * start_uds_server - Unix Domain Socket server main
196 * @psockfile: path to UDS inode
198 void *start_uds_server(void *psockfile
)
203 char *sockfile
= (char *)psockfile
;
207 struct sockaddr_un local
;
208 struct sockaddr_un remote
;
212 sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
214 perr("cannot create uds socket %d - ", errno
);
218 local
.sun_family
= AF_UNIX
;
219 strncpy(local
.sun_path
, sockfile
, sizeof(local
.sun_path
));
221 if (unlink(local
.sun_path
) != 0) {
222 perr("cannot unlink %s\n", local
.sun_path
);
226 info("bind socket to %s\n", local
.sun_path
);
228 ret
= bind(sock
, (struct sockaddr
*)&local
, sizeof(local
));
230 perr("cannot bind uds socket %d - ", errno
);
234 ret
= listen(sock
, INTERNAL_UDS_QUEUE_LEN
);
236 perr("cannot set up uds listening queue %d - ", errno
);
241 size_t t
= sizeof(remote
);
242 info("unix domain socket server: waiting for a connection\n");
244 sock2
= accept(sock
, (struct sockaddr
*)&remote
, (socklen_t
*) & t
);
246 perr("cannot do accept on uds socket %d - ", errno
);
250 info("unix domain socket server: connected to client\n");
252 /* We're not interested in joining...
253 so a single thread id is sufficient */
254 ret
= pthread_create(&tid
, NULL
, uds_thread
, &sock2
);
256 perr("uds server: error creating thread - ");
263 info("unix domain socket server: quit\n");
268 * softirq_handler - Signal handling multiplexer
269 * @number: signal number
271 void softirq_handler(int number
)
286 switch (++sigusr2
% 2) {
289 print_packet_buffer
= versatile_print
;
294 print_packet_buffer
= NULL
;
299 print_packet_buffer
= versatile_print
;
308 info("caught SIGINT! ... bye bye\n");
313 info("caught SIGHUP! ... ignoring\n");
324 * fetch_packets_and_print - Traverses RX_RING and prints content
326 * @pfd: file descriptor for polling
328 void fetch_packets(ring_buff_t
* rb
, struct pollfd
*pfd
, int timeout
, FILE * pcap
, int packet_type
, int sock
)
335 /* This is our critical path ... */
336 while (likely(!sigint
)) {
337 while (mem_notify_user_for_rx(rb
->frames
[i
]) && likely(!sigint
)) {
338 struct frame_map
*fm
= rb
->frames
[i
].iov_base
;
339 ring_buff_bytes_t
*rbb
=
340 (ring_buff_bytes_t
*) (rb
->frames
[i
].iov_base
+ sizeof(*fm
) + sizeof(short));
342 /* Check if the user wants to have a specific
344 if (packet_type
!= PACKET_DONT_CARE
) {
345 if (fm
->s_ll
.sll_pkttype
!= packet_type
) {
346 goto __out_notify_kernel
;
351 pcap_dump(pcap
, &fm
->tp_h
, (struct ethhdr
*)rbb
);
354 if (print_packet_buffer
) {
355 /* This path here slows us down ... well, but
356 the user wants to see what's going on */
357 print_packet_buffer(rbb
, &fm
->tp_h
);
360 /* Pending singals will be delivered after netstat
362 hold_softirq(2, SIGUSR1
, SIGALRM
);
363 pthread_mutex_lock(&gs_loc_mutex
);
365 netstat
.per_sec
.frames
++;
366 netstat
.per_sec
.bytes
+= fm
->tp_h
.tp_len
;
368 netstat
.total
.frames
++;
369 netstat
.total
.bytes
+= fm
->tp_h
.tp_len
;
371 pthread_mutex_unlock(&gs_loc_mutex
);
372 restore_softirq(2, SIGUSR1
, SIGALRM
);
375 i
= (i
+ 1) % rb
->layout
.tp_frame_nr
;
378 /* This is very important, otherwise kernel starts
380 mem_notify_kernel_for_rx(&(fm
->tp_h
));
383 while ((ret
= poll(pfd
, 1, timeout
)) <= 0)
386 if (ret
> 0 && (pfd
->revents
& (POLLHUP
| POLLRDHUP
| POLLERR
| POLLNVAL
))) {
387 if (pfd
->revents
& (POLLHUP
| POLLRDHUP
)) {
388 err("Hangup on socket occured.\n\n");
390 } else if (pfd
->revents
& POLLERR
) {
391 /* recv is more specififc on the error */
393 if (recv(sock
, &foo
, sizeof(foo
), MSG_PEEK
) != -1)
394 goto __out_grab_frame
; /* Hmm... no error */
395 if (errno
== ENETDOWN
) {
396 err("Interface went down\n\n");
398 err("%s\n\n", strerror(errno
));
401 } else if (pfd
->revents
& POLLNVAL
) {
402 err("Invalid polling request on socket.\n\n");
408 /* Look-ahead if current frame is status kernel, otherwise we have
409 have incoming frames and poll spins / hangs all the time :( */
410 for (; ((struct tpacket_hdr
*)rb
->frames
[i
].iov_base
)->tp_status
411 != TP_STATUS_USER
; i
= (i
+ 1) % rb
->layout
.tp_frame_nr
)
413 /* Why this should be okay:
414 1) Current frame[i] is TP_STATUS_USER:
415 This is our original case that occurs without
417 2) Current frame[i] is not TP_STATUS_USER:
418 poll returns correctly with return value 1 (number of
419 file descriptors), so an event has occured which has
420 to be POLLIN since all error conditions have been
421 caught previously. Furthermore, during ring traversal
422 a frame that has been set to TP_STATUS_USER will be
423 given back to kernel on finish with TP_STATUS_KERNEL.
424 So, if we look ahead all skipped frames are not ready
425 for user access. Since the kernel decides to put
426 frames, which are 'behind' our pointer, into
427 TP_STATUS_USER we do one loop and return at the
428 correct position after passing the for loop again. If
429 we grab frame which are 'in front of' our pointer
430 we'll fetch them within the first for loop.
436 * init_system - Initializes netsniff-ng main
437 * @sd: system configuration data
440 * @pfd: file descriptor for polling
442 static int init_system(system_data_t
* sd
, int *sock
, ring_buff_t
** rb
, struct pollfd
*pfd
)
444 int stmp
, i
, ret
, bpf_len
= 0;
447 struct sock_filter
*bpf
= NULL
;
449 struct ifreq
*ifr
= NULL
;
450 struct ifreq
*ifr_elem
= NULL
;
451 struct itimerval val_r
;
458 /* We are only allowed to do these nasty things as root ;) */
461 /* Scheduler timeslice & prio tuning */
462 if (!sd
->no_prioritization
) {
463 set_proc_prio(DEFAULT_PROCESS_PRIO
);
464 set_sched_status(DEFAULT_SCHED_POLICY
, DEFAULT_SCHED_PRIO
);
467 register_softirq(SIGINT
, &softirq_handler
);
468 register_softirq(SIGALRM
, &softirq_handler
);
469 register_softirq(SIGUSR1
, &softirq_handler
);
470 register_softirq(SIGUSR2
, &softirq_handler
);
471 register_softirq(SIGHUP
, &softirq_handler
);
474 ret
= daemonize(sd
->pidfile
, sd
->logfile
, sd
->sockfile
, start_uds_server
);
476 err("daemonize failed");
481 /* Print program header */
484 (*rb
) = (ring_buff_t
*) malloc(sizeof(**rb
));
486 perr("Cannot allocate ring buffer\n");
490 memset((*rb
), 0, sizeof(**rb
));
492 /* User didn't specify a device, so we switch to the default running
493 dev. This is the first running dev found (except lo). If we find
494 nothing, we switch to lo. */
496 sd
->dev
= strdup("lo");
498 perror("Cannot allocate mem");
502 stmp
= socket(AF_INET
, SOCK_DGRAM
, 0);
508 ifc
.ifc_len
= sizeof(dev_buff
);
509 ifc
.ifc_buf
= dev_buff
;
511 if (ioctl(stmp
, SIOCGIFCONF
, &ifc
) < 0) {
512 perror("ioctl(SIOCGIFCONF)");
518 for (i
= 0; i
< ifc
.ifc_len
/ sizeof(struct ifreq
); ++i
) {
521 if (ioctl(stmp
, SIOCGIFFLAGS
, ifr_elem
) < 0) {
522 perror("ioctl(SIOCGIFFLAGS)");
526 if ((ifr_elem
->ifr_flags
& IFF_UP
) &&
527 (ifr_elem
->ifr_flags
& IFF_RUNNING
) && strncmp(ifr_elem
->ifr_name
, "lo", IFNAMSIZ
)) {
528 sd
->dev
= strdup(ifr_elem
->ifr_name
);
530 perror("Cannot allocate mem");
539 info("No device specified, using `%s`.\n\n", sd
->dev
);
542 (*sock
) = alloc_pf_sock();
543 put_dev_into_promisc_mode((*sock
), ethdev_to_ifindex((*sock
), sd
->dev
));
545 if (sd
->bypass_bpf
== BPF_NO_BYPASS
) {
546 /* XXX: If you try to create custom filters with tcpdump, you
547 have to edit the ret opcode, otherwise your payload
548 will be cut off at 96 Byte:
550 { 0x6, 0, 0, 0xFFFFFFFF },
552 The kernel now takes skb->len instead of 0xFFFFFFFF ;)
555 /* Berkeley Packet Filter stuff */
556 parse_rules(sd
->rulefile
, &bpf
, &bpf_len
);
557 inject_kernel_bpf((*sock
), bpf
, bpf_len
* sizeof(*bpf
));
559 /* Print info for the user */
560 bpf_dump_all(bpf
, bpf_len
);
562 info("No filter applied. Sniffing all traffic.\n\n");
566 create_virt_rx_ring((*sock
), (*rb
), sd
->dev
);
567 bind_dev_to_rx_ring((*sock
), ethdev_to_ifindex((*sock
), sd
->dev
), (*rb
));
568 mmap_virt_rx_ring((*sock
), (*rb
));
570 alloc_frame_buffer((*rb
));
571 prepare_polling((*sock
), pfd
);
573 memset(&netstat
, 0, sizeof(netstat
));
575 /* Timer settings for counter update */
576 val_r
.it_value
.tv_sec
= (INTERVAL_COUNTER_REFR
/ 1000);
577 val_r
.it_value
.tv_usec
= (INTERVAL_COUNTER_REFR
* 1000) % 1000000;
578 val_r
.it_interval
= val_r
.it_value
;
580 ret
= setitimer(ITIMER_REAL
, &val_r
, NULL
);
582 perr("cannot set itimer - ");
586 clock_gettime(CLOCK_REALTIME
, &netstat
.m_start
);
588 info("--- Listening ---\n\n");
595 * cleanup_system - Cleans up netsniff-ng main
596 * @sd: system configuration data
600 static void cleanup_system(system_data_t
* sd
, int *sock
, ring_buff_t
** rb
)
608 destroy_virt_rx_ring((*sock
), (*rb
));
614 * FIXME Find a way to print a uint64_t
615 * on 32 and 64 bit arch w/o gcc warnings
618 info("captured frames: %llu, "
619 "captured bytes: %llu [%llu KiB, %llu MiB, %llu GiB]\n",
620 netstat
.total
.frames
, netstat
.total
.bytes
,
621 netstat
.total
.bytes
/ 1024,
622 netstat
.total
.bytes
/ (1024 * 1024), netstat
.total
.bytes
/ (1024 * 1024 * 1024));
627 undaemonize(sd
->pidfile
);
632 * main - Main routine
633 * @argc: number of args
634 * @argv: arguments passed from tty
636 int main(int argc
, char **argv
)
638 FILE *dump_pcap
= NULL
;
646 static struct option long_options
[] = {
647 {"dev", required_argument
, 0, 'd'},
648 {"dump", required_argument
, 0, 'p'},
649 {"replay", required_argument
, 0, 'r'},
650 {"quit-after", required_argument
, 0, 'q'},
651 {"generate", required_argument
, 0, 'g'},
652 {"type", required_argument
, 0, 't'},
653 {"filter", required_argument
, 0, 'f'},
654 {"bind-cpu", required_argument
, 0, 'b'},
655 {"unbind-cpu", required_argument
, 0, 'B'},
656 {"prio-norm", no_argument
, 0, 'H'},
657 {"non-block", no_argument
, 0, 'n'},
658 {"no-color", no_argument
, 0, 'N'},
659 {"silent", no_argument
, 0, 's'},
660 {"daemonize", no_argument
, 0, 'D'},
661 {"pidfile", required_argument
, 0, 'P'},
662 {"logfile", required_argument
, 0, 'L'},
663 {"sockfile", required_argument
, 0, 'S'},
664 {"version", no_argument
, 0, 'v'},
665 {"help", no_argument
, 0, 'h'},
669 sd
= malloc(sizeof(*sd
));
671 err("No mem left!\n");
675 memset(sd
, 0, sizeof(*sd
));
676 memset(&pfd
, 0, sizeof(pfd
));
678 /* Some default sys configuration */
679 sd
->blocking_mode
= POLL_WAIT_INF
;
680 sd
->bypass_bpf
= BPF_BYPASS
;
681 sd
->packet_type
= PACKET_DONT_CARE
;
683 while ((c
= getopt_long(argc
, argv
, "vhd:p:P:L:Df:sS:b:B:Hnt:", long_options
, &opt_idx
)) != EOF
) {
697 sd
->dev
= strdup(optarg
);
699 perror("Cannot allocate mem");
706 sd
->blocking_mode
= POLL_WAIT_NONE
;
711 sd
->no_prioritization
= PROC_NO_HIGHPRIO
;
716 if (!strncmp(optarg
, "host", strlen("host"))) {
717 sd
->packet_type
= PACKET_HOST
;
718 } else if (!strncmp(optarg
, "broadcast", strlen("broadcast"))) {
719 sd
->packet_type
= PACKET_BROADCAST
;
720 } else if (!strncmp(optarg
, "multicast", strlen("multicast"))) {
721 sd
->packet_type
= PACKET_MULTICAST
;
722 } else if (!strncmp(optarg
, "others", strlen("others"))) {
723 sd
->packet_type
= PACKET_OTHERHOST
;
724 } else if (!strncmp(optarg
, "outgoing", strlen("outgoing"))) {
725 sd
->packet_type
= PACKET_OUTGOING
;
727 sd
->packet_type
= PACKET_DONT_CARE
;
733 sd
->bypass_bpf
= BPF_NO_BYPASS
;
734 sd
->rulefile
= optarg
;
739 /* Switch to silent mode */
740 print_packet_buffer
= NULL
;
745 sd
->sysdaemon
= SYSD_ENABLE
;
750 sd
->pidfile
= optarg
;
755 sd
->logfile
= optarg
;
760 sd
->sockfile
= optarg
;
765 set_cpu_affinity(optarg
);
770 set_cpu_affinity_inv(optarg
);
775 if ((dump_pcap
= fopen(optarg
, "w+")) == NULL
) {
776 perr("Can't open file: ");
780 sf_write_header(dump_pcap
, LINKTYPE_EN10MB
, 0, PCAP_DEFAULT_SNAPSHOT_LEN
);
796 fprintf(stderr
, "Option -%c requires an argument!\n", optopt
);
801 if (isprint(optopt
)) {
802 fprintf(stderr
, "Unknown option character `0x%X\'!\n", optopt
);
817 if (sd
->sysdaemon
&& (!sd
->pidfile
|| !sd
->logfile
|| !sd
->sockfile
)) {
822 for (i
= optind
; i
< argc
; ++i
) {
823 err("Non-option argument %s!\n", argv
[i
]);
834 init_system(sd
, &sock
, &rb
, &pfd
);
835 fetch_packets(rb
, &pfd
, sd
->blocking_mode
, dump_pcap
, sd
->packet_type
, sock
);
836 cleanup_system(sd
, &sock
, &rb
);
838 if (dump_pcap
!= NULL
) {