From 97e6f994785ce5f3f486f8eddb62df964119d121 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 26 May 2014 15:10:33 +0200 Subject: netsniff-ng: Restore tpacket v2 capturing Some older systems (e.g. RHEL 6) don't have tpacket v3 available, but only tpacket v2. However, since commit d8cdc6a ("ring: netsniff-ng: migrate capture only to TPACKET_V3") we solely rely on tpacket v3 for capturing packets. This patch restores the possibility to capture using tpacket v2. For now this is just a fallback if the configure script doesn't detect tpacket v3 (and thus HAVE_TPACKET3 isn't set). Thus, on most modern systems this shouldn't change anything and they will continue using tpacket v3. For now this fix contains quite a bit of ugly #ifdefery which should be cleaned up in the future. Fixes #76 Signed-off-by: Tobias Klauser --- configure | 1 - dissector.h | 8 +++---- netsniff-ng.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- pcap_io.h | 2 ++ ring.h | 12 ++++++++-- ring_rx.c | 17 +++++++++++++- ring_rx.h | 10 +++++---- 7 files changed, 109 insertions(+), 13 deletions(-) diff --git a/configure b/configure index d9cebff..1ac21be 100755 --- a/configure +++ b/configure @@ -206,7 +206,6 @@ EOF if [ ! -x $TMPDIR/tpacketv3test ] ; then echo "[NO]" MISSING_DEFS=1 - tools_remove "netsniff-ng" else echo "[YES]" HAVE_TPACKET3=1 diff --git a/dissector.h b/dissector.h index f4963c9..c78ea48 100644 --- a/dissector.h +++ b/dissector.h @@ -77,15 +77,15 @@ static inline void __show_frame_hdr(uint8_t *packet, size_t len, int linktype, tprintf("%s %s %u", packet_types[pkttype] ? : "?", if_indextoname(s_ll->sll_ifindex, tmp) ? : "?", - v3 ? hdr.h3->tp_len : hdr.h2->tp_len); + tpacket_uhdr(hdr, tp_len, v3)); break; default: tprintf("%s %s %u %us.%uns %s\n", packet_types[pkttype] ? : "?", if_indextoname(s_ll->sll_ifindex, tmp) ? : "?", - v3 ? hdr.h3->tp_len : hdr.h2->tp_len, - v3 ? hdr.h3->tp_sec : hdr.h2->tp_sec, - v3 ? hdr.h3->tp_nsec : hdr.h2->tp_nsec, + tpacket_uhdr(hdr, tp_len, v3), + tpacket_uhdr(hdr, tp_sec, v3), + tpacket_uhdr(hdr, tp_nsec, v3), v3 ? "" : __show_ts_source(hdr.h2->tp_status)); break; } diff --git a/netsniff-ng.c b/netsniff-ng.c index af36d5c..984f9ca 100644 --- a/netsniff-ng.c +++ b/netsniff-ng.c @@ -790,6 +790,7 @@ static void print_pcap_file_stats(int sock, struct ctx *ctx) } } +#ifdef HAVE_TPACKET3 static void walk_t3_block(struct block_desc *pbd, struct ctx *ctx, int sock, int *fd, unsigned long *frame_count) { @@ -856,6 +857,7 @@ next: } } } +#endif /* HAVE_TPACKET3 */ static void recv_only_or_dump(struct ctx *ctx) { @@ -867,8 +869,10 @@ static void recv_only_or_dump(struct ctx *ctx) struct pollfd rx_poll; struct sock_fprog bpf_ops; struct timeval start, end, diff; - struct block_desc *pbd; unsigned long frame_count = 0; +#ifdef HAVE_TPACKET3 + struct block_desc *pbd; +#endif sock = pf_socket(); @@ -939,6 +943,7 @@ static void recv_only_or_dump(struct ctx *ctx) bug_on(gettimeofday(&start, NULL)); while (likely(sigint == 0)) { +#ifdef HAVE_TPACKET3 while (user_may_pull_from_rx_block((pbd = (void *) rx_ring.frames[it].iov_base))) { walk_t3_block(pbd, ctx, sock, &fd, &frame_count); @@ -949,6 +954,71 @@ static void recv_only_or_dump(struct ctx *ctx) if (unlikely(sigint == 1)) break; } +#else + while (user_may_pull_from_rx(rx_ring.frames[it].iov_base)) { + struct frame_map *hdr = rx_ring.frames[it].iov_base; + uint8_t *packet = ((uint8_t *) hdr) + hdr->tp_h.tp_mac; + pcap_pkthdr_t phdr; + + if (ctx->packet_type != -1) + if (ctx->packet_type != hdr->s_ll.sll_pkttype) + goto next; + + frame_count++; + + if (unlikely(ring_frame_size(&rx_ring) < hdr->tp_h.tp_snaplen)) { + /* XXX: silently ignore for now. We used to + * report them with sock_rx_net_stats() */ + goto next; + } + + if (dump_to_pcap(ctx)) { + tpacket_hdr_to_pcap_pkthdr(&hdr->tp_h, &hdr->s_ll, &phdr, ctx->magic); + + ret = __pcap_io->write_pcap(fd, &phdr, ctx->magic, packet, + pcap_get_length(&phdr, ctx->magic)); + if (unlikely(ret != (int) pcap_get_total_length(&phdr, ctx->magic))) + panic("Write error to pcap!\n"); + } + + show_frame_hdr(hdr, ctx->print_mode); + + dissector_entry_point(packet, hdr->tp_h.tp_snaplen, + ctx->link_type, ctx->print_mode); + + if (frame_count_max != 0) { + if (unlikely(frame_count >= frame_count_max)) { + sigint = 1; + break; + } + } + +next: + kernel_may_pull_from_rx(&hdr->tp_h); + it = (it + 1) % rx_ring.layout.tp_frame_nr; + + if (unlikely(sigint == 1)) + break; + + if (dump_to_pcap(ctx)) { + if (ctx->dump_mode == DUMP_INTERVAL_SIZE) { + interval += hdr->tp_h.tp_snaplen; + if (interval > ctx->dump_interval) { + next_dump = true; + interval = 0; + } + } + + if (next_dump) { + fd = next_multi_pcap_file(ctx, fd); + next_dump = false; + + if (unlikely(ctx->verbose)) + print_pcap_file_stats(sock, ctx); + } + } + } +#endif /* HAVE_TPACKET3 */ ret = poll(&rx_poll, 1, -1); if (unlikely(ret < 0)) { diff --git a/pcap_io.h b/pcap_io.h index 061c214..529cde0 100644 --- a/pcap_io.h +++ b/pcap_io.h @@ -416,6 +416,7 @@ static inline void tpacket_hdr_to_pcap_pkthdr(struct tpacket2_hdr *thdr, thdr->tp_status, sll, phdr, type); } +#ifdef HAVE_TPACKET3 static inline void tpacket3_hdr_to_pcap_pkthdr(struct tpacket3_hdr *thdr, struct sockaddr_ll *sll, pcap_pkthdr_t *phdr, @@ -425,6 +426,7 @@ static inline void tpacket3_hdr_to_pcap_pkthdr(struct tpacket3_hdr *thdr, thdr->tp_snaplen, thdr->tp_len, 0, sll, phdr, type); } +#endif static inline void pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr, enum pcap_type type, diff --git a/ring.h b/ring.h index acf5d59..3b02c76 100644 --- a/ring.h +++ b/ring.h @@ -35,6 +35,14 @@ union tpacket_uhdr { void *raw; }; +#ifdef HAVE_TPACKET3 +#define tpacket_uhdr(hdr, member, v3) \ + ((v3) ? ((hdr).h3)->member : ((hdr).h2)->member) +#else +#define tpacket_uhdr(hdr, member, v3) \ + (((hdr).h2)->member) +#endif /* HAVE_TPACKET3 */ + struct frame_map { struct tpacket2_hdr tp_h __aligned_tpacket; struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket2_hdr)); @@ -132,12 +140,12 @@ static inline void set_sockopt_tpacket_v2(int sock) __set_sockopt_tpacket(sock, TPACKET_V2); } +#ifdef HAVE_TPACKET3 static inline void set_sockopt_tpacket_v3(int sock) { -#ifdef HAVE_TPACKET3 __set_sockopt_tpacket(sock, TPACKET_V3); -#endif } +#endif static inline int get_sockopt_tpacket(int sock) { diff --git a/ring_rx.c b/ring_rx.c index 7a3d21d..1b8dd23 100644 --- a/ring_rx.c +++ b/ring_rx.c @@ -58,6 +58,8 @@ static void setup_rx_ring_layout(int sock, struct ring *ring, size_t size, ring->layout.tp_frame_nr = ring->layout.tp_block_size / ring->layout.tp_frame_size * ring->layout.tp_block_nr; + +#ifdef HAVE_TPACKET3 if (v3) { /* Pass out, if this will ever change and we do crap on it! */ build_bug_on(offsetof(struct tpacket_req, tp_frame_nr) != @@ -70,6 +72,9 @@ static void setup_rx_ring_layout(int sock, struct ring *ring, size_t size, ring->layout3.tp_feature_req_word = 0; set_sockopt_tpacket_v3(sock); +#else + if (0) { +#endif /* HAVE_TPACKET3 */ } else { set_sockopt_tpacket_v2(sock); } @@ -80,11 +85,17 @@ static void setup_rx_ring_layout(int sock, struct ring *ring, size_t size, static void create_rx_ring(int sock, struct ring *ring, bool verbose) { int ret; +#ifdef HAVE_TPACKET3 bool v3 = get_sockopt_tpacket(sock) == TPACKET_V3; + size_t layout_size = v3 ? sizeof(ring->layout3) : sizeof(ring->layout); +#else + bool v3 = false; + size_t layout_size = sizeof(ring->layout); +#endif /* HAVE_TPACKET3 */ retry: ret = setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &ring->raw, - v3 ? sizeof(ring->layout3) : sizeof(ring->layout)); + layout_size); if (errno == ENOMEM && ring->layout.tp_block_nr > 1) { ring->layout.tp_block_nr >>= 1; @@ -115,11 +126,15 @@ static void alloc_rx_ring_frames(int sock, struct ring *ring) { int num; size_t size; +#if HAVE_TPACKET3 bool v3 = get_sockopt_tpacket(sock) == TPACKET_V3; if (v3) { num = ring->layout3.tp_block_nr; size = ring->layout3.tp_block_size; +#else + if (0) { +#endif /* HAVE_TPACKET3 */ } else { num = ring->layout.tp_frame_nr; size = ring->layout.tp_frame_size; diff --git a/ring_rx.h b/ring_rx.h index 02c65bc..60a0eeb 100644 --- a/ring_rx.h +++ b/ring_rx.h @@ -22,19 +22,21 @@ static inline int user_may_pull_from_rx(struct tpacket2_hdr *hdr) return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER); } -static inline int user_may_pull_from_rx_block(struct block_desc *pbd) +static inline void kernel_may_pull_from_rx(struct tpacket2_hdr *hdr) { - return ((pbd->h1.block_status & TP_STATUS_USER) == TP_STATUS_USER); + hdr->tp_status = TP_STATUS_KERNEL; } -static inline void kernel_may_pull_from_rx(struct tpacket2_hdr *hdr) +#ifdef HAVE_TPACKET3 +static inline int user_may_pull_from_rx_block(struct block_desc *pbd) { - hdr->tp_status = TP_STATUS_KERNEL; + return ((pbd->h1.block_status & TP_STATUS_USER) == TP_STATUS_USER); } static inline void kernel_may_pull_from_rx_block(struct block_desc *pbd) { pbd->h1.block_status = TP_STATUS_KERNEL; } +#endif /* HAVE_TPACKETV3 */ #endif /* RX_RING_H */ -- cgit v1.2.3-54-g00ecf