Warning message
[netsniff-ng.git] / src / netsniff-ng.c
blob6e384a3c979021a3a17933b4e4bc4ce97ef3fa7d
1 /* XXX: Coding Style - use the tool indent with the following (Linux kernel
2 * code indents)
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
9 * netsniff-ng
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
23 * for more details.
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
30 * order to use this.
33 #define _GNU_SOURCE
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <signal.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <assert.h>
45 #include <ctype.h>
46 #include <pthread.h>
47 #include <netsniff-ng.h>
49 #include <sys/un.h>
50 #include <sys/types.h>
51 #include <sys/poll.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>
62 * Global vars
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;
74 * Functions
77 /**
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;
87 netstat.t_elapsed++;
89 if (unlikely(netstat.t_elapsed % 60 == 0)) {
90 netstat.s_per_min.frames =
91 curr_weight * netstat.per_min.frames + (1.f -
92 curr_weight) *
93 netstat.s_per_min.frames;
94 netstat.s_per_min.bytes =
95 curr_weight * netstat.per_min.bytes + (1.f -
96 curr_weight) *
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 -
104 curr_weight) *
105 netstat.s_per_sec.frames;
106 netstat.s_per_sec.bytes =
107 curr_weight * netstat.per_sec.bytes + (1.f -
108 curr_weight) *
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);
133 d_sec = 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)
174 int ret;
175 int sock;
177 /* Signalmask is per thread. we don't want to interrupt the
178 send-syscall */
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);
187 if (ret < 0) {
188 perr("cannot send ring buffer stats - ");
191 pthread_mutex_unlock(&gs_loc_mutex);
193 close(sock);
195 dbg("unix domain socket server: quitting thread\n");
196 pthread_exit(0);
200 * start_uds_server - Unix Domain Socket server main
201 * @psockfile: path to UDS inode
203 void *start_uds_server(void *psockfile)
205 int ret, len;
206 int sock, sock2;
208 char *sockfile = (char *)psockfile;
210 pthread_t tid;
212 struct sockaddr_un local;
213 struct sockaddr_un remote;
215 sock = socket(AF_UNIX, SOCK_STREAM, 0);
216 if (sock < 0) {
217 perr("cannot create uds socket %d - ", errno);
218 pthread_exit(0);
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);
230 if (ret < 0) {
231 perr("cannot bind uds socket %d - ", errno);
232 pthread_exit(0);
235 ret = listen(sock, INTERNAL_UDS_QUEUE_LEN);
236 if (ret < 0) {
237 perr("cannot set up uds listening queue %d - ", errno);
238 pthread_exit(0);
241 while (1) {
242 size_t t = sizeof(remote);
243 dbg("unix domain socket server: waiting for a connection\n");
245 sock2 =
246 accept(sock, (struct sockaddr *)&remote, (socklen_t *) & t);
247 if (sock2 < 0) {
248 perr("cannot do accept on uds socket %d - ", errno);
249 pthread_exit(0);
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);
257 if (ret < 0) {
258 perr("uds server: error creating thread - ");
259 pthread_exit(0);
262 pthread_detach(tid);
265 dbg("unix domain socket server: quit\n");
266 pthread_exit(0);
270 * softirq_handler - Signal handling multiplexer
271 * @number: signal number
273 void softirq_handler(int number)
275 switch (number) {
276 case SIGALRM:
278 refresh_counters();
279 break;
281 case SIGUSR1:
283 print_counters();
284 break;
286 case SIGUSR2:
288 switch (++sigusr2 % 2) {
289 case 0:
291 print_packet_buffer =
292 print_packet_buffer_mode_1;
293 break;
295 case 1:
297 print_packet_buffer = NULL;
298 break;
300 default:
302 print_packet_buffer =
303 print_packet_buffer_mode_1;
304 break;
307 break;
309 case SIGINT:
311 sigint = 1;
312 dbg("caught SIGINT! ... bye bye\n");
313 break;
315 case SIGHUP:
317 dbg("caught SIGHUP! ... ignoring\n");
318 break;
320 default:
322 break;
328 * fetch_packets_and_print - Traverses RX_RING and prints content
329 * @rb: ring buffer
330 * @pfd: file descriptor for polling
332 void fetch_packets(ring_buff_t * rb, struct pollfd *pfd, int timeout)
334 int i = 0;
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
348 manipulation */
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
364 to drop packages */
365 mem_notify_kernel(&(fm->tp_h));
368 poll(pfd, 1, timeout);
373 * init_system - Initializes netsniff-ng main
374 * @sd: system configuration data
375 * @sock: socket
376 * @rb: ring buffer
377 * @pfd: file descriptor for polling
379 static int init_system(system_data_t * sd, int *sock, ring_buff_t ** rb,
380 struct pollfd *pfd)
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 ;) */
388 check_for_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);
402 if (sd->sysdaemon) {
403 ret =
404 daemonize(sd->pidfile, sd->logfile, sd->sockfile,
405 start_uds_server);
406 if (ret != 0) {
407 err("daemonize failed");
408 exit(EXIT_FAILURE);
412 /* Print program header */
413 header();
416 bpf = (struct sock_filter **)malloc(sizeof(*bpf));
417 if (bpf == NULL) {
418 perr("Cannot allocate socket filter\n");
419 exit(EXIT_FAILURE);
422 memset(bpf, 0, sizeof(**bpf));
424 (*rb) = (ring_buff_t *) malloc(sizeof(**rb));
425 if ((*rb) == NULL) {
426 perr("Cannot allocate ring buffer\n");
427 exit(EXIT_FAILURE);
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)); */
445 /* RX_RING stuff */
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);
461 if (ret < 0) {
462 perr("cannot set itimer - ");
463 exit(EXIT_FAILURE);
466 clock_gettime(CLOCK_REALTIME, &netstat.m_start);
469 free(*bpf);
470 free(bpf);
472 return 0;
476 * cleanup_system - Cleans up netsniff-ng main
477 * @sd: system configuration data
478 * @sock: socket
479 * @rb: ring buffer
481 static void cleanup_system(system_data_t * sd, int *sock, ring_buff_t ** rb)
483 net_stat((*sock));
484 destroy_virt_ring((*sock), (*rb));
486 free((*rb));
487 close((*sock));
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));
501 if (sd->sysdaemon) {
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)
513 int i, c;
514 int sock;
516 system_data_t *sd;
517 ring_buff_t *rb;
518 struct pollfd pfd;
520 sd = malloc(sizeof(*sd));
521 if (!sd) {
522 err("No mem left!\n");
523 exit(EXIT_FAILURE);
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) {
533 switch (c) {
534 case 'h':
536 help();
537 break;
539 case 'v':
541 version();
542 break;
544 case 'd':
546 sd->dev = optarg;
547 break;
549 case 'n':
551 sd->blocking_mode = 0;
552 break;
554 case 'H':
556 sd->no_prioritization = 1;
557 break;
559 case 'f':
561 dbg("XXX: Berkeley Packet Filter currently not supported\ndue to Linux kernel bug.\n\n")
562 sd->rulefile = optarg;
563 break;
565 case 's':
567 /* Switch to silent mode */
568 print_packet_buffer = NULL;
569 break;
571 case 'D':
573 sd->sysdaemon = 1;
574 break;
576 case 'P':
578 sd->pidfile = optarg;
579 break;
581 case 'L':
583 sd->logfile = optarg;
584 break;
586 case 'S':
588 sd->sockfile = optarg;
589 break;
591 case 'b':
593 set_cpu_affinity(optarg);
594 break;
596 case 'B':
598 set_cpu_affinity_inv(optarg);
599 break;
602 case '?':
604 switch (optopt) {
605 case 'd':
606 case 'f':
607 case 'P':
608 case 'L':
609 case 'S':
610 case 'b':
611 case 'B':
613 fprintf(stderr,
614 "option -%c requires an argument\n",
615 optopt);
616 break;
618 default:
620 if (isprint(optopt)) {
621 fprintf(stderr,
622 "unknown option character `0x%X\'\n",
623 optopt);
625 break;
629 return 1;
631 default:
633 abort();
638 if (argc < 2 || !sd->dev || !sd->rulefile) {
639 help();
640 exit(EXIT_FAILURE);
643 if (sd->sysdaemon && (!sd->pidfile || !sd->logfile || !sd->sockfile)) {
644 help();
645 exit(EXIT_FAILURE);
648 for (i = optind; i < argc; ++i) {
649 err("non-option argument %s\n", argv[i]);
652 if (optind < argc) {
653 exit(EXIT_FAILURE);
657 * Main stuff
660 init_system(sd, &sock, &rb, &pfd);
661 fetch_packets(rb, &pfd, sd->blocking_mode);
662 cleanup_system(sd, &sock, &rb);
664 free(sd);
665 return 0;