added poll support to rxtx
[netsniff-ng.git] / src / netsniff-ng.c
blob7ed17a317f7cb8630ece79f1720cca567d9d2f02
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2009-2011 Daniel Borkmann.
5 * Copyright 2010 Emmanuel Roullit.
6 * Subject to the GPL.
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <signal.h>
12 #include <getopt.h>
13 #include <ctype.h>
14 #include <time.h>
15 #include <string.h>
16 #include <sys/socket.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/time.h>
20 #include <unistd.h>
21 #include <stdbool.h>
22 #include <pthread.h>
23 #include <fcntl.h>
25 #include "rx_ring.h"
26 #include "tx_ring.h"
27 #include "netdev.h"
28 #include "compiler.h"
29 #include "pcap.h"
30 #include "poll.h"
31 #include "bpf.h"
32 #include "version.h"
33 #include "signals.h"
34 #include "write_or_die.h"
35 #include "die.h"
36 #include "opt_memcpy.h"
37 #include "tprintf.h"
38 #include "dissector.h"
39 #include "xmalloc.h"
40 #include "psched.h"
41 #include "misc.h"
42 #include "mtrand.h"
44 #define CPU_UNKNOWN -1
45 #define CPU_NOTOUCH -2
46 #define PACKET_ALL -1
48 struct mode {
49 char *device_in;
50 char *device_out;
51 char *filter;
52 int cpu;
53 int dump;
54 /* dissector */
55 int link_type;
56 int print_mode;
57 /* 0 for automatic, > 0 for manual */
58 unsigned int reserve_size;
59 int packet_type;
60 bool randomize;
61 bool promiscuous;
62 enum pcap_ops_groups pcap;
63 unsigned long kpull;
66 struct tx_stats {
67 unsigned long tx_bytes;
68 unsigned long tx_packets;
71 static sig_atomic_t sigint = 0;
73 static unsigned long interval = TX_KERNEL_PULL_INT;
74 static int tx_sock;
75 static struct itimerval itimer;
77 static const char *short_options = "d:i:o:rf:Mt:S:k:b:B:HQmcsqlxCXNvh";
79 static struct option long_options[] = {
80 {"dev", required_argument, 0, 'd'},
81 {"in", required_argument, 0, 'i'},
82 {"out", required_argument, 0, 'o'},
83 {"randomize", no_argument, 0, 'r'},
84 {"mmap", no_argument, 0, 'm'},
85 {"clrw", no_argument, 0, 'c'},
86 {"filter", required_argument, 0, 'f'},
87 {"no-promisc", no_argument, 0, 'M'},
88 {"type", required_argument, 0, 't'},
89 {"ring-size", required_argument, 0, 'S'},
90 {"kernel-pull", required_argument, 0, 'k'},
91 {"bind-cpu", required_argument, 0, 'b'},
92 {"unbind-cpu", required_argument, 0, 'B'},
93 {"prio-high", no_argument, 0, 'H'},
94 {"notouch-irq", no_argument, 0, 'Q'},
95 {"silent", no_argument, 0, 's'},
96 {"less", no_argument, 0, 'q'},
97 {"payload", no_argument, 0, 'l'},
98 {"payload-hex", no_argument, 0, 'x'},
99 {"c-style", no_argument, 0, 'C'},
100 {"all-hex", no_argument, 0, 'X'},
101 {"no-payload", no_argument, 0, 'N'},
102 {"version", no_argument, 0, 'v'},
103 {"help", no_argument, 0, 'h'},
104 {0, 0, 0, 0}
107 static void signal_handler(int number)
109 switch (number) {
110 case SIGINT:
111 sigint = 1;
112 break;
113 case SIGHUP:
114 break;
115 default:
116 break;
120 static void timer_elapsed(int number)
122 itimer.it_interval.tv_sec = 0;
123 itimer.it_interval.tv_usec = interval;
124 itimer.it_value.tv_sec = 0;
125 itimer.it_value.tv_usec = interval;
127 pull_and_flush_tx_ring(tx_sock);
128 setitimer(ITIMER_REAL, &itimer, NULL);
131 void enter_mode_pcap_to_tx(struct mode *mode)
133 int irq, ifindex, fd = 0, ret;
134 unsigned int size, it = 0;
135 struct ring tx_ring;
136 struct frame_map *hdr;
137 struct sock_fprog bpf_ops;
138 struct tx_stats stats;
139 uint8_t *out = NULL;
141 set_memcpy();
142 tx_sock = pf_socket();
144 if (!pcap_ops[mode->pcap])
145 panic("pcap group not supported!\n");
146 fd = open_or_die(mode->device_in, O_RDONLY);
147 ret = pcap_ops[mode->pcap]->pull_file_header(fd);
148 if (ret)
149 panic("error reading pcap header!\n");
150 if (pcap_ops[mode->pcap]->prepare_reading_pcap) {
151 ret = pcap_ops[mode->pcap]->prepare_reading_pcap(fd);
152 if (ret)
153 panic("error prepare reading pcap!\n");
156 memset(&tx_ring, 0, sizeof(tx_ring));
157 memset(&bpf_ops, 0, sizeof(bpf_ops));
158 memset(&stats, 0, sizeof(stats));
160 ifindex = device_ifindex(mode->device_out);
161 size = ring_size(mode->device_out, mode->reserve_size);
163 bpf_parse_rules(mode->filter, &bpf_ops);
165 set_packet_loss_discard(tx_sock);
166 setup_tx_ring_layout(tx_sock, &tx_ring, size);
167 create_tx_ring(tx_sock, &tx_ring);
168 mmap_tx_ring(tx_sock, &tx_ring);
169 alloc_tx_ring_frames(&tx_ring);
170 bind_tx_ring(tx_sock, &tx_ring, ifindex);
172 dissector_init_all(mode->print_mode);
174 if (mode->cpu >= 0 && ifindex > 0) {
175 irq = device_irq_number(mode->device_out);
176 device_bind_irq_to_cpu(mode->cpu, irq);
177 printf("IRQ: %s:%d > CPU%d\n", mode->device_out, irq,
178 mode->cpu);
181 if (mode->kpull)
182 interval = mode->kpull;
184 itimer.it_interval.tv_sec = 0;
185 itimer.it_interval.tv_usec = interval;
186 itimer.it_value.tv_sec = 0;
187 itimer.it_value.tv_usec = interval;
188 setitimer(ITIMER_REAL, &itimer, NULL);
190 printf("BPF:\n");
191 bpf_dump_all(&bpf_ops);
192 printf("MD: TX %luus %s\n\n", interval, pcap_ops[mode->pcap]->name);
194 while (likely(sigint == 0)) {
195 while (user_may_pull_from_tx(tx_ring.frames[it].iov_base)) {
196 struct pcap_pkthdr phdr;
197 hdr = tx_ring.frames[it].iov_base;
198 /* Kernel assumes: data = ph.raw + po->tp_hdrlen -
199 * sizeof(struct sockaddr_ll); */
200 out = ((uint8_t *) hdr) + TPACKET_HDRLEN -
201 sizeof(struct sockaddr_ll);
203 do {
204 ret = pcap_ops[mode->pcap]->read_pcap_pkt(fd, &phdr,
205 out, ring_frame_size(&tx_ring));
206 if (unlikely(ret <= 0))
207 goto out;
208 } while (mode->filter && !bpf_run_filter(&bpf_ops, out, phdr.len));
209 pcap_pkthdr_to_tpacket_hdr(&phdr, &hdr->tp_h);
211 stats.tx_bytes += hdr->tp_h.tp_len;;
212 stats.tx_packets++;
214 show_frame_hdr(hdr, mode->print_mode, RING_MODE_EGRESS);
215 dissector_entry_point(out, hdr->tp_h.tp_snaplen,
216 mode->link_type);
218 kernel_may_pull_from_tx(&hdr->tp_h);
219 next_slot(&it, &tx_ring);
221 if (unlikely(sigint == 1))
222 break;
225 out:
226 fflush(stdout);
227 printf("\n");
228 printf("\r%lu frames outgoing\n", stats.tx_packets);
229 printf("\r%lu bytes outgoing\n", stats.tx_bytes);
231 dissector_cleanup_all();
232 destroy_tx_ring(tx_sock, &tx_ring);
234 close(tx_sock);
235 if (pcap_ops[mode->pcap]->prepare_close_pcap)
236 pcap_ops[mode->pcap]->prepare_close_pcap(fd);
237 close(fd);
240 /* If netsniff-ngs in device is on a tap, it can efficiently filter out
241 * some interesting packets and give them to the out device for testing
242 * or debugging for instance. */
243 void enter_mode_rx_to_tx(struct mode *mode)
245 int rx_sock, ifindex_in, ifindex_out;
246 unsigned int size_in, size_out, it_in = 0, it_out = 0;
247 uint8_t *in, *out;
248 short ifflags = 0;
249 struct frame_map *hdr_in, *hdr_out;
250 struct ring tx_ring;
251 struct ring rx_ring;
252 struct pollfd rx_poll;
253 struct sock_fprog bpf_ops;
255 if (!strncmp(mode->device_in, mode->device_out,
256 strlen(mode->device_in)))
257 panic("Ingress/egress devices must be different!\n");
259 set_memcpy();
260 rx_sock = pf_socket();
261 tx_sock = pf_socket();
263 memset(&tx_ring, 0, sizeof(tx_ring));
264 memset(&rx_ring, 0, sizeof(rx_ring));
265 memset(&rx_poll, 0, sizeof(rx_poll));
266 memset(&bpf_ops, 0, sizeof(bpf_ops));
268 ifindex_in = device_ifindex(mode->device_in);
269 size_in = ring_size(mode->device_in, mode->reserve_size);
271 ifindex_out = device_ifindex(mode->device_in);
272 size_out = ring_size(mode->device_in, mode->reserve_size);
274 bpf_parse_rules(mode->filter, &bpf_ops);
275 bpf_attach_to_sock(rx_sock, &bpf_ops);
277 setup_rx_ring_layout(rx_sock, &rx_ring, size_in);
278 create_rx_ring(rx_sock, &rx_ring);
279 mmap_rx_ring(rx_sock, &rx_ring);
280 alloc_rx_ring_frames(&rx_ring);
281 bind_rx_ring(rx_sock, &rx_ring, ifindex_in);
282 prepare_polling(rx_sock, &rx_poll);
284 set_packet_loss_discard(tx_sock);
285 setup_tx_ring_layout(tx_sock, &tx_ring, size_out);
286 create_tx_ring(tx_sock, &tx_ring);
287 mmap_tx_ring(tx_sock, &tx_ring);
288 alloc_tx_ring_frames(&tx_ring);
289 bind_tx_ring(tx_sock, &tx_ring, ifindex_out);
291 mt_init_by_seed_time();
292 dissector_init_all(mode->print_mode);
294 if (mode->promiscuous == true) {
295 ifflags = enter_promiscuous_mode(mode->device_in);
296 printf("PROMISC\n");
299 if (mode->kpull)
300 interval = mode->kpull;
302 itimer.it_interval.tv_sec = 0;
303 itimer.it_interval.tv_usec = interval;
304 itimer.it_value.tv_sec = 0;
305 itimer.it_value.tv_usec = interval;
306 setitimer(ITIMER_REAL, &itimer, NULL);
308 printf("BPF:\n");
309 bpf_dump_all(&bpf_ops);
310 printf("MD: RXTX %luus\n\n", interval);
311 printf("Running! Hang up with ^C!\n\n");
313 while (likely(sigint == 0)) {
314 while (user_may_pull_from_rx(rx_ring.frames[it_in].iov_base)) {
315 hdr_in = rx_ring.frames[it_in].iov_base;
316 in = ((uint8_t *) hdr_in) + hdr_in->tp_h.tp_mac;
317 if (mode->packet_type != PACKET_ALL)
318 if (mode->packet_type != hdr_in->s_ll.sll_pkttype)
319 goto next;
321 hdr_out = tx_ring.frames[it_out].iov_base;
322 out = ((uint8_t *) hdr_out) + TPACKET_HDRLEN -
323 sizeof(struct sockaddr_ll);
325 /* If we cannot pull, look for a different slot. */
326 for (; !user_may_pull_from_tx(tx_ring.frames[it_out].iov_base) &&
327 likely(!sigint);) {
328 if (mode->randomize)
329 next_rnd_slot(&it_out, &tx_ring);
330 else
331 next_slot(&it_out, &tx_ring);
332 hdr_out = tx_ring.frames[it_out].iov_base;
333 out = ((uint8_t *) hdr_out) + TPACKET_HDRLEN -
334 sizeof(struct sockaddr_ll);
337 tpacket_hdr_clone(&hdr_out->tp_h, &hdr_in->tp_h);
338 __memcpy(out, in, hdr_in->tp_h.tp_len);
340 kernel_may_pull_from_tx(&hdr_out->tp_h);
341 if (mode->randomize)
342 next_rnd_slot(&it_out, &tx_ring);
343 else
344 next_slot(&it_out, &tx_ring);
346 /* Should actually be avoided ... */
347 show_frame_hdr(hdr_in, mode->print_mode, RING_MODE_INGRESS);
348 dissector_entry_point(in, hdr_in->tp_h.tp_snaplen,
349 mode->link_type);
350 next:
351 kernel_may_pull_from_rx(&hdr_in->tp_h);
352 next_slot(&it_in, &rx_ring);
354 if (unlikely(sigint == 1))
355 goto out;
358 poll(&rx_poll, 1, -1);
359 poll_error_maybe_die(rx_sock, &rx_poll);
361 out:
362 sock_print_net_stats(rx_sock);
364 dissector_cleanup_all();
365 destroy_tx_ring(tx_sock, &tx_ring);
366 destroy_rx_ring(rx_sock, &rx_ring);
368 if (mode->promiscuous == true)
369 leave_promiscuous_mode(mode->device_in, ifflags);
371 close(tx_sock);
372 close(rx_sock);
375 void enter_mode_read_pcap(struct mode *mode)
377 int ret, fd;
378 struct pcap_pkthdr phdr;
379 struct sock_fprog bpf_ops;
380 struct tx_stats stats;
381 struct frame_map fm;
382 uint8_t *out;
383 size_t out_len;
385 if (!pcap_ops[mode->pcap])
386 panic("pcap group not supported!\n");
387 fd = open_or_die(mode->device_in, O_RDONLY);
388 ret = pcap_ops[mode->pcap]->pull_file_header(fd);
389 if (ret)
390 panic("error reading pcap header!\n");
391 if (pcap_ops[mode->pcap]->prepare_reading_pcap) {
392 ret = pcap_ops[mode->pcap]->prepare_reading_pcap(fd);
393 if (ret)
394 panic("error prepare reading pcap!\n");
397 memset(&fm, 0, sizeof(fm));
398 memset(&bpf_ops, 0, sizeof(bpf_ops));
399 memset(&stats, 0, sizeof(stats));
401 bpf_parse_rules(mode->filter, &bpf_ops);
402 dissector_init_all(mode->print_mode);
404 out_len = 15000;
405 out = xmalloc(out_len);
407 printf("BPF:\n");
408 bpf_dump_all(&bpf_ops);
409 printf("MD: RD %s\n\n", pcap_ops[mode->pcap]->name);
411 while (likely(sigint == 0)) {
412 do {
413 ret = pcap_ops[mode->pcap]->read_pcap_pkt(fd, &phdr,
414 out, out_len);
415 if (unlikely(ret <= 0))
416 goto out;
417 } while (mode->filter && !bpf_run_filter(&bpf_ops, out, phdr.len));
418 pcap_pkthdr_to_tpacket_hdr(&phdr, &fm.tp_h);
420 stats.tx_bytes += fm.tp_h.tp_len;;
421 stats.tx_packets++;
423 show_frame_hdr(&fm, mode->print_mode, RING_MODE_EGRESS);
424 dissector_entry_point(out, fm.tp_h.tp_snaplen,
425 mode->link_type);
427 out:
428 fflush(stdout);
429 printf("\n");
430 printf("\r%lu frames outgoing\n", stats.tx_packets);
431 printf("\r%lu bytes outgoing\n", stats.tx_bytes);
433 xfree(out);
434 dissector_cleanup_all();
435 if (pcap_ops[mode->pcap]->prepare_close_pcap)
436 pcap_ops[mode->pcap]->prepare_close_pcap(fd);
437 close(fd);
440 void enter_mode_rx_only_or_dump(struct mode *mode)
442 int sock, irq, ifindex, fd = 0, ret;
443 unsigned int size, it = 0;
444 short ifflags = 0;
445 uint8_t *packet;
446 struct ring rx_ring;
447 struct pollfd rx_poll;
448 struct frame_map *hdr;
449 struct sock_fprog bpf_ops;
451 set_memcpy();
452 sock = pf_socket();
454 if (mode->dump) {
455 if (!pcap_ops[mode->pcap])
456 panic("pcap group not supported!\n");
457 fd = open_or_die_m(mode->device_out,
458 O_RDWR | O_CREAT | O_TRUNC,
459 S_IRUSR | S_IWUSR);
460 ret = pcap_ops[mode->pcap]->push_file_header(fd);
461 if (ret)
462 panic("error writing pcap header!\n");
465 memset(&rx_ring, 0, sizeof(rx_ring));
466 memset(&rx_poll, 0, sizeof(rx_poll));
467 memset(&bpf_ops, 0, sizeof(bpf_ops));
469 ifindex = device_ifindex(mode->device_in);
470 size = ring_size(mode->device_in, mode->reserve_size);
472 bpf_parse_rules(mode->filter, &bpf_ops);
473 bpf_attach_to_sock(sock, &bpf_ops);
475 setup_rx_ring_layout(sock, &rx_ring, size);
476 create_rx_ring(sock, &rx_ring);
477 mmap_rx_ring(sock, &rx_ring);
478 alloc_rx_ring_frames(&rx_ring);
479 bind_rx_ring(sock, &rx_ring, ifindex);
481 prepare_polling(sock, &rx_poll);
482 dissector_init_all(mode->print_mode);
484 if (mode->cpu >= 0 && ifindex > 0) {
485 irq = device_irq_number(mode->device_in);
486 device_bind_irq_to_cpu(mode->cpu, irq);
487 printf("IRQ: %s:%d > CPU%d\n", mode->device_in, irq,
488 mode->cpu);
491 if (mode->promiscuous == true) {
492 ifflags = enter_promiscuous_mode(mode->device_in);
493 printf("PROMISC\n");
496 printf("BPF:\n");
497 bpf_dump_all(&bpf_ops);
498 printf("MD: RX %s\n\n", mode->dump ? pcap_ops[mode->pcap]->name : "");
500 while (likely(sigint == 0)) {
501 while (user_may_pull_from_rx(rx_ring.frames[it].iov_base)) {
502 hdr = rx_ring.frames[it].iov_base;
503 packet = ((uint8_t *) hdr) + hdr->tp_h.tp_mac;
505 if (mode->packet_type != PACKET_ALL)
506 if (mode->packet_type != hdr->s_ll.sll_pkttype)
507 goto next;
509 if (mode->dump) {
510 struct pcap_pkthdr phdr;
511 tpacket_hdr_to_pcap_pkthdr(&hdr->tp_h, &phdr);
512 ret = pcap_ops[mode->pcap]->write_pcap_pkt(fd, &phdr,
513 packet, phdr.len);
514 if (unlikely(ret != sizeof(phdr) + phdr.len))
515 panic("Write error to pcap!\n");
518 show_frame_hdr(hdr, mode->print_mode, RING_MODE_INGRESS);
519 dissector_entry_point(packet, hdr->tp_h.tp_snaplen,
520 mode->link_type);
521 next:
522 kernel_may_pull_from_rx(&hdr->tp_h);
523 next_slot(&it, &rx_ring);
525 if (unlikely(sigint == 1))
526 break;
529 poll(&rx_poll, 1, -1);
530 poll_error_maybe_die(sock, &rx_poll);
533 sock_print_net_stats(sock);
535 dissector_cleanup_all();
536 destroy_rx_ring(sock, &rx_ring);
538 if (mode->promiscuous == true)
539 leave_promiscuous_mode(mode->device_in, ifflags);
541 close(sock);
542 if (mode->dump) {
543 pcap_ops[mode->pcap]->fsync_pcap(fd);
544 if (pcap_ops[mode->pcap]->prepare_close_pcap)
545 pcap_ops[mode->pcap]->prepare_close_pcap(fd);
546 close(fd);
550 static void help(void)
552 printf("\n%s %s, the packet sniffing beast\n", PROGNAME_STRING,
553 VERSION_STRING);
554 printf("http://www.netsniff-ng.org\n\n");
555 printf("Usage: netsniff-ng [options]\n");
556 printf("Options for input/output:\n");
557 printf(" -i|-d|--dev|--in <dev|pcap> Input source as netdev or pcap\n");
558 printf(" -o|--out <dev|pcap> Output source as netdev or pcap\n");
559 printf(" -r|--randomize Randomize packet forwarding order\n");
560 printf(" -f|--filter <bpf-file> Use BPF filter rule from file\n");
561 printf(" -M|--no-promisc No promiscuous mode for netdev\n");
562 printf(" -t|--type <type> Only handle packets of defined type:\n");
563 printf(" host|broadcast|multicast|others|outgoing\n");
564 printf(" -m|--mmap Mmap pcap file, otherwise use scatter/gather I/O\n");
565 printf(" -c|--clrw Instead scatter/gather I/O use read/write I/O\n");
566 printf(" -S|--ring-size <size> Manually set ring size to <size>:\n");
567 printf(" mmap space in KB/MB/GB, e.g. \'10MB\'\n");
568 printf(" -k|--kernel-pull <int> Kernel pull from user interval in us\n");
569 printf(" Default is 10us where the TX_RING\n");
570 printf(" is populated with payload from uspace\n");
571 printf(" -b|--bind-cpu <cpu> Bind to specific CPU or CPU-range\n");
572 printf(" -B|--unbind-cpu <cpu> Forbid to use specific CPU or CPU-range\n");
573 printf(" -H|--prio-high Make this high priorize process\n");
574 printf(" -Q|--notouch-irq Do not touch IRQ CPU affinity of NIC\n");
575 printf(" -s|--silent Do not print captured packets\n");
576 printf(" -q|--less Print less-verbose packet information\n");
577 printf(" -l|--payload Only print human-readable payload\n");
578 printf(" -x|--payload-hex Only print payload in hex format\n");
579 printf(" -C|--c-style Print full packet in C style hex format\n");
580 printf(" -X|--all-hex Print packets in hex format\n");
581 printf(" -N|--no-payload Only print packet header\n");
582 printf(" -v|--version Show version\n");
583 printf(" -h|--help Show this help\n");
584 printf("\n");
585 printf("Examples:\n");
586 printf(" netsniff-ng --in eth0 --out dump.pcap --silent --bind-cpu 0\n");
587 printf(" netsniff-ng --in dump.pcap --mmap --out eth0 --silent --bind-cpu 0\n");
588 printf(" netsniff-ng --in dump.pcap --no-payload\n");
589 printf(" netsniff-ng --in eth0 --out eth1 --silent --randomize --bind-cpu 0\n");
590 printf(" netsniff-ng --in any --filter icmp.bpf\n");
591 printf(" netsniff-ng --dev wlan0 --prio-norm --all-hex --type outgoing\n");
592 printf("\n");
593 printf("Note:\n");
594 printf(" This tool is targeted for network developers! You should\n");
595 printf(" be aware of what you are doing and what these options above\n");
596 printf(" mean!\n");
597 printf("\n");
598 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
599 printf("Copyright (C) 2009-2011 Daniel Borkmann <daniel@netsniff-ng.org>\n");
600 printf("Copyright (C) 2009-2011 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n");
601 printf("License: GNU GPL version 2\n");
602 printf("This is free software: you are free to change and redistribute it.\n");
603 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
605 die();
608 static void version(void)
610 printf("\n%s %s, the packet sniffing beast\n", PROGNAME_STRING,
611 VERSION_STRING);
612 printf("http://www.netsniff-ng.org\n\n");
613 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
614 printf("Copyright (C) 2009-2011 Daniel Borkmann <daniel@netsniff-ng.org>\n");
615 printf("Copyright (C) 2009-2011 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n");
616 printf("License: GNU GPL version 2\n");
617 printf("This is free software: you are free to change and redistribute it.\n");
618 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
620 die();
623 static void header(void)
625 printf("%s%s%s\n", colorize_start(bold), PROGNAME_STRING " "
626 VERSION_STRING, colorize_end());
629 int main(int argc, char **argv)
631 int c, i, j, opt_index;
632 char *ptr;
633 bool prio_high = false;
634 struct mode mode;
635 void (*enter_mode)(struct mode *mode) = NULL;
637 check_for_root_maybe_die();
639 memset(&mode, 0, sizeof(mode));
640 mode.link_type = LINKTYPE_EN10MB;
641 mode.print_mode = FNTTYPE_PRINT_NORM;
642 mode.cpu = CPU_UNKNOWN;
643 mode.packet_type = PACKET_ALL;
644 mode.promiscuous = true;
645 mode.randomize = false;
646 mode.pcap = PCAP_OPS_SG;
648 while ((c = getopt_long(argc, argv, short_options, long_options,
649 &opt_index)) != EOF) {
650 switch (c) {
651 case 'd':
652 case 'i':
653 mode.device_in = xstrdup(optarg);
654 break;
655 case 'o':
656 mode.device_out = xstrdup(optarg);
657 break;
658 case 'r':
659 mode.randomize = true;
660 break;
661 case 'f':
662 mode.filter = xstrdup(optarg);
663 break;
664 case 'M':
665 mode.promiscuous = false;
666 break;
667 case 't':
668 if (!strncmp(optarg, "host", strlen("host")))
669 mode.packet_type = PACKET_HOST;
670 else if (!strncmp(optarg, "broadcast", strlen("broadcast")))
671 mode.packet_type = PACKET_BROADCAST;
672 else if (!strncmp(optarg, "multicast", strlen("multicast")))
673 mode.packet_type = PACKET_MULTICAST;
674 else if (!strncmp(optarg, "others", strlen("others")))
675 mode.packet_type = PACKET_OTHERHOST;
676 else if (!strncmp(optarg, "outgoing", strlen("outgoing")))
677 mode.packet_type = PACKET_OUTGOING;
678 else
679 mode.packet_type = PACKET_ALL;
680 break;
681 case 'S':
682 ptr = optarg;
683 mode.reserve_size = 0;
685 for (j = i = strlen(optarg); i > 0; --i) {
686 if (!isdigit(optarg[j - i]))
687 break;
688 ptr++;
691 if (!strncmp(ptr, "KB", strlen("KB")))
692 mode.reserve_size = 1 << 10;
693 else if (!strncmp(ptr, "MB", strlen("MB")))
694 mode.reserve_size = 1 << 20;
695 else if (!strncmp(ptr, "GB", strlen("GB")))
696 mode.reserve_size = 1 << 30;
697 else
698 panic("Syntax error in ring size param!\n");
700 *ptr = 0;
701 mode.reserve_size *= atoi(optarg);
702 break;
703 case 'b':
704 set_cpu_affinity(optarg, 0);
705 if (mode.cpu != CPU_NOTOUCH)
706 mode.cpu = atoi(optarg);
707 break;
708 case 'B':
709 set_cpu_affinity(optarg, 1);
710 break;
711 case 'H':
712 prio_high = true;
713 break;
714 case 'c':
715 mode.pcap = PCAP_OPS_RW;
716 break;
717 case 'm':
718 mode.pcap = PCAP_OPS_MMAP;
719 break;
720 case 'Q':
721 mode.cpu = CPU_NOTOUCH;
722 break;
723 case 's':
724 mode.print_mode = FNTTYPE_PRINT_NONE;
725 break;
726 case 'q':
727 mode.print_mode = FNTTYPE_PRINT_LESS;
728 break;
729 case 'l':
730 mode.print_mode = FNTTYPE_PRINT_CHR1;
731 break;
732 case 'x':
733 mode.print_mode = FNTTYPE_PRINT_HEX1;
734 break;
735 case 'C':
736 mode.print_mode = FNTTYPE_PRINT_PAAC;
737 break;
738 case 'X':
739 mode.print_mode = FNTTYPE_PRINT_HEX2;
740 break;
741 case 'N':
742 mode.print_mode = FNTTYPE_PRINT_NOPA;
743 break;
744 case 'k':
745 mode.kpull = atol(optarg);
746 break;
747 case 'v':
748 version();
749 break;
750 case 'h':
751 help();
752 break;
753 case '?':
754 switch (optopt) {
755 case 'd':
756 case 'i':
757 case 'o':
758 case 'f':
759 case 't':
760 case 'S':
761 case 'b':
762 case 'k':
763 case 'B':
764 case 'e':
765 panic("Option -%c requires an argument!\n",
766 optopt);
767 default:
768 if (isprint(optopt))
769 whine("Unknown option character "
770 "`0x%X\'!\n", optopt);
771 die();
773 default:
774 break;
778 if (!mode.device_in)
779 mode.device_in = xstrdup("any");
781 register_signal(SIGINT, signal_handler);
782 register_signal(SIGHUP, signal_handler);
783 register_signal(SIGUSR1, signal_handler);
784 register_signal(SIGSEGV, muntrace_handler);
785 register_signal_f(SIGALRM, timer_elapsed, SA_SIGINFO);
787 init_pcap();
788 tprintf_init();
789 header();
791 if (prio_high == true) {
792 set_proc_prio(DEFAULT_PROCESS_PRIO);
793 set_sched_status(DEFAULT_SCHED_POLICY, DEFAULT_SCHED_PRIO);
796 if (mode.device_in && (device_mtu(mode.device_in) ||
797 !strncmp("any", mode.device_in, strlen(mode.device_in)))) {
798 if (!mode.device_out) {
799 mode.dump = 0;
800 enter_mode = enter_mode_rx_only_or_dump;
801 } else if (device_mtu(mode.device_out))
802 enter_mode = enter_mode_rx_to_tx;
803 else {
804 mode.dump = 1;
805 enter_mode = enter_mode_rx_only_or_dump;
807 } else {
808 if (mode.device_out && device_mtu(mode.device_out))
809 enter_mode = enter_mode_pcap_to_tx;
810 else
811 enter_mode = enter_mode_read_pcap;
814 if (!enter_mode)
815 panic("Selection not supported!\n");
816 enter_mode(&mode);
818 tprintf_cleanup();
819 cleanup_pcap();
821 if (mode.device_in)
822 xfree(mode.device_in);
823 if (mode.device_out)
824 xfree(mode.device_out);
825 return 0;