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 -l80 -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>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or (at
18 * your option) any later version.
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
29 * Note: Your kernel has to be compiled with CONFIG_PACKET_MMAP=y option in
47 #include <netsniff-ng.h>
50 #include <sys/types.h>
53 #include <netsniff-ng/misc.h>
54 #include <netsniff-ng/system.h>
55 #include <netsniff-ng/rx_ring.h>
56 #include <netsniff-ng/signal.h>
57 #include <netsniff-ng/macros.h>
58 #include <netsniff-ng/types.h>
59 #include <netsniff-ng/print.h>
65 volatile sig_atomic_t sigint
= 0;
66 volatile sig_atomic_t sigusr2
= 0;
68 ring_buff_stat_t netstat
;
69 pthread_mutex_t gs_loc_mutex
;
71 print_packet_buff_t print_packet_buffer
= print_packet_buffer_mode_1
;
78 * refresh_counters - Refreshes global packet counters
80 static inline void refresh_counters(void)
82 float curr_weight
= 0.68f
;
84 netstat
.per_min
.frames
+= netstat
.per_sec
.frames
;
85 netstat
.per_min
.bytes
+= netstat
.per_sec
.bytes
;
89 if (unlikely(netstat
.t_elapsed
% 60 == 0)) {
90 netstat
.s_per_min
.frames
=
91 curr_weight
* netstat
.per_min
.frames
+ (1.f
-
93 netstat
.s_per_min
.frames
;
94 netstat
.s_per_min
.bytes
=
95 curr_weight
* netstat
.per_min
.bytes
+ (1.f
-
97 netstat
.s_per_min
.bytes
;
99 netstat
.per_min
.frames
= netstat
.per_min
.bytes
= 0;
102 netstat
.s_per_sec
.frames
=
103 curr_weight
* netstat
.per_sec
.frames
+ (1.f
-
105 netstat
.s_per_sec
.frames
;
106 netstat
.s_per_sec
.bytes
=
107 curr_weight
* netstat
.per_sec
.bytes
+ (1.f
-
109 netstat
.s_per_sec
.bytes
;
111 netstat
.per_sec
.frames
= netstat
.per_sec
.bytes
= 0;
115 * print_counters - Prints global counters to terminal
117 static inline void print_counters(void)
119 uint64_t d_day
, d_h
, d_min
, d_sec
, d_nsec
;
121 struct timespec t_curr
, diff
;
123 clock_gettime(CLOCK_REALTIME
, &t_curr
);
125 timespec_subtract(&diff
, &t_curr
, &netstat
.m_start
);
127 d_day
= DIV_S2DAYS(diff
.tv_sec
);
128 diff
.tv_sec
= MOD_DAYS2S(diff
.tv_sec
);
129 d_h
= DIV_S2HOURS(diff
.tv_sec
);
130 diff
.tv_sec
= MOD_HOURS2S(diff
.tv_sec
);
131 d_min
= DIV_S2MINUT(diff
.tv_sec
);
132 diff
.tv_sec
= MOD_MINUT2S(diff
.tv_sec
);
134 d_nsec
= diff
.tv_nsec
;
137 * FIXME Find a way to print a uint64_t
138 * on 32 and 64 bit arch w/o gcc warnings
140 dbg("stats summary:\n");
141 dbg("--------------------------------------------------------------------------------------------\n");
142 dbg("elapsed time: %llu d, %llu h, %llu min, %llu s, %llu ns\n", d_day
,
143 d_h
, d_min
, d_sec
, d_nsec
);
144 dbg("-----------+--------------------------+--------------------------+--------------------------\n");
145 dbg(" | per sec | per min | total \n");
146 dbg("-----------+--------------------------+--------------------------+--------------------------\n");
147 dbg(" frames | %24llu | %24llu | %24llu \n",
148 netstat
.s_per_sec
.frames
, netstat
.s_per_min
.frames
,
149 netstat
.total
.frames
);
150 dbg("-----------+--------------------------+--------------------------+--------------------------\n");
151 dbg(" in B | %24llu | %24llu | %24llu \n", netstat
.s_per_sec
.bytes
,
152 netstat
.s_per_min
.bytes
, netstat
.total
.bytes
);
153 dbg(" in KB | %24llu | %24llu | %24llu \n",
154 DIV_KBYTES(netstat
.s_per_sec
.bytes
),
155 DIV_KBYTES(netstat
.s_per_min
.bytes
),
156 DIV_KBYTES(netstat
.total
.bytes
));
157 dbg(" in MB | %24llu | %24llu | %24llu \n",
158 DIV_MBYTES(netstat
.s_per_sec
.bytes
),
159 DIV_MBYTES(netstat
.s_per_min
.bytes
),
160 DIV_MBYTES(netstat
.total
.bytes
));
161 dbg(" in GB | %24llu | %24llu | %24llu \n",
162 DIV_GBYTES(netstat
.s_per_sec
.bytes
),
163 DIV_GBYTES(netstat
.s_per_min
.bytes
),
164 DIV_GBYTES(netstat
.total
.bytes
));
165 dbg("-----------+--------------------------+--------------------------+--------------------------\n");
169 * uds_thread - Unix Domain Socket thread for sending internal counter states
170 * @psock: socket pointer
172 static void *uds_thread(void *psock
)
177 /* Signalmask is per thread. we don't want to interrupt the
179 hold_softirq_pthread(2, SIGUSR1
, SIGALRM
);
181 dbg("unix domain socket server: entering thread\n");
182 sock
= *((int *)psock
);
184 pthread_mutex_lock(&gs_loc_mutex
);
186 ret
= send(sock
, &netstat
, sizeof(netstat
), 0);
188 perr("cannot send ring buffer stats - ");
191 pthread_mutex_unlock(&gs_loc_mutex
);
195 dbg("unix domain socket server: quitting thread\n");
200 * start_uds_server - Unix Domain Socket server main
201 * @psockfile: path to UDS inode
203 void *start_uds_server(void *psockfile
)
208 char *sockfile
= (char *)psockfile
;
212 struct sockaddr_un local
;
213 struct sockaddr_un remote
;
215 sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
217 perr("cannot create uds socket %d - ", errno
);
221 local
.sun_family
= AF_UNIX
;
222 strncpy(local
.sun_path
, sockfile
, sizeof(local
.sun_path
));
223 unlink(local
.sun_path
);
225 len
= strlen(local
.sun_path
) + sizeof(local
.sun_family
);
227 dbg("bind socket to %s\n", local
.sun_path
);
229 ret
= bind(sock
, (struct sockaddr
*)&local
, len
);
231 perr("cannot bind uds socket %d - ", errno
);
235 ret
= listen(sock
, INTERNAL_UDS_QUEUE_LEN
);
237 perr("cannot set up uds listening queue %d - ", errno
);
242 size_t t
= sizeof(remote
);
243 dbg("unix domain socket server: waiting for a connection\n");
246 accept(sock
, (struct sockaddr
*)&remote
, (socklen_t
*) & t
);
248 perr("cannot do accept on uds socket %d - ", errno
);
252 dbg("unix domain socket server: connected to client\n");
254 /* We're not interested in joining...
255 so a single thread id is sufficient */
256 ret
= pthread_create(&tid
, NULL
, uds_thread
, &sock2
);
258 perr("uds server: error creating thread - ");
265 dbg("unix domain socket server: quit\n");
270 * softirq_handler - Signal handling multiplexer
271 * @number: signal number
273 void softirq_handler(int number
)
288 switch (++sigusr2
% 2) {
291 print_packet_buffer
=
292 print_packet_buffer_mode_1
;
297 print_packet_buffer
= NULL
;
302 print_packet_buffer
=
303 print_packet_buffer_mode_1
;
312 dbg("caught SIGINT! ... bye bye\n");
317 dbg("caught SIGHUP! ... ignoring\n");
328 * fetch_packets_and_print - Traverses RX_RING and prints content
330 * @pfd: file descriptor for polling
332 void fetch_packets(ring_buff_t
* rb
, struct pollfd
*pfd
, int timeout
)
336 while (likely(!sigint
)) {
337 while (mem_notify_user(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
+
341 sizeof(*fm
) + sizeof(short));
343 if (print_packet_buffer
) {
344 print_packet_buffer(rbb
, &fm
->tp_h
);
347 /* Pending singals will be delivered after netstat
349 hold_softirq(2, SIGUSR1
, SIGALRM
);
350 pthread_mutex_lock(&gs_loc_mutex
);
352 netstat
.per_sec
.frames
++;
353 netstat
.per_sec
.bytes
+= fm
->tp_h
.tp_len
;
355 netstat
.total
.frames
++;
356 netstat
.total
.bytes
+= fm
->tp_h
.tp_len
;
358 pthread_mutex_unlock(&gs_loc_mutex
);
359 restore_softirq(2, SIGUSR1
, SIGALRM
);
361 i
= (i
+ 1) % rb
->layout
.tp_frame_nr
;
363 /* This is very important, otherwise kernel starts
365 mem_notify_kernel(&(fm
->tp_h
));
368 poll(pfd
, 1, timeout
);
373 * init_system - Initializes netsniff-ng main
374 * @sd: system configuration data
377 * @pfd: file descriptor for polling
379 static int init_system(system_data_t
* sd
, int *sock
, ring_buff_t
** rb
,
382 int ret
/*, bpf_len = 0 */ ;
384 /* struct sock_filter **bpf; */
385 struct itimerval val_r
;
387 /* We are only allowed to do these nasty things as root ;) */
390 /* Scheduler timeslice & prio tuning */
391 if (!sd
->no_prioritization
) {
392 set_proc_prio(DEFAULT_PROCESS_PRIO
);
393 set_sched_status(DEFAULT_SCHED_POLICY
, DEFAULT_SCHED_PRIO
);
396 register_softirq(SIGINT
, &softirq_handler
);
397 register_softirq(SIGALRM
, &softirq_handler
);
398 register_softirq(SIGUSR1
, &softirq_handler
);
399 register_softirq(SIGUSR2
, &softirq_handler
);
400 register_softirq(SIGHUP
, &softirq_handler
);
404 daemonize(sd
->pidfile
, sd
->logfile
, sd
->sockfile
,
407 err("daemonize failed");
412 /* Print program header */
416 bpf = (struct sock_filter **)malloc(sizeof(*bpf));
418 perr("Cannot allocate socket filter\n");
422 memset(bpf, 0, sizeof(**bpf));
424 (*rb
) = (ring_buff_t
*) malloc(sizeof(**rb
));
426 perr("Cannot allocate ring buffer\n");
430 memset((*rb
), 0, sizeof(**rb
));
432 (*sock
) = alloc_pf_sock();
433 put_dev_into_promisc_mode((*sock
), ethdev_to_ifindex((*sock
), sd
->dev
));
435 /* FIXME: Somehow there seems to be a bug within the Linux kernel.
436 If we do attach a packet filter to the socket the receiving
437 message will be cut off at some length... if we do not
438 attach a packet filter everything will be fine and all of the
439 package payload will be shown. */
441 /* Berkeley Packet Filter stuff
442 parse_rules(sd->rulefile, bpf, &bpf_len);
443 inject_kernel_bpf((*sock), *bpf, bpf_len * sizeof(**bpf)); */
446 create_virt_ring((*sock
), (*rb
));
447 bind_dev_to_ring((*sock
), ethdev_to_ifindex((*sock
), sd
->dev
), (*rb
));
448 mmap_virt_ring((*sock
), (*rb
));
450 alloc_frame_buffer((*rb
));
451 prepare_polling((*sock
), pfd
);
453 memset(&netstat
, 0, sizeof(netstat
));
455 /* Timer settings for counter update */
456 val_r
.it_value
.tv_sec
= (INTERVAL_COUNTER_REFR
/ 1000);
457 val_r
.it_value
.tv_usec
= (INTERVAL_COUNTER_REFR
* 1000) % 1000000;
458 val_r
.it_interval
= val_r
.it_value
;
460 ret
= setitimer(ITIMER_REAL
, &val_r
, NULL
);
462 perr("cannot set itimer - ");
466 clock_gettime(CLOCK_REALTIME
, &netstat
.m_start
);
476 * cleanup_system - Cleans up netsniff-ng main
477 * @sd: system configuration data
481 static void cleanup_system(system_data_t
* sd
, int *sock
, ring_buff_t
** rb
)
484 destroy_virt_ring((*sock
), (*rb
));
490 * FIXME Find a way to print a uint64_t
491 * on 32 and 64 bit arch w/o gcc warnings
494 dbg("captured frames: %llu, "
495 "captured bytes: %llu [%llu KB, %llu MB, %llu GB]\n",
496 netstat
.total
.frames
, netstat
.total
.bytes
,
497 netstat
.total
.bytes
/ 1024,
498 netstat
.total
.bytes
/ (1024 * 1024),
499 netstat
.total
.bytes
/ (1024 * 1024 * 1024));
502 undaemonize(sd
->pidfile
);
507 * main - Main routine
508 * @argc: number of args
509 * @argv: arguments passed from tty
511 int main(int argc
, char **argv
)
520 sd
= malloc(sizeof(*sd
));
522 err("No mem left!\n");
526 memset(sd
, 0, sizeof(*sd
));
527 memset(&pfd
, 0, sizeof(pfd
));
529 /* Default sys configuration */
530 sd
->blocking_mode
= -1;
532 while ((c
= getopt(argc
, argv
, "vhd:P:L:Df:sS:b:B:Hn")) != EOF
) {
551 sd
->blocking_mode
= 0;
556 sd
->no_prioritization
= 1;
561 dbg("XXX: Berkeley Packet Filter currently not supported\ndue to Linux kernel bug.\n\n")
562 sd
->rulefile
= optarg
;
567 /* Switch to silent mode */
568 print_packet_buffer
= NULL
;
578 sd
->pidfile
= optarg
;
583 sd
->logfile
= optarg
;
588 sd
->sockfile
= optarg
;
593 set_cpu_affinity(optarg
);
598 set_cpu_affinity_inv(optarg
);
614 "option -%c requires an argument\n",
620 if (isprint(optopt
)) {
622 "unknown option character `0x%X\'\n",
638 if (argc
< 2 || !sd
->dev
|| !sd
->rulefile
) {
643 if (sd
->sysdaemon
&& (!sd
->pidfile
|| !sd
->logfile
|| !sd
->sockfile
)) {
648 for (i
= optind
; i
< argc
; ++i
) {
649 err("non-option argument %s\n", argv
[i
]);
660 init_system(sd
, &sock
, &rb
, &pfd
);
661 fetch_packets(rb
, &pfd
, sd
->blocking_mode
);
662 cleanup_system(sd
, &sock
, &rb
);