From 303e1c4e5ad27cda41a48b70abb47f4885520729 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 28 Jan 2013 10:52:54 +0100 Subject: [PATCH] netsniff-ng: pcap: support for multiple pcap types Features and supported types can be seen with: netsniff-ng -D Types can be selected with their magic number: netsniff-ng --in eth0 --out dump.pcap --silent -T 0xa1b2c3d4 --bind-cpu 0 Four types are currently supported: - tcpdump-capable (default) - tcpdump-capable with ns resolution - Alexey Kuznetsov' pcap format - netsniff-ng's pcap format Signed-off-by: Daniel Borkmann --- src/built_in.h | 8 +- src/netsniff-ng.c | 137 +++++----- src/netsniff-ng/Makefile | 9 +- src/pcap.c | 27 -- src/pcap.h | 646 +++++++++++++++++++++++++++++++++-------------- src/pcap_mm.c | 500 ++++++++++++++++-------------------- src/pcap_rw.c | 224 ++++++++-------- src/pcap_sg.c | 512 ++++++++++++++++++------------------- 8 files changed, 1124 insertions(+), 939 deletions(-) delete mode 100644 src/pcap.c rewrite src/pcap.h (71%) rewrite src/pcap_mm.c (75%) rewrite src/pcap_rw.c (80%) rewrite src/pcap_sg.c (87%) diff --git a/src/built_in.h b/src/built_in.h index 17bad9f3..b48193e1 100644 --- a/src/built_in.h +++ b/src/built_in.h @@ -129,16 +129,12 @@ typedef uint8_t u8; # define __deprecated /* unimplemented */ #endif -#ifndef EXPORT_SYMBOL -# define EXPORT_SYMBOL(x) /* empty, just for readability */ -#endif - #ifndef unreachable # define unreachable() do { } while (1) #endif -#ifndef __unused -# define __unused __attribute__ ((__unused__)) +#ifndef __maybe_unused +# define __maybe_unused __attribute__ ((__unused__)) #endif #ifndef noinline diff --git a/src/netsniff-ng.c b/src/netsniff-ng.c index b0e2c257..6c0f3459 100644 --- a/src/netsniff-ng.c +++ b/src/netsniff-ng.c @@ -58,18 +58,18 @@ enum dump_mode { struct ctx { char *device_in, *device_out, *device_trans, *filter, *prefix; - int cpu, rfraw, dump, print_mode, dump_dir, jumbo_support, packet_type, verbose; + int cpu, rfraw, dump, print_mode, dump_dir, packet_type, verbose; unsigned long kpull, dump_interval, reserve_size, tx_bytes, tx_packets; - bool randomize, promiscuous, enforce; + bool randomize, promiscuous, enforce, jumbo; enum pcap_ops_groups pcap; enum dump_mode dump_mode; - uid_t uid; gid_t gid; uint32_t link_type; + uid_t uid; gid_t gid; uint32_t link_type, magic; }; volatile sig_atomic_t sigint = 0; static volatile bool next_dump = false; -static const char *short_options = "d:i:o:rf:MJt:S:k:n:b:B:HQmcsqXlvhF:RGAP:Vu:g:"; +static const char *short_options = "d:i:o:rf:MJt:S:k:n:b:B:HQmcsqXlvhF:RGAP:Vu:g:T:D"; static const struct option long_options[] = { {"dev", required_argument, NULL, 'd'}, {"in", required_argument, NULL, 'i'}, @@ -85,6 +85,7 @@ static const struct option long_options[] = { {"prefix", required_argument, NULL, 'P'}, {"user", required_argument, NULL, 'u'}, {"group", required_argument, NULL, 'g'}, + {"magic", required_argument, NULL, 'T'}, {"rand", no_argument, NULL, 'r'}, {"rfraw", no_argument, NULL, 'R'}, {"mmap", no_argument, NULL, 'm'}, @@ -94,6 +95,7 @@ static const struct option long_options[] = { {"no-promisc", no_argument, NULL, 'M'}, {"prio-high", no_argument, NULL, 'H'}, {"notouch-irq", no_argument, NULL, 'Q'}, + {"dump-pcap-types", no_argument, NULL, 'D'}, {"silent", no_argument, NULL, 's'}, {"less", no_argument, NULL, 'q'}, {"hex", no_argument, NULL, 'X'}, @@ -184,7 +186,7 @@ static void pcap_to_xmit(struct ctx *ctx) struct frame_map *hdr; struct sock_fprog bpf_ops; struct timeval start, end, diff; - struct pcap_pkthdr phdr; + pcap_pkthdr_t phdr; if (!device_up_and_running(ctx->device_out) && !ctx->rfraw) panic("Device not up and running!\n"); @@ -195,12 +197,12 @@ static void pcap_to_xmit(struct ctx *ctx) fd = open_or_die(ctx->device_in, O_RDONLY | O_LARGEFILE | O_NOATIME); - ret = __pcap_io->pull_file_header(fd, &ctx->link_type); + ret = __pcap_io->pull_fhdr_pcap(fd, &ctx->magic, &ctx->link_type); if (ret) panic("Error reading pcap header!\n"); - if (__pcap_io->prepare_reading_pcap) { - ret = __pcap_io->prepare_reading_pcap(fd); + if (__pcap_io->prepare_access_pcap) { + ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, ctx->jumbo); if (ret) panic("Error prepare reading pcap!\n"); } @@ -226,7 +228,7 @@ static void pcap_to_xmit(struct ctx *ctx) set_packet_loss_discard(tx_sock); set_sockopt_hwtimestamp(tx_sock, ctx->device_out); - setup_tx_ring_layout(tx_sock, &tx_ring, size, ctx->jumbo_support); + setup_tx_ring_layout(tx_sock, &tx_ring, size, ctx->jumbo); create_tx_ring(tx_sock, &tx_ring, ctx->verbose); mmap_tx_ring(tx_sock, &tx_ring); alloc_tx_ring_frames(&tx_ring); @@ -250,7 +252,7 @@ static void pcap_to_xmit(struct ctx *ctx) printf("BPF:\n"); bpf_dump_all(&bpf_ops); - printf("MD: TX %luus %s ", interval, pcap_ops[ctx->pcap]->name); + printf("MD: TX %luus %s ", interval, pcap_ops_group_to_str[ctx->pcap]); if (ctx->rfraw) printf("802.11 raw via %s ", ctx->device_out); #ifdef _LARGEFILE64_SOURCE @@ -278,24 +280,25 @@ static void pcap_to_xmit(struct ctx *ctx) while (likely(sigint == 0)) { while (user_may_pull_from_tx(tx_ring.frames[it].iov_base)) { hdr = tx_ring.frames[it].iov_base; - - /* Kernel assumes: data = ph.raw + po->tp_hdrlen - - * sizeof(struct sockaddr_ll); */ out = ((uint8_t *) hdr) + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); do { - ret = __pcap_io->read_pcap_pkt(fd, &phdr, out, - ring_frame_size(&tx_ring)); + ret = __pcap_io->read_pcap(fd, &phdr, ctx->magic, out, + ring_frame_size(&tx_ring)); if (unlikely(ret <= 0)) goto out; - if (ring_frame_size(&tx_ring) < phdr.len) { - phdr.len = ring_frame_size(&tx_ring); + if (ring_frame_size(&tx_ring) < + pcap_get_length(&phdr, ctx->magic)) { + pcap_set_length(&phdr, ctx->magic, + ring_frame_size(&tx_ring)); trunced++; } - } while (ctx->filter && !bpf_run_filter(&bpf_ops, out, phdr.len)); + } while (ctx->filter && + !bpf_run_filter(&bpf_ops, out, + pcap_get_length(&phdr, ctx->magic))); - pcap_pkthdr_to_tpacket_hdr(&phdr, &hdr->tp_h); + pcap_pkthdr_to_tpacket_hdr(&phdr, ctx->magic, &hdr->tp_h, &hdr->s_ll); ctx->tx_bytes += hdr->tp_h.tp_len;; ctx->tx_packets++; @@ -337,7 +340,7 @@ static void pcap_to_xmit(struct ctx *ctx) leave_rfmon_mac80211(ctx->device_trans, ctx->device_out); if (__pcap_io->prepare_close_pcap) - __pcap_io->prepare_close_pcap(fd, PCAP_MODE_READ); + __pcap_io->prepare_close_pcap(fd, PCAP_MODE_RD); close(fd); close(tx_sock); @@ -388,7 +391,7 @@ static void receive_to_xmit(struct ctx *ctx) bpf_parse_rules(ctx->device_in, ctx->filter, &bpf_ops); bpf_attach_to_sock(rx_sock, &bpf_ops); - setup_rx_ring_layout(rx_sock, &rx_ring, size_in, ctx->jumbo_support); + setup_rx_ring_layout(rx_sock, &rx_ring, size_in, ctx->jumbo); create_rx_ring(rx_sock, &rx_ring, ctx->verbose); mmap_rx_ring(rx_sock, &rx_ring); alloc_rx_ring_frames(&rx_ring); @@ -396,7 +399,7 @@ static void receive_to_xmit(struct ctx *ctx) prepare_polling(rx_sock, &rx_poll); set_packet_loss_discard(tx_sock); - setup_tx_ring_layout(tx_sock, &tx_ring, size_out, ctx->jumbo_support); + setup_tx_ring_layout(tx_sock, &tx_ring, size_out, ctx->jumbo); create_tx_ring(tx_sock, &tx_ring, ctx->verbose); mmap_tx_ring(tx_sock, &tx_ring); alloc_tx_ring_frames(&tx_ring); @@ -558,21 +561,22 @@ static void read_pcap(struct ctx *ctx) int ret, fd, fdo = 0; unsigned long trunced = 0; size_t out_len; - struct pcap_pkthdr phdr; + pcap_pkthdr_t phdr; struct sock_fprog bpf_ops; struct frame_map fm; struct timeval start, end, diff; + struct sockaddr_ll sll; bug_on(!__pcap_io); fd = open_or_die(ctx->device_in, O_RDONLY | O_LARGEFILE | O_NOATIME); - ret = __pcap_io->pull_file_header(fd, &ctx->link_type); + ret = __pcap_io->pull_fhdr_pcap(fd, &ctx->magic, &ctx->link_type); if (ret) panic("Error reading pcap header!\n"); - if (__pcap_io->prepare_reading_pcap) { - ret = __pcap_io->prepare_reading_pcap(fd); + if (__pcap_io->prepare_access_pcap) { + ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, ctx->jumbo); if (ret) panic("Error prepare reading pcap!\n"); } @@ -591,7 +595,7 @@ static void read_pcap(struct ctx *ctx) printf("BPF:\n"); bpf_dump_all(&bpf_ops); - printf("MD: RD %s ", __pcap_io->name); + printf("MD: RD %s ", pcap_ops_group_to_str[ctx->pcap]); #ifdef _LARGEFILE64_SOURCE printf("lf64 "); #endif @@ -612,22 +616,25 @@ static void read_pcap(struct ctx *ctx) while (likely(sigint == 0)) { do { - ret = __pcap_io->read_pcap_pkt(fd, &phdr, out, out_len); + ret = __pcap_io->read_pcap(fd, &phdr, ctx->magic, + out, out_len); if (unlikely(ret < 0)) goto out; - if (unlikely(phdr.len == 0)) { + if (unlikely(pcap_get_length(&phdr, ctx->magic) == 0)) { trunced++; continue; } - if (unlikely(phdr.len > out_len)) { - phdr.len = out_len; + if (unlikely(pcap_get_length(&phdr, ctx->magic) > out_len)) { + pcap_set_length(&phdr, ctx->magic, out_len); trunced++; } - } while (ctx->filter && !bpf_run_filter(&bpf_ops, out, phdr.len)); + } while (ctx->filter && + !bpf_run_filter(&bpf_ops, out, + pcap_get_length(&phdr, ctx->magic))); - pcap_pkthdr_to_tpacket_hdr(&phdr, &fm.tp_h); + pcap_pkthdr_to_tpacket_hdr(&phdr, ctx->magic, &fm.tp_h, &sll); ctx->tx_bytes += fm.tp_h.tp_len; ctx->tx_packets++; @@ -658,7 +665,7 @@ static void read_pcap(struct ctx *ctx) dissector_cleanup_all(); if (__pcap_io->prepare_close_pcap) - __pcap_io->prepare_close_pcap(fd, PCAP_MODE_READ); + __pcap_io->prepare_close_pcap(fd, PCAP_MODE_RD); close(fd); if (ctx->device_out) @@ -679,7 +686,7 @@ static void finish_multi_pcap_file(struct ctx *ctx, int fd) __pcap_io->fsync_pcap(fd); if (__pcap_io->prepare_close_pcap) - __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WRITE); + __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WR); close(fd); @@ -695,7 +702,7 @@ static int next_multi_pcap_file(struct ctx *ctx, int fd) __pcap_io->fsync_pcap(fd); if (__pcap_io->prepare_close_pcap) - __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WRITE); + __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WR); close(fd); @@ -705,12 +712,12 @@ static int next_multi_pcap_file(struct ctx *ctx, int fd) fd = open_or_die_m(fname, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, DEFFILEMODE); - ret = __pcap_io->push_file_header(fd, ctx->link_type); + ret = __pcap_io->push_fhdr_pcap(fd, ctx->magic, ctx->link_type); if (ret) panic("Error writing pcap header!\n"); - if (__pcap_io->prepare_writing_pcap) { - ret = __pcap_io->prepare_writing_pcap(fd); + if (__pcap_io->prepare_access_pcap) { + ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_WR, ctx->jumbo); if (ret) panic("Error prepare writing pcap!\n"); } @@ -734,12 +741,12 @@ static int begin_multi_pcap_file(struct ctx *ctx) fd = open_or_die_m(fname, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, DEFFILEMODE); - ret = __pcap_io->push_file_header(fd, ctx->link_type); + ret = __pcap_io->push_fhdr_pcap(fd, ctx->magic, ctx->link_type); if (ret) panic("Error writing pcap header!\n"); - if (__pcap_io->prepare_writing_pcap) { - ret = __pcap_io->prepare_writing_pcap(fd); + if (__pcap_io->prepare_access_pcap) { + ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_WR, ctx->jumbo); if (ret) panic("Error prepare writing pcap!\n"); } @@ -766,7 +773,7 @@ static void finish_single_pcap_file(struct ctx *ctx, int fd) __pcap_io->fsync_pcap(fd); if (__pcap_io->prepare_close_pcap) - __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WRITE); + __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WR); close(fd); } @@ -780,12 +787,12 @@ static int begin_single_pcap_file(struct ctx *ctx) fd = open_or_die_m(ctx->device_out, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, DEFFILEMODE); - ret = __pcap_io->push_file_header(fd, ctx->link_type); + ret = __pcap_io->push_fhdr_pcap(fd, ctx->magic, ctx->link_type); if (ret) panic("Error writing pcap header!\n"); - if (__pcap_io->prepare_writing_pcap) { - ret = __pcap_io->prepare_writing_pcap(fd); + if (__pcap_io->prepare_access_pcap) { + ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_WR, ctx->jumbo); if (ret) panic("Error prepare writing pcap!\n"); } @@ -823,7 +830,7 @@ static void recv_only_or_dump(struct ctx *ctx) struct frame_map *hdr; struct sock_fprog bpf_ops; struct timeval start, end, diff; - struct pcap_pkthdr phdr; + pcap_pkthdr_t phdr; if (!device_up_and_running(ctx->device_in) && !ctx->rfraw) panic("Device not up and running!\n"); @@ -853,7 +860,7 @@ static void recv_only_or_dump(struct ctx *ctx) set_sockopt_hwtimestamp(sock, ctx->device_in); - setup_rx_ring_layout(sock, &rx_ring, size, ctx->jumbo_support); + setup_rx_ring_layout(sock, &rx_ring, size, ctx->jumbo); create_rx_ring(sock, &rx_ring, ctx->verbose); mmap_rx_ring(sock, &rx_ring); alloc_rx_ring_frames(&rx_ring); @@ -878,7 +885,7 @@ static void recv_only_or_dump(struct ctx *ctx) printf("BPF:\n"); bpf_dump_all(&bpf_ops); - printf("MD: RX %s ", ctx->dump ? pcap_ops[ctx->pcap]->name : ""); + printf("MD: RX %s ", ctx->dump ? pcap_ops_group_to_str[ctx->pcap] : ""); if (ctx->rfraw) printf("802.11 raw via %s ", ctx->device_in); #ifdef _LARGEFILE64_SOURCE @@ -933,10 +940,11 @@ static void recv_only_or_dump(struct ctx *ctx) } if (dump_to_pcap(ctx)) { - tpacket_hdr_to_pcap_pkthdr(&hdr->tp_h, &phdr); + tpacket_hdr_to_pcap_pkthdr(&hdr->tp_h, &hdr->s_ll, &phdr, ctx->magic); - ret = __pcap_io->write_pcap_pkt(fd, &phdr, packet, phdr.len); - if (unlikely(ret != sizeof(phdr) + phdr.len)) + ret = __pcap_io->write_pcap(fd, &phdr, ctx->magic, packet, + pcap_get_length(&phdr, ctx->magic)); + if (unlikely(ret != pcap_get_total_length(&phdr, ctx->magic))) panic("Write error to pcap!\n"); } @@ -1046,6 +1054,7 @@ static void help(void) " -l|--ascii Print human-readable packet data\n" "Options, advanced:\n" " -P|--prefix Prefix for pcaps stored in directory\n" + " -T|--magic Pcap magic number/pcap type to process\n" " -r|--rand Randomize packet forwarding order\n" " -M|--no-promisc No promiscuous mode for netdev\n" " -A|--no-sock-mem Don't tune core socket memory\n" @@ -1064,10 +1073,11 @@ static void help(void) " -H|--prio-high Make this high priority process\n" " -Q|--notouch-irq Do not touch IRQ CPU affinity of NIC\n" " -V|--verbose Be more verbose\n" + " -D|--dump-pcap-types Dump pcap types and magic numbers\n" " -v|--version Show version\n" " -h|--help Guess what?!\n\n" "Examples:\n" - " netsniff-ng --in eth0 --out dump.pcap --silent --bind-cpu 0\n" + " netsniff-ng --in eth0 --out dump.pcap --silent -T 0xa1b2c3d4 --bind-cpu 0\n" " netsniff-ng --in wlan0 --rfraw --out dump.pcap --silent --bind-cpu 0\n" " netsniff-ng --in dump.pcap --mmap --out eth0 -k1000 --silent --bind-cpu 0\n" " netsniff-ng --in dump.pcap --out dump.cfg --silent --bind-cpu 0\n" @@ -1121,7 +1131,8 @@ int main(int argc, char **argv) .dump_interval = 60, .dump_mode = DUMP_INTERVAL_TIME, .uid = getuid(), - .gid = getgid() + .gid = getgid(), + .magic = ORIGINAL_TCPDUMP_MAGIC, }; srand(time(NULL)); @@ -1147,7 +1158,11 @@ int main(int argc, char **argv) ctx.randomize = true; break; case 'J': - ctx.jumbo_support = 1; + ctx.jumbo = true; + break; + case 'T': + ctx.magic = (uint32_t) strtoul(optarg, NULL, 0); + pcap_check_magic(ctx.magic); break; case 'f': ctx.filter = xstrdup(optarg); @@ -1219,7 +1234,7 @@ int main(int argc, char **argv) ops_touched = 1; break; case 'm': - ctx.pcap = PCAP_OPS_MMAP; + ctx.pcap = PCAP_OPS_MM; ops_touched = 1; break; case 'G': @@ -1292,6 +1307,10 @@ int main(int argc, char **argv) case 'V': ctx.verbose = 1; break; + case 'D': + pcap_dump_type_features(); + die(); + break; case 'v': version(); break; @@ -1311,6 +1330,7 @@ int main(int argc, char **argv) case 'S': case 'b': case 'k': + case 'T': case 'u': case 'g': case 'B': @@ -1380,7 +1400,7 @@ int main(int argc, char **argv) register_signal_f(SIGALRM, timer_elapsed, SA_SIGINFO); main_loop = pcap_to_xmit; if (!ops_touched) - ctx.pcap = PCAP_OPS_MMAP; + ctx.pcap = PCAP_OPS_MM; } else { main_loop = read_pcap; if (!ops_touched) @@ -1390,8 +1410,6 @@ int main(int argc, char **argv) bug_on(!main_loop); - init_pcap(ctx.pcap, ctx.jumbo_support); - if (setsockmem) set_system_socket_memory(vals); xlockme(); @@ -1403,7 +1421,6 @@ int main(int argc, char **argv) reset_system_socket_memory(vals); tprintf_cleanup(); - cleanup_pcap(); free(ctx.device_in); free(ctx.device_out); diff --git a/src/netsniff-ng/Makefile b/src/netsniff-ng/Makefile index 2f0bad5a..a8d97d7e 100644 --- a/src/netsniff-ng/Makefile +++ b/src/netsniff-ng/Makefile @@ -3,8 +3,7 @@ netsniff-ng-libs = -lnl-genl-3 \ -lpcap \ -lpthread -netsniff-ng-objs = hash.o \ - dissector.o \ +netsniff-ng-objs = dissector.o \ dissector_eth.o \ dissector_80211.o \ proto_arp.o \ @@ -33,14 +32,14 @@ netsniff-ng-objs = hash.o \ xio.o \ xutils.o \ xmalloc.o \ + hash.o \ bpf.o \ oui.o \ - pcap.o \ pcap_rw.o \ pcap_sg.o \ - pcap_mmap.o \ - mac80211.o \ + pcap_mm.o \ ring_rx.o \ ring_tx.o \ tprintf.o \ + mac80211.o \ netsniff-ng.o diff --git a/src/pcap.c b/src/pcap.c deleted file mode 100644 index 481ccb43..00000000 --- a/src/pcap.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * netsniff-ng - the packet sniffing beast - * By Daniel Borkmann - * Copyright 2011 Daniel Borkmann. - * Subject to the GPL, version 2. - */ - -#include -#include "pcap.h" - -const struct pcap_file_ops *pcap_ops[PCAP_OPS_SIZ] = {0}; - -int pcap_ops_group_register(const struct pcap_file_ops *ops, - enum pcap_ops_groups group) -{ - if (!ops) - return -EINVAL; - if (pcap_ops[group]) - return -EBUSY; - pcap_ops[group] = ops; - return 0; -} - -void pcap_ops_group_unregister(enum pcap_ops_groups group) -{ - pcap_ops[group] = NULL; -} diff --git a/src/pcap.h b/src/pcap.h dissimilarity index 71% index 152488f6..23afd972 100644 --- a/src/pcap.h +++ b/src/pcap.h @@ -1,186 +1,460 @@ -/* - * netsniff-ng - the packet sniffing beast - * By Daniel Borkmann - * Copyright 2009, 2010 Daniel Borkmann. - * Copyright 2010 Emmanuel Roullit. - * Subject to the GPL, version 2. - */ - -#ifndef PCAP_H -#define PCAP_H - -#include -#include -#include -#include -#include - -#include "built_in.h" -#include "die.h" - -#define TCPDUMP_MAGIC 0xa1b2c3d4 -#define PCAP_VERSION_MAJOR 2 -#define PCAP_VERSION_MINOR 4 -#define PCAP_DEFAULT_SNAPSHOT_LEN 65535 - -#define LINKTYPE_NULL 0 /* BSD loopback encapsulation */ -#define LINKTYPE_EN10MB 1 /* Ethernet (10Mb) */ -#define LINKTYPE_EN3MB 2 /* Experimental Ethernet (3Mb) */ -#define LINKTYPE_AX25 3 /* Amateur Radio AX.25 */ -#define LINKTYPE_PRONET 4 /* Proteon ProNET Token Ring */ -#define LINKTYPE_CHAOS 5 /* Chaos */ -#define LINKTYPE_IEEE802 6 /* 802.5 Token Ring */ -#define LINKTYPE_ARCNET 7 /* ARCNET, with BSD-style header */ -#define LINKTYPE_SLIP 8 /* Serial Line IP */ -#define LINKTYPE_PPP 9 /* Point-to-point Protocol */ -#define LINKTYPE_FDDI 10 /* FDDI */ -#define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 wireless */ - -struct pcap_filehdr { - uint32_t magic; - uint16_t version_major; - uint16_t version_minor; - int32_t thiszone; - uint32_t sigfigs; - uint32_t snaplen; - uint32_t linktype; -}; - -struct pcap_timeval { - int32_t tv_sec; - int32_t tv_usec; -}; - -struct pcap_nsf_pkthdr { - struct timeval ts; - uint32_t caplen; - uint32_t len; -}; - -struct pcap_pkthdr { - struct pcap_timeval ts; - uint32_t caplen; - uint32_t len; -}; - -static inline void tpacket_hdr_to_pcap_pkthdr(struct tpacket2_hdr *thdr, - struct pcap_pkthdr *phdr) -{ - phdr->ts.tv_sec = thdr->tp_sec; - phdr->ts.tv_usec = (thdr->tp_nsec / 1000); - phdr->caplen = thdr->tp_snaplen; -/* FIXME */ -/* phdr->len = thdr->tp_len; */ - phdr->len = thdr->tp_snaplen; -} - -static inline void pcap_pkthdr_to_tpacket_hdr(struct pcap_pkthdr *phdr, - struct tpacket2_hdr *thdr) -{ - thdr->tp_sec = phdr->ts.tv_sec; - thdr->tp_nsec = phdr->ts.tv_usec * 1000; - thdr->tp_snaplen = phdr->caplen; - thdr->tp_len = phdr->len; -} - -enum pcap_ops_groups { - PCAP_OPS_RW = 0, -#define PCAP_OPS_RW PCAP_OPS_RW - PCAP_OPS_SG, -#define PCAP_OPS_SG PCAP_OPS_SG - PCAP_OPS_MMAP, -#define PCAP_OPS_MMAP PCAP_OPS_MMAP - __PCAP_OPS_MAX, -}; -#define PCAP_OPS_MAX (__PCAP_OPS_MAX - 1) -#define PCAP_OPS_SIZ (__PCAP_OPS_MAX) - -enum pcap_mode { - PCAP_MODE_READ = 0, - PCAP_MODE_WRITE, -}; - -struct pcap_file_ops { - const char *name; - int (*pull_file_header)(int fd, uint32_t *linktype); - int (*push_file_header)(int fd, uint32_t linktype); - int (*prepare_writing_pcap)(int fd); - ssize_t (*write_pcap_pkt)(int fd, struct pcap_pkthdr *hdr, - uint8_t *packet, size_t len); - void (*fsync_pcap)(int fd); - int (*prepare_reading_pcap)(int fd); - ssize_t (*read_pcap_pkt)(int fd, struct pcap_pkthdr *hdr, - uint8_t *packet, size_t len); - void (*prepare_close_pcap)(int fd, enum pcap_mode mode); -}; - -extern const struct pcap_file_ops *pcap_ops[PCAP_OPS_SIZ]; - -extern int pcap_ops_group_register(const struct pcap_file_ops *ops, - enum pcap_ops_groups group); -extern void pcap_ops_group_unregister(enum pcap_ops_groups group); - -static inline const struct pcap_file_ops * -pcap_ops_group_get(enum pcap_ops_groups group) -{ - return pcap_ops[group]; -} - -static inline void pcap_prepare_header(struct pcap_filehdr *hdr, - uint32_t linktype, - int32_t thiszone, uint32_t snaplen) -{ - hdr->magic = TCPDUMP_MAGIC; - hdr->version_major = PCAP_VERSION_MAJOR; - hdr->version_minor = PCAP_VERSION_MINOR; - hdr->thiszone = thiszone; - hdr->sigfigs = 0; - hdr->snaplen = snaplen; - hdr->linktype = linktype; -} - -static inline void pcap_validate_header(struct pcap_filehdr *hdr) -{ - if (unlikely(hdr->magic != TCPDUMP_MAGIC || - hdr->version_major != PCAP_VERSION_MAJOR || - hdr->version_minor != PCAP_VERSION_MINOR || - (hdr->linktype != LINKTYPE_EN10MB && - hdr->linktype != LINKTYPE_IEEE802_11))) - panic("This file has not a valid pcap header\n"); -} - -extern int init_pcap_mmap(int jumbo_support); -extern int init_pcap_rw(int jumbo_support); -extern int init_pcap_sg(int jumbo_support); - -extern void cleanup_pcap_mmap(void); -extern void cleanup_pcap_rw(void); -extern void cleanup_pcap_sg(void); - -static inline int init_pcap(enum pcap_ops_groups ops, int jumbo_support) -{ - switch (ops) { - case PCAP_OPS_RW: - init_pcap_rw(jumbo_support); - break; - case PCAP_OPS_SG: - init_pcap_sg(jumbo_support); - break; - case PCAP_OPS_MMAP: - init_pcap_mmap(jumbo_support); - break; - default: - bug(); - } - - return 0; -} - -static inline void cleanup_pcap(void) -{ - cleanup_pcap_rw(); - cleanup_pcap_sg(); - cleanup_pcap_mmap(); -} - -#endif /* PCAP_H */ +/* + * netsniff-ng - the packet sniffing beast + * By Daniel Borkmann + * Copyright 2009 - 2013 Daniel Borkmann. + * Copyright 2010 Emmanuel Roullit. + * Subject to the GPL, version 2. + */ + +#ifndef PCAP_H +#define PCAP_H + +#include +#include +#include +#include +#include +#include + +#include "built_in.h" +#include "die.h" +#include "xio.h" + +#define TCPDUMP_MAGIC 0xa1b2c3d4 +#define ORIGINAL_TCPDUMP_MAGIC TCPDUMP_MAGIC +#define NSEC_TCPDUMP_MAGIC 0xa1b23c4d +#define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34 +#define BORKMANN_TCPDUMP_MAGIC 0xa1e2cb12 + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 +#define PCAP_DEFAULT_SNAPSHOT_LEN 65535 + +#define LINKTYPE_EN10MB 1 /* Ethernet (10Mb) */ +#define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 wireless */ + +struct pcap_filehdr { + uint32_t magic; + uint16_t version_major; + uint16_t version_minor; + int32_t thiszone; + uint32_t sigfigs; + uint32_t snaplen; + uint32_t linktype; +}; + +struct pcap_timeval { + int32_t tv_sec; + int32_t tv_usec; +}; + +struct pcap_timeval_ns { + int32_t tv_sec; + int32_t tv_nsec; +}; + +struct pcap_pkthdr { + struct pcap_timeval ts; + uint32_t caplen; + uint32_t len; +}; + +struct pcap_pkthdr_ns { + struct pcap_timeval_ns ts; + uint32_t caplen; + uint32_t len; +}; + +struct pcap_pkthdr_kuz { + struct pcap_timeval ts; + uint32_t caplen; + uint32_t len; + int ifindex; + uint16_t protocol; + uint8_t pkttype; +}; + +struct pcap_pkthdr_bkm { + struct pcap_timeval_ns ts; + uint32_t caplen; + uint32_t len; + uint32_t ifindex; + uint16_t protocol; + uint8_t hatype; + uint8_t pkttype; +}; + +typedef union { + struct pcap_pkthdr ppo; + struct pcap_pkthdr_ns ppn; + struct pcap_pkthdr_kuz ppk; + struct pcap_pkthdr_bkm ppb; +} pcap_pkthdr_t; + +enum pcap_type { + DEFAULT = ORIGINAL_TCPDUMP_MAGIC, + NSEC = NSEC_TCPDUMP_MAGIC, + KUZNETZOV = KUZNETZOV_TCPDUMP_MAGIC, + BORKMANN = BORKMANN_TCPDUMP_MAGIC, +}; + +enum pcap_ops_groups { + PCAP_OPS_RW = 0, + PCAP_OPS_SG, + PCAP_OPS_MM, +}; + +enum pcap_mode { + PCAP_MODE_RD = 0, + PCAP_MODE_WR, +}; + +struct pcap_file_ops { + int (*pull_fhdr_pcap)(int fd, uint32_t *magic, uint32_t *linktype); + int (*push_fhdr_pcap)(int fd, uint32_t magic, uint32_t linktype); + int (*prepare_access_pcap)(int fd, enum pcap_mode mode, bool jumbo); + ssize_t (*write_pcap)(int fd, pcap_pkthdr_t *phdr, enum pcap_type type, + const uint8_t *packet, size_t len); + ssize_t (*read_pcap)(int fd, pcap_pkthdr_t *phdr, enum pcap_type type, + uint8_t *packet, size_t len); + void (*prepare_close_pcap)(int fd, enum pcap_mode mode); + void (*fsync_pcap)(int fd); +}; + +extern const struct pcap_file_ops pcap_rw_ops; +extern const struct pcap_file_ops pcap_sg_ops; +extern const struct pcap_file_ops pcap_mm_ops; + +static inline void pcap_check_magic(uint32_t magic) +{ + switch (magic) { + case DEFAULT: + case NSEC: + case KUZNETZOV: + case BORKMANN: + break; + default: + panic("This file has not a valid pcap header\n"); + } +} + +static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, enum pcap_type type) +{ + switch (type) { +#define CASE_RET_CAPLEN(what, member) \ + case (what): \ + return phdr->member.caplen + CASE_RET_CAPLEN(DEFAULT, ppo); + CASE_RET_CAPLEN(NSEC, ppn); + CASE_RET_CAPLEN(KUZNETZOV, ppk); + CASE_RET_CAPLEN(BORKMANN, ppb); + default: + bug(); + } +} + +static inline void pcap_set_length(pcap_pkthdr_t *phdr, enum pcap_type type, u32 len) +{ + switch (type) { +#define CASE_SET_CAPLEN(what, member) \ + case (what): \ + phdr->member.caplen = len; \ + break + CASE_SET_CAPLEN(DEFAULT, ppo); + CASE_SET_CAPLEN(NSEC, ppn); + CASE_SET_CAPLEN(KUZNETZOV, ppk); + CASE_SET_CAPLEN(BORKMANN, ppb); + default: + bug(); + } +} + +static inline u32 pcap_get_hdr_length(pcap_pkthdr_t *phdr, enum pcap_type type) +{ + switch (type) { +#define CASE_RET_HDRLEN(what, member) \ + case (what): \ + return sizeof(phdr->member) + CASE_RET_HDRLEN(DEFAULT, ppo); + CASE_RET_HDRLEN(NSEC, ppn); + CASE_RET_HDRLEN(KUZNETZOV, ppk); + CASE_RET_HDRLEN(BORKMANN, ppb); + default: + bug(); + } +} + +static inline u32 pcap_get_total_length(pcap_pkthdr_t *phdr, enum pcap_type type) +{ + switch (type) { +#define CASE_RET_TOTLEN(what, member) \ + case (what): \ + return phdr->member.caplen + sizeof(phdr->member) + CASE_RET_TOTLEN(DEFAULT, ppo); + CASE_RET_TOTLEN(NSEC, ppn); + CASE_RET_TOTLEN(KUZNETZOV, ppk); + CASE_RET_TOTLEN(BORKMANN, ppb); + default: + bug(); + } +} + +static inline void tpacket_hdr_to_pcap_pkthdr(struct tpacket2_hdr *thdr, + struct sockaddr_ll *sll, + pcap_pkthdr_t *phdr, + enum pcap_type type) +{ + switch (type) { + case DEFAULT: + phdr->ppo.ts.tv_sec = thdr->tp_sec; + phdr->ppo.ts.tv_usec = thdr->tp_nsec / 1000; + phdr->ppo.caplen = thdr->tp_snaplen; + phdr->ppo.len = thdr->tp_len; + break; + + case NSEC: + phdr->ppn.ts.tv_sec = thdr->tp_sec; + phdr->ppn.ts.tv_nsec = thdr->tp_nsec; + phdr->ppn.caplen = thdr->tp_snaplen; + phdr->ppn.len = thdr->tp_len; + break; + + case KUZNETZOV: + phdr->ppk.ts.tv_sec = thdr->tp_sec; + phdr->ppk.ts.tv_usec = thdr->tp_nsec / 1000; + phdr->ppk.caplen = thdr->tp_snaplen; + phdr->ppk.len = thdr->tp_len; + phdr->ppk.ifindex = sll->sll_ifindex; + phdr->ppk.protocol = sll->sll_protocol; + phdr->ppk.pkttype = sll->sll_pkttype; + break; + + case BORKMANN: + phdr->ppb.ts.tv_sec = thdr->tp_sec; + phdr->ppb.ts.tv_nsec = thdr->tp_nsec; + phdr->ppb.caplen = thdr->tp_snaplen; + phdr->ppb.len = thdr->tp_len; + phdr->ppb.ifindex = (u32) sll->sll_ifindex; + phdr->ppb.protocol = sll->sll_protocol; + phdr->ppb.hatype = sll->sll_hatype; + phdr->ppb.pkttype = sll->sll_pkttype; + break; + + default: + bug(); + } +} + +static inline void pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr, + enum pcap_type type, + struct tpacket2_hdr *thdr, + struct sockaddr_ll *sll) +{ + switch (type) { + case DEFAULT: + thdr->tp_sec = phdr->ppo.ts.tv_sec; + thdr->tp_nsec = phdr->ppo.ts.tv_usec * 1000; + thdr->tp_snaplen = phdr->ppo.caplen; + thdr->tp_len = phdr->ppo.len; + break; + + case NSEC: + thdr->tp_sec = phdr->ppn.ts.tv_sec; + thdr->tp_nsec = phdr->ppn.ts.tv_nsec; + thdr->tp_snaplen = phdr->ppn.caplen; + thdr->tp_len = phdr->ppn.len; + break; + + case KUZNETZOV: + thdr->tp_sec = phdr->ppk.ts.tv_sec; + thdr->tp_nsec = phdr->ppk.ts.tv_usec * 1000; + thdr->tp_snaplen = phdr->ppk.caplen; + thdr->tp_len = phdr->ppk.len; + sll->sll_ifindex = phdr->ppk.ifindex; + sll->sll_protocol = phdr->ppk.protocol; + sll->sll_pkttype = phdr->ppk.pkttype; + break; + + case BORKMANN: + thdr->tp_sec = phdr->ppb.ts.tv_sec; + thdr->tp_nsec = phdr->ppb.ts.tv_nsec; + thdr->tp_snaplen = phdr->ppb.caplen; + thdr->tp_len = phdr->ppb.len; + sll->sll_ifindex = (int) phdr->ppb.ifindex; + sll->sll_protocol = phdr->ppb.protocol; + sll->sll_hatype = phdr->ppb.hatype; + sll->sll_pkttype = phdr->ppb.pkttype; + break; + + default: + bug(); + } +} + +#define FEATURE_UNKNOWN (0 << 0) +#define FEATURE_TIMEVAL_MS (1 << 0) +#define FEATURE_TIMEVAL_NS (1 << 1) +#define FEATURE_LEN (1 << 2) +#define FEATURE_CAPLEN (1 << 3) +#define FEATURE_IFINDEX (1 << 4) +#define FEATURE_PROTO (1 << 5) +#define FEATURE_HATYPE (1 << 6) +#define FEATURE_PKTTYPE (1 << 7) + +struct pcap_magic_type { + uint32_t magic; + char *desc; + uint16_t features; +}; + +static const struct pcap_magic_type const pcap_magic_types[] __maybe_unused = { + { + .magic = ORIGINAL_TCPDUMP_MAGIC, + .desc = "tcpdump-capable pcap", + .features = FEATURE_TIMEVAL_MS | + FEATURE_LEN | + FEATURE_CAPLEN, + }, { + .magic = NSEC_TCPDUMP_MAGIC, + .desc = "tcpdump-capable pcap with ns resolution", + .features = FEATURE_TIMEVAL_NS | + FEATURE_LEN | + FEATURE_CAPLEN, + }, { + .magic = KUZNETZOV_TCPDUMP_MAGIC, + .desc = "Alexey Kuznetzov's pcap", + .features = FEATURE_TIMEVAL_MS | + FEATURE_LEN | + FEATURE_CAPLEN | + FEATURE_IFINDEX | + FEATURE_PROTO | + FEATURE_PKTTYPE, + }, { + .magic = BORKMANN_TCPDUMP_MAGIC, + .desc = "netsniff-ng pcap", + .features = FEATURE_TIMEVAL_NS | + FEATURE_LEN | + FEATURE_CAPLEN | + FEATURE_IFINDEX | + FEATURE_PROTO | + FEATURE_HATYPE | + FEATURE_PKTTYPE, + }, +}; + +static inline void pcap_dump_type_features(void) +{ + int i; + + for (i = 0; i < array_size(pcap_magic_types); ++i) { + printf("%s:\n", pcap_magic_types[i].desc); + printf(" magic: 0x%x\n", pcap_magic_types[i].magic); + printf(" features:\n"); + + if (pcap_magic_types[i].features == FEATURE_UNKNOWN) { + printf(" unknown\n"); + continue; + } + + if (pcap_magic_types[i].features & FEATURE_TIMEVAL_MS) + printf(" timeval in us\n"); + if (pcap_magic_types[i].features & FEATURE_TIMEVAL_NS) + printf(" timeval in ns\n"); + if (pcap_magic_types[i].features & FEATURE_LEN) + printf(" packet length\n"); + if (pcap_magic_types[i].features & FEATURE_CAPLEN) + printf(" packet cap-length\n"); + if (pcap_magic_types[i].features & FEATURE_IFINDEX) + printf(" packet ifindex\n"); + if (pcap_magic_types[i].features & FEATURE_PROTO) + printf(" packet protocol\n"); + if (pcap_magic_types[i].features & FEATURE_HATYPE) + printf(" hardware type\n"); + if (pcap_magic_types[i].features & FEATURE_PKTTYPE) + printf(" packet type\n"); + } +} + +static const char *pcap_ops_group_to_str[] __maybe_unused = { + [PCAP_OPS_RW] = "rw", + [PCAP_OPS_SG] = "sg", + [PCAP_OPS_MM] = "mm", +}; + +static const struct pcap_file_ops const *pcap_ops[] __maybe_unused = { + [PCAP_OPS_RW] = &pcap_rw_ops, + [PCAP_OPS_SG] = &pcap_sg_ops, + [PCAP_OPS_MM] = &pcap_mm_ops, +}; + +static inline void pcap_prepare_header(struct pcap_filehdr *hdr, uint32_t magic, + uint32_t linktype, int32_t thiszone, + uint32_t snaplen) +{ + hdr->magic = magic; + hdr->version_major = PCAP_VERSION_MAJOR; + hdr->version_minor = PCAP_VERSION_MINOR; + hdr->thiszone = thiszone; + hdr->sigfigs = 0; + hdr->snaplen = snaplen; + hdr->linktype = linktype; +} + +static inline void pcap_validate_header(const struct pcap_filehdr *hdr) +{ + pcap_check_magic(hdr->magic); + + switch (hdr->linktype) { + case LINKTYPE_EN10MB: + case LINKTYPE_IEEE802_11: + break; + default: + panic("This file has not a valid pcap header\n"); + } + + if (unlikely(hdr->version_major != PCAP_VERSION_MAJOR)) + panic("This file has not a valid pcap header\n"); + if (unlikely(hdr->version_minor != PCAP_VERSION_MINOR)) + panic("This file has not a valid pcap header\n"); +} + +static int pcap_generic_pull_fhdr(int fd, uint32_t *magic, + uint32_t *linktype) __maybe_unused; + +static int pcap_generic_pull_fhdr(int fd, uint32_t *magic, uint32_t *linktype) +{ + ssize_t ret; + struct pcap_filehdr hdr; + + ret = read(fd, &hdr, sizeof(hdr)); + if (unlikely(ret != sizeof(hdr))) + return -EIO; + + pcap_validate_header(&hdr); + + *magic = hdr.magic; + *linktype = hdr.linktype; + + return 0; +} + +static int pcap_generic_push_fhdr(int fd, uint32_t magic, + uint32_t linktype) __maybe_unused; + +static int pcap_generic_push_fhdr(int fd, uint32_t magic, uint32_t linktype) +{ + ssize_t ret; + struct pcap_filehdr hdr; + + memset(&hdr, 0, sizeof(hdr)); + + pcap_prepare_header(&hdr, magic, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN); + + ret = write_or_die(fd, &hdr, sizeof(hdr)); + if (unlikely(ret != sizeof(hdr))) + panic("Failed to write pkt file header!\n"); + + return 0; +} + +#endif /* PCAP_H */ diff --git a/src/pcap_mm.c b/src/pcap_mm.c dissimilarity index 75% index 943ba020..6c9e6afe 100644 --- a/src/pcap_mm.c +++ b/src/pcap_mm.c @@ -1,278 +1,222 @@ -/* - * netsniff-ng - the packet sniffing beast - * By Daniel Borkmann - * Copyright 2011 Daniel Borkmann. - * Subject to the GPL, version 2. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include - -#include "pcap.h" -#include "xio.h" -#include "xutils.h" -#include "locking.h" -#include "built_in.h" - -#define DEFAULT_SLOTS 1000 - -static struct spinlock lock; -static off_t map_size = 0; -static char *pstart, *pcurr; -static int jumbo_frames = 0; - -static inline off_t get_map_size(void) -{ - int allocsz = jumbo_frames ? 16 : 3; - return PAGE_ALIGN(sizeof(struct pcap_filehdr) + - (PAGE_SIZE * allocsz) * DEFAULT_SLOTS); -} - -static int pcap_mmap_pull_file_header(int fd, uint32_t *linktype) -{ - ssize_t ret; - struct pcap_filehdr hdr; - - ret = read(fd, &hdr, sizeof(hdr)); - if (unlikely(ret != sizeof(hdr))) - return -EIO; - - pcap_validate_header(&hdr); - - *linktype = hdr.linktype; - - return 0; -} - -static int pcap_mmap_push_file_header(int fd, uint32_t linktype) -{ - ssize_t ret; - struct pcap_filehdr hdr; - - fmemset(&hdr, 0, sizeof(hdr)); - pcap_prepare_header(&hdr, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN); - - ret = write_or_die(fd, &hdr, sizeof(hdr)); - if (unlikely(ret != sizeof(hdr))) { - whine("Failed to write pkt file header!\n"); - return -EIO; - } - - return 0; -} - -static int pcap_mmap_prepare_writing_pcap(int fd) -{ - int ret; - off_t pos; - struct stat sb; - - spinlock_lock(&lock); - - map_size = get_map_size(); - - ret = fstat(fd, &sb); - if (ret < 0) - panic("Cannot fstat pcap file!\n"); - if (!S_ISREG (sb.st_mode)) - panic("pcap dump file is not a regular file!\n"); - - pos = lseek(fd, map_size, SEEK_SET); - if (pos < 0) - panic("Cannot lseek pcap file!\n"); - - ret = write_or_die(fd, "", 1); - if (ret != 1) - panic("Cannot write file!\n"); - - pstart = mmap(0, map_size, PROT_WRITE, MAP_SHARED - /*| MAP_HUGETLB*/, fd, 0); - if (pstart == MAP_FAILED) - panic("mmap of file failed!"); - - ret = madvise(pstart, map_size, MADV_SEQUENTIAL); - if (ret < 0) - panic("Failed to give kernel mmap advise!\n"); - - pcurr = pstart + sizeof(struct pcap_filehdr); - - spinlock_unlock(&lock); - - return 0; -} - -static ssize_t pcap_mmap_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr, - uint8_t *packet, size_t len) -{ - int ret; - off_t pos; - - spinlock_lock(&lock); - - if ((off_t) (pcurr - pstart) + sizeof(*hdr) + len > map_size) { - off_t map_size_old = map_size; - off_t offset = (pcurr - pstart); - - map_size = PAGE_ALIGN(map_size_old * 10 / 8); - - pos = lseek(fd, map_size, SEEK_SET); - if (pos < 0) - panic("Cannot lseek pcap file!\n"); - - ret = write_or_die(fd, "", 1); - if (ret != 1) - panic("Cannot write file!\n"); - - pstart = mremap(pstart, map_size_old, map_size, MREMAP_MAYMOVE); - if (pstart == MAP_FAILED) - panic("mmap of file failed!"); - - ret = madvise(pstart, map_size, MADV_SEQUENTIAL); - if (ret < 0) - panic("Failed to give kernel mmap advise!\n"); - - pcurr = pstart + offset; - } - - fmemcpy(pcurr, hdr, sizeof(*hdr)); - pcurr += sizeof(*hdr); - - fmemcpy(pcurr, packet, len); - pcurr += len; - - spinlock_unlock(&lock); - - return sizeof(*hdr) + len; -} - -static int pcap_mmap_prepare_reading_pcap(int fd) -{ - int ret; - struct stat sb; - - spinlock_lock(&lock); - - ret = fstat(fd, &sb); - if (ret < 0) - panic("Cannot fstat pcap file!\n"); - - if (!S_ISREG (sb.st_mode)) - panic("pcap dump file is not a regular file!\n"); - - map_size = sb.st_size; - - pstart = mmap(0, map_size, PROT_READ, MAP_SHARED | MAP_LOCKED - /*| MAP_HUGETLB*/, fd, 0); - if (pstart == MAP_FAILED) - panic("mmap of file failed!"); - - ret = madvise(pstart, map_size, MADV_SEQUENTIAL); - if (ret < 0) - panic("Failed to give kernel mmap advise!\n"); - - pcurr = pstart + sizeof(struct pcap_filehdr); - - spinlock_unlock(&lock); - - return 0; -} - -static ssize_t pcap_mmap_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr, - uint8_t *packet, size_t len) -{ - ssize_t ret; - spinlock_lock(&lock); - - if (unlikely((off_t) (pcurr + sizeof(*hdr) - pstart) > map_size)) { - spinlock_unlock(&lock); - return -ENOMEM; - } - - fmemcpy(hdr, pcurr, sizeof(*hdr)); - pcurr += sizeof(*hdr); - - if (unlikely((off_t) (pcurr + hdr->caplen - pstart) > map_size)) { - ret = -ENOMEM; - goto out_err; - } - - if (unlikely(hdr->caplen == 0 || hdr->caplen > len)) { - ret = -EINVAL; /* Bogus packet */ - goto out_err; - } - - fmemcpy(packet, pcurr, hdr->caplen); - pcurr += hdr->caplen; - - spinlock_unlock(&lock); - - return sizeof(*hdr) + hdr->caplen; - -out_err: - spinlock_unlock(&lock); - return ret; -} - -static void pcap_mmap_fsync_pcap(int fd) -{ - spinlock_lock(&lock); - - msync(pstart, (off_t) (pcurr - pstart), MS_ASYNC); - - spinlock_unlock(&lock); -} - -static void pcap_mmap_prepare_close_pcap(int fd, enum pcap_mode mode) -{ - int ret; - - spinlock_lock(&lock); - - ret = munmap(pstart, map_size); - if (ret < 0) - panic("Cannot unmap the pcap file!\n"); - - if (mode == PCAP_MODE_WRITE) { - ret = ftruncate(fd, (off_t) (pcurr - pstart)); - if (ret) - panic("Cannot truncate the pcap file!\n"); - } - - spinlock_unlock(&lock); -} - -const struct pcap_file_ops pcap_mmap_ops = { - .name = "mmap", - .pull_file_header = pcap_mmap_pull_file_header, - .push_file_header = pcap_mmap_push_file_header, - .prepare_writing_pcap = pcap_mmap_prepare_writing_pcap, - .write_pcap_pkt = pcap_mmap_write_pcap_pkt, - .prepare_reading_pcap = pcap_mmap_prepare_reading_pcap, - .read_pcap_pkt = pcap_mmap_read_pcap_pkt, - .fsync_pcap = pcap_mmap_fsync_pcap, - .prepare_close_pcap = pcap_mmap_prepare_close_pcap, -}; - -int init_pcap_mmap(int jumbo_support) -{ - spinlock_init(&lock); - - jumbo_frames = jumbo_support; - - set_ioprio_be(); - - return pcap_ops_group_register(&pcap_mmap_ops, PCAP_OPS_MMAP); -} - -void cleanup_pcap_mmap(void) -{ - spinlock_destroy(&lock); - - pcap_ops_group_unregister(PCAP_OPS_MMAP); -} - +/* + * netsniff-ng - the packet sniffing beast + * By Daniel Borkmann + * Copyright 2011 - 2013 Daniel Borkmann. + * Subject to the GPL, version 2. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include "pcap.h" +#include "xio.h" +#include "xutils.h" +#include "built_in.h" + +static size_t map_size = 0; +static char *ptr_va_start, *ptr_va_curr; + +static void __pcap_mmap_write_need_remap(int fd) +{ + int ret; + off_t pos, map_size_old = map_size; + off_t offset = ptr_va_curr - ptr_va_start; + + map_size = PAGE_ALIGN(map_size_old * 10 / 8); + + pos = lseek(fd, map_size, SEEK_SET); + if (pos < 0) + panic("Cannot lseek pcap file!\n"); + + ret = write_or_die(fd, "", 1); + if (ret != 1) + panic("Cannot write file!\n"); + + ptr_va_start = mremap(ptr_va_start, map_size_old, map_size, MREMAP_MAYMOVE); + if (ptr_va_start == MAP_FAILED) + panic("mmap of file failed!"); + + ret = madvise(ptr_va_start, map_size, MADV_SEQUENTIAL); + if (ret < 0) + panic("Failed to give kernel mmap advise!\n"); + + ptr_va_curr = ptr_va_start + offset; +} + +static ssize_t pcap_mm_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type, + const uint8_t *packet, size_t len) +{ + size_t hdrsize = pcap_get_hdr_length(phdr, type); + + if ((off_t) (ptr_va_curr - ptr_va_start) + hdrsize + len > map_size) + __pcap_mmap_write_need_remap(fd); + + switch (type) { +#define CASE_HDR_WRITE(what, __member__) \ + case (what): \ + fmemcpy(ptr_va_curr, &phdr->__member__, hdrsize); \ + break + CASE_HDR_WRITE(DEFAULT, ppo); + CASE_HDR_WRITE(NSEC, ppn); + CASE_HDR_WRITE(KUZNETZOV, ppk); + CASE_HDR_WRITE(BORKMANN, ppb); + default: + bug(); + } + + ptr_va_curr += hdrsize; + fmemcpy(ptr_va_curr, packet, len); + ptr_va_curr += len; + + return hdrsize + len; +} + +static ssize_t pcap_mm_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type, + uint8_t *packet, size_t len) +{ + size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen; + + if (unlikely((off_t) (ptr_va_curr + hdrsize - ptr_va_start) > map_size)) + return -EIO; + + switch (type) { +#define CASE_HDR_READ(what, __member__) \ + case (what): \ + fmemcpy(&phdr->__member__, ptr_va_curr, hdrsize); \ + break + CASE_HDR_READ(DEFAULT, ppo); + CASE_HDR_READ(NSEC, ppn); + CASE_HDR_READ(KUZNETZOV, ppk); + CASE_HDR_READ(BORKMANN, ppb); + default: + bug(); + } + + ptr_va_curr += hdrsize; + hdrlen = pcap_get_length(phdr, type); + + if (unlikely((off_t) (ptr_va_curr + hdrlen - ptr_va_start) > map_size)) + return -EIO; + if (unlikely(hdrlen == 0 || hdrlen > len)) + return -EINVAL; + + fmemcpy(packet, ptr_va_curr, hdrlen); + ptr_va_curr += hdrlen; + + return hdrsize + hdrlen; +} + +static inline off_t ____get_map_size(bool jumbo) +{ + int allocsz = jumbo ? 16 : 3; + + return PAGE_ALIGN(sizeof(struct pcap_filehdr) + (PAGE_SIZE * allocsz) * 1024); +} + +static void __pcap_mm_prepare_access_wr(int fd, bool jumbo) +{ + int ret; + off_t pos; + struct stat sb; + + map_size = ____get_map_size(jumbo); + + ret = fstat(fd, &sb); + if (ret < 0) + panic("Cannot fstat pcap file!\n"); + if (!S_ISREG (sb.st_mode)) + panic("pcap dump file is not a regular file!\n"); + + pos = lseek(fd, map_size, SEEK_SET); + if (pos < 0) + panic("Cannot lseek pcap file!\n"); + + ret = write_or_die(fd, "", 1); + if (ret != 1) + panic("Cannot write file!\n"); + + ptr_va_start = mmap(0, map_size, PROT_WRITE, MAP_SHARED /*| MAP_HUGETLB*/, fd, 0); + if (ptr_va_start == MAP_FAILED) + panic("mmap of file failed!"); + ret = madvise(ptr_va_start, map_size, MADV_SEQUENTIAL); + if (ret < 0) + panic("Failed to give kernel mmap advise!\n"); + + ptr_va_curr = ptr_va_start + sizeof(struct pcap_filehdr); +} + +static void __pcap_mm_prepare_access_rd(int fd) +{ + int ret; + struct stat sb; + + ret = fstat(fd, &sb); + if (ret < 0) + panic("Cannot fstat pcap file!\n"); + if (!S_ISREG (sb.st_mode)) + panic("pcap dump file is not a regular file!\n"); + + map_size = sb.st_size; + ptr_va_start = mmap(0, map_size, PROT_READ, MAP_SHARED | MAP_LOCKED /*| MAP_HUGETLB*/, fd, 0); + if (ptr_va_start == MAP_FAILED) + panic("mmap of file failed!"); + ret = madvise(ptr_va_start, map_size, MADV_SEQUENTIAL); + if (ret < 0) + panic("Failed to give kernel mmap advise!\n"); + + ptr_va_curr = ptr_va_start + sizeof(struct pcap_filehdr); +} + +static int pcap_mm_prepare_access(int fd, enum pcap_mode mode, bool jumbo) +{ + set_ioprio_be(); + + switch (mode) { + case PCAP_MODE_RD: + __pcap_mm_prepare_access_rd(fd); + break; + case PCAP_MODE_WR: + __pcap_mm_prepare_access_wr(fd, jumbo); + break; + default: + bug(); + } + + return 0; +} + +static void pcap_mm_fsync(int fd) +{ + msync(ptr_va_start, (off_t) (ptr_va_curr - ptr_va_start), MS_ASYNC); +} + +static void pcap_mm_prepare_close(int fd, enum pcap_mode mode) +{ + int ret; + + ret = munmap(ptr_va_start, map_size); + if (ret < 0) + panic("Cannot unmap the pcap file!\n"); + + if (mode == PCAP_MODE_WR) { + ret = ftruncate(fd, (off_t) (ptr_va_curr - ptr_va_start)); + if (ret) + panic("Cannot truncate the pcap file!\n"); + } +} + +const struct pcap_file_ops pcap_mm_ops = { + .pull_fhdr_pcap = pcap_generic_pull_fhdr, + .push_fhdr_pcap = pcap_generic_push_fhdr, + .prepare_access_pcap = pcap_mm_prepare_access, + .prepare_close_pcap = pcap_mm_prepare_close, + .read_pcap = pcap_mm_read, + .write_pcap = pcap_mm_write, + .fsync_pcap = pcap_mm_fsync, +}; diff --git a/src/pcap_rw.c b/src/pcap_rw.c dissimilarity index 80% index 717f4891..c8ff55e7 100644 --- a/src/pcap_rw.c +++ b/src/pcap_rw.c @@ -1,114 +1,110 @@ -/* - * netsniff-ng - the packet sniffing beast - * By Daniel Borkmann - * Copyright 2009, 2010, 2011 Daniel Borkmann. - * Subject to the GPL, version 2. - */ - -#include -#include -#include -#include -#include - -#include "pcap.h" -#include "built_in.h" -#include "xutils.h" -#include "xio.h" -#include "die.h" - -static int pcap_rw_pull_file_header(int fd, uint32_t *linktype) -{ - ssize_t ret; - struct pcap_filehdr hdr; - - ret = read(fd, &hdr, sizeof(hdr)); - if (unlikely(ret != sizeof(hdr))) - return -EIO; - - pcap_validate_header(&hdr); - - *linktype = hdr.linktype; - - return 0; -} - -static int pcap_rw_push_file_header(int fd, uint32_t linktype) -{ - ssize_t ret; - struct pcap_filehdr hdr; - - memset(&hdr, 0, sizeof(hdr)); - pcap_prepare_header(&hdr, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN); - - ret = write_or_die(fd, &hdr, sizeof(hdr)); - if (unlikely(ret != sizeof(hdr))) { - whine("Failed to write pkt file header!\n"); - return -EIO; - } - - return 0; -} - -static ssize_t pcap_rw_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr, - uint8_t *packet, size_t len) -{ - ssize_t ret = write_or_die(fd, hdr, sizeof(*hdr)); - if (unlikely(ret != sizeof(*hdr))) { - whine("Failed to write pkt header!\n"); - return -EIO; - } - - if (unlikely(hdr->len != len)) - return -EINVAL; - - ret = write_or_die(fd, packet, hdr->len); - if (unlikely(ret != hdr->len)) { - whine("Failed to write pkt payload!\n"); - return -EIO; - } - - return sizeof(*hdr) + hdr->len; -} - -static ssize_t pcap_rw_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr, - uint8_t *packet, size_t len) -{ - ssize_t ret = read(fd, hdr, sizeof(*hdr)); - if (unlikely(ret != sizeof(*hdr))) - return -EIO; - - if (unlikely(hdr->caplen == 0 || hdr->caplen > len)) - return -EINVAL; /* Bogus packet */ - - ret = read(fd, packet, hdr->caplen); - if (unlikely(ret != hdr->caplen)) - return -EIO; - - return sizeof(*hdr) + hdr->caplen; -} - -static void pcap_rw_fsync_pcap(int fd) -{ - fdatasync(fd); -} - -const struct pcap_file_ops pcap_rw_ops = { - .name = "read-write", - .pull_file_header = pcap_rw_pull_file_header, - .push_file_header = pcap_rw_push_file_header, - .write_pcap_pkt = pcap_rw_write_pcap_pkt, - .read_pcap_pkt = pcap_rw_read_pcap_pkt, - .fsync_pcap = pcap_rw_fsync_pcap, -}; - -int init_pcap_rw(int jumbo_support) -{ - set_ioprio_rt(); - return pcap_ops_group_register(&pcap_rw_ops, PCAP_OPS_RW); -} - -void cleanup_pcap_rw(void) -{ - pcap_ops_group_unregister(PCAP_OPS_RW); -} +/* + * netsniff-ng - the packet sniffing beast + * By Daniel Borkmann + * Copyright 2009 - 2013 Daniel Borkmann. + * Subject to the GPL, version 2. + */ + +#include +#include +#include +#include +#include +#include + +#include "pcap.h" +#include "built_in.h" +#include "xutils.h" +#include "xio.h" +#include "die.h" + +static ssize_t pcap_rw_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type, + const uint8_t *packet, size_t len) +{ + ssize_t ret, hdrlen = 0, hdrsize = 0; + + switch (type) { +#define PCAP_HDR_WRITE(__member__) do { \ + hdrlen = phdr->__member__.caplen; \ + hdrsize = sizeof(phdr->__member__); \ + ret = write_or_die(fd, &phdr->__member__, hdrsize); \ + } while (0) +#define CASE_HDR_WRITE(what, member) \ + case (what): \ + PCAP_HDR_WRITE(member); \ + break + CASE_HDR_WRITE(DEFAULT, ppo); + CASE_HDR_WRITE(NSEC, ppn); + CASE_HDR_WRITE(KUZNETZOV, ppk); + CASE_HDR_WRITE(BORKMANN, ppb); + default: + bug(); + } + + if (unlikely(ret != hdrsize)) + panic("Failed to write pkt header!\n"); + if (unlikely(hdrlen != len)) + return -EINVAL; + + ret = write_or_die(fd, packet, hdrlen); + if (unlikely(ret != hdrlen)) + panic("Failed to write pkt payload!\n"); + + return hdrsize + hdrlen; +} + +static ssize_t pcap_rw_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type, + uint8_t *packet, size_t len) +{ + ssize_t ret, hdrlen = 0, hdrsize = 0; + + switch (type) { +#define PCAP_HDR_READ(__member__) do { \ + hdrsize = sizeof(phdr->__member__); \ + ret = read_or_die(fd, &phdr->__member__, hdrsize); \ + if (unlikely(ret != hdrsize)) \ + return -EIO; \ + hdrlen = phdr->__member__.caplen; \ + } while (0) +#define CASE_HDR_READ(what, member) \ + case (what): \ + PCAP_HDR_READ(member); \ + break + CASE_HDR_READ(DEFAULT, ppo); + CASE_HDR_READ(NSEC, ppn); + CASE_HDR_READ(KUZNETZOV, ppk); + CASE_HDR_READ(BORKMANN, ppb); + default: + bug(); + } + + if (unlikely(hdrlen == 0 || hdrlen > len)) + return -EINVAL; + + ret = read(fd, packet, hdrlen); + if (unlikely(ret != hdrlen)) + return -EIO; + + return hdrsize + hdrlen; +} + +static int pcap_rw_prepare_access(int fd, enum pcap_mode mode, bool jumbo) +{ + set_ioprio_rt(); + + return 0; +} + +static void pcap_rw_fsync(int fd) +{ + fdatasync(fd); +} + +const struct pcap_file_ops pcap_rw_ops = { + .pull_fhdr_pcap = pcap_generic_pull_fhdr, + .push_fhdr_pcap = pcap_generic_push_fhdr, + .prepare_access_pcap = pcap_rw_prepare_access, + .read_pcap = pcap_rw_read, + .write_pcap = pcap_rw_write, + .fsync_pcap = pcap_rw_fsync, +}; diff --git a/src/pcap_sg.c b/src/pcap_sg.c dissimilarity index 87% index f49b032b..620e0724 100644 --- a/src/pcap_sg.c +++ b/src/pcap_sg.c @@ -1,263 +1,249 @@ -/* - * netsniff-ng - the packet sniffing beast - * By Daniel Borkmann - * Copyright 2011 Daniel Borkmann. - * Subject to the GPL, version 2. - */ - -#include -#include -#include -#include -#include -#include - -#include "pcap.h" -#include "xmalloc.h" -#include "xio.h" -#include "xutils.h" -#include "locking.h" -#include "built_in.h" - -#define IOVSIZ 1000 -#define ALLSIZ (PAGE_SIZE * 3) -#define ALLSIZ_2K (PAGE_SIZE * 3) // 12K max -#define ALLSIZ_JUMBO (PAGE_SIZE * 16) // 64K max - -static struct iovec iov[IOVSIZ]; -static unsigned long c = 0; -static struct spinlock lock; -static ssize_t iov_used; - -static int pcap_sg_pull_file_header(int fd, uint32_t *linktype) -{ - ssize_t ret; - struct pcap_filehdr hdr; - - ret = read(fd, &hdr, sizeof(hdr)); - if (unlikely(ret != sizeof(hdr))) - return -EIO; - - pcap_validate_header(&hdr); - - *linktype = hdr.linktype; - - return 0; -} - -static int pcap_sg_push_file_header(int fd, uint32_t linktype) -{ - ssize_t ret; - struct pcap_filehdr hdr; - - fmemset(&hdr, 0, sizeof(hdr)); - pcap_prepare_header(&hdr, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN); - - ret = write_or_die(fd, &hdr, sizeof(hdr)); - if (unlikely(ret != sizeof(hdr))) { - whine("Failed to write pkt file header!\n"); - return -EIO; - } - - return 0; -} - -static ssize_t pcap_sg_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr, - uint8_t *packet, size_t len) -{ - ssize_t ret; - - spinlock_lock(&lock); - - if (unlikely(c == IOVSIZ)) { - ret = writev(fd, iov, IOVSIZ); - if (ret < 0) - panic("writev I/O error!\n"); - - c = 0; - } - - iov[c].iov_len = 0; - fmemcpy(iov[c].iov_base, hdr, sizeof(*hdr)); - - iov[c].iov_len += sizeof(*hdr); - fmemcpy(iov[c].iov_base + iov[c].iov_len, packet, len); - - iov[c].iov_len += len; - ret = iov[c].iov_len; - - c++; - - spinlock_unlock(&lock); - - return ret; -} - -static int pcap_sg_prepare_reading_pcap(int fd) -{ - spinlock_lock(&lock); - if (readv(fd, iov, IOVSIZ) <= 0) - return -EIO; - - iov_used = 0; - c = 0; - spinlock_unlock(&lock); - - return 0; -} - -static ssize_t pcap_sg_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr, - uint8_t *packet, size_t len) -{ - ssize_t ret = 0; - - /* In contrast to writing, reading gets really ugly ... */ - spinlock_lock(&lock); - - if (likely(iov[c].iov_len - iov_used >= sizeof(*hdr))) { - fmemcpy(hdr, iov[c].iov_base + iov_used, sizeof(*hdr)); - iov_used += sizeof(*hdr); - } else { - size_t offset = 0; - ssize_t remainder; - - offset = iov[c].iov_len - iov_used; - remainder = sizeof(*hdr) - offset; - if (remainder < 0) - remainder = 0; - - bug_on(offset + remainder != sizeof(*hdr)); - - fmemcpy(hdr, iov[c].iov_base + iov_used, offset); - - iov_used = 0; - c++; - - if (c == IOVSIZ) { - /* We need to refetch! */ - c = 0; - if (readv(fd, iov, IOVSIZ) <= 0) { - ret = -EIO; - goto out_err; - } - } - - /* Now we copy the remainder and go on with business ... */ - fmemcpy((uint8_t *) hdr + offset, - iov[c].iov_base + iov_used, remainder); - iov_used += remainder; - } - - /* header read completed */ - - if (unlikely(hdr->caplen == 0 || hdr->caplen > len)) { - ret = -EINVAL; /* Bogus packet */ - goto out_err; - } - - /* now we read data ... */ - - if (likely(iov[c].iov_len - iov_used >= hdr->caplen)) { - fmemcpy(packet, iov[c].iov_base + iov_used, hdr->caplen); - iov_used += hdr->caplen; - } else { - size_t offset = 0; - ssize_t remainder; - - offset = iov[c].iov_len - iov_used; - remainder = hdr->caplen - offset; - if (remainder < 0) - remainder = 0; - - bug_on(offset + remainder != hdr->caplen); - - fmemcpy(packet, iov[c].iov_base + iov_used, offset); - - iov_used = 0; - c++; - - if (c == IOVSIZ) { - /* We need to refetch! */ - c = 0; - if (readv(fd, iov, IOVSIZ) <= 0) { - ret = -EIO; - goto out_err; - } - } - - /* Now we copy the remainder and go on with business ... */ - fmemcpy(packet + offset, iov[c].iov_base + iov_used, remainder); - iov_used += remainder; - } - - spinlock_unlock(&lock); - - return sizeof(*hdr) + hdr->caplen; - -out_err: - spinlock_unlock(&lock); - return ret; -} - -static void pcap_sg_fsync_pcap(int fd) -{ - ssize_t ret; - - spinlock_lock(&lock); - ret = writev(fd, iov, c); - if (ret < 0) - panic("writev I/O error!\n"); - - c = 0; - - fdatasync(fd); - spinlock_unlock(&lock); -} - -const struct pcap_file_ops pcap_sg_ops = { - .name = "scatter-gather", - .pull_file_header = pcap_sg_pull_file_header, - .push_file_header = pcap_sg_push_file_header, - .write_pcap_pkt = pcap_sg_write_pcap_pkt, - .prepare_reading_pcap = pcap_sg_prepare_reading_pcap, - .read_pcap_pkt = pcap_sg_read_pcap_pkt, - .fsync_pcap = pcap_sg_fsync_pcap, -}; - -int init_pcap_sg(int jumbo_support) -{ - unsigned long i; - size_t allocsz = 0; - - c = 0; - - fmemset(iov, 0, sizeof(iov)); - - if (jumbo_support) - allocsz = ALLSIZ_JUMBO; - else - allocsz = ALLSIZ_2K; - - for (i = 0; i < IOVSIZ; ++i) { - iov[i].iov_base = xzmalloc_aligned(allocsz, 64); - iov[i].iov_len = allocsz; - } - - spinlock_init(&lock); - - set_ioprio_rt(); - - return pcap_ops_group_register(&pcap_sg_ops, PCAP_OPS_SG); -} - -void cleanup_pcap_sg(void) -{ - unsigned long i; - - spinlock_destroy(&lock); - - for (i = 0; i < IOVSIZ; ++i) - xfree(iov[i].iov_base); - - pcap_ops_group_unregister(PCAP_OPS_SG); -} +/* + * netsniff-ng - the packet sniffing beast + * By Daniel Borkmann + * Copyright 2011 - 2013 Daniel Borkmann. + * Subject to the GPL, version 2. + */ + +#include +#include +#include +#include +#include +#include + +#include "pcap.h" +#include "xmalloc.h" +#include "xio.h" +#include "xutils.h" +#include "built_in.h" + +static struct iovec iov[1024] __cacheline_aligned; +static off_t iov_off_rd = 0, iov_slot = 0; + +static ssize_t pcap_sg_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type, + const uint8_t *packet, size_t len) +{ + ssize_t ret; + + if (unlikely(iov_slot == array_size(iov))) { + ret = writev(fd, iov, array_size(iov)); + if (ret < 0) + panic("Writev I/O error: %s!\n", strerror(errno)); + + iov_slot = 0; + } + + iov[iov_slot].iov_len = 0; + switch (type) { +#define PCAP_HDR_WRITE(__member__) do { \ + fmemcpy(iov[iov_slot].iov_base, &phdr->__member__, \ + sizeof(phdr->__member__)); \ + iov[iov_slot].iov_len += sizeof(phdr->__member__); \ + } while(0) +#define CASE_HDR_WRITE(what, member) \ + case (what): \ + PCAP_HDR_WRITE(member); \ + break + CASE_HDR_WRITE(DEFAULT, ppo); + CASE_HDR_WRITE(NSEC, ppn); + CASE_HDR_WRITE(KUZNETZOV, ppk); + CASE_HDR_WRITE(BORKMANN, ppb); + default: + bug(); + } + + fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len, packet, len); + ret = (iov[iov_slot].iov_len += len); + iov_slot++; + + return ret; +} + +static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type, + uint8_t *packet, size_t len, size_t hdrsize) +{ + int ret; + size_t offset = 0; + ssize_t remainder; + + offset = iov[iov_slot].iov_len - iov_off_rd; + remainder = hdrsize - offset; + if (remainder < 0) + remainder = 0; + + bug_on(offset + remainder != hdrsize); + + switch (type) { +#define CASE_HDR_PREAD(what, __member__) \ + case (what): \ + fmemcpy(&phdr->__member__, \ + iov[iov_slot].iov_base + iov_off_rd, offset); \ + break + CASE_HDR_PREAD(DEFAULT, ppo); + CASE_HDR_PREAD(NSEC, ppn); + CASE_HDR_PREAD(KUZNETZOV, ppk); + CASE_HDR_PREAD(BORKMANN, ppb); + default: + bug(); + } + + iov_off_rd = 0; + iov_slot++; + + if (iov_slot == array_size(iov)) { + iov_slot = 0; + ret = readv(fd, iov, array_size(iov)); + if (unlikely(ret <= 0)) + return -EIO; + } + + switch (type) { +#define CASE_HDR_RREAD(what, __member__) \ + case (what): \ + fmemcpy(&phdr->__member__ + offset, \ + iov[iov_slot].iov_base + iov_off_rd, remainder); \ + break + CASE_HDR_RREAD(DEFAULT, ppo); + CASE_HDR_RREAD(NSEC, ppn); + CASE_HDR_RREAD(KUZNETZOV, ppk); + CASE_HDR_RREAD(BORKMANN, ppb); + default: + bug(); + } + + iov_off_rd += remainder; + + return hdrsize; +} + +static ssize_t __pcap_sg_inter_iov_data_read(int fd, uint8_t *packet, size_t len, size_t hdrlen) +{ + int ret; + size_t offset = 0; + ssize_t remainder; + + offset = iov[iov_slot].iov_len - iov_off_rd; + remainder = hdrlen - offset; + if (remainder < 0) + remainder = 0; + + bug_on(offset + remainder != hdrlen); + + fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, offset); + iov_off_rd = 0; + iov_slot++; + + if (iov_slot == array_size(iov)) { + iov_slot = 0; + ret = readv(fd, iov, array_size(iov)); + if (unlikely(ret <= 0)) + return -EIO; + } + + fmemcpy(packet + offset, iov[iov_slot].iov_base + iov_off_rd, remainder); + iov_off_rd += remainder; + + return hdrlen; +} + +static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type, + uint8_t *packet, size_t len) +{ + ssize_t ret = 0; + size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen; + + if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrsize)) { + switch (type) { +#define CASE_HDR_READ(what, __member__) \ + case (what): \ + fmemcpy(&phdr->__member__, \ + iov[iov_slot].iov_base + iov_off_rd, hdrsize); \ + break + CASE_HDR_READ(DEFAULT, ppo); + CASE_HDR_READ(NSEC, ppn); + CASE_HDR_READ(KUZNETZOV, ppk); + CASE_HDR_READ(BORKMANN, ppb); + default: + bug(); + } + + iov_off_rd += hdrsize; + } else { + ret = __pcap_sg_inter_iov_hdr_read(fd, phdr, type, packet, + len, hdrsize); + if (unlikely(ret < 0)) + return ret; + } + + hdrlen = pcap_get_length(phdr, type); + if (unlikely(hdrlen == 0 || hdrlen > len)) + return -EINVAL; + + if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrlen)) { + fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, hdrlen); + iov_off_rd += hdrlen; + } else { + ret = __pcap_sg_inter_iov_data_read(fd, packet, len, hdrlen); + if (unlikely(ret < 0)) + return ret; + } + + return hdrsize + hdrlen; +} + +static void pcap_sg_fsync(int fd) +{ + ssize_t ret = writev(fd, iov, iov_slot); + if (ret < 0) + panic("Writev I/O error: %s!\n", strerror(errno)); + + iov_slot = 0; + fdatasync(fd); +} + +static int pcap_sg_prepare_access(int fd, enum pcap_mode mode, bool jumbo) +{ + int i, ret; + size_t len = 0; + + iov_slot = 0; + len = jumbo ? (PAGE_SIZE * 16) /* 64k max */ : + (PAGE_SIZE * 3) /* 12k max */; + + for (i = 0; i < array_size(iov); ++i) { + iov[i].iov_base = xzmalloc_aligned(len, 64); + iov[i].iov_len = len; + } + + set_ioprio_rt(); + + if (mode == PCAP_MODE_RD) { + ret = readv(fd, iov, array_size(iov)); + if (ret <= 0) + return -EIO; + + iov_off_rd = 0; + iov_slot = 0; + } + + return 0; +} + +static void pcap_sg_prepare_close(int fd, enum pcap_mode mode) +{ + int i; + + for (i = 0; i < array_size(iov); ++i) + xfree(iov[i].iov_base); +} + +const struct pcap_file_ops pcap_sg_ops = { + .pull_fhdr_pcap = pcap_generic_pull_fhdr, + .push_fhdr_pcap = pcap_generic_push_fhdr, + .prepare_access_pcap = pcap_sg_prepare_access, + .prepare_close_pcap = pcap_sg_prepare_close, + .read_pcap = pcap_sg_read, + .write_pcap = pcap_sg_write, + .fsync_pcap = pcap_sg_fsync, +}; -- 2.11.4.GIT