From edca6174b09d14c75a7bbc25af122a37ff16ecea Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 4 Jun 2014 10:52:53 +0200 Subject: dissector: Restore paket type if capturing from nlmon device The kernel sets the skb pkttype to PACKET_OUTGOING for all packets being sent through dev_queue_xmit_nit(). However, if capturing packets from an nlmon device, this causes the information on whether the netlink packet was sent to kernel- or userspace (PACKET_KERNEL/PACKET_USER) to be overwritten. A previous attempt by Daniel Borkmann to fix this in kernel space [1] by not overwriting the packet type for netlink packets was not regarded as the proper solution. [1] http://patchwork.ozlabs.org/patch/338612/ Thus, attempt to fix this in userspace by looking at the pid field of the netlink packet, which is always 0 for messages to kernel space [2]. [2] http://www.carisma.slowglass.com/~tgr/libnl/doc/core.html#core_netlink_fundamentals Signed-off-by: Tobias Klauser --- dissector.h | 29 ++++++++++++++++++++++------- netsniff-ng.c | 12 ++++++++---- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/dissector.h b/dissector.h index e564697..f4963c9 100644 --- a/dissector.h +++ b/dissector.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "ring.h" #include "tprintf.h" @@ -48,26 +49,39 @@ static inline const char *__show_ts_source(uint32_t status) return ""; } -static inline void __show_frame_hdr(struct sockaddr_ll *s_ll, - void *raw, int mode, bool v3) +static inline void __show_frame_hdr(uint8_t *packet, size_t len, int linktype, + struct sockaddr_ll *s_ll, void *raw_hdr, + int mode, bool v3) { char tmp[IFNAMSIZ]; union tpacket_uhdr hdr; + uint8_t pkttype = s_ll->sll_pkttype; if (mode == PRINT_NONE) return; - hdr.raw = raw; + /* + * If we're capturing on nlmon0, all packets will have sll_pkttype set + * to PACKET_OUTGOING, but we actually want PACKET_USER/PACKET_KERNEL as + * it originally was set in the kernel. Thus, use nlmsghdr->nlmsg_pid to + * restore the type. + */ + if (linktype == AF_NETLINK && len >= sizeof(struct nlmsghdr)) { + struct nlmsghdr *hdr = (struct nlmsghdr *) packet; + pkttype = hdr->nlmsg_pid == 0 ? PACKET_KERNEL : PACKET_USER; + } + + hdr.raw = raw_hdr; switch (mode) { case PRINT_LESS: tprintf("%s %s %u", - packet_types[s_ll->sll_pkttype] ? : "?", + packet_types[pkttype] ? : "?", if_indextoname(s_ll->sll_ifindex, tmp) ? : "?", v3 ? hdr.h3->tp_len : hdr.h2->tp_len); break; default: tprintf("%s %s %u %us.%uns %s\n", - packet_types[s_ll->sll_pkttype] ? : "?", + 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, @@ -77,9 +91,10 @@ static inline void __show_frame_hdr(struct sockaddr_ll *s_ll, } } -static inline void show_frame_hdr(struct frame_map *hdr, int mode) +static inline void show_frame_hdr(uint8_t *packet, size_t len, int linktype, + struct frame_map *hdr, int mode) { - __show_frame_hdr(&hdr->s_ll, &hdr->tp_h, mode, false); + __show_frame_hdr(packet, len, linktype, &hdr->s_ll, &hdr->tp_h, mode, false); } extern void dissector_init_all(int fnttype); diff --git a/netsniff-ng.c b/netsniff-ng.c index c126115..397f50d 100644 --- a/netsniff-ng.c +++ b/netsniff-ng.c @@ -277,7 +277,8 @@ static void pcap_to_xmit(struct ctx *ctx) ctx->tx_bytes += hdr->tp_h.tp_len;; ctx->tx_packets++; - show_frame_hdr(hdr, ctx->print_mode); + show_frame_hdr(out, hdr->tp_h.tp_snaplen, + ctx->link_type, hdr, ctx->print_mode); dissector_entry_point(out, hdr->tp_h.tp_snaplen, ctx->link_type, ctx->print_mode); @@ -424,7 +425,8 @@ static void receive_to_xmit(struct ctx *ctx) it_out = 0; } - show_frame_hdr(hdr_in, ctx->print_mode); + show_frame_hdr(in, hdr_in->tp_h.tp_snaplen, + ctx->link_type, hdr_in, ctx->print_mode); dissector_entry_point(in, hdr_in->tp_h.tp_snaplen, ctx->link_type, ctx->print_mode); @@ -594,7 +596,8 @@ static void read_pcap(struct ctx *ctx) ctx->tx_bytes += fm.tp_h.tp_len; ctx->tx_packets++; - show_frame_hdr(&fm, ctx->print_mode); + show_frame_hdr(out, fm.tp_h.tp_snaplen, ctx->link_type, &fm, + ctx->print_mode); dissector_entry_point(out, fm.tp_h.tp_snaplen, ctx->link_type, ctx->print_mode); @@ -817,7 +820,8 @@ static void walk_t3_block(struct block_desc *pbd, struct ctx *ctx, panic("Write error to pcap!\n"); } - __show_frame_hdr(sll, hdr, ctx->print_mode, true); + __show_frame_hdr(packet, hdr->tp_snaplen, ctx->link_type, sll, + hdr, ctx->print_mode, true); dissector_entry_point(packet, hdr->tp_snaplen, ctx->link_type, ctx->print_mode); -- cgit v1.2.3-54-g00ecf