src: setfsuid / setfsgid
[netsniff-ng.git] / src / netsniff-ng.c
blob25390d6bb4e1ef21c4ccf0dfe5fcfff2a5a836e6
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2009-2013 Daniel Borkmann.
5 * Copyright 2010 Emmanuel Roullit.
6 * Subject to the GPL, version 2.
8 * The first sniffer that invoked both, the zero-copy RX_RING as well as
9 * the zero-copy TX_RING for high-performance network I/O and scatter/gather
10 * or mmaped PCAP I/O.
12 * "I knew that danger lay ahead, of course; but I did not expect to
13 * meet it in our own Shire. Can't a hobbit walk from the Water to the
14 * River in peace?" "But it is not your own Shire," said Gildor. "Others
15 * dwelt here before hobbits were; and others will dwell here again when
16 * hobbits are no more. The wide world is all about you: you can fence
17 * yourselves in, but you cannot for ever fence it out."
19 * -- The Lord of the Rings, Gildor to Frodo,
20 * Chapter 'Three is Company'.
23 #define _GNU_SOURCE
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <signal.h>
27 #include <getopt.h>
28 #include <ctype.h>
29 #include <time.h>
30 #include <string.h>
31 #include <sys/socket.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <sys/fsuid.h>
36 #include <unistd.h>
37 #include <stdbool.h>
38 #include <pthread.h>
39 #include <fcntl.h>
41 #include "ring_rx.h"
42 #include "ring_tx.h"
43 #include "mac80211.h"
44 #include "xutils.h"
45 #include "built_in.h"
46 #include "pcap.h"
47 #include "bpf.h"
48 #include "xio.h"
49 #include "die.h"
50 #include "tprintf.h"
51 #include "dissector.h"
52 #include "xmalloc.h"
54 enum dump_mode {
55 DUMP_INTERVAL_TIME,
56 DUMP_INTERVAL_SIZE,
59 struct ctx {
60 char *device_in, *device_out, *device_trans, *filter, *prefix;
61 int cpu, rfraw, dump, print_mode, dump_dir, jumbo_support, packet_type, verbose;
62 unsigned long kpull, dump_interval, reserve_size, tx_bytes, tx_packets;
63 bool randomize, promiscuous;
64 enum pcap_ops_groups pcap;
65 enum dump_mode dump_mode;
66 uint32_t link_type;
69 volatile sig_atomic_t sigint = 0;
71 static volatile bool next_dump = false;
73 static const char *short_options = "d:i:o:rf:MJt:S:k:n:b:B:HQmcsqXlvhF:RgAP:V";
74 static const struct option long_options[] = {
75 {"dev", required_argument, NULL, 'd'},
76 {"in", required_argument, NULL, 'i'},
77 {"out", required_argument, NULL, 'o'},
78 {"filter", required_argument, NULL, 'f'},
79 {"num", required_argument, NULL, 'n'},
80 {"type", required_argument, NULL, 't'},
81 {"interval", required_argument, NULL, 'F'},
82 {"ring-size", required_argument, NULL, 'S'},
83 {"kernel-pull", required_argument, NULL, 'k'},
84 {"bind-cpu", required_argument, NULL, 'b'},
85 {"unbind-cpu", required_argument, NULL, 'B'},
86 {"prefix", required_argument, NULL, 'P'},
87 {"rand", no_argument, NULL, 'r'},
88 {"rfraw", no_argument, NULL, 'R'},
89 {"mmap", no_argument, NULL, 'm'},
90 {"sg", no_argument, NULL, 'g'},
91 {"clrw", no_argument, NULL, 'c'},
92 {"jumbo-support", no_argument, NULL, 'J'},
93 {"no-promisc", no_argument, NULL, 'M'},
94 {"prio-high", no_argument, NULL, 'H'},
95 {"notouch-irq", no_argument, NULL, 'Q'},
96 {"silent", no_argument, NULL, 's'},
97 {"less", no_argument, NULL, 'q'},
98 {"hex", no_argument, NULL, 'X'},
99 {"ascii", no_argument, NULL, 'l'},
100 {"no-sock-mem", no_argument, NULL, 'A'},
101 {"verbose", no_argument, NULL, 'V'},
102 {"version", no_argument, NULL, 'v'},
103 {"help", no_argument, NULL, 'h'},
104 {NULL, 0, NULL, 0}
107 static int tx_sock;
109 static struct itimerval itimer;
111 static unsigned long frame_count_max = 0, interval = TX_KERNEL_PULL_INT;
113 #define set_system_socket_memory(vals) \
114 do { \
115 if ((vals[0] = get_system_socket_mem(sock_rmem_max)) < SMEM_SUG_MAX) \
116 set_system_socket_mem(sock_rmem_max, SMEM_SUG_MAX); \
117 if ((vals[1] = get_system_socket_mem(sock_rmem_def)) < SMEM_SUG_DEF) \
118 set_system_socket_mem(sock_rmem_def, SMEM_SUG_DEF); \
119 if ((vals[2] = get_system_socket_mem(sock_wmem_max)) < SMEM_SUG_MAX) \
120 set_system_socket_mem(sock_wmem_max, SMEM_SUG_MAX); \
121 if ((vals[3] = get_system_socket_mem(sock_wmem_def)) < SMEM_SUG_DEF) \
122 set_system_socket_mem(sock_wmem_def, SMEM_SUG_DEF); \
123 } while (0)
125 #define reset_system_socket_memory(vals) \
126 do { \
127 set_system_socket_mem(sock_rmem_max, vals[0]); \
128 set_system_socket_mem(sock_rmem_def, vals[1]); \
129 set_system_socket_mem(sock_wmem_max, vals[2]); \
130 set_system_socket_mem(sock_wmem_def, vals[3]); \
131 } while (0)
133 #define __pcap_io pcap_ops[ctx->pcap]
135 static void signal_handler(int number)
137 switch (number) {
138 case SIGINT:
139 sigint = 1;
140 case SIGHUP:
141 default:
142 break;
146 static void timer_elapsed(int unused)
148 itimer.it_interval.tv_sec = 0;
149 itimer.it_interval.tv_usec = interval;
151 itimer.it_value.tv_sec = 0;
152 itimer.it_value.tv_usec = interval;
154 pull_and_flush_tx_ring(tx_sock);
155 setitimer(ITIMER_REAL, &itimer, NULL);
158 static void timer_next_dump(int unused)
160 itimer.it_interval.tv_sec = interval;
161 itimer.it_interval.tv_usec = 0;
163 itimer.it_value.tv_sec = interval;
164 itimer.it_value.tv_usec = 0;
166 next_dump = true;
167 setitimer(ITIMER_REAL, &itimer, NULL);
170 static inline bool dump_to_pcap(struct ctx *ctx)
172 return ctx->dump;
175 static void pcap_to_xmit(struct ctx *ctx)
177 __label__ out;
178 uint8_t *out = NULL;
179 int irq, ifindex, fd = 0, ret;
180 unsigned int size, it = 0;
181 unsigned long trunced = 0;
182 struct ring tx_ring;
183 struct frame_map *hdr;
184 struct sock_fprog bpf_ops;
185 struct timeval start, end, diff;
186 struct pcap_pkthdr phdr;
188 if (!device_up_and_running(ctx->device_out) && !ctx->rfraw)
189 panic("Device not up and running!\n");
191 bug_on(!__pcap_io);
193 tx_sock = pf_socket();
195 fd = open_or_die(ctx->device_in, O_RDONLY | O_LARGEFILE | O_NOATIME);
197 ret = __pcap_io->pull_file_header(fd, &ctx->link_type);
198 if (ret)
199 panic("Error reading pcap header!\n");
201 if (__pcap_io->prepare_reading_pcap) {
202 ret = __pcap_io->prepare_reading_pcap(fd);
203 if (ret)
204 panic("Error prepare reading pcap!\n");
207 fmemset(&tx_ring, 0, sizeof(tx_ring));
208 fmemset(&bpf_ops, 0, sizeof(bpf_ops));
210 if (ctx->rfraw) {
211 ctx->device_trans = xstrdup(ctx->device_out);
212 xfree(ctx->device_out);
214 enter_rfmon_mac80211(ctx->device_trans, &ctx->device_out);
215 if (ctx->link_type != LINKTYPE_IEEE802_11)
216 panic("Wrong linktype of pcap!\n");
219 ifindex = device_ifindex(ctx->device_out);
221 size = ring_size(ctx->device_out, ctx->reserve_size);
223 bpf_parse_rules(ctx->filter, &bpf_ops);
225 set_packet_loss_discard(tx_sock);
226 set_sockopt_hwtimestamp(tx_sock, ctx->device_out);
228 setup_tx_ring_layout(tx_sock, &tx_ring, size, ctx->jumbo_support);
229 create_tx_ring(tx_sock, &tx_ring, ctx->verbose);
230 mmap_tx_ring(tx_sock, &tx_ring);
231 alloc_tx_ring_frames(&tx_ring);
232 bind_tx_ring(tx_sock, &tx_ring, ifindex);
234 dissector_init_all(ctx->print_mode);
236 if (ctx->cpu >= 0 && ifindex > 0) {
237 irq = device_irq_number(ctx->device_out);
238 device_bind_irq_to_cpu(irq, ctx->cpu);
240 if (ctx->verbose)
241 printf("IRQ: %s:%d > CPU%d\n",
242 ctx->device_out, irq, ctx->cpu);
245 if (ctx->kpull)
246 interval = ctx->kpull;
248 if (ctx->verbose) {
249 printf("BPF:\n");
250 bpf_dump_all(&bpf_ops);
252 printf("MD: TX %luus %s ", interval, pcap_ops[ctx->pcap]->name);
253 if (ctx->rfraw)
254 printf("802.11 raw via %s ", ctx->device_out);
255 #ifdef _LARGEFILE64_SOURCE
256 printf("lf64 ");
257 #endif
258 ioprio_print();
259 printf("\n");
261 printf("Running! Hang up with ^C!\n\n");
262 fflush(stdout);
264 itimer.it_interval.tv_sec = 0;
265 itimer.it_interval.tv_usec = interval;
267 itimer.it_value.tv_sec = 0;
268 itimer.it_value.tv_usec = interval;
270 setitimer(ITIMER_REAL, &itimer, NULL);
272 bug_on(gettimeofday(&start, NULL));
274 while (likely(sigint == 0)) {
275 while (user_may_pull_from_tx(tx_ring.frames[it].iov_base)) {
276 hdr = tx_ring.frames[it].iov_base;
278 /* Kernel assumes: data = ph.raw + po->tp_hdrlen -
279 * sizeof(struct sockaddr_ll); */
280 out = ((uint8_t *) hdr) + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll);
282 do {
283 ret = __pcap_io->read_pcap_pkt(fd, &phdr, out,
284 ring_frame_size(&tx_ring));
285 if (unlikely(ret <= 0))
286 goto out;
288 if (ring_frame_size(&tx_ring) < phdr.len) {
289 phdr.len = ring_frame_size(&tx_ring);
290 trunced++;
292 } while (ctx->filter && !bpf_run_filter(&bpf_ops, out, phdr.len));
294 pcap_pkthdr_to_tpacket_hdr(&phdr, &hdr->tp_h);
296 ctx->tx_bytes += hdr->tp_h.tp_len;;
297 ctx->tx_packets++;
299 show_frame_hdr(hdr, ctx->print_mode, RING_MODE_EGRESS);
301 dissector_entry_point(out, hdr->tp_h.tp_snaplen,
302 ctx->link_type, ctx->print_mode);
304 kernel_may_pull_from_tx(&hdr->tp_h);
306 it++;
307 if (it >= tx_ring.layout.tp_frame_nr)
308 it = 0;
310 if (unlikely(sigint == 1))
311 break;
313 if (frame_count_max != 0) {
314 if (ctx->tx_packets >= frame_count_max) {
315 sigint = 1;
316 break;
322 out:
324 bug_on(gettimeofday(&end, NULL));
325 diff = tv_subtract(end, start);
327 bpf_release(&bpf_ops);
329 dissector_cleanup_all();
330 destroy_tx_ring(tx_sock, &tx_ring);
332 if (ctx->rfraw)
333 leave_rfmon_mac80211(ctx->device_trans, ctx->device_out);
335 if (__pcap_io->prepare_close_pcap)
336 __pcap_io->prepare_close_pcap(fd, PCAP_MODE_READ);
338 close(fd);
339 close(tx_sock);
341 fflush(stdout);
342 printf("\n");
343 printf("\r%12lu packets outgoing\n", ctx->tx_packets);
344 printf("\r%12lu packets truncated in file\n", trunced);
345 printf("\r%12lu bytes outgoing\n", ctx->tx_bytes);
346 printf("\r%12lu sec, %lu usec in total\n", diff.tv_sec, diff.tv_usec);
349 static void receive_to_xmit(struct ctx *ctx)
351 short ifflags = 0;
352 uint8_t *in, *out;
353 int rx_sock, ifindex_in, ifindex_out;
354 unsigned int size_in, size_out, it_in = 0, it_out = 0;
355 unsigned long frame_count = 0;
356 struct frame_map *hdr_in, *hdr_out;
357 struct ring tx_ring, rx_ring;
358 struct pollfd rx_poll;
359 struct sock_fprog bpf_ops;
361 if (!strncmp(ctx->device_in, ctx->device_out, IFNAMSIZ))
362 panic("Ingress/egress devices must be different!\n");
363 if (!device_up_and_running(ctx->device_out))
364 panic("Egress device not up and running!\n");
365 if (!device_up_and_running(ctx->device_in))
366 panic("Ingress device not up and running!\n");
368 rx_sock = pf_socket();
369 tx_sock = pf_socket();
371 fmemset(&tx_ring, 0, sizeof(tx_ring));
372 fmemset(&rx_ring, 0, sizeof(rx_ring));
373 fmemset(&rx_poll, 0, sizeof(rx_poll));
374 fmemset(&bpf_ops, 0, sizeof(bpf_ops));
376 ifindex_in = device_ifindex(ctx->device_in);
377 ifindex_out = device_ifindex(ctx->device_out);
379 size_in = ring_size(ctx->device_in, ctx->reserve_size);
380 size_out = ring_size(ctx->device_out, ctx->reserve_size);
382 enable_kernel_bpf_jit_compiler();
384 bpf_parse_rules(ctx->filter, &bpf_ops);
385 bpf_attach_to_sock(rx_sock, &bpf_ops);
387 setup_rx_ring_layout(rx_sock, &rx_ring, size_in, ctx->jumbo_support);
388 create_rx_ring(rx_sock, &rx_ring, ctx->verbose);
389 mmap_rx_ring(rx_sock, &rx_ring);
390 alloc_rx_ring_frames(&rx_ring);
391 bind_rx_ring(rx_sock, &rx_ring, ifindex_in);
392 prepare_polling(rx_sock, &rx_poll);
394 set_packet_loss_discard(tx_sock);
395 setup_tx_ring_layout(tx_sock, &tx_ring, size_out, ctx->jumbo_support);
396 create_tx_ring(tx_sock, &tx_ring, ctx->verbose);
397 mmap_tx_ring(tx_sock, &tx_ring);
398 alloc_tx_ring_frames(&tx_ring);
399 bind_tx_ring(tx_sock, &tx_ring, ifindex_out);
401 dissector_init_all(ctx->print_mode);
403 if (ctx->promiscuous)
404 ifflags = enter_promiscuous_mode(ctx->device_in);
406 if (ctx->kpull)
407 interval = ctx->kpull;
409 itimer.it_interval.tv_sec = 0;
410 itimer.it_interval.tv_usec = interval;
412 itimer.it_value.tv_sec = 0;
413 itimer.it_value.tv_usec = interval;
415 setitimer(ITIMER_REAL, &itimer, NULL);
417 if (ctx->verbose) {
418 printf("BPF:\n");
419 bpf_dump_all(&bpf_ops);
421 printf("MD: RXTX %luus\n\n", interval);
423 printf("Running! Hang up with ^C!\n\n");
424 fflush(stdout);
426 while (likely(sigint == 0)) {
427 while (user_may_pull_from_rx(rx_ring.frames[it_in].iov_base)) {
428 __label__ next;
430 hdr_in = rx_ring.frames[it_in].iov_base;
431 in = ((uint8_t *) hdr_in) + hdr_in->tp_h.tp_mac;
433 frame_count++;
435 if (ctx->packet_type != -1)
436 if (ctx->packet_type != hdr_in->s_ll.sll_pkttype)
437 goto next;
439 hdr_out = tx_ring.frames[it_out].iov_base;
440 out = ((uint8_t *) hdr_out) + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll);
442 for (; !user_may_pull_from_tx(tx_ring.frames[it_out].iov_base) &&
443 likely(!sigint);) {
444 if (ctx->randomize)
445 next_rnd_slot(&it_out, &tx_ring);
446 else {
447 it_out++;
448 if (it_out >= tx_ring.layout.tp_frame_nr)
449 it_out = 0;
452 hdr_out = tx_ring.frames[it_out].iov_base;
453 out = ((uint8_t *) hdr_out) + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll);
456 tpacket_hdr_clone(&hdr_out->tp_h, &hdr_in->tp_h);
457 fmemcpy(out, in, hdr_in->tp_h.tp_len);
459 kernel_may_pull_from_tx(&hdr_out->tp_h);
460 if (ctx->randomize)
461 next_rnd_slot(&it_out, &tx_ring);
462 else {
463 it_out++;
464 if (it_out >= tx_ring.layout.tp_frame_nr)
465 it_out = 0;
468 show_frame_hdr(hdr_in, ctx->print_mode, RING_MODE_INGRESS);
470 dissector_entry_point(in, hdr_in->tp_h.tp_snaplen,
471 ctx->link_type, ctx->print_mode);
473 if (frame_count_max != 0) {
474 if (frame_count >= frame_count_max) {
475 sigint = 1;
476 break;
480 next:
482 kernel_may_pull_from_rx(&hdr_in->tp_h);
484 it_in++;
485 if (it_in >= rx_ring.layout.tp_frame_nr)
486 it_in = 0;
488 if (unlikely(sigint == 1))
489 goto out;
492 poll(&rx_poll, 1, -1);
493 poll_error_maybe_die(rx_sock, &rx_poll);
496 out:
498 sock_print_net_stats(rx_sock, 0);
500 bpf_release(&bpf_ops);
502 dissector_cleanup_all();
504 destroy_tx_ring(tx_sock, &tx_ring);
505 destroy_rx_ring(rx_sock, &rx_ring);
507 if (ctx->promiscuous)
508 leave_promiscuous_mode(ctx->device_in, ifflags);
510 close(tx_sock);
511 close(rx_sock);
514 static void translate_pcap_to_txf(int fdo, uint8_t *out, size_t len)
516 size_t bytes_done = 0;
517 char bout[80];
519 slprintf(bout, sizeof(bout), "{\n ");
520 write_or_die(fdo, bout, strlen(bout));
522 while (bytes_done < len) {
523 slprintf(bout, sizeof(bout), "0x%02x, ", out[bytes_done]);
524 write_or_die(fdo, bout, strlen(bout));
526 bytes_done++;
528 if (bytes_done % 10 == 0) {
529 slprintf(bout, sizeof(bout), "\n");
530 write_or_die(fdo, bout, strlen(bout));
532 if (bytes_done < len) {
533 slprintf(bout, sizeof(bout), " ");
534 write_or_die(fdo, bout, strlen(bout));
538 if (bytes_done % 10 != 0) {
539 slprintf(bout, sizeof(bout), "\n");
540 write_or_die(fdo, bout, strlen(bout));
543 slprintf(bout, sizeof(bout), "}\n\n");
544 write_or_die(fdo, bout, strlen(bout));
547 static void read_pcap(struct ctx *ctx)
549 __label__ out;
550 uint8_t *out;
551 int ret, fd, fdo = 0;
552 unsigned long trunced = 0;
553 size_t out_len;
554 struct pcap_pkthdr phdr;
555 struct sock_fprog bpf_ops;
556 struct frame_map fm;
557 struct timeval start, end, diff;
559 bug_on(!__pcap_io);
561 fd = open_or_die(ctx->device_in, O_RDONLY | O_LARGEFILE | O_NOATIME);
563 ret = __pcap_io->pull_file_header(fd, &ctx->link_type);
564 if (ret)
565 panic("Error reading pcap header!\n");
567 if (__pcap_io->prepare_reading_pcap) {
568 ret = __pcap_io->prepare_reading_pcap(fd);
569 if (ret)
570 panic("Error prepare reading pcap!\n");
573 fmemset(&fm, 0, sizeof(fm));
574 fmemset(&bpf_ops, 0, sizeof(bpf_ops));
576 bpf_parse_rules(ctx->filter, &bpf_ops);
578 dissector_init_all(ctx->print_mode);
580 out_len = round_up(1024 * 1024, PAGE_SIZE);
581 out = xmalloc_aligned(out_len, CO_CACHE_LINE_SIZE);
583 if (ctx->verbose) {
584 printf("BPF:\n");
585 bpf_dump_all(&bpf_ops);
587 printf("MD: RD %s ", __pcap_io->name);
588 #ifdef _LARGEFILE64_SOURCE
589 printf("lf64 ");
590 #endif
591 ioprio_print();
592 printf("\n");
594 printf("Running! Hang up with ^C!\n\n");
595 fflush(stdout);
597 if (ctx->device_out)
598 fdo = open_or_die_m(ctx->device_out, O_RDWR | O_CREAT |
599 O_TRUNC | O_LARGEFILE, DEFFILEMODE);
601 bug_on(gettimeofday(&start, NULL));
603 while (likely(sigint == 0)) {
604 do {
605 ret = __pcap_io->read_pcap_pkt(fd, &phdr, out, out_len);
606 if (unlikely(ret < 0))
607 goto out;
609 if (unlikely(phdr.len == 0)) {
610 trunced++;
611 continue;
614 if (unlikely(phdr.len > out_len)) {
615 phdr.len = out_len;
616 trunced++;
618 } while (ctx->filter && !bpf_run_filter(&bpf_ops, out, phdr.len));
620 pcap_pkthdr_to_tpacket_hdr(&phdr, &fm.tp_h);
622 ctx->tx_bytes += fm.tp_h.tp_len;
623 ctx->tx_packets++;
625 show_frame_hdr(&fm, ctx->print_mode, RING_MODE_EGRESS);
627 dissector_entry_point(out, fm.tp_h.tp_snaplen,
628 ctx->link_type, ctx->print_mode);
630 if (ctx->device_out)
631 translate_pcap_to_txf(fdo, out, fm.tp_h.tp_snaplen);
633 if (frame_count_max != 0) {
634 if (ctx->tx_packets >= frame_count_max) {
635 sigint = 1;
636 break;
641 out:
643 bug_on(gettimeofday(&end, NULL));
644 diff = tv_subtract(end, start);
646 bpf_release(&bpf_ops);
648 dissector_cleanup_all();
650 if (__pcap_io->prepare_close_pcap)
651 __pcap_io->prepare_close_pcap(fd, PCAP_MODE_READ);
653 close(fd);
654 if (ctx->device_out)
655 close(fdo);
657 xfree(out);
659 fflush(stdout);
660 printf("\n");
661 printf("\r%12lu packets outgoing\n", ctx->tx_packets);
662 printf("\r%12lu packets truncated in file\n", trunced);
663 printf("\r%12lu bytes outgoing\n", ctx->tx_bytes);
664 printf("\r%12lu sec, %lu usec in total\n", diff.tv_sec, diff.tv_usec);
667 static void finish_multi_pcap_file(struct ctx *ctx, int fd)
669 __pcap_io->fsync_pcap(fd);
671 if (__pcap_io->prepare_close_pcap)
672 __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WRITE);
674 close(fd);
676 fmemset(&itimer, 0, sizeof(itimer));
677 setitimer(ITIMER_REAL, &itimer, NULL);
680 static int next_multi_pcap_file(struct ctx *ctx, int fd)
682 int ret;
683 char fname[512];
685 __pcap_io->fsync_pcap(fd);
687 if (__pcap_io->prepare_close_pcap)
688 __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WRITE);
690 close(fd);
692 slprintf(fname, sizeof(fname), "%s/%s%lu.pcap", ctx->device_out,
693 ctx->prefix ? : "dump-", time(0));
695 fd = open_or_die_m(fname, O_RDWR | O_CREAT | O_TRUNC |
696 O_LARGEFILE, DEFFILEMODE);
698 ret = __pcap_io->push_file_header(fd, ctx->link_type);
699 if (ret)
700 panic("Error writing pcap header!\n");
702 if (__pcap_io->prepare_writing_pcap) {
703 ret = __pcap_io->prepare_writing_pcap(fd);
704 if (ret)
705 panic("Error prepare writing pcap!\n");
708 return fd;
711 static int begin_multi_pcap_file(struct ctx *ctx)
713 int fd, ret;
714 char fname[256];
716 bug_on(!__pcap_io);
718 if (ctx->device_out[strlen(ctx->device_out) - 1] == '/')
719 ctx->device_out[strlen(ctx->device_out) - 1] = 0;
721 slprintf(fname, sizeof(fname), "%s/%s%lu.pcap", ctx->device_out,
722 ctx->prefix ? : "dump-", time(0));
724 fd = open_or_die_m(fname, O_RDWR | O_CREAT | O_TRUNC |
725 O_LARGEFILE, DEFFILEMODE);
727 ret = __pcap_io->push_file_header(fd, ctx->link_type);
728 if (ret)
729 panic("Error writing pcap header!\n");
731 if (__pcap_io->prepare_writing_pcap) {
732 ret = __pcap_io->prepare_writing_pcap(fd);
733 if (ret)
734 panic("Error prepare writing pcap!\n");
737 if (ctx->dump_mode == DUMP_INTERVAL_TIME) {
738 interval = ctx->dump_interval;
740 itimer.it_interval.tv_sec = interval;
741 itimer.it_interval.tv_usec = 0;
743 itimer.it_value.tv_sec = interval;
744 itimer.it_value.tv_usec = 0;
746 setitimer(ITIMER_REAL, &itimer, NULL);
747 } else {
748 interval = 0;
751 return fd;
754 static void finish_single_pcap_file(struct ctx *ctx, int fd)
756 __pcap_io->fsync_pcap(fd);
758 if (__pcap_io->prepare_close_pcap)
759 __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WRITE);
761 close(fd);
764 static int begin_single_pcap_file(struct ctx *ctx)
766 int fd, ret;
768 bug_on(!__pcap_io);
770 fd = open_or_die_m(ctx->device_out, O_RDWR | O_CREAT | O_TRUNC |
771 O_LARGEFILE, DEFFILEMODE);
773 ret = __pcap_io->push_file_header(fd, ctx->link_type);
774 if (ret)
775 panic("Error writing pcap header!\n");
777 if (__pcap_io->prepare_writing_pcap) {
778 ret = __pcap_io->prepare_writing_pcap(fd);
779 if (ret)
780 panic("Error prepare writing pcap!\n");
783 return fd;
786 static void print_pcap_file_stats(int sock, struct ctx *ctx, unsigned long skipped)
788 unsigned long good, bad;
789 struct tpacket_stats kstats;
790 socklen_t slen = sizeof(kstats);
792 fmemset(&kstats, 0, sizeof(kstats));
793 getsockopt(sock, SOL_PACKET, PACKET_STATISTICS, &kstats, &slen);
795 if (ctx->print_mode == PRINT_NONE) {
796 good = kstats.tp_packets - kstats.tp_drops - skipped;
797 bad = kstats.tp_drops + skipped;
799 printf(".(+%lu/-%lu)", good, bad);
800 fflush(stdout);
804 static void recv_only_or_dump(struct ctx *ctx)
806 uint8_t *packet;
807 short ifflags = 0;
808 int sock, irq, ifindex, fd = 0, ret;
809 unsigned int size, it = 0;
810 unsigned long frame_count = 0, skipped = 0;
811 struct ring rx_ring;
812 struct pollfd rx_poll;
813 struct frame_map *hdr;
814 struct sock_fprog bpf_ops;
815 struct timeval start, end, diff;
816 struct pcap_pkthdr phdr;
818 if (!device_up_and_running(ctx->device_in) && !ctx->rfraw)
819 panic("Device not up and running!\n");
821 sock = pf_socket();
823 if (ctx->rfraw) {
824 ctx->device_trans = xstrdup(ctx->device_in);
825 xfree(ctx->device_in);
827 enter_rfmon_mac80211(ctx->device_trans, &ctx->device_in);
828 ctx->link_type = LINKTYPE_IEEE802_11;
831 if (dump_to_pcap(ctx)) {
832 __label__ try_file;
833 struct stat stats;
835 fmemset(&stats, 0, sizeof(stats));
836 ret = stat(ctx->device_out, &stats);
837 if (ret < 0) {
838 ctx->dump_dir = 0;
839 goto try_file;
842 ctx->dump_dir = S_ISDIR(stats.st_mode);
843 if (ctx->dump_dir) {
844 fd = begin_multi_pcap_file(ctx);
845 } else {
846 try_file:
847 fd = begin_single_pcap_file(ctx);
851 fmemset(&rx_ring, 0, sizeof(rx_ring));
852 fmemset(&rx_poll, 0, sizeof(rx_poll));
853 fmemset(&bpf_ops, 0, sizeof(bpf_ops));
855 ifindex = device_ifindex(ctx->device_in);
857 size = ring_size(ctx->device_in, ctx->reserve_size);
859 enable_kernel_bpf_jit_compiler();
861 bpf_parse_rules(ctx->filter, &bpf_ops);
862 bpf_attach_to_sock(sock, &bpf_ops);
864 set_sockopt_hwtimestamp(sock, ctx->device_in);
866 setup_rx_ring_layout(sock, &rx_ring, size, ctx->jumbo_support);
867 create_rx_ring(sock, &rx_ring, ctx->verbose);
868 mmap_rx_ring(sock, &rx_ring);
869 alloc_rx_ring_frames(&rx_ring);
870 bind_rx_ring(sock, &rx_ring, ifindex);
872 prepare_polling(sock, &rx_poll);
873 dissector_init_all(ctx->print_mode);
875 if (ctx->cpu >= 0 && ifindex > 0) {
876 irq = device_irq_number(ctx->device_in);
877 device_bind_irq_to_cpu(irq, ctx->cpu);
879 if (ctx->verbose)
880 printf("IRQ: %s:%d > CPU%d\n",
881 ctx->device_in, irq, ctx->cpu);
884 if (ctx->promiscuous)
885 ifflags = enter_promiscuous_mode(ctx->device_in);
887 if (ctx->verbose) {
888 printf("BPF:\n");
889 bpf_dump_all(&bpf_ops);
891 printf("MD: RX %s ", ctx->dump ? pcap_ops[ctx->pcap]->name : "");
892 if (ctx->rfraw)
893 printf("802.11 raw via %s ", ctx->device_in);
894 #ifdef _LARGEFILE64_SOURCE
895 printf("lf64 ");
896 #endif
897 ioprio_print();
898 printf("\n");
900 printf("Running! Hang up with ^C!\n\n");
901 fflush(stdout);
903 bug_on(gettimeofday(&start, NULL));
905 while (likely(sigint == 0)) {
906 while (user_may_pull_from_rx(rx_ring.frames[it].iov_base)) {
907 __label__ next;
909 hdr = rx_ring.frames[it].iov_base;
910 packet = ((uint8_t *) hdr) + hdr->tp_h.tp_mac;
911 frame_count++;
913 if (ctx->packet_type != -1)
914 if (ctx->packet_type != hdr->s_ll.sll_pkttype)
915 goto next;
917 if (unlikely(ring_frame_size(&rx_ring) < hdr->tp_h.tp_snaplen)) {
918 skipped++;
919 goto next;
922 if (dump_to_pcap(ctx)) {
923 tpacket_hdr_to_pcap_pkthdr(&hdr->tp_h, &phdr);
925 ret = __pcap_io->write_pcap_pkt(fd, &phdr, packet, phdr.len);
926 if (unlikely(ret != sizeof(phdr) + phdr.len))
927 panic("Write error to pcap!\n");
930 show_frame_hdr(hdr, ctx->print_mode, RING_MODE_INGRESS);
932 dissector_entry_point(packet, hdr->tp_h.tp_snaplen,
933 ctx->link_type, ctx->print_mode);
935 if (frame_count_max != 0) {
936 if (frame_count >= frame_count_max) {
937 sigint = 1;
938 break;
942 next:
944 kernel_may_pull_from_rx(&hdr->tp_h);
946 it++;
947 if (it >= rx_ring.layout.tp_frame_nr)
948 it = 0;
950 if (unlikely(sigint == 1))
951 break;
953 if (dump_to_pcap(ctx)) {
954 if (ctx->dump_mode == DUMP_INTERVAL_SIZE) {
955 interval += hdr->tp_h.tp_snaplen;
957 if (interval > ctx->dump_interval) {
958 next_dump = true;
959 interval = 0;
963 if (next_dump) {
964 fd = next_multi_pcap_file(ctx, fd);
965 next_dump = false;
967 if (ctx->verbose)
968 print_pcap_file_stats(sock, ctx, skipped);
973 poll(&rx_poll, 1, -1);
974 poll_error_maybe_die(sock, &rx_poll);
977 bug_on(gettimeofday(&end, NULL));
978 diff = tv_subtract(end, start);
980 if (!(ctx->dump_dir && ctx->print_mode == PRINT_NONE)) {
981 sock_print_net_stats(sock, skipped);
983 printf("\r%12lu sec, %lu usec in total\n",
984 diff.tv_sec, diff.tv_usec);
985 } else {
986 printf("\n\n");
987 fflush(stdout);
990 bpf_release(&bpf_ops);
991 dissector_cleanup_all();
992 destroy_rx_ring(sock, &rx_ring);
994 if (ctx->promiscuous)
995 leave_promiscuous_mode(ctx->device_in, ifflags);
997 if (ctx->rfraw)
998 leave_rfmon_mac80211(ctx->device_trans, ctx->device_in);
1000 close(sock);
1002 if (dump_to_pcap(ctx)) {
1003 if (ctx->dump_dir)
1004 finish_multi_pcap_file(ctx, fd);
1005 else
1006 finish_single_pcap_file(ctx, fd);
1010 static void help(void)
1012 printf("\nnetsniff-ng %s, the packet sniffing beast\n", VERSION_STRING);
1013 puts("http://www.netsniff-ng.org\n\n"
1014 "Usage: netsniff-ng [options]\n"
1015 "Options:\n"
1016 " -i|-d|--dev|--in <dev|pcap> Input source as netdev or pcap\n"
1017 " -o|--out <dev|pcap|dir|txf> Output sink as netdev, pcap, directory, txf file\n"
1018 " -f|--filter <bpf-file> Use BPF filter file from bpfc\n"
1019 " -t|--type <type> Only handle packets of defined type:\n"
1020 " host|broadcast|multicast|others|outgoing\n"
1021 " -F|--interval <size/time> Dump interval in time or size if -o is a directory\n"
1022 " pcap swap spec: <num>KiB/MiB/GiB/s/sec/min/hrs\n"
1023 " -J|--jumbo-support Support for 64KB Super Jumbo Frames\n"
1024 " Default RX/TX slot: 2048Byte\n"
1025 " -R|--rfraw Capture or inject raw 802.11 frames\n"
1026 " -n|--num <uint> Number of packets until exit\n"
1027 " `-- 0 Loop until interrupted (default)\n"
1028 " `- n Send n packets and done\n"
1029 "Options for printing:\n"
1030 " -s|--silent Do not print captured packets\n"
1031 " -q|--less Print less-verbose packet information\n"
1032 " -X|--hex Print packet data in hex format\n"
1033 " -l|--ascii Print human-readable packet data\n"
1034 "Options, advanced:\n"
1035 " -P|--prefix <name> Prefix for pcaps stored in directory\n"
1036 " -r|--rand Randomize packet forwarding order\n"
1037 " -M|--no-promisc No promiscuous mode for netdev\n"
1038 " -A|--no-sock-mem Don't tune core socket memory\n"
1039 " -m|--mmap Mmap pcap file i.e., for replaying\n"
1040 " -g|--sg Scatter/gather pcap file I/O\n"
1041 " -c|--clrw Use slower read(2)/write(2) I/O\n"
1042 " -S|--ring-size <size> Manually set ring size to <size>:\n"
1043 " mmap space in KiB/MiB/GiB, e.g. \'10MiB\'\n"
1044 " -k|--kernel-pull <uint> Kernel pull from user interval in us\n"
1045 " Default is 10us where the TX_RING\n"
1046 " is populated with payload from uspace\n"
1047 " -b|--bind-cpu <cpu> Bind to specific CPU (or CPU-range)\n"
1048 " -B|--unbind-cpu <cpu> Forbid to use specific CPU (or CPU-range)\n"
1049 " -H|--prio-high Make this high priority process\n"
1050 " -Q|--notouch-irq Do not touch IRQ CPU affinity of NIC\n"
1051 " -V|--verbose Be more verbose\n"
1052 " -v|--version Show version\n"
1053 " -h|--help Guess what?!\n\n"
1054 "Examples:\n"
1055 " netsniff-ng --in eth0 --out dump.pcap --silent --bind-cpu 0\n"
1056 " netsniff-ng --in wlan0 --rfraw --out dump.pcap --silent --bind-cpu 0\n"
1057 " netsniff-ng --in dump.pcap --mmap --out eth0 -k1000 --silent --bind-cpu 0\n"
1058 " netsniff-ng --in dump.pcap --out dump.txf --silent --bind-cpu 0\n"
1059 " netsniff-ng --in eth0 --out eth1 --silent --bind-cpu 0 --type host\n"
1060 " netsniff-ng --in eth1 --out /opt/probe/ -s -m -J --interval 100MiB -b 0\n"
1061 " netsniff-ng --in any --filter http.bpf --jumbo-support --ascii -V\n\n"
1062 "Note:\n"
1063 " This tool is targeted for network developers! You should\n"
1064 " be aware of what you are doing and what these options above\n"
1065 " mean! Use netsniff-ng's bpfc compiler for generating filter files.\n"
1066 " Further, netsniff-ng automatically enables the kernel BPF JIT\n"
1067 " if present. Txf file output is only possible if the input source\n"
1068 " is a pcap file.\n\n"
1069 "Please report bugs to <bugs@netsniff-ng.org>\n"
1070 "Copyright (C) 2009-2013 Daniel Borkmann <daniel@netsniff-ng.org>\n"
1071 "Copyright (C) 2009-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n"
1072 "Copyright (C) 2012 Markus Amend <markus@netsniff-ng.org>\n"
1073 "License: GNU GPL version 2.0\n"
1074 "This is free software: you are free to change and redistribute it.\n"
1075 "There is NO WARRANTY, to the extent permitted by law.\n");
1076 die();
1079 static void version(void)
1081 printf("\nnetsniff-ng %s, the packet sniffing beast\n", VERSION_STRING);
1082 puts("http://www.netsniff-ng.org\n\n"
1083 "Please report bugs to <bugs@netsniff-ng.org>\n"
1084 "Copyright (C) 2009-2013 Daniel Borkmann <daniel@netsniff-ng.org>\n"
1085 "Copyright (C) 2009-2012 Emmanuel Roullit <emmanuel@netsniff-ng.org>\n"
1086 "Copyright (C) 2012 Markus Amend <markus@netsniff-ng.org>\n"
1087 "License: GNU GPL version 2.0\n"
1088 "This is free software: you are free to change and redistribute it.\n"
1089 "There is NO WARRANTY, to the extent permitted by law.\n");
1090 die();
1093 static void header(void)
1095 printf("%s%s%s\n", colorize_start(bold), "netsniff-ng " VERSION_STRING, colorize_end());
1098 int main(int argc, char **argv)
1100 char *ptr;
1101 int c, i, j, opt_index, ops_touched = 0, vals[4] = {0};
1102 bool prio_high = false, setsockmem = true;
1103 void (*main_loop)(struct ctx *ctx) = NULL;
1104 struct ctx ctx = {
1105 .link_type = LINKTYPE_EN10MB,
1106 .print_mode = PRINT_NORM,
1107 .cpu = -1,
1108 .packet_type = -1,
1109 .promiscuous = true,
1110 .randomize = false,
1111 .pcap = PCAP_OPS_SG,
1112 .dump_interval = 60,
1113 .dump_mode = DUMP_INTERVAL_TIME,
1116 setfsuid(getuid());
1117 setfsgid(getgid());
1119 srand(time(NULL));
1121 while ((c = getopt_long(argc, argv, short_options, long_options,
1122 &opt_index)) != EOF) {
1123 switch (c) {
1124 case 'd':
1125 case 'i':
1126 ctx.device_in = xstrdup(optarg);
1127 break;
1128 case 'o':
1129 ctx.device_out = xstrdup(optarg);
1130 break;
1131 case 'P':
1132 ctx.prefix = xstrdup(optarg);
1133 break;
1134 case 'R':
1135 ctx.link_type = LINKTYPE_IEEE802_11;
1136 ctx.rfraw = 1;
1137 break;
1138 case 'r':
1139 ctx.randomize = true;
1140 break;
1141 case 'J':
1142 ctx.jumbo_support = 1;
1143 break;
1144 case 'f':
1145 ctx.filter = xstrdup(optarg);
1146 break;
1147 case 'M':
1148 ctx.promiscuous = false;
1149 break;
1150 case 'A':
1151 setsockmem = false;
1152 break;
1153 case 't':
1154 if (!strncmp(optarg, "host", strlen("host")))
1155 ctx.packet_type = PACKET_HOST;
1156 else if (!strncmp(optarg, "broadcast", strlen("broadcast")))
1157 ctx.packet_type = PACKET_BROADCAST;
1158 else if (!strncmp(optarg, "multicast", strlen("multicast")))
1159 ctx.packet_type = PACKET_MULTICAST;
1160 else if (!strncmp(optarg, "others", strlen("others")))
1161 ctx.packet_type = PACKET_OTHERHOST;
1162 else if (!strncmp(optarg, "outgoing", strlen("outgoing")))
1163 ctx.packet_type = PACKET_OUTGOING;
1164 else
1165 ctx.packet_type = -1;
1166 break;
1167 case 'S':
1168 ptr = optarg;
1169 ctx.reserve_size = 0;
1171 for (j = i = strlen(optarg); i > 0; --i) {
1172 if (!isdigit(optarg[j - i]))
1173 break;
1174 ptr++;
1177 if (!strncmp(ptr, "KiB", strlen("KiB")))
1178 ctx.reserve_size = 1 << 10;
1179 else if (!strncmp(ptr, "MiB", strlen("MiB")))
1180 ctx.reserve_size = 1 << 20;
1181 else if (!strncmp(ptr, "GiB", strlen("GiB")))
1182 ctx.reserve_size = 1 << 30;
1183 else
1184 panic("Syntax error in ring size param!\n");
1185 *ptr = 0;
1187 ctx.reserve_size *= strtol(optarg, NULL, 0);
1188 break;
1189 case 'b':
1190 set_cpu_affinity(optarg, 0);
1191 /* Take the first CPU for rebinding the IRQ */
1192 if (ctx.cpu != -2)
1193 ctx.cpu = strtol(optarg, NULL, 0);
1194 break;
1195 case 'B':
1196 set_cpu_affinity(optarg, 1);
1197 break;
1198 case 'H':
1199 prio_high = true;
1200 break;
1201 case 'c':
1202 ctx.pcap = PCAP_OPS_RW;
1203 ops_touched = 1;
1204 break;
1205 case 'm':
1206 ctx.pcap = PCAP_OPS_MMAP;
1207 ops_touched = 1;
1208 break;
1209 case 'g':
1210 ctx.pcap = PCAP_OPS_SG;
1211 ops_touched = 1;
1212 break;
1213 case 'Q':
1214 ctx.cpu = -2;
1215 break;
1216 case 's':
1217 ctx.print_mode = PRINT_NONE;
1218 break;
1219 case 'q':
1220 ctx.print_mode = PRINT_LESS;
1221 break;
1222 case 'X':
1223 ctx.print_mode =
1224 (ctx.print_mode == PRINT_ASCII) ?
1225 PRINT_HEX_ASCII : PRINT_HEX;
1226 break;
1227 case 'l':
1228 ctx.print_mode =
1229 (ctx.print_mode == PRINT_HEX) ?
1230 PRINT_HEX_ASCII : PRINT_ASCII;
1231 break;
1232 case 'k':
1233 ctx.kpull = strtol(optarg, NULL, 0);
1234 break;
1235 case 'n':
1236 frame_count_max = strtol(optarg, NULL, 0);
1237 break;
1238 case 'F':
1239 ptr = optarg;
1240 ctx.dump_interval = 0;
1242 for (j = i = strlen(optarg); i > 0; --i) {
1243 if (!isdigit(optarg[j - i]))
1244 break;
1245 ptr++;
1248 if (!strncmp(ptr, "KiB", strlen("KiB"))) {
1249 ctx.dump_interval = 1 << 10;
1250 ctx.dump_mode = DUMP_INTERVAL_SIZE;
1251 } else if (!strncmp(ptr, "MiB", strlen("MiB"))) {
1252 ctx.dump_interval = 1 << 20;
1253 ctx.dump_mode = DUMP_INTERVAL_SIZE;
1254 } else if (!strncmp(ptr, "GiB", strlen("GiB"))) {
1255 ctx.dump_interval = 1 << 30;
1256 ctx.dump_mode = DUMP_INTERVAL_SIZE;
1257 } else if (!strncmp(ptr, "sec", strlen("sec"))) {
1258 ctx.dump_interval = 1;
1259 ctx.dump_mode = DUMP_INTERVAL_TIME;
1260 } else if (!strncmp(ptr, "min", strlen("min"))) {
1261 ctx.dump_interval = 60;
1262 ctx.dump_mode = DUMP_INTERVAL_TIME;
1263 } else if (!strncmp(ptr, "hrs", strlen("hrs"))) {
1264 ctx.dump_interval = 60 * 60;
1265 ctx.dump_mode = DUMP_INTERVAL_TIME;
1266 } else if (!strncmp(ptr, "s", strlen("s"))) {
1267 ctx.dump_interval = 1;
1268 ctx.dump_mode = DUMP_INTERVAL_TIME;
1269 } else {
1270 panic("Syntax error in time/size param!\n");
1273 *ptr = 0;
1274 ctx.dump_interval *= strtol(optarg, NULL, 0);
1275 break;
1276 case 'V':
1277 ctx.verbose = 1;
1278 break;
1279 case 'v':
1280 version();
1281 break;
1282 case 'h':
1283 help();
1284 break;
1285 case '?':
1286 switch (optopt) {
1287 case 'd':
1288 case 'i':
1289 case 'o':
1290 case 'f':
1291 case 't':
1292 case 'P':
1293 case 'F':
1294 case 'n':
1295 case 'S':
1296 case 'b':
1297 case 'k':
1298 case 'B':
1299 case 'e':
1300 panic("Option -%c requires an argument!\n",
1301 optopt);
1302 default:
1303 if (isprint(optopt))
1304 whine("Unknown option character "
1305 "`0x%X\'!\n", optopt);
1306 die();
1308 default:
1309 break;
1313 if (!ctx.device_in)
1314 ctx.device_in = xstrdup("any");
1316 register_signal(SIGINT, signal_handler);
1317 register_signal(SIGHUP, signal_handler);
1319 header();
1321 init_pcap(ctx.jumbo_support);
1322 tprintf_init();
1324 if (prio_high) {
1325 set_proc_prio(get_default_proc_prio());
1326 set_sched_status(get_default_sched_policy(), get_default_sched_prio());
1329 if (ctx.device_in && (device_mtu(ctx.device_in) ||
1330 !strncmp("any", ctx.device_in, strlen(ctx.device_in)))) {
1331 if (!ctx.device_out) {
1332 ctx.dump = 0;
1333 main_loop = recv_only_or_dump;
1334 } else if (device_mtu(ctx.device_out)) {
1335 register_signal_f(SIGALRM, timer_elapsed, SA_SIGINFO);
1336 main_loop = receive_to_xmit;
1337 } else {
1338 ctx.dump = 1;
1339 register_signal_f(SIGALRM, timer_next_dump, SA_SIGINFO);
1340 main_loop = recv_only_or_dump;
1341 if (!ops_touched)
1342 ctx.pcap = PCAP_OPS_SG;
1344 } else {
1345 if (ctx.device_out && device_mtu(ctx.device_out)) {
1346 register_signal_f(SIGALRM, timer_elapsed, SA_SIGINFO);
1347 main_loop = pcap_to_xmit;
1348 if (!ops_touched)
1349 ctx.pcap = PCAP_OPS_MMAP;
1350 } else {
1351 main_loop = read_pcap;
1352 if (!ops_touched)
1353 ctx.pcap = PCAP_OPS_SG;
1357 bug_on(!main_loop);
1359 if (setsockmem)
1360 set_system_socket_memory(vals);
1362 main_loop(&ctx);
1364 if (setsockmem)
1365 reset_system_socket_memory(vals);
1367 tprintf_cleanup();
1368 cleanup_pcap();
1370 free(ctx.device_in);
1371 free(ctx.device_out);
1372 free(ctx.device_trans);
1373 free(ctx.prefix);
1375 return 0;