summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Klauser <tklauser@distanz.ch>2014-06-04 10:52:53 +0200
committerTobias Klauser <tklauser@distanz.ch>2014-06-04 10:52:53 +0200
commitedca6174b09d14c75a7bbc25af122a37ff16ecea (patch)
treea378bbdf9792b774a8d61885569c1df273088204
parent96cbba90a5ccf29c2124b8d4d46ed534861ccf44 (diff)
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 <tklauser@distanz.ch>
-rw-r--r--dissector.h29
-rw-r--r--netsniff-ng.c12
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 <sys/socket.h>
#include <linux/if_packet.h>
#include <linux/if.h>
+#include <libnl3/netlink/msg.h>
#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);