[PATCH 0/3] Add suport for Linux "cooked" header sniff & dissect

80 views
Skip to first unread message

Vadim Kochan

unread,
Jun 13, 2015, 8:32:07 AM6/13/15
to netsn...@googlegroups.com, Vadim Kochan
This series adds supporting of Linux "cooked" header

http://www.tcpdump.org/linktypes/LINKTYPE_NETLINK.html

which is compatible with Wireshark. Also it can be dissected by new
dissector_sll.c while dumping.

Needs to test on archs's with different byte ordering.

1) Moved some device's stuff string conversion functions from proto_nlmsg.c
to dev.c to be used in dissector_sll.c

2) Add suporting Linux "cooked" header.
Added -w,--cooked option which replaces L2 header frame with cooked
header for each frame and allows to dump & dissect Ethernet & Netlink
packets together.

Linux "cooked" header is automatically used for Netlink link type
for the other cases (for -i any) it needs to specify "--cooked" option.

Used dgram packet socket when sniffing with "--cooked" option
to pull L2 header and wrap packet with Linux "cooked" header, it allows
compatibility with Wireshark.

3) Added dissector_sll.c to dissect packets with Linux "cooked" header.
Meanwhile it can dump only Netlink & Ethernet protos (L3 layer). This
dissector is used if link type is LINKTYPE_LINUX_SLL.

Vadim Kochan (3):
dev: Add device string convertions (addr, dev type)
netsniff-ng: Add support of Linux "cooked" header
netsniff-ng: Add dissector for Linux "cooked" packets

dev.c | 111 +++++++++++++++
dev.h | 3 +
dissector.c | 12 +-
dissector.h | 2 +-
dissector_sll.c | 114 +++++++++++++++
dissector_sll.h | 18 +++
linktype.h | 1 +
netsniff-ng.8 | 16 ++-
netsniff-ng.c | 35 +++--
netsniff-ng/Makefile | 1 +
pcap_io.h | 390 ++++++++++++++++++++++++++++++++++++---------------
pcap_mm.c | 28 +++-
pcap_rw.c | 30 +++-
pcap_sg.c | 83 +++++------
pkt_buff.h | 2 +-
proto_nlmsg.c | 120 +---------------
sock.c | 10 ++
sock.h | 1 +
18 files changed, 688 insertions(+), 289 deletions(-)
create mode 100644 dissector_sll.c
create mode 100644 dissector_sll.h

--
2.4.2

Vadim Kochan

unread,
Jun 13, 2015, 8:32:08 AM6/13/15
to netsn...@googlegroups.com, Vadim Kochan
From: Vadim Kochan <vad...@gmail.com>

Move device string convertions funcs (device_type2str, device_addr2str)
from proto_nlmsg.c to dev.c to use them in other modules.

Signed-off-by: Vadim Kochan <vad...@gmail.com>
---
dev.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
dev.h | 3 ++
proto_nlmsg.c | 116 ++--------------------------------------------------------
3 files changed, 118 insertions(+), 112 deletions(-)

diff --git a/dev.c b/dev.c
index 2b3a7a5..292e15e 100644
--- a/dev.c
+++ b/dev.c
@@ -5,6 +5,7 @@
#include <sys/socket.h>
#include <linux/if_arp.h>
#include <ifaddrs.h>
+#include <arpa/inet.h>

#include "dev.h"
#include "str.h"
@@ -221,3 +222,113 @@ void device_leave_promiscuous_mode(const char *ifname, short oldflags)

device_set_flags(ifname, oldflags);
}
+
+char *device_type2str(uint16_t type)
+{
+ switch (type) {
+ case ARPHRD_ETHER: return "ether";
+ case ARPHRD_EETHER: return "eether";
+ case ARPHRD_AX25: return "ax25";
+ case ARPHRD_PRONET: return "pronet";
+ case ARPHRD_CHAOS: return "chaos";
+ case ARPHRD_IEEE802: return "ieee802";
+ case ARPHRD_ARCNET: return "arcnet";
+ case ARPHRD_APPLETLK: return "appletlk";
+ case ARPHRD_DLCI: return "dlci";
+ case ARPHRD_ATM: return "atm";
+ case ARPHRD_METRICOM: return "metricom";
+ case ARPHRD_IEEE1394: return "ieee1394";
+ case ARPHRD_INFINIBAND: return "infiniband";
+ case ARPHRD_SLIP: return "slip";
+ case ARPHRD_CSLIP: return "cslip";
+ case ARPHRD_SLIP6: return "slip6";
+ case ARPHRD_CSLIP6: return "cslip6";
+ case ARPHRD_RSRVD: return "RSRVD";
+ case ARPHRD_ADAPT: return "adapt";
+ case ARPHRD_ROSE: return "rose";
+ case ARPHRD_X25: return "x25";
+ case ARPHRD_HWX25: return "hwx25";
+ case ARPHRD_CAN: return "can";
+ case ARPHRD_PPP: return "ppp";
+ case ARPHRD_HDLC: return "hdlc";
+ case ARPHRD_LAPB: return "lapb";
+ case ARPHRD_DDCMP: return "ddcmp";
+ case ARPHRD_RAWHDLC: return "rawhdlc";
+ case ARPHRD_TUNNEL: return "tunnel";
+ case ARPHRD_TUNNEL6: return "tunnel6";
+ case ARPHRD_FRAD: return "frad";
+ case ARPHRD_SKIP: return "skip";
+ case ARPHRD_LOOPBACK: return "loopback";
+ case ARPHRD_LOCALTLK: return "localtlk";
+ case ARPHRD_FDDI: return "fddi";
+ case ARPHRD_BIF: return "bif";
+ case ARPHRD_SIT: return "sit";
+ case ARPHRD_IPDDP: return "ipddp";
+ case ARPHRD_IPGRE: return "ipgre";
+ case ARPHRD_PIMREG: return "pimreg";
+ case ARPHRD_HIPPI: return "hippi";
+ case ARPHRD_ASH: return "ash";
+ case ARPHRD_ECONET: return "econet";
+ case ARPHRD_IRDA: return "irda";
+ case ARPHRD_FCPP: return "fcpp";
+ case ARPHRD_FCAL: return "fcal";
+ case ARPHRD_FCPL: return "fcpl";
+ case ARPHRD_FCFABRIC: return "fcfb0";
+ case ARPHRD_FCFABRIC + 1: return "fcfb1";
+ case ARPHRD_FCFABRIC + 2: return "fcfb2";
+ case ARPHRD_FCFABRIC + 3: return "fcfb3";
+ case ARPHRD_FCFABRIC + 4: return "fcfb4";
+ case ARPHRD_FCFABRIC + 5: return "fcfb5";
+ case ARPHRD_FCFABRIC + 6: return "fcfb6";
+ case ARPHRD_FCFABRIC + 7: return "fcfb7";
+ case ARPHRD_FCFABRIC + 8: return "fcfb8";
+ case ARPHRD_FCFABRIC + 9: return "fcfb9";
+ case ARPHRD_FCFABRIC + 10: return "fcfb10";
+ case ARPHRD_FCFABRIC + 11: return "fcfb11";
+ case ARPHRD_FCFABRIC + 12: return "fcfb12";
+ case ARPHRD_IEEE802_TR: return "ieee802_tr";
+ case ARPHRD_IEEE80211: return "ieee80211";
+ case ARPHRD_IEEE80211_PRISM: return "ieee80211_prism";
+ case ARPHRD_IEEE80211_RADIOTAP: return "ieee80211_radiotap";
+ case ARPHRD_IEEE802154: return "ieee802154";
+ case ARPHRD_PHONET: return "phonet";
+ case ARPHRD_PHONET_PIPE: return "phonet_pipe";
+ case ARPHRD_CAIF: return "caif";
+ case ARPHRD_IP6GRE: return "ip6gre";
+ case ARPHRD_NETLINK: return "netlink";
+ case ARPHRD_NONE: return "none";
+ case ARPHRD_VOID: return "void";
+
+ default: return "Unknown";
+ }
+}
+
+/* Taken from iproute2 ll_addr_n2a func */
+const char *device_addr2str(const unsigned char *addr, int alen, int type,
+ char *buf, int blen)
+{
+ int i;
+ int l;
+
+ if (alen == 4 &&
+ (type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) {
+ return inet_ntop(AF_INET, addr, buf, blen);
+ }
+ if (alen == 16 && type == ARPHRD_TUNNEL6) {
+ return inet_ntop(AF_INET6, addr, buf, blen);
+ }
+ l = 0;
+ for (i=0; i<alen; i++) {
+ if (i==0) {
+ snprintf(buf+l, blen, "%02x", addr[i]);
+ blen -= 2;
+ l += 2;
+ } else {
+ snprintf(buf+l, blen, ":%02x", addr[i]);
+ blen -= 3;
+ l += 3;
+ }
+ }
+ return buf;
+}
+
diff --git a/dev.h b/dev.h
index adb1c43..3b26d86 100644
--- a/dev.h
+++ b/dev.h
@@ -15,5 +15,8 @@ extern int device_up_and_running(const char *ifname);
extern u32 device_bitrate(const char *ifname);
extern short device_enter_promiscuous_mode(const char *ifname);
extern void device_leave_promiscuous_mode(const char *ifname, short oldflags);
+extern char *device_type2str(uint16_t type);
+extern const char *device_addr2str(const unsigned char *addr, int alen,
+ int type, char *buf, int blen);

#endif /* DEV_H */
diff --git a/proto_nlmsg.c b/proto_nlmsg.c
index 50a0d3f..9dc9f6b 100644
--- a/proto_nlmsg.c
+++ b/proto_nlmsg.c
@@ -15,6 +15,7 @@
#include <linux/if_arp.h>
#include <arpa/inet.h>

+#include "dev.h"
#include "pkt_buff.h"
#include "proto.h"
#include "protos.h"
@@ -165,115 +166,6 @@ static const char *nlmsg_rtnl_type2str(uint16_t type)
}
}

-static char *if_type2str(uint16_t type)
-{
- switch (type) {
- case ARPHRD_ETHER: return "ether";
- case ARPHRD_EETHER: return "eether";
- case ARPHRD_AX25: return "ax25";
- case ARPHRD_PRONET: return "pronet";
- case ARPHRD_CHAOS: return "chaos";
- case ARPHRD_IEEE802: return "ieee802";
- case ARPHRD_ARCNET: return "arcnet";
- case ARPHRD_APPLETLK: return "appletlk";
- case ARPHRD_DLCI: return "dlci";
- case ARPHRD_ATM: return "atm";
- case ARPHRD_METRICOM: return "metricom";
- case ARPHRD_IEEE1394: return "ieee1394";
- case ARPHRD_INFINIBAND: return "infiniband";
- case ARPHRD_SLIP: return "slip";
- case ARPHRD_CSLIP: return "cslip";
- case ARPHRD_SLIP6: return "slip6";
- case ARPHRD_CSLIP6: return "cslip6";
- case ARPHRD_RSRVD: return "RSRVD";
- case ARPHRD_ADAPT: return "adapt";
- case ARPHRD_ROSE: return "rose";
- case ARPHRD_X25: return "x25";
- case ARPHRD_HWX25: return "hwx25";
- case ARPHRD_CAN: return "can";
- case ARPHRD_PPP: return "ppp";
- case ARPHRD_HDLC: return "hdlc";
- case ARPHRD_LAPB: return "lapb";
- case ARPHRD_DDCMP: return "ddcmp";
- case ARPHRD_RAWHDLC: return "rawhdlc";
- case ARPHRD_TUNNEL: return "tunnel";
- case ARPHRD_TUNNEL6: return "tunnel6";
- case ARPHRD_FRAD: return "frad";
- case ARPHRD_SKIP: return "skip";
- case ARPHRD_LOOPBACK: return "loopback";
- case ARPHRD_LOCALTLK: return "localtlk";
- case ARPHRD_FDDI: return "fddi";
- case ARPHRD_BIF: return "bif";
- case ARPHRD_SIT: return "sit";
- case ARPHRD_IPDDP: return "ipddp";
- case ARPHRD_IPGRE: return "ipgre";
- case ARPHRD_PIMREG: return "pimreg";
- case ARPHRD_HIPPI: return "hippi";
- case ARPHRD_ASH: return "ash";
- case ARPHRD_ECONET: return "econet";
- case ARPHRD_IRDA: return "irda";
- case ARPHRD_FCPP: return "fcpp";
- case ARPHRD_FCAL: return "fcal";
- case ARPHRD_FCPL: return "fcpl";
- case ARPHRD_FCFABRIC: return "fcfb0";
- case ARPHRD_FCFABRIC + 1: return "fcfb1";
- case ARPHRD_FCFABRIC + 2: return "fcfb2";
- case ARPHRD_FCFABRIC + 3: return "fcfb3";
- case ARPHRD_FCFABRIC + 4: return "fcfb4";
- case ARPHRD_FCFABRIC + 5: return "fcfb5";
- case ARPHRD_FCFABRIC + 6: return "fcfb6";
- case ARPHRD_FCFABRIC + 7: return "fcfb7";
- case ARPHRD_FCFABRIC + 8: return "fcfb8";
- case ARPHRD_FCFABRIC + 9: return "fcfb9";
- case ARPHRD_FCFABRIC + 10: return "fcfb10";
- case ARPHRD_FCFABRIC + 11: return "fcfb11";
- case ARPHRD_FCFABRIC + 12: return "fcfb12";
- case ARPHRD_IEEE802_TR: return "ieee802_tr";
- case ARPHRD_IEEE80211: return "ieee80211";
- case ARPHRD_IEEE80211_PRISM: return "ieee80211_prism";
- case ARPHRD_IEEE80211_RADIOTAP: return "ieee80211_radiotap";
- case ARPHRD_IEEE802154: return "ieee802154";
- case ARPHRD_PHONET: return "phonet";
- case ARPHRD_PHONET_PIPE: return "phonet_pipe";
- case ARPHRD_CAIF: return "caif";
- case ARPHRD_IP6GRE: return "ip6gre";
- case ARPHRD_NETLINK: return "netlink";
- case ARPHRD_NONE: return "none";
- case ARPHRD_VOID: return "void";
-
- default: return "Unknown";
- }
-}
-
-/* Taken from iproute2 */
-static const char *ll_addr_n2a(const unsigned char *addr, int alen, int type,
- char *buf, int blen)
-{
- int i;
- int l;
-
- if (alen == 4 &&
- (type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) {
- return inet_ntop(AF_INET, addr, buf, blen);
- }
- if (alen == 16 && type == ARPHRD_TUNNEL6) {
- return inet_ntop(AF_INET6, addr, buf, blen);
- }
- l = 0;
- for (i=0; i<alen; i++) {
- if (i==0) {
- snprintf(buf+l, blen, "%02x", addr[i]);
- blen -= 2;
- l += 2;
- } else {
- snprintf(buf+l, blen, ":%02x", addr[i]);
- blen -= 3;
- l += 3;
- }
- }
- return buf;
-}
-
static char *nlmsg_type2str(uint16_t proto, uint16_t type, char *buf, int len)
{
if (proto == NETLINK_ROUTE && type < RTM_MAX) {
@@ -336,7 +228,7 @@ static void rtnl_print_ifinfo(struct nlmsghdr *hdr)
colorize_start(bold), af_link, colorize_end());
tprintf(", Type %d (%s%s%s)", ifi->ifi_type,
colorize_start(bold),
- if_type2str(ifi->ifi_type),
+ device_type2str(ifi->ifi_type),
colorize_end());
tprintf(", Index %d", ifi->ifi_index);
tprintf(", Flags 0x%x (%s%s%s)", ifi->ifi_flags,
@@ -354,13 +246,13 @@ static void rtnl_print_ifinfo(struct nlmsghdr *hdr)
switch (attr->rta_type) {
case IFLA_ADDRESS:
attr_fmt(attr, "Address %s",
- ll_addr_n2a(RTA_DATA(attr),
+ device_addr2str(RTA_DATA(attr),
RTA_LEN(attr), ifi->ifi_type,
if_addr, sizeof(if_addr)));
break;
case IFLA_BROADCAST:
attr_fmt(attr, "Broadcast %s",
- ll_addr_n2a(RTA_DATA(attr),
+ device_addr2str(RTA_DATA(attr),
RTA_LEN(attr), ifi->ifi_type,
if_addr, sizeof(if_addr)));
break;
--
2.4.2

Vadim Kochan

unread,
Jun 13, 2015, 8:32:10 AM6/13/15
to netsn...@googlegroups.com, Vadim Kochan
From: Vadim Kochan <vad...@gmail.com>

Use Linux "cooked" header for Netlink interface automatically
of as replavement of L2 header by specifiyng "--cooked" option.

http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html

"cooked" header makes sense to use for default or nsec pcap types
which does not contain protocol info.

Added new LINKTYPE_LINUX_SLL which indicates pcap file with
Linux "cooked" header as L2 layer header.This pcap file is
compatible with Wireshark's "cooked" header & vice-versa.

Signed-off-by: Vadim Kochan <vad...@gmail.com>
---
linktype.h | 1 +
netsniff-ng.8 | 16 ++-
netsniff-ng.c | 25 +++-
pcap_io.h | 390 +++++++++++++++++++++++++++++++++++++++++-----------------
pcap_mm.c | 28 ++++-
pcap_rw.c | 30 ++++-
pcap_sg.c | 83 +++++++------
sock.c | 10 ++
sock.h | 1 +
9 files changed, 418 insertions(+), 166 deletions(-)

diff --git a/linktype.h b/linktype.h
index a78f8be..80b5f2d 100644
--- a/linktype.h
+++ b/linktype.h
@@ -21,6 +21,7 @@
#define LINKTYPE_C_HDLC 104
#define LINKTYPE_IEEE802_11 105
#define LINKTYPE_FRELAY 107
+#define LINKTYPE_LINUX_SLL 113
#define LINKTYPE_ECONET 115
#define LINKTYPE_IEEE802_11_RADIOTAP 127
#define LINKTYPE_ARCNET_LINUX 129
diff --git a/netsniff-ng.8 b/netsniff-ng.8
index 677a78c..25d5edb 100644
--- a/netsniff-ng.8
+++ b/netsniff-ng.8
@@ -69,7 +69,9 @@ netsniff-ng can also be used to debug netlink traffic.
Defines an input device. This can either be a networking device, a pcap file
or stdin (\[lq]\-\[rq]). In case of a pcap file, the pcap type (\[lq]\-D\[rq]
option) is determined automatically by the pcap file magic. In case of stdin,
-it is assumed that the input stream is a pcap file.
+it is assumed that the input stream is a pcap file. If the pcap link type is a
+Netlink and pcap type is default or nsec then each packet will be wrapped
+with pcap cooked header [2].
.PP
.SS -o <dev|pcap|dir|cfg|->, --out <dev|pcap|dir|cfg|->
Defines the output device. This can either be a networking device, a pcap file,
@@ -84,7 +86,10 @@ input device is a pcap file. To specify a pcap file as the output device, the
file name must have \[lq].pcap\[rq] as its extension. If stdout is given as a
device, then a trafgen configuration will be written to stdout if the input
device is a pcap file, or a pcap file if the input device is a networking
-device.
+device. In case if the input device is a Netlink monitor device and pcap type
+is default or nsec then each packet will be wrapped with pcap cooked header [2]
+to keep Netlink family number (Kuznetzov's and netsniff-ng pcap types already
+contains family number in protocol number field).
.PP
.SS -C <id>, --fanout-group <id>
If multiple netsniff-ng instances are being started that all have the same packet
@@ -254,6 +259,11 @@ possible addresses. Thus, to save bandwidth or for mirroring of Maxmind's
databases (to bypass their traffic limit policy), different hosts or IP
addresses can be placed into geoip.conf, separated by a newline.
.PP
+.SS -w, --cooked
+Replace each frame link header with Linux "cooked" header [3] which keeps info
+about link type and protocol. It allows to dump and dissect frames captured
+from different link types when -i "any" was specified.
+.PP
.SS -V, --verbose
Be more verbose during startup i.e. show detailed ring setup information.
.PP
@@ -588,6 +598,8 @@ in the payload itself as reported here. However, the filtering for VLANs works
reliable if your NIC supports it. See bpfc(8) for an example.
.PP
[1] http://lkml.indiana.edu/hypermail/linux/kernel/0710.3/3816.html
+ [2] http://www.tcpdump.org/linktypes/LINKTYPE_NETLINK.html
+ [3] http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
.PP
.SH LEGAL
netsniff-ng is licensed under the GNU GPL version 2.0.
diff --git a/netsniff-ng.c b/netsniff-ng.c
index d3e9a13..34b3015 100644
--- a/netsniff-ng.c
+++ b/netsniff-ng.c
@@ -69,7 +69,8 @@ struct ctx {
static volatile sig_atomic_t sigint = 0, sighup = 0;
static volatile bool next_dump = false;

-static const char *short_options = "d:i:o:rf:MNJt:S:k:n:b:HQmcsqXlvhF:RGAP:Vu:g:T:DBUC:K:L:";
+static const char *short_options =
+ "d:i:o:rf:MNJt:S:k:n:b:HQmcsqXlvhF:RGAP:Vu:g:T:DBUC:K:L:w";
static const struct option long_options[] = {
{"dev", required_argument, NULL, 'd'},
{"in", required_argument, NULL, 'i'},
@@ -106,6 +107,7 @@ static const struct option long_options[] = {
{"ascii", no_argument, NULL, 'l'},
{"no-sock-mem", no_argument, NULL, 'A'},
{"update", no_argument, NULL, 'U'},
+ {"cooked", no_argument, NULL, 'w'},
{"verbose", no_argument, NULL, 'V'},
{"version", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
@@ -237,6 +239,8 @@ static void pcap_to_xmit(struct ctx *ctx)
if (ret)
panic("Error reading pcap header!\n");

+ pcap_pkthdr_init(&phdr, ctx->link_type);
+
if (__pcap_io->prepare_access_pcap) {
ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, ctx->jumbo);
if (ret)
@@ -589,6 +593,8 @@ static void read_pcap(struct ctx *ctx)
if (ret)
panic("Error reading pcap header!\n");

+ pcap_pkthdr_init(&phdr, ctx->link_type);
+
if (__pcap_io->prepare_access_pcap) {
ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, ctx->jumbo);
if (ret)
@@ -906,6 +912,8 @@ static void walk_t3_block(struct block_desc *pbd, struct ctx *ctx,
uint8_t *packet = ((uint8_t *) hdr + hdr->tp_mac);
pcap_pkthdr_t phdr;

+ pcap_pkthdr_init(&phdr, ctx->link_type);
+
if (ctx->packet_type != -1)
if (ctx->packet_type != sll->sll_pkttype)
goto next;
@@ -956,7 +964,10 @@ static void recv_only_or_dump(struct ctx *ctx)
struct timeval start, end, diff;
unsigned long frame_count = 0;

- sock = pf_socket();
+ if (ctx->link_type == LINKTYPE_LINUX_SLL)
+ sock = pf_socket_dgram();
+ else
+ sock = pf_socket();

ifindex = device_ifindex(ctx->device_in);

@@ -1036,6 +1047,8 @@ static void recv_only_or_dump(struct ctx *ctx)
uint8_t *packet = ((uint8_t *) hdr) + hdr->tp_h.tp_mac;
pcap_pkthdr_t phdr;

+ pcap_pkthdr_init(&phdr, ctx->link_type);
+
if (ctx->packet_type != -1)
if (ctx->packet_type != hdr->s_ll.sll_pkttype)
goto next;
@@ -1138,6 +1151,7 @@ static void init_ctx(struct ctx *ctx)
ctx->magic = ORIGINAL_TCPDUMP_MAGIC;
ctx->print_mode = PRINT_NORM;
ctx->pcap = PCAP_OPS_SG;
+ ctx->link_type = 0;

ctx->dump_mode = DUMP_INTERVAL_TIME;
ctx->dump_interval = 60;
@@ -1196,6 +1210,7 @@ static void __noreturn help(void)
" -X|--hex Print packet data in hex format\n"
" -l|--ascii Print human-readable packet data\n"
" -U|--update Update GeoIP databases\n"
+ " -w|--cooked Use Linux sll \"cooked\" header instead of link header\n"
" -V|--verbose Be more verbose\n"
" -v|--version Show version and exit\n"
" -h|--help Guess what?!\n\n"
@@ -1441,6 +1456,9 @@ int main(int argc, char **argv)
update_geoip();
die();
break;
+ case 'w':
+ ctx.link_type = LINKTYPE_LINUX_SLL;
+ break;
case 'v':
version();
break;
@@ -1512,7 +1530,8 @@ int main(int argc, char **argv)
if (ctx.rfraw)
setup_rfmon_mac80211_dev(&ctx, &ctx.device_in);

- ctx.link_type = pcap_devtype_to_linktype(ctx.device_in);
+ if (!ctx.link_type)
+ ctx.link_type = pcap_dev_to_linktype(ctx.device_in);

if (!ctx.device_out) {
ctx.dump = 0;
diff --git a/pcap_io.h b/pcap_io.h
index 35faa51..81f8ebd 100644
--- a/pcap_io.h
+++ b/pcap_io.h
@@ -90,12 +90,25 @@ struct pcap_pkthdr_bkm {
uint8_t pkttype;
};

-typedef union {
- struct pcap_pkthdr ppo;
- struct pcap_pkthdr_ns ppn;
- struct pcap_pkthdr_kuz ppk;
- struct pcap_pkthdr_bkm ppb;
- uint8_t raw;
+/* DLT_LINUX_SLL - fake link-layer header */
+struct pcap_pkthdr_ll {
+ uint16_t pkttype;
+ uint16_t hatype;
+ uint16_t len;
+ uint8_t addr[8];
+ uint16_t protocol;
+};
+
+typedef struct {
+ union {
+ struct pcap_pkthdr ppo;
+ struct pcap_pkthdr_ns ppn;
+ struct pcap_pkthdr_kuz ppk;
+ struct pcap_pkthdr_bkm ppb;
+ uint8_t raw;
+ } h;
+ struct pcap_pkthdr_ll ll_hdr;
+ uint32_t link_type;
} pcap_pkthdr_t;

enum pcap_type {
@@ -150,9 +163,9 @@ static inline uint16_t tp_to_pcap_tsource(uint32_t status)
return 0;
}

-static inline int pcap_devtype_to_linktype(const char *ifname)
+static inline int pcap_devtype_to_linktype(int dev_type)
{
- switch (device_type(ifname)) {
+ switch (dev_type) {
case ARPHRD_TUNNEL:
case ARPHRD_TUNNEL6:
case ARPHRD_LOOPBACK:
@@ -192,6 +205,11 @@ static inline int pcap_devtype_to_linktype(const char *ifname)
}
}

+static inline int pcap_dev_to_linktype(const char *ifname)
+{
+ return pcap_devtype_to_linktype(device_type(ifname));
+}
+
static inline void pcap_check_magic(uint32_t magic)
{
switch (magic) {
@@ -232,8 +250,8 @@ static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, enum pcap_type type)
switch (type) {
#define CASE_RET_CAPLEN(what, member, swap) \
case (what): \
- return (swap ? ___constant_swab32(phdr->member.caplen) : \
- phdr->member.caplen)
+ return (swap ? ___constant_swab32(phdr->h.member.caplen) : \
+ phdr->h.member.caplen)

CASE_RET_CAPLEN(DEFAULT, ppo, 0);
CASE_RET_CAPLEN(NSEC, ppn, 0);
@@ -255,7 +273,7 @@ static inline void pcap_set_length(pcap_pkthdr_t *phdr, enum pcap_type type, u32
switch (type) {
#define CASE_SET_CAPLEN(what, member, swap) \
case (what): \
- phdr->member.caplen = (swap ? ___constant_swab32(len) : len); \
+ phdr->h.member.caplen = (swap ? ___constant_swab32(len) : len); \
break

CASE_SET_CAPLEN(DEFAULT, ppo, 0);
@@ -278,7 +296,7 @@ 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)
+ return sizeof(phdr->h.member)

CASE_RET_HDRLEN(DEFAULT, ppo);
CASE_RET_HDRLEN(NSEC, ppn);
@@ -300,8 +318,8 @@ static inline u32 pcap_get_total_length(pcap_pkthdr_t *phdr, enum pcap_type type
switch (type) {
#define CASE_RET_TOTLEN(what, member, swap) \
case (what): \
- return ((swap ? ___constant_swab32(phdr->member.caplen) : \
- phdr->member.caplen) + sizeof(phdr->member))
+ return ((swap ? ___constant_swab32(phdr->h.member.caplen) : \
+ phdr->h.member.caplen) + sizeof(phdr->h.member))

CASE_RET_TOTLEN(DEFAULT, ppo, 0);
CASE_RET_TOTLEN(NSEC, ppn, 0);
@@ -318,6 +336,103 @@ static inline u32 pcap_get_total_length(pcap_pkthdr_t *phdr, enum pcap_type type
}
}

+static inline void pcap_pkthdr_add_hdr(pcap_pkthdr_t *phdr,
+ enum pcap_type type, uint32_t len)
+{
+ switch (type) {
+#define CASE_ADD_TOTLEN(what, member, swap) \
+ case (what): \
+ phdr->h.member.caplen += swap ? ___constant_swab32(len) : len; \
+ phdr->h.member.len += swap ? ___constant_swab32(len) : len; \
+ break;
+
+ CASE_ADD_TOTLEN(DEFAULT, ppo, 0);
+ CASE_ADD_TOTLEN(NSEC, ppn, 0);
+ CASE_ADD_TOTLEN(KUZNETZOV, ppk, 0);
+ CASE_ADD_TOTLEN(BORKMANN, ppb, 0);
+
+ CASE_ADD_TOTLEN(DEFAULT_SWAPPED, ppo, 1);
+ CASE_ADD_TOTLEN(NSEC_SWAPPED, ppn, 1);
+ CASE_ADD_TOTLEN(KUZNETZOV_SWAPPED, ppk, 1);
+ CASE_ADD_TOTLEN(BORKMANN_SWAPPED, ppb, 1);
+
+ default:
+ bug();
+ }
+}
+
+static inline void pcap_pkthdr_sub_hdr(pcap_pkthdr_t *phdr,
+ enum pcap_type type, uint32_t len)
+{
+ switch (type) {
+#define CASE_SUB_TOTLEN(what, member, swap) \
+ case (what): \
+ phdr->h.member.caplen -= swap ? ___constant_swab32(len) : len; \
+ phdr->h.member.len -= swap ? ___constant_swab32(len) : len; \
+ break;
+
+ CASE_SUB_TOTLEN(DEFAULT, ppo, 0);
+ CASE_SUB_TOTLEN(NSEC, ppn, 0);
+ CASE_SUB_TOTLEN(KUZNETZOV, ppk, 0);
+ CASE_SUB_TOTLEN(BORKMANN, ppb, 0);
+
+ CASE_SUB_TOTLEN(DEFAULT_SWAPPED, ppo, 1);
+ CASE_SUB_TOTLEN(NSEC_SWAPPED, ppn, 1);
+ CASE_SUB_TOTLEN(KUZNETZOV_SWAPPED, ppk, 1);
+ CASE_SUB_TOTLEN(BORKMANN_SWAPPED, ppb, 1);
+
+ default:
+ bug();
+ }
+}
+
+static inline void sockaddr_to_pcap_ll(struct pcap_pkthdr_ll *pcap_ll,
+ struct sockaddr_ll *sll, enum pcap_type type)
+{
+ pcap_ll->protocol = sll->sll_protocol;
+ pcap_ll->hatype = cpu_to_be16(sll->sll_hatype);
+ pcap_ll->pkttype = cpu_to_be16(sll->sll_pkttype);
+ pcap_ll->len = cpu_to_be16(sll->sll_halen);
+ memcpy(pcap_ll->addr, sll->sll_addr, 8);
+}
+
+static inline void pcap_pkthdr_add_ll_hdr(pcap_pkthdr_t *phdr,
+ enum pcap_type type, struct sockaddr_ll *sll)
+{
+ pcap_pkthdr_add_hdr(phdr, type, sizeof(struct pcap_pkthdr_ll));
+ sockaddr_to_pcap_ll(&phdr->ll_hdr, sll, type);
+}
+
+static inline bool pcap_pkthdr_has_ll(pcap_pkthdr_t *phdr, enum pcap_type type)
+{
+ bool is_swapped = false;
+ int link_type;
+
+ switch (type) {
+ case DEFAULT_SWAPPED:
+ case NSEC_SWAPPED:
+ is_swapped = true;
+ case DEFAULT:
+ case NSEC:
+ if (is_swapped)
+ link_type = ___constant_swab32(phdr->link_type);
+ else
+ link_type = phdr->link_type;
+
+ if (link_type == LINKTYPE_NETLINK || link_type ==
+ LINKTYPE_LINUX_SLL)
+ return true;
+
+ return false;
+ case BORKMANN_SWAPPED:
+ case KUZNETZOV_SWAPPED:
+ case KUZNETZOV:
+ case BORKMANN:
+ default:
+ return false;
+ }
+}
+
static inline void
__tpacket_hdr_to_pcap_pkthdr(uint32_t sec, uint32_t nsec, uint32_t snaplen,
uint32_t len, uint32_t status,
@@ -326,80 +441,83 @@ __tpacket_hdr_to_pcap_pkthdr(uint32_t sec, uint32_t nsec, uint32_t snaplen,
{
switch (type) {
case DEFAULT:
- phdr->ppo.ts.tv_sec = sec;
- phdr->ppo.ts.tv_usec = nsec / 1000;
- phdr->ppo.caplen = snaplen;
- phdr->ppo.len = len;
+ phdr->h.ppo.ts.tv_sec = sec;
+ phdr->h.ppo.ts.tv_usec = nsec / 1000;
+ phdr->h.ppo.caplen = snaplen;
+ phdr->h.ppo.len = len;
break;

case DEFAULT_SWAPPED:
- phdr->ppo.ts.tv_sec = ___constant_swab32(sec);
- phdr->ppo.ts.tv_usec = ___constant_swab32(nsec / 1000);
- phdr->ppo.caplen = ___constant_swab32(snaplen);
- phdr->ppo.len = ___constant_swab32(len);
+ phdr->h.ppo.ts.tv_sec = ___constant_swab32(sec);
+ phdr->h.ppo.ts.tv_usec = ___constant_swab32(nsec / 1000);
+ phdr->h.ppo.caplen = ___constant_swab32(snaplen);
+ phdr->h.ppo.len = ___constant_swab32(len);
break;

case NSEC:
- phdr->ppn.ts.tv_sec = sec;
- phdr->ppn.ts.tv_nsec = nsec;
- phdr->ppn.caplen = snaplen;
- phdr->ppn.len = len;
+ phdr->h.ppn.ts.tv_sec = sec;
+ phdr->h.ppn.ts.tv_nsec = nsec;
+ phdr->h.ppn.caplen = snaplen;
+ phdr->h.ppn.len = len;
break;

case NSEC_SWAPPED:
- phdr->ppn.ts.tv_sec = ___constant_swab32(sec);
- phdr->ppn.ts.tv_nsec = ___constant_swab32(nsec);
- phdr->ppn.caplen = ___constant_swab32(snaplen);
- phdr->ppn.len = ___constant_swab32(len);
+ phdr->h.ppn.ts.tv_sec = ___constant_swab32(sec);
+ phdr->h.ppn.ts.tv_nsec = ___constant_swab32(nsec);
+ phdr->h.ppn.caplen = ___constant_swab32(snaplen);
+ phdr->h.ppn.len = ___constant_swab32(len);
break;

case KUZNETZOV:
- phdr->ppk.ts.tv_sec = sec;
- phdr->ppk.ts.tv_usec = nsec / 1000;
- phdr->ppk.caplen = snaplen;
- phdr->ppk.len = len;
- phdr->ppk.ifindex = sll->sll_ifindex;
- phdr->ppk.protocol = sll->sll_protocol;
- phdr->ppk.pkttype = sll->sll_pkttype;
+ phdr->h.ppk.ts.tv_sec = sec;
+ phdr->h.ppk.ts.tv_usec = nsec / 1000;
+ phdr->h.ppk.caplen = snaplen;
+ phdr->h.ppk.len = len;
+ phdr->h.ppk.ifindex = sll->sll_ifindex;
+ phdr->h.ppk.protocol = sll->sll_protocol;
+ phdr->h.ppk.pkttype = sll->sll_pkttype;
break;

case KUZNETZOV_SWAPPED:
- phdr->ppk.ts.tv_sec = ___constant_swab32(sec);
- phdr->ppk.ts.tv_usec = ___constant_swab32(nsec / 1000);
- phdr->ppk.caplen = ___constant_swab32(snaplen);
- phdr->ppk.len = ___constant_swab32(len);
- phdr->ppk.ifindex = ___constant_swab32(sll->sll_ifindex);
- phdr->ppk.protocol = ___constant_swab16(sll->sll_protocol);
- phdr->ppk.pkttype = sll->sll_pkttype;
+ phdr->h.ppk.ts.tv_sec = ___constant_swab32(sec);
+ phdr->h.ppk.ts.tv_usec = ___constant_swab32(nsec / 1000);
+ phdr->h.ppk.caplen = ___constant_swab32(snaplen);
+ phdr->h.ppk.len = ___constant_swab32(len);
+ phdr->h.ppk.ifindex = ___constant_swab32(sll->sll_ifindex);
+ phdr->h.ppk.protocol = ___constant_swab16(sll->sll_protocol);
+ phdr->h.ppk.pkttype = sll->sll_pkttype;
break;

case BORKMANN:
- phdr->ppb.ts.tv_sec = sec;
- phdr->ppb.ts.tv_nsec = nsec;
- phdr->ppb.caplen = snaplen;
- phdr->ppb.len = len;
- phdr->ppb.tsource = tp_to_pcap_tsource(status);
- phdr->ppb.ifindex = (u16) sll->sll_ifindex;
- phdr->ppb.protocol = sll->sll_protocol;
- phdr->ppb.hatype = sll->sll_hatype;
- phdr->ppb.pkttype = sll->sll_pkttype;
+ phdr->h.ppb.ts.tv_sec = sec;
+ phdr->h.ppb.ts.tv_nsec = nsec;
+ phdr->h.ppb.caplen = snaplen;
+ phdr->h.ppb.len = len;
+ phdr->h.ppb.tsource = tp_to_pcap_tsource(status);
+ phdr->h.ppb.ifindex = (u16) sll->sll_ifindex;
+ phdr->h.ppb.protocol = sll->sll_protocol;
+ phdr->h.ppb.hatype = sll->sll_hatype;
+ phdr->h.ppb.pkttype = sll->sll_pkttype;
break;

case BORKMANN_SWAPPED:
- phdr->ppb.ts.tv_sec = ___constant_swab32(sec);
- phdr->ppb.ts.tv_nsec = ___constant_swab32(nsec);
- phdr->ppb.caplen = ___constant_swab32(snaplen);
- phdr->ppb.len = ___constant_swab32(len);
- phdr->ppb.tsource = ___constant_swab16(tp_to_pcap_tsource(status));
- phdr->ppb.ifindex = ___constant_swab16((u16) sll->sll_ifindex);
- phdr->ppb.protocol = ___constant_swab16(sll->sll_protocol);
- phdr->ppb.hatype = sll->sll_hatype;
- phdr->ppb.pkttype = sll->sll_pkttype;
+ phdr->h.ppb.ts.tv_sec = ___constant_swab32(sec);
+ phdr->h.ppb.ts.tv_nsec = ___constant_swab32(nsec);
+ phdr->h.ppb.caplen = ___constant_swab32(snaplen);
+ phdr->h.ppb.len = ___constant_swab32(len);
+ phdr->h.ppb.tsource = ___constant_swab16(tp_to_pcap_tsource(status));
+ phdr->h.ppb.ifindex = ___constant_swab16((u16) sll->sll_ifindex);
+ phdr->h.ppb.protocol = ___constant_swab16(sll->sll_protocol);
+ phdr->h.ppb.hatype = sll->sll_hatype;
+ phdr->h.ppb.pkttype = sll->sll_pkttype;
break;

default:
bug();
}
+
+ if (pcap_pkthdr_has_ll(phdr, type))
+ pcap_pkthdr_add_ll_hdr(phdr, type, sll);
}

/* We need to do this crap here since member offsets are not interleaved,
@@ -428,6 +546,47 @@ static inline void tpacket3_hdr_to_pcap_pkthdr(struct tpacket3_hdr *thdr,
}
#endif

+static inline void pcap_pkthdr_to_sockaddr(pcap_pkthdr_t *phdr,
+ struct sockaddr_ll *sll, enum pcap_type type)
+{
+ switch (type) {
+ case DEFAULT:
+ case DEFAULT_SWAPPED:
+ case NSEC:
+ case NSEC_SWAPPED:
+ if (pcap_pkthdr_has_ll(phdr, type)) {
+ sll->sll_protocol = phdr->ll_hdr.protocol;
+ sll->sll_hatype = be16_to_cpu(phdr->ll_hdr.hatype);
+ sll->sll_pkttype = be16_to_cpu(phdr->ll_hdr.pkttype);
+ sll->sll_halen = be16_to_cpu(phdr->ll_hdr.len);
+ memcpy(sll->sll_addr, phdr->ll_hdr.addr, 8);
+ }
+ break;
+ case KUZNETZOV:
+ sll->sll_ifindex = phdr->h.ppk.ifindex;
+ sll->sll_protocol = phdr->h.ppk.protocol;
+ sll->sll_pkttype = phdr->h.ppk.pkttype;
+ break;
+ case KUZNETZOV_SWAPPED:
+ sll->sll_ifindex = ___constant_swab32(phdr->h.ppk.ifindex);
+ sll->sll_protocol = ___constant_swab16(phdr->h.ppk.protocol);
+ sll->sll_pkttype = phdr->h.ppk.pkttype;
+ break;
+ case BORKMANN:
+ sll->sll_ifindex = phdr->h.ppb.ifindex;
+ sll->sll_protocol = phdr->h.ppb.protocol;
+ sll->sll_hatype = phdr->h.ppb.hatype;
+ sll->sll_pkttype = phdr->h.ppb.pkttype;
+ break;
+ case BORKMANN_SWAPPED:
+ sll->sll_ifindex = ___constant_swab16(phdr->h.ppb.ifindex);
+ sll->sll_protocol = ___constant_swab16(phdr->h.ppb.protocol);
+ sll->sll_hatype = phdr->h.ppb.hatype;
+ sll->sll_pkttype = phdr->h.ppb.pkttype;
+ break;
+ }
+}
+
static inline void pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr,
enum pcap_type type,
struct tpacket2_hdr *thdr,
@@ -435,86 +594,84 @@ static inline void pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr,
{
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;
+ if (pcap_pkthdr_has_ll(phdr, type))
+ pcap_pkthdr_sub_hdr(phdr, type, sizeof(phdr->ll_hdr));
+
+ thdr->tp_sec = phdr->h.ppo.ts.tv_sec;
+ thdr->tp_nsec = phdr->h.ppo.ts.tv_usec * 1000;
+ thdr->tp_snaplen = phdr->h.ppo.caplen;
+ thdr->tp_len = phdr->h.ppo.len;
break;

case DEFAULT_SWAPPED:
- thdr->tp_sec = ___constant_swab32(phdr->ppo.ts.tv_sec);
- thdr->tp_nsec = ___constant_swab32(phdr->ppo.ts.tv_usec) * 1000;
- thdr->tp_snaplen = ___constant_swab32(phdr->ppo.caplen);
- thdr->tp_len = ___constant_swab32(phdr->ppo.len);
+ if (pcap_pkthdr_has_ll(phdr, type))
+ pcap_pkthdr_sub_hdr(phdr, type, sizeof(phdr->ll_hdr));
+
+ thdr->tp_sec = ___constant_swab32(phdr->h.ppo.ts.tv_sec);
+ thdr->tp_nsec = ___constant_swab32(phdr->h.ppo.ts.tv_usec) * 1000;
+ thdr->tp_snaplen = ___constant_swab32(phdr->h.ppo.caplen);
+ thdr->tp_len = ___constant_swab32(phdr->h.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;
+ if (pcap_pkthdr_has_ll(phdr, type))
+ pcap_pkthdr_sub_hdr(phdr, type, sizeof(phdr->ll_hdr));
+
+ thdr->tp_sec = phdr->h.ppn.ts.tv_sec;
+ thdr->tp_nsec = phdr->h.ppn.ts.tv_nsec;
+ thdr->tp_snaplen = phdr->h.ppn.caplen;
+ thdr->tp_len = phdr->h.ppn.len;
break;

case NSEC_SWAPPED:
- thdr->tp_sec = ___constant_swab32(phdr->ppn.ts.tv_sec);
- thdr->tp_nsec = ___constant_swab32(phdr->ppn.ts.tv_nsec);
- thdr->tp_snaplen = ___constant_swab32(phdr->ppn.caplen);
- thdr->tp_len = ___constant_swab32(phdr->ppn.len);
+ if (pcap_pkthdr_has_ll(phdr, type))
+ pcap_pkthdr_sub_hdr(phdr, type, sizeof(phdr->ll_hdr));
+
+ thdr->tp_sec = ___constant_swab32(phdr->h.ppn.ts.tv_sec);
+ thdr->tp_nsec = ___constant_swab32(phdr->h.ppn.ts.tv_nsec);
+ thdr->tp_snaplen = ___constant_swab32(phdr->h.ppn.caplen);
+ thdr->tp_len = ___constant_swab32(phdr->h.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;
- if (sll) {
- sll->sll_ifindex = phdr->ppk.ifindex;
- sll->sll_protocol = phdr->ppk.protocol;
- sll->sll_pkttype = phdr->ppk.pkttype;
- }
+ thdr->tp_sec = phdr->h.ppk.ts.tv_sec;
+ thdr->tp_nsec = phdr->h.ppk.ts.tv_usec * 1000;
+ thdr->tp_snaplen = phdr->h.ppk.caplen;
+ thdr->tp_len = phdr->h.ppk.len;
break;

case KUZNETZOV_SWAPPED:
- thdr->tp_sec = ___constant_swab32(phdr->ppk.ts.tv_sec);
- thdr->tp_nsec = ___constant_swab32(phdr->ppk.ts.tv_usec) * 1000;
- thdr->tp_snaplen = ___constant_swab32(phdr->ppk.caplen);
- thdr->tp_len = ___constant_swab32(phdr->ppk.len);
- if (sll) {
- sll->sll_ifindex = ___constant_swab32(phdr->ppk.ifindex);
- sll->sll_protocol = ___constant_swab16(phdr->ppk.protocol);
- sll->sll_pkttype = phdr->ppk.pkttype;
- }
+ thdr->tp_sec = ___constant_swab32(phdr->h.ppk.ts.tv_sec);
+ thdr->tp_nsec = ___constant_swab32(phdr->h.ppk.ts.tv_usec) * 1000;
+ thdr->tp_snaplen = ___constant_swab32(phdr->h.ppk.caplen);
+ thdr->tp_len = ___constant_swab32(phdr->h.ppk.len);
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;
- if (sll) {
- sll->sll_ifindex = phdr->ppb.ifindex;
- sll->sll_protocol = phdr->ppb.protocol;
- sll->sll_hatype = phdr->ppb.hatype;
- sll->sll_pkttype = phdr->ppb.pkttype;
- }
+ thdr->tp_sec = phdr->h.ppb.ts.tv_sec;
+ thdr->tp_nsec = phdr->h.ppb.ts.tv_nsec;
+ thdr->tp_snaplen = phdr->h.ppb.caplen;
+ thdr->tp_len = phdr->h.ppb.len;
break;

case BORKMANN_SWAPPED:
- thdr->tp_sec = ___constant_swab32(phdr->ppb.ts.tv_sec);
- thdr->tp_nsec = ___constant_swab32(phdr->ppb.ts.tv_nsec);
- thdr->tp_snaplen = ___constant_swab32(phdr->ppb.caplen);
- thdr->tp_len = ___constant_swab32(phdr->ppb.len);
- if (sll) {
- sll->sll_ifindex = ___constant_swab16(phdr->ppb.ifindex);
- sll->sll_protocol = ___constant_swab16(phdr->ppb.protocol);
- sll->sll_hatype = phdr->ppb.hatype;
- sll->sll_pkttype = phdr->ppb.pkttype;
- }
+ thdr->tp_sec = ___constant_swab32(phdr->h.ppb.ts.tv_sec);
+ thdr->tp_nsec = ___constant_swab32(phdr->h.ppb.ts.tv_nsec);
+ thdr->tp_snaplen = ___constant_swab32(phdr->h.ppb.caplen);
+ thdr->tp_len = ___constant_swab32(phdr->h.ppb.len);
break;

default:
bug();
}
+
+ if (sll)
+ pcap_pkthdr_to_sockaddr(phdr, sll, type);
+}
+
+static inline void pcap_pkthdr_init(pcap_pkthdr_t *phdr, uint32_t link_type)
+{
+ phdr->link_type = link_type;
}

#define FEATURE_UNKNOWN (0 << 0)
@@ -659,6 +816,7 @@ static const bool pcap_supported_linktypes[LINKTYPE_MAX] __maybe_unused = {
[LINKTYPE_IEEE802_15_4_LINUX] = true,
[LINKTYPE_INFINIBAND] = true,
[LINKTYPE_NETLINK] = true,
+ [LINKTYPE_LINUX_SLL] = true,
};

static inline void pcap_validate_header(const struct pcap_filehdr *hdr)
diff --git a/pcap_mm.c b/pcap_mm.c
index f7b248e..b4bbae4 100644
--- a/pcap_mm.c
+++ b/pcap_mm.c
@@ -56,8 +56,18 @@ static ssize_t pcap_mm_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
if ((off_t) (ptr_va_curr - ptr_va_start) + hdrsize + len > map_size)
__pcap_mmap_write_need_remap(fd);

- fmemcpy(ptr_va_curr, &phdr->raw, hdrsize);
+ fmemcpy(ptr_va_curr, &phdr->h.raw, hdrsize);
ptr_va_curr += hdrsize;
+
+ if (pcap_pkthdr_has_ll(phdr, type)) {
+ size_t ll_len = sizeof(struct pcap_pkthdr_ll);
+
+ fmemcpy(ptr_va_curr, &phdr->ll_hdr, ll_len);
+ ptr_va_curr += ll_len;
+ len -= ll_len;
+ hdrsize += ll_len;
+ }
+
fmemcpy(ptr_va_curr, packet, len);
ptr_va_curr += len;

@@ -72,8 +82,22 @@ static ssize_t pcap_mm_read(int fd __maybe_unused, pcap_pkthdr_t *phdr,
if (unlikely((off_t) (ptr_va_curr + hdrsize - ptr_va_start) > (off_t) map_size))
return -EIO;

- fmemcpy(&phdr->raw, ptr_va_curr, hdrsize);
+ fmemcpy(&phdr->h.raw, ptr_va_curr, hdrsize);
ptr_va_curr += hdrsize;
+
+ if (pcap_pkthdr_has_ll(phdr, type)) {
+ size_t ll_len = sizeof(struct pcap_pkthdr_ll);
+
+ if (unlikely((off_t) (ptr_va_curr + ll_len - ptr_va_start) >
+ (off_t) map_size))
+ return -EIO;
+
+ fmemcpy(&phdr->ll_hdr, ptr_va_curr, ll_len);
+ ptr_va_curr += hdrsize;
+ hdrsize += ll_len;
+ len -= ll_len;
+ }
+
hdrlen = pcap_get_length(phdr, type);

if (unlikely((off_t) (ptr_va_curr + hdrlen - ptr_va_start) > (off_t) map_size))
diff --git a/pcap_rw.c b/pcap_rw.c
index b6be922..651cef7 100644
--- a/pcap_rw.c
+++ b/pcap_rw.c
@@ -21,12 +21,25 @@ 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, hdrsize = pcap_get_hdr_length(phdr, type), hdrlen = 0;
+ ssize_t ll_len = 0;

- ret = write_or_die(fd, &phdr->raw, hdrsize);
+ ret = write_or_die(fd, &phdr->h.raw, hdrsize);
if (unlikely(ret != hdrsize))
panic("Failed to write pkt header!\n");

+ if (pcap_pkthdr_has_ll(phdr, type)) {
+ ll_len = sizeof(struct pcap_pkthdr_ll);
+ int ret_ll = write_or_die(fd, (uint8_t *)&phdr->ll_hdr, ll_len);
+
+ if (unlikely(ret_ll != sizeof(phdr->ll_hdr)))
+ panic("Failed to write pkt header!\n");
+ }
+
hdrlen = pcap_get_length(phdr, type);
+ hdrlen -= ll_len;
+ len -= ll_len;
+ hdrsize += ll_len;
+
if (unlikely(hdrlen != (ssize_t) len))
return -EINVAL;

@@ -41,12 +54,25 @@ 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, hdrsize = pcap_get_hdr_length(phdr, type), hdrlen = 0;
+ ssize_t ll_len = 0;

- ret = read_or_die(fd, &phdr->raw, hdrsize);
+ ret = read_or_die(fd, &phdr->h.raw, hdrsize);
if (unlikely(ret != hdrsize))
return -EIO;

+ if (pcap_pkthdr_has_ll(phdr, type)) {
+ ll_len = sizeof(struct pcap_pkthdr_ll);
+ int ret_ll = read(fd, &phdr->ll_hdr, ll_len);
+
+ if (unlikely(ret_ll != ll_len))
+ return -EIO;
+ }
+
hdrlen = pcap_get_length(phdr, type);
+ hdrlen -= ll_len;
+ len -= ll_len;
+ hdrsize += ll_len;
+
if (unlikely(hdrlen == 0 || hdrlen > (ssize_t) len))
return -EINVAL;

diff --git a/pcap_sg.c b/pcap_sg.c
index 80c2c5d..fdfef9a 100644
--- a/pcap_sg.c
+++ b/pcap_sg.c
@@ -33,61 +33,40 @@ static ssize_t pcap_sg_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
iov_slot = 0;
}

- fmemcpy(iov[iov_slot].iov_base, &phdr->raw, hdrsize);
+ fmemcpy(iov[iov_slot].iov_base, &phdr->h.raw, hdrsize);
iov[iov_slot].iov_len = hdrsize;

- fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len, packet, len);
- ret = (iov[iov_slot].iov_len += len);
+ if (pcap_pkthdr_has_ll(phdr, type)) {
+ ssize_t ll_hdrlen = sizeof(struct pcap_pkthdr_ll);

- iov_slot++;
- return ret;
-}
-
-static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, pcap_pkthdr_t *phdr,
- 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);
-
- fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, offset);
- iov_off_rd = 0;
- iov_slot++;
+ fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len,
+ &phdr->ll_hdr, ll_hdrlen);

- if (iov_slot == array_size(iov)) {
- iov_slot = 0;
- ret = readv(fd, iov, array_size(iov));
- if (unlikely(ret <= 0))
- return -EIO;
+ ret = (iov[iov_slot].iov_len += ll_hdrlen);
+ len -= ll_hdrlen;
}

- fmemcpy(&phdr->raw + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
- iov_off_rd += remainder;
+ fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len, packet, len);
+ ret = (iov[iov_slot].iov_len += len);

- return hdrsize;
+ iov_slot++;
+ return ret;
}

-static ssize_t __pcap_sg_inter_iov_data_read(int fd, uint8_t *packet, size_t hdrlen)
+static ssize_t __pcap_sg_inter_iov_read(int fd, uint8_t *buf, size_t len)
{
int ret;
size_t offset = 0;
ssize_t remainder;

offset = iov[iov_slot].iov_len - iov_off_rd;
- remainder = hdrlen - offset;
+ remainder = len - offset;
if (remainder < 0)
remainder = 0;

- bug_on(offset + remainder != hdrlen);
+ bug_on(offset + remainder != len);

- fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, offset);
+ fmemcpy(buf, iov[iov_slot].iov_base + iov_off_rd, offset);
iov_off_rd = 0;
iov_slot++;

@@ -98,10 +77,10 @@ static ssize_t __pcap_sg_inter_iov_data_read(int fd, uint8_t *packet, size_t hdr
return -EIO;
}

- fmemcpy(packet + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
+ fmemcpy(buf + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
iov_off_rd += remainder;

- return hdrlen;
+ return len;
}

static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
@@ -109,17 +88,39 @@ static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
{
ssize_t ret = 0;
size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen;
+ ssize_t ll_len = 0;

if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrsize)) {
- fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, hdrsize);
+ fmemcpy(&phdr->h.raw, iov[iov_slot].iov_base + iov_off_rd, hdrsize);
iov_off_rd += hdrsize;
} else {
- ret = __pcap_sg_inter_iov_hdr_read(fd, phdr, hdrsize);
+ ret = __pcap_sg_inter_iov_read(fd, (uint8_t *)phdr, hdrsize);
if (unlikely(ret < 0))
return ret;
}

+ if (pcap_pkthdr_has_ll(phdr, type)) {
+ ll_len = sizeof(phdr->ll_hdr);
+
+ if (likely(iov[iov_slot].iov_len - iov_off_rd >= ll_len)) {
+ fmemcpy((uint8_t *)&phdr->ll_hdr, iov[iov_slot].iov_base +
+ iov_off_rd, ll_len);
+
+ iov_off_rd += ll_len;
+ } else {
+ ret = __pcap_sg_inter_iov_read(fd, (uint8_t *)phdr,
+ ll_len);
+
+ if (unlikely(ret < 0))
+ return ret;
+ }
+ }
+
hdrlen = pcap_get_length(phdr, type);
+ len -= ll_len;
+ hdrlen -= ll_len;
+ hdrsize += ll_len;
+
if (unlikely(hdrlen == 0 || hdrlen > len))
return -EINVAL;

@@ -127,7 +128,7 @@ static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
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, hdrlen);
+ ret = __pcap_sg_inter_iov_read(fd, (uint8_t *)packet, hdrlen);
if (unlikely(ret < 0))
return ret;
}
diff --git a/sock.c b/sock.c
index 7cfa4a0..9c3d789 100644
--- a/sock.c
+++ b/sock.c
@@ -33,6 +33,16 @@ int pf_socket(void)
return sock;
}

+int pf_socket_dgram(void)
+{
+ int sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (unlikely(sock < 0))
+ panic("Creation of PF dgram socket failed: %s\n",
+ strerror(errno));
+
+ return sock;
+}
+
/* Avail in kernel >= 3.14
* in commit d346a3fae3 (packet: introduce PACKET_QDISC_BYPASS socket option)
*/
diff --git a/sock.h b/sock.h
index 50f7102..e63cd32 100644
--- a/sock.h
+++ b/sock.h
@@ -3,6 +3,7 @@

extern int af_socket(int af);
extern int pf_socket(void);
+extern int pf_socket_dgram(void);
extern void set_nonblocking(int fd);
extern int set_nonblocking_sloppy(int fd);
extern int set_reuseaddr(int fd);
--
2.4.2

Vadim Kochan

unread,
Jun 13, 2015, 8:32:12 AM6/13/15
to netsn...@googlegroups.com, Vadim Kochan
From: Vadim Kochan <vad...@gmail.com>

Added dissector_sll.c which uses sockaddr_ll to lookup & print
higher L3 layer protocol.

This dissector is mapped by LINKTYPE_LINUX_SLL link type.

Sample output of dissected Netlink & Ethernet packets.
Truncated manually some longer lines by "...":

> nlmon0 20 1434193547s.717131169ns #6
[ Linux "cooked" Pkt Type 4 (outgoing), If Type 824 (netlink), Addr Len 0, Src (), Proto 0x0 ]
[ NLMSG Family 0 (routing), Len 20, Type 0x0003 (DONE)...

> wlp3s0 52 1434194181s.436224709ns #9
[ Linux "cooked" Pkt Type 4 (outgoing), If Type 1 (ether), Addr Len 6, Src (XX:XX:XX:XX:XX:XX), Proto 0x800 ]
[ IPv4 Addr (XXX.XXX.XXX.XXX => 212.42.76.253), Proto (6), TTL (64), TOS (0), ...
), CSum (0x1ef5) is ok ]
[ Geo (local => Ukraine) ]
[ TCP Port (45849 => 443 (https)), SN (0x1744209), AN (0x46ca9611), DataOff (8) ...
[ Chr .....w.Rj).. ]
[ Hex XX XX XX XX XX XX XX XX XX XX XX XX ]

Signed-off-by: Vadim Kochan <vad...@gmail.com>
---
dissector.c | 12 +++++-
dissector.h | 2 +-
dissector_sll.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++
dissector_sll.h | 18 ++++++++
netsniff-ng.c | 10 ++---
netsniff-ng/Makefile | 1 +
pkt_buff.h | 2 +-
proto_nlmsg.c | 4 +-
8 files changed, 152 insertions(+), 11 deletions(-)
create mode 100644 dissector_sll.c
create mode 100644 dissector_sll.h

diff --git a/dissector.c b/dissector.c
index 4cad588..6aa253d 100644
--- a/dissector.c
+++ b/dissector.c
@@ -14,6 +14,7 @@
#include "proto.h"
#include "dissector.h"
#include "dissector_eth.h"
+#include "dissector_sll.h"
#include "dissector_80211.h"
#include "dissector_netlink.h"
#include "linktype.h"
@@ -61,7 +62,7 @@ static void dissector_main(struct pkt_buff *pkt, struct protocol *start,
}

void dissector_entry_point(uint8_t *packet, size_t len, int linktype, int mode,
- uint16_t proto)
+ struct sockaddr_ll *sll)
{
struct protocol *proto_start, *proto_end;
struct pkt_buff *pkt;
@@ -71,7 +72,7 @@ void dissector_entry_point(uint8_t *packet, size_t len, int linktype, int mode,

pkt = pkt_alloc(packet, len);
pkt->link_type = linktype;
- pkt->proto = proto;
+ pkt->sll = sll;

switch (linktype) {
case LINKTYPE_EN10MB:
@@ -91,6 +92,11 @@ void dissector_entry_point(uint8_t *packet, size_t len, int linktype, int mode,
proto_start = dissector_get_netlink_entry_point();
proto_end = dissector_get_netlink_exit_point();
break;
+ case LINKTYPE_LINUX_SLL:
+ case ___constant_swab32(LINKTYPE_LINUX_SLL):
+ proto_start = dissector_get_sll_entry_point();
+ proto_end = dissector_get_sll_exit_point();
+ break;
default:
proto_start = &none_ops;
proto_end = NULL;
@@ -120,6 +126,7 @@ void dissector_init_all(int fnttype)
dissector_init_ethernet(fnttype);
dissector_init_ieee80211(fnttype);
dissector_init_netlink(fnttype);
+ dissector_init_sll(fnttype);
}

void dissector_cleanup_all(void)
@@ -127,4 +134,5 @@ void dissector_cleanup_all(void)
dissector_cleanup_ethernet();
dissector_cleanup_ieee80211();
dissector_cleanup_netlink();
+ dissector_cleanup_sll();
}
diff --git a/dissector.h b/dissector.h
index a99442e..5580110 100644
--- a/dissector.h
+++ b/dissector.h
@@ -105,7 +105,7 @@ static inline void show_frame_hdr(uint8_t *packet, size_t len, int linktype,

extern void dissector_init_all(int fnttype);
extern void dissector_entry_point(uint8_t *packet, size_t len, int linktype,
- int mode, uint16_t proto);
+ int mode, struct sockaddr_ll *sll);
extern void dissector_cleanup_all(void);
extern int dissector_set_print_type(void *ptr, int type);

diff --git a/dissector_sll.c b/dissector_sll.c
new file mode 100644
index 0000000..ff42a61
--- /dev/null
+++ b/dissector_sll.c
@@ -0,0 +1,114 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Subject to the GPL, version 2.
+ */
+
+#include "oui.h"
+#include "protos.h"
+#include "pcap_io.h"
+#include "pkt_buff.h"
+#include "dissector.h"
+#include "dissector_sll.h"
+#include "dissector_eth.h"
+
+static char *pkt_type2str(uint8_t pkttype)
+{
+ switch (pkttype) {
+ case PACKET_HOST:
+ return "host";
+ case PACKET_BROADCAST:
+ return "broadcast";
+ case PACKET_MULTICAST:
+ return "multicast";
+ case PACKET_OTHERHOST:
+ return "other host";
+ case PACKET_OUTGOING:
+ return "outgoing";
+ case PACKET_USER:
+ return "user";
+ case PACKET_KERNEL:
+ return "kernel";
+ }
+
+ return "Unknown";
+}
+
+static void sll_print_full(struct pkt_buff *pkt)
+{
+ struct sockaddr_ll *sll = pkt->sll;
+ char addr_str[40] = {};
+
+ if (!pkt || !sll)
+ return;
+
+ tprintf(" [ Linux \"cooked\"");
+ tprintf(" Pkt Type %d (%s)", sll->sll_pkttype,
+ pkt_type2str(sll->sll_pkttype));
+ tprintf(", If Type %d (%s)", sll->sll_hatype,
+ device_type2str(sll->sll_hatype));
+ tprintf(", Addr Len %d", sll->sll_halen);
+ tprintf(", Src (%s)", device_addr2str(sll->sll_addr, sll->sll_halen,
+ sll->sll_hatype, addr_str, sizeof(addr_str)));
+ tprintf(", Proto 0x%x", ntohs(sll->sll_protocol));
+
+ tprintf(" ]\n");
+
+ switch (pcap_devtype_to_linktype(sll->sll_hatype)) {
+ case LINKTYPE_EN10MB:
+ case ___constant_swab32(LINKTYPE_EN10MB):
+ pkt_set_dissector(pkt, &eth_lay2, ntohs(sll->sll_protocol));
+ break;
+ case LINKTYPE_NETLINK:
+ case ___constant_swab32(LINKTYPE_NETLINK):
+ pkt->dissector = &nlmsg_ops;
+ break;
+ default:
+ tprintf(" [ Uknown protocol ]\n");
+ }
+}
+
+static void sll_print_less(struct pkt_buff *pkt)
+{
+ struct sockaddr_ll *sll = pkt->sll;
+ char addr_str[40] = {};
+
+ if (!pkt || !sll)
+ return;
+
+ tprintf(" Pkt Type %d (%s)", sll->sll_pkttype,
+ pkt_type2str(sll->sll_pkttype));
+ tprintf(", If Type %d (%s)", sll->sll_hatype,
+ device_type2str(sll->sll_hatype));
+ tprintf(", Addr Len %d", sll->sll_halen);
+ tprintf(", Src (%s)", device_addr2str(sll->sll_addr, sll->sll_halen,
+ sll->sll_hatype, addr_str, sizeof(addr_str)));
+ tprintf(", Proto 0x%x", ntohs(sll->sll_protocol));
+}
+
+struct protocol sll_ops = {
+ .key = 0,
+ .print_full = sll_print_full,
+ .print_less = sll_print_less,
+};
+
+struct protocol *dissector_get_sll_entry_point(void)
+{
+ return &sll_ops;
+}
+
+struct protocol *dissector_get_sll_exit_point(void)
+{
+ return &none_ops;
+}
+
+void dissector_init_sll(int fnttype)
+{
+ dissector_set_print_type(&sll_ops, fnttype);
+ dissector_set_print_type(&none_ops, fnttype);
+ dissector_init_oui();
+}
+
+void dissector_cleanup_sll(void)
+{
+ dissector_cleanup_oui();
+}
diff --git a/dissector_sll.h b/dissector_sll.h
new file mode 100644
index 0000000..2067942
--- /dev/null
+++ b/dissector_sll.h
@@ -0,0 +1,18 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Subject to the GPL, version 2.
+ */
+
+#ifndef DISSECTOR_SLL_H
+#define DISSECTOR_SLL_H
+
+#include "hash.h"
+#include "proto.h"
+
+extern void dissector_init_sll(int fnttype);
+extern void dissector_cleanup_sll(void);
+
+extern struct protocol *dissector_get_sll_entry_point(void);
+extern struct protocol *dissector_get_sll_exit_point(void);
+
+#endif /* DISSECTOR_SLL_H */
diff --git a/netsniff-ng.c b/netsniff-ng.c
index 34b3015..0a6efc5 100644
--- a/netsniff-ng.c
+++ b/netsniff-ng.c
@@ -320,7 +320,7 @@ static void pcap_to_xmit(struct ctx *ctx)

dissector_entry_point(out, hdr->tp_h.tp_snaplen,
ctx->link_type, ctx->print_mode,
- hdr->s_ll.sll_protocol);
+ &hdr->s_ll);

kernel_may_pull_from_tx(&hdr->tp_h);

@@ -471,7 +471,7 @@ static void receive_to_xmit(struct ctx *ctx)

dissector_entry_point(in, hdr_in->tp_h.tp_snaplen,
ctx->link_type, ctx->print_mode,
- hdr_in->s_ll.sll_protocol);
+ &hdr_in->s_ll);

if (frame_count_max != 0) {
if (frame_count >= frame_count_max) {
@@ -666,7 +666,7 @@ static void read_pcap(struct ctx *ctx)

dissector_entry_point(out, fm.tp_h.tp_snaplen,
ctx->link_type, ctx->print_mode,
- fm.s_ll.sll_protocol);
+ &fm.s_ll);

if (is_out_pcap) {
size_t pcap_len = pcap_get_length(&phdr, ctx->magic);
@@ -935,7 +935,7 @@ static void walk_t3_block(struct block_desc *pbd, struct ctx *ctx,
hdr, ctx->print_mode, true, *frame_count);

dissector_entry_point(packet, hdr->tp_snaplen, ctx->link_type,
- ctx->print_mode, sll->sll_protocol);
+ ctx->print_mode, sll);
next:
hdr = (void *) ((uint8_t *) hdr + hdr->tp_next_offset);
sll = (void *) ((uint8_t *) hdr + TPACKET_ALIGN(sizeof(*hdr)));
@@ -1076,7 +1076,7 @@ static void recv_only_or_dump(struct ctx *ctx)

dissector_entry_point(packet, hdr->tp_h.tp_snaplen,
ctx->link_type, ctx->print_mode,
- hdr->s_ll.sll_protocol);
+ &hdr->s_ll);

if (frame_count_max != 0) {
if (unlikely(frame_count >= frame_count_max)) {
diff --git a/netsniff-ng/Makefile b/netsniff-ng/Makefile
index 92990ff..33701a4 100644
--- a/netsniff-ng/Makefile
+++ b/netsniff-ng/Makefile
@@ -12,6 +12,7 @@ netsniff-ng-libs += -lGeoIP \
endif

netsniff-ng-objs = dissector.o \
+ dissector_sll.o \
dissector_eth.o \
dissector_80211.o \
dissector_netlink.o \
diff --git a/pkt_buff.h b/pkt_buff.h
index 28872ef..30b999e 100644
--- a/pkt_buff.h
+++ b/pkt_buff.h
@@ -21,7 +21,7 @@ struct pkt_buff {

struct protocol *dissector;
uint32_t link_type;
- uint16_t proto;
+ struct sockaddr_ll *sll;
};

static inline struct pkt_buff *pkt_alloc(uint8_t *packet, unsigned int len)
diff --git a/proto_nlmsg.c b/proto_nlmsg.c
index 9dc9f6b..e7f60c8 100644
--- a/proto_nlmsg.c
+++ b/proto_nlmsg.c
@@ -639,7 +639,7 @@ static void nlmsg(struct pkt_buff *pkt)
struct nlmsghdr *hdr = (struct nlmsghdr *) pkt_pull(pkt, sizeof(*hdr));

while (hdr) {
- nlmsg_print(ntohs(pkt->proto), hdr);
+ nlmsg_print(ntohs(pkt->sll->sll_protocol), hdr);

if (!pkt_pull(pkt, NLMSG_PAYLOAD(hdr, 0)))
break;
@@ -654,7 +654,7 @@ static void nlmsg(struct pkt_buff *pkt)
static void nlmsg_less(struct pkt_buff *pkt)
{
struct nlmsghdr *hdr = (struct nlmsghdr *) pkt_pull(pkt, sizeof(*hdr));
- uint16_t family = ntohs(pkt->proto);
+ uint16_t family = ntohs(pkt->sll->sll_protocol);
char type[32];

if (hdr == NULL)
--
2.4.2

Daniel Borkmann

unread,
Jun 13, 2015, 6:57:58 PM6/13/15
to netsn...@googlegroups.com, Vadim Kochan
On 06/13/2015 02:30 PM, Vadim Kochan wrote:
> From: Vadim Kochan <vad...@gmail.com>
>
> Move device string convertions funcs (device_type2str, device_addr2str)
> from proto_nlmsg.c to dev.c to use them in other modules.
>
> Signed-off-by: Vadim Kochan <vad...@gmail.com>

Patch 1/3 applied with minor modifications, thanks!

Daniel Borkmann

unread,
Jun 13, 2015, 7:22:32 PM6/13/15
to netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
On 06/13/2015 02:30 PM, Vadim Kochan wrote:
> From: Vadim Kochan <vad...@gmail.com>
>
> Use Linux "cooked" header for Netlink interface automatically
> of as replavement of L2 header by specifiyng "--cooked" option.
>
> http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
>
> "cooked" header makes sense to use for default or nsec pcap types
> which does not contain protocol info.
>
> Added new LINKTYPE_LINUX_SLL which indicates pcap file with
> Linux "cooked" header as L2 layer header.This pcap file is
> compatible with Wireshark's "cooked" header & vice-versa.
>
> Signed-off-by: Vadim Kochan <vad...@gmail.com>

First, patch 3/3 looks okay. Will apply it once we have this
part resolved.

Then, I've worked through this patch finally. I had it applied
locally to fix up some minor things (i.e. some places don't have
proper Linux kernel coding style, etc), but still have some
thoughts here:

Anyway, what I don't yet like is that we need to tough every pcap
backend layer. I.e. the pcap i/o layer was designed in mind that
we could easily add other formats without having to touch mm/sg/rw
methods. Have you tested all of these with all corner cases?

I.e. why not letting pcap_get_hdr_length() handle the additional
sll size in order to avoid putting upper layer logic into the
backend section (it should be decoupled from this, also for
performance reasons)?

That also leaves me wondering, if it would be easier/possible to
add two internal/pseudp pcap magic types that just are pcap-us + sll
and pcap-ns + sll format, and since this number is unknown to others,
we'd need an automatic detection, that would remap the default to
the cooked type magics. Perhaps that could shrink the extra fast-path
logic we need to handle this (it would just need to have some extra
logic with the pcap file header itself, the rest might only be the
mapping of pkt-hdr, but no extra backend changes would be needed)?

What do you think?

Thanks,
Daniel

...

Vadim Kochan

unread,
Jun 14, 2015, 4:37:38 AM6/14/15
to Daniel Borkmann, netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
On Sun, Jun 14, 2015 at 01:22:25AM +0200, Daniel Borkmann wrote:
> On 06/13/2015 02:30 PM, Vadim Kochan wrote:
> >From: Vadim Kochan <vad...@gmail.com>
> >
> >Use Linux "cooked" header for Netlink interface automatically
> >of as replavement of L2 header by specifiyng "--cooked" option.
> >
> > http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
> >
> >"cooked" header makes sense to use for default or nsec pcap types
> >which does not contain protocol info.
> >
> >Added new LINKTYPE_LINUX_SLL which indicates pcap file with
> >Linux "cooked" header as L2 layer header.This pcap file is
> >compatible with Wireshark's "cooked" header & vice-versa.
> >
> >Signed-off-by: Vadim Kochan <vad...@gmail.com>
>
> First, patch 3/3 looks okay. Will apply it once we have this
> part resolved.
>
> Then, I've worked through this patch finally. I had it applied
> locally to fix up some minor things (i.e. some places don't have
> proper Linux kernel coding style, etc), but still have some
> thoughts here:
>
> Anyway, what I don't yet like is that we need to tough every pcap
Yeah, it looks ugly ...

> backend layer. I.e. the pcap i/o layer was designed in mind that
> we could easily add other formats without having to touch mm/sg/rw
> methods. Have you tested all of these with all corner cases?
I was testing them earlier each kind of IO writer/reader.

>
> I.e. why not letting pcap_get_hdr_length() handle the additional
> sll size in order to avoid putting upper layer logic into the
> backend section (it should be decoupled from this, also for
> performance reasons)?
>
> That also leaves me wondering, if it would be easier/possible to
> add two internal/pseudp pcap magic types that just are pcap-us + sll
> and pcap-ns + sll format, and since this number is unknown to others,
> we'd need an automatic detection, that would remap the default to
> the cooked type magics. Perhaps that could shrink the extra fast-path
> logic we need to handle this (it would just need to have some extra
> logic with the pcap file header itself, the rest might only be the
> mapping of pkt-hdr, but no extra backend changes would be needed)?
>
> What do you think?
I will try to rework this better.

Regards,
Vadim Kochan

Daniel Borkmann

unread,
Jun 14, 2015, 5:45:56 AM6/14/15
to Vadim Kochan, netsn...@googlegroups.com, tkla...@distanz.ch
On 06/14/2015 10:36 AM, Vadim Kochan wrote:
...
>> I.e. why not letting pcap_get_hdr_length() handle the additional
>> sll size in order to avoid putting upper layer logic into the
>> backend section (it should be decoupled from this, also for
>> performance reasons)?
>>
>> That also leaves me wondering, if it would be easier/possible to
>> add two internal/pseudp pcap magic types that just are pcap-us + sll
>> and pcap-ns + sll format, and since this number is unknown to others,
>> we'd need an automatic detection, that would remap the default to
>> the cooked type magics. Perhaps that could shrink the extra fast-path
>> logic we need to handle this (it would just need to have some extra
>> logic with the pcap file header itself, the rest might only be the
>> mapping of pkt-hdr, but no extra backend changes would be needed)?
>>
>> What do you think?
> I will try to rework this better.

Great, let me know if you stumble upon some obstacles. I think we're
almost there when we get this resolved.

Thanks again,
Daniel

Vadim Kochan

unread,
Jun 15, 2015, 9:11:40 PM6/15/15
to netsn...@googlegroups.com, Vadim Kochan
From: Vadim Kochan <vad...@gmail.com>

This series adds supporting of Linux "cooked" header

http://www.tcpdump.org/linktypes/LINKTYPE_NETLINK.html

which is compatible with Wireshark. Also it can be dissected by new
dissector_sll.c while dumping.

Needs to test on archs's with different byte ordering.

1) Add suporting Linux "cooked" header.
Added -w,--cooked option which replaces L2 header frame with cooked
header for each frame and allows to dump & dissect Ethernet & Netlink
packets together.

Linux "cooked" header is automatically used for Netlink link type
for the other cases (for -i any) it needs to specify "--cooked" option.

Used dgram packet socket when sniffing with "--cooked" option
to pull L2 header and wrap packet with Linux "cooked" header, it allows
compatibility with Wireshark.

2) Added dissector_sll.c to dissect packets with Linux "cooked" header.
Meanwhile it can dump only Netlink & Ethernet protos (L3 layer). This
dissector is used if link type is LINKTYPE_LINUX_SLL.

Vadim Kochan (2):
netsniff-ng: Add support of Linux "cooked" header
netsniff-ng: Add dissector for Linux "cooked" packets

dev.c | 2 +-
dev.h | 4 +-
dissector.c | 12 +-
dissector.h | 2 +-
dissector_sll.c | 113 ++++++++++++++
dissector_sll.h | 18 +++
linktype.h | 1 +
netsniff-ng.8 | 12 +-
netsniff-ng.c | 36 ++++-
netsniff-ng/Makefile | 1 +
pcap_io.h | 409 ++++++++++++++++++++++++++++++++-------------------
pcap_mm.c | 5 +-
pcap_rw.c | 4 +-
pcap_sg.c | 8 +-
pkt_buff.h | 2 +-
proto_nlmsg.c | 4 +-
sock.c | 10 ++
sock.h | 1 +
18 files changed, 466 insertions(+), 178 deletions(-)
create mode 100644 dissector_sll.c
create mode 100644 dissector_sll.h

--
2.4.2

Vadim Kochan

unread,
Jun 15, 2015, 9:11:42 PM6/15/15
to netsn...@googlegroups.com, Vadim Kochan
From: Vadim Kochan <vad...@gmail.com>

Use Linux "cooked" header for Netlink interface automatically
or as replacement of L2 header if "--cooked" option is specified.

http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html

"cooked" header makes sense to use for default or nsec pcap types
which does not contain protocol info.

Added new LINKTYPE_LINUX_SLL which indicates pcap file with
Linux "cooked" header as L2 layer header.This pcap file is
compatible with Wireshark's "cooked" header & vice-versa.

Signed-off-by: Vadim Kochan <vad...@gmail.com>
---
linktype.h | 1 +
netsniff-ng.8 | 12 +-
netsniff-ng.c | 26 +++-
pcap_io.h | 400 ++++++++++++++++++++++++++++++++++++----------------------
pcap_mm.c | 5 +-
pcap_rw.c | 4 +-
pcap_sg.c | 8 +-
sock.c | 10 ++
sock.h | 1 +
9 files changed, 305 insertions(+), 162 deletions(-)

diff --git a/linktype.h b/linktype.h
index a78f8be..80b5f2d 100644
--- a/linktype.h
+++ b/linktype.h
@@ -21,6 +21,7 @@
#define LINKTYPE_C_HDLC 104
#define LINKTYPE_IEEE802_11 105
#define LINKTYPE_FRELAY 107
+#define LINKTYPE_LINUX_SLL 113
#define LINKTYPE_ECONET 115
#define LINKTYPE_IEEE802_11_RADIOTAP 127
#define LINKTYPE_ARCNET_LINUX 129
diff --git a/netsniff-ng.8 b/netsniff-ng.8
index 677a78c..e7c50cd 100644
--- a/netsniff-ng.8
+++ b/netsniff-ng.8
@@ -84,7 +84,10 @@ input device is a pcap file. To specify a pcap file as the output device, the
file name must have \[lq].pcap\[rq] as its extension. If stdout is given as a
device, then a trafgen configuration will be written to stdout if the input
device is a pcap file, or a pcap file if the input device is a networking
-device.
+device. In case if the input device is a Netlink monitor device and pcap type is
+default or nsec then each packet will be wrapped with pcap cooked header [2] to
+keep Netlink family number (Kuznetzov's and netsniff-ng pcap types already
+contains family number in protocol number field).
.PP
.SS -C <id>, --fanout-group <id>
If multiple netsniff-ng instances are being started that all have the same packet
@@ -254,6 +257,11 @@ possible addresses. Thus, to save bandwidth or for mirroring of Maxmind's
databases (to bypass their traffic limit policy), different hosts or IP
addresses can be placed into geoip.conf, separated by a newline.
.PP
+.SS -w, --cooked
+Replace each frame link header with Linux "cooked" header [3] which keeps info
+about link type and protocol. It allows to dump and dissect frames captured
+from different link types when -i "any" was specified.
+.PP
.SS -V, --verbose
Be more verbose during startup i.e. show detailed ring setup information.
.PP
@@ -588,6 +596,8 @@ in the payload itself as reported here. However, the filtering for VLANs works
reliable if your NIC supports it. See bpfc(8) for an example.
.PP
[1] http://lkml.indiana.edu/hypermail/linux/kernel/0710.3/3816.html
+ [2] http://www.tcpdump.org/linktypes/LINKTYPE_NETLINK.html
+ [3] http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
.PP
.SH LEGAL
netsniff-ng is licensed under the GNU GPL version 2.0.
diff --git a/netsniff-ng.c b/netsniff-ng.c
index d3e9a13..1f7c5a5 100644
--- a/netsniff-ng.c
+++ b/netsniff-ng.c
@@ -69,7 +69,9 @@ struct ctx {
static volatile sig_atomic_t sigint = 0, sighup = 0;
static volatile bool next_dump = false;

-static const char *short_options = "d:i:o:rf:MNJt:S:k:n:b:HQmcsqXlvhF:RGAP:Vu:g:T:DBUC:K:L:";
+static const char *short_options =
+ "d:i:o:rf:MNJt:S:k:n:b:HQmcsqXlvhF:RGAP:Vu:g:T:DBUC:K:L:w";
+
static const struct option long_options[] = {
{"dev", required_argument, NULL, 'd'},
{"in", required_argument, NULL, 'i'},
@@ -106,6 +108,7 @@ static const struct option long_options[] = {
{"ascii", no_argument, NULL, 'l'},
{"no-sock-mem", no_argument, NULL, 'A'},
{"update", no_argument, NULL, 'U'},
+ {"cooked", no_argument, NULL, 'w'},
{"verbose", no_argument, NULL, 'V'},
{"version", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
@@ -237,6 +240,8 @@ static void pcap_to_xmit(struct ctx *ctx)
if (ret)
panic("Error reading pcap header!\n");

+ pcap_pkthdr_init(&phdr, ctx->link_type);
+
if (__pcap_io->prepare_access_pcap) {
ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, ctx->jumbo);
if (ret)
@@ -589,6 +594,8 @@ static void read_pcap(struct ctx *ctx)
if (ret)
panic("Error reading pcap header!\n");

+ pcap_pkthdr_init(&phdr, ctx->link_type);
+
if (__pcap_io->prepare_access_pcap) {
ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, ctx->jumbo);
if (ret)
@@ -906,6 +913,8 @@ static void walk_t3_block(struct block_desc *pbd, struct ctx *ctx,
uint8_t *packet = ((uint8_t *) hdr + hdr->tp_mac);
pcap_pkthdr_t phdr;

+ pcap_pkthdr_init(&phdr, ctx->link_type);
+
if (ctx->packet_type != -1)
if (ctx->packet_type != sll->sll_pkttype)
goto next;
@@ -956,7 +965,10 @@ static void recv_only_or_dump(struct ctx *ctx)
struct timeval start, end, diff;
unsigned long frame_count = 0;

- sock = pf_socket();
+ if (ctx->link_type == LINKTYPE_LINUX_SLL)
+ sock = pf_socket_dgram();
+ else
+ sock = pf_socket();

ifindex = device_ifindex(ctx->device_in);

@@ -1036,6 +1048,8 @@ static void recv_only_or_dump(struct ctx *ctx)
uint8_t *packet = ((uint8_t *) hdr) + hdr->tp_h.tp_mac;
pcap_pkthdr_t phdr;

+ pcap_pkthdr_init(&phdr, ctx->link_type);
+
if (ctx->packet_type != -1)
if (ctx->packet_type != hdr->s_ll.sll_pkttype)
goto next;
@@ -1138,6 +1152,7 @@ static void init_ctx(struct ctx *ctx)
ctx->magic = ORIGINAL_TCPDUMP_MAGIC;
ctx->print_mode = PRINT_NORM;
ctx->pcap = PCAP_OPS_SG;
+ ctx->link_type = 0;

ctx->dump_mode = DUMP_INTERVAL_TIME;
ctx->dump_interval = 60;
@@ -1196,6 +1211,7 @@ static void __noreturn help(void)
" -X|--hex Print packet data in hex format\n"
" -l|--ascii Print human-readable packet data\n"
" -U|--update Update GeoIP databases\n"
+ " -w|--cooked Use Linux sll \"cooked\" header instead of link header\n"
" -V|--verbose Be more verbose\n"
" -v|--version Show version and exit\n"
" -h|--help Guess what?!\n\n"
@@ -1441,6 +1457,9 @@ int main(int argc, char **argv)
update_geoip();
die();
break;
+ case 'w':
+ ctx.link_type = LINKTYPE_LINUX_SLL;
+ break;
case 'v':
version();
break;
@@ -1512,7 +1531,8 @@ int main(int argc, char **argv)
if (ctx.rfraw)
setup_rfmon_mac80211_dev(&ctx, &ctx.device_in);

- ctx.link_type = pcap_devtype_to_linktype(ctx.device_in);
+ if (!ctx.link_type)
+ ctx.link_type = pcap_devtype_to_linktype(ctx.device_in);

if (!ctx.device_out) {
ctx.dump = 0;
diff --git a/pcap_io.h b/pcap_io.h
index 35faa51..4c4ec95 100644
--- a/pcap_io.h
+++ b/pcap_io.h
@@ -58,16 +58,31 @@ struct pcap_timeval_ns {
int32_t tv_nsec;
};

+struct linux_sll {
+ uint16_t pkttype;
+ uint16_t hatype;
+ uint16_t len;
+ uint8_t addr[8];
+ uint16_t protocol;
+};
+#define LINUX_SLL_SIZE (sizeof(struct linux_sll))
+
struct pcap_pkthdr {
struct pcap_timeval ts;
uint32_t caplen;
uint32_t len;
+
+ /* depends on link type */
+ struct linux_sll sll;
};

struct pcap_pkthdr_ns {
struct pcap_timeval_ns ts;
uint32_t caplen;
uint32_t len;
+
+ /* depends on link type */
+ struct linux_sll sll;
};

struct pcap_pkthdr_kuz {
@@ -90,12 +105,15 @@ struct pcap_pkthdr_bkm {
uint8_t pkttype;
};

-typedef union {
- struct pcap_pkthdr ppo;
- struct pcap_pkthdr_ns ppn;
- struct pcap_pkthdr_kuz ppk;
- struct pcap_pkthdr_bkm ppb;
- uint8_t raw;
+typedef struct {
+ union {
+ struct pcap_pkthdr ppo;
+ struct pcap_pkthdr_ns ppn;
+ struct pcap_pkthdr_kuz ppk;
+ struct pcap_pkthdr_bkm ppb;
+ uint8_t raw;
+ } h;
+ uint32_t link_type;
} pcap_pkthdr_t;

enum pcap_type {
@@ -192,6 +210,20 @@ static inline int pcap_devtype_to_linktype(const char *ifname)
}
}

+static inline bool pcap_has_sll_hdr(pcap_pkthdr_t *phdr)
+{
+ switch (phdr->link_type) {
+ case LINKTYPE_NETLINK:
+ case ___constant_swab32(LINKTYPE_NETLINK):
+ return true;
+ case LINKTYPE_LINUX_SLL:
+ case ___constant_swab32(LINKTYPE_LINUX_SLL):
+ return true;
+ }
+
+ return false;
+}
+
static inline void pcap_check_magic(uint32_t magic)
{
switch (magic) {
@@ -229,21 +261,27 @@ static inline bool pcap_magic_is_swapped(uint32_t magic)

static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, enum pcap_type type)
{
+ int caplen;
+
switch (type) {
-#define CASE_RET_CAPLEN(what, member, swap) \
+#define CASE_RET_CAPLEN(what, member, swap, check_sll) \
case (what): \
- return (swap ? ___constant_swab32(phdr->member.caplen) : \
- phdr->member.caplen)
-
- CASE_RET_CAPLEN(DEFAULT, ppo, 0);
- CASE_RET_CAPLEN(NSEC, ppn, 0);
- CASE_RET_CAPLEN(KUZNETZOV, ppk, 0);
- CASE_RET_CAPLEN(BORKMANN, ppb, 0);
-
- CASE_RET_CAPLEN(DEFAULT_SWAPPED, ppo, 1);
- CASE_RET_CAPLEN(NSEC_SWAPPED, ppn, 1);
- CASE_RET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1);
- CASE_RET_CAPLEN(BORKMANN_SWAPPED, ppb, 1);
+ caplen = swap ? ___constant_swab32(phdr->h.member.caplen) : \
+ phdr->h.member.caplen; \
+ if (check_sll && pcap_has_sll_hdr(phdr)) \
+ caplen -= swap ? ___constant_swab32(LINUX_SLL_SIZE) : \
+ LINUX_SLL_SIZE; \
+ return caplen;
+
+ CASE_RET_CAPLEN(DEFAULT, ppo, 0, true);
+ CASE_RET_CAPLEN(NSEC, ppn, 0, true);
+ CASE_RET_CAPLEN(KUZNETZOV, ppk, 0, false);
+ CASE_RET_CAPLEN(BORKMANN, ppb, 0, false);
+
+ CASE_RET_CAPLEN(DEFAULT_SWAPPED, ppo, 1, true);
+ CASE_RET_CAPLEN(NSEC_SWAPPED, ppn, 1, true);
+ CASE_RET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1, false);
+ CASE_RET_CAPLEN(BORKMANN_SWAPPED, ppb, 1, false);

default:
bug();
@@ -252,21 +290,27 @@ static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, enum pcap_type type)

static inline void pcap_set_length(pcap_pkthdr_t *phdr, enum pcap_type type, u32 len)
{
+ int caplen;
+
switch (type) {
-#define CASE_SET_CAPLEN(what, member, swap) \
+#define CASE_SET_CAPLEN(what, member, swap, check_sll) \
case (what): \
- phdr->member.caplen = (swap ? ___constant_swab32(len) : len); \
- break
+ caplen = (swap ? ___constant_swab32(len) : len); \
+ if (check_sll && pcap_has_sll_hdr(phdr)) \
+ caplen += swap ? ___constant_swab32(LINUX_SLL_SIZE) : \
+ LINUX_SLL_SIZE; \
+ phdr->h.member.caplen = caplen; \
+ break;

- CASE_SET_CAPLEN(DEFAULT, ppo, 0);
- CASE_SET_CAPLEN(NSEC, ppn, 0);
- CASE_SET_CAPLEN(KUZNETZOV, ppk, 0);
- CASE_SET_CAPLEN(BORKMANN, ppb, 0);
+ CASE_SET_CAPLEN(DEFAULT, ppo, 0, true);
+ CASE_SET_CAPLEN(NSEC, ppn, 0, true);
+ CASE_SET_CAPLEN(KUZNETZOV, ppk, 0, false);
+ CASE_SET_CAPLEN(BORKMANN, ppb, 0, false);

- CASE_SET_CAPLEN(DEFAULT_SWAPPED, ppo, 1);
- CASE_SET_CAPLEN(NSEC_SWAPPED, ppn, 1);
- CASE_SET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1);
- CASE_SET_CAPLEN(BORKMANN_SWAPPED, ppb, 1);
+ CASE_SET_CAPLEN(DEFAULT_SWAPPED, ppo, 1, true);
+ CASE_SET_CAPLEN(NSEC_SWAPPED, ppn, 1, true);
+ CASE_SET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1, false);
+ CASE_SET_CAPLEN(BORKMANN_SWAPPED, ppb, 1, false);

default:
bug();
@@ -276,19 +320,21 @@ static inline void pcap_set_length(pcap_pkthdr_t *phdr, enum pcap_type type, u32
static inline u32 pcap_get_hdr_length(pcap_pkthdr_t *phdr, enum pcap_type type)
{
switch (type) {
-#define CASE_RET_HDRLEN(what, member) \
+#define CASE_RET_HDRLEN(what, member, check_sll) \
case (what): \
- return sizeof(phdr->member)
+ if (check_sll && !pcap_has_sll_hdr(phdr)) \
+ return sizeof(phdr->h.member) - LINUX_SLL_SIZE; \
+ return sizeof(phdr->h.member);

- CASE_RET_HDRLEN(DEFAULT, ppo);
- CASE_RET_HDRLEN(NSEC, ppn);
- CASE_RET_HDRLEN(KUZNETZOV, ppk);
- CASE_RET_HDRLEN(BORKMANN, ppb);
+ CASE_RET_HDRLEN(DEFAULT, ppo, true);
+ CASE_RET_HDRLEN(NSEC, ppn, true);
+ CASE_RET_HDRLEN(KUZNETZOV, ppk, false);
+ CASE_RET_HDRLEN(BORKMANN, ppb, false);

- CASE_RET_HDRLEN(DEFAULT_SWAPPED, ppo);
- CASE_RET_HDRLEN(NSEC_SWAPPED, ppn);
- CASE_RET_HDRLEN(KUZNETZOV_SWAPPED, ppk);
- CASE_RET_HDRLEN(BORKMANN_SWAPPED, ppb);
+ CASE_RET_HDRLEN(DEFAULT_SWAPPED, ppo, true);
+ CASE_RET_HDRLEN(NSEC_SWAPPED, ppn, true);
+ CASE_RET_HDRLEN(KUZNETZOV_SWAPPED, ppk, false);
+ CASE_RET_HDRLEN(BORKMANN_SWAPPED, ppb, false);

default:
bug();
@@ -297,25 +343,32 @@ static inline u32 pcap_get_hdr_length(pcap_pkthdr_t *phdr, enum pcap_type type)

static inline u32 pcap_get_total_length(pcap_pkthdr_t *phdr, enum pcap_type type)
{
- switch (type) {
-#define CASE_RET_TOTLEN(what, member, swap) \
- case (what): \
- return ((swap ? ___constant_swab32(phdr->member.caplen) : \
- phdr->member.caplen) + sizeof(phdr->member))
+ return pcap_get_length(phdr, type) + pcap_get_hdr_length(phdr, type);
+}

- CASE_RET_TOTLEN(DEFAULT, ppo, 0);
- CASE_RET_TOTLEN(NSEC, ppn, 0);
- CASE_RET_TOTLEN(KUZNETZOV, ppk, 0);
- CASE_RET_TOTLEN(BORKMANN, ppb, 0);
+static inline void sockaddr_to_linux_sll(struct sockaddr_ll *sll,
+ struct linux_sll *ll)
+{
+ ll->protocol = sll->sll_protocol;
+ ll->hatype = cpu_to_be16(sll->sll_hatype);
+ ll->pkttype = cpu_to_be16(sll->sll_pkttype);
+ ll->len = cpu_to_be16(sll->sll_halen);
+ memcpy(ll->addr, sll->sll_addr, 8);
+}

- CASE_RET_TOTLEN(DEFAULT_SWAPPED, ppo, 1);
- CASE_RET_TOTLEN(NSEC_SWAPPED, ppn, 1);
- CASE_RET_TOTLEN(KUZNETZOV_SWAPPED, ppk, 1);
- CASE_RET_TOTLEN(BORKMANN_SWAPPED, ppb, 1);
+static inline void linux_sll_to_sockaddr(struct linux_sll *ll,
+ struct sockaddr_ll *sll)
+{
+ sll->sll_protocol = ll->protocol;
+ sll->sll_hatype = be16_to_cpu(ll->hatype);
+ sll->sll_pkttype = be16_to_cpu(ll->pkttype);
+ sll->sll_halen = be16_to_cpu(ll->len);
+ memcpy(sll->sll_addr, ll->addr, 8);
+}

- default:
- bug();
- }
+static inline void pcap_pkthdr_init(pcap_pkthdr_t *phdr, uint32_t link_type)
+{
+ phdr->link_type = link_type;
}

static inline void
@@ -324,77 +377,99 @@ __tpacket_hdr_to_pcap_pkthdr(uint32_t sec, uint32_t nsec, uint32_t snaplen,
struct sockaddr_ll *sll, pcap_pkthdr_t *phdr,
enum pcap_type type)
{
+ int sll_len = 0;
+
switch (type) {
case DEFAULT:
- phdr->ppo.ts.tv_sec = sec;
- phdr->ppo.ts.tv_usec = nsec / 1000;
- phdr->ppo.caplen = snaplen;
- phdr->ppo.len = len;
+ if (pcap_has_sll_hdr(phdr)) {
+ sockaddr_to_linux_sll(sll, &phdr->h.ppo.sll);
+ sll_len = LINUX_SLL_SIZE;
+ }
+
+ phdr->h.ppo.ts.tv_sec = sec;
+ phdr->h.ppo.ts.tv_usec = nsec / 1000;
+ phdr->h.ppo.caplen = snaplen + sll_len;
+ phdr->h.ppo.len = len + sll_len;
break;

case DEFAULT_SWAPPED:
- phdr->ppo.ts.tv_sec = ___constant_swab32(sec);
- phdr->ppo.ts.tv_usec = ___constant_swab32(nsec / 1000);
- phdr->ppo.caplen = ___constant_swab32(snaplen);
- phdr->ppo.len = ___constant_swab32(len);
+ if (pcap_has_sll_hdr(phdr)) {
+ sockaddr_to_linux_sll(sll, &phdr->h.ppo.sll);
+ sll_len = ___constant_swab32(LINUX_SLL_SIZE);
+ }
+
+ phdr->h.ppo.ts.tv_sec = ___constant_swab32(sec);
+ phdr->h.ppo.ts.tv_usec = ___constant_swab32(nsec / 1000);
+ phdr->h.ppo.caplen = ___constant_swab32(snaplen) + sll_len;
+ phdr->h.ppo.len = ___constant_swab32(len) + sll_len;
break;

case NSEC:
- phdr->ppn.ts.tv_sec = sec;
- phdr->ppn.ts.tv_nsec = nsec;
- phdr->ppn.caplen = snaplen;
- phdr->ppn.len = len;
+ if (pcap_has_sll_hdr(phdr)) {
+ sockaddr_to_linux_sll(sll, &phdr->h.ppn.sll);
+ sll_len = LINUX_SLL_SIZE;
+ }
+
+ phdr->h.ppn.ts.tv_sec = sec;
+ phdr->h.ppn.ts.tv_nsec = nsec;
+ phdr->h.ppn.caplen = snaplen + sll_len;
+ phdr->h.ppn.len = len + sll_len;
break;

case NSEC_SWAPPED:
- phdr->ppn.ts.tv_sec = ___constant_swab32(sec);
- phdr->ppn.ts.tv_nsec = ___constant_swab32(nsec);
- phdr->ppn.caplen = ___constant_swab32(snaplen);
- phdr->ppn.len = ___constant_swab32(len);
+ if (pcap_has_sll_hdr(phdr)) {
+ sockaddr_to_linux_sll(sll, &phdr->h.ppn.sll);
+ sll_len = ___constant_swab32(LINUX_SLL_SIZE);
+ }
+
+ phdr->h.ppn.ts.tv_sec = ___constant_swab32(sec);
+ phdr->h.ppn.ts.tv_nsec = ___constant_swab32(nsec);
+ phdr->h.ppn.caplen = ___constant_swab32(snaplen) + sll_len;
+ phdr->h.ppn.len = ___constant_swab32(len) + sll_len;
@@ -433,82 +508,106 @@ static inline void pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr,
struct tpacket2_hdr *thdr,
struct sockaddr_ll *sll)
{
+ int sll_len = 0;
+
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;
+ if (pcap_has_sll_hdr(phdr)) {
+ linux_sll_to_sockaddr(&phdr->h.ppo.sll, sll);
+ sll_len = LINUX_SLL_SIZE;
+ }
+
+ thdr->tp_sec = phdr->h.ppo.ts.tv_sec;
+ thdr->tp_nsec = phdr->h.ppo.ts.tv_usec * 1000;
+ thdr->tp_snaplen = phdr->h.ppo.caplen - sll_len;
+ thdr->tp_len = phdr->h.ppo.len - sll_len;
break;

case DEFAULT_SWAPPED:
- thdr->tp_sec = ___constant_swab32(phdr->ppo.ts.tv_sec);
- thdr->tp_nsec = ___constant_swab32(phdr->ppo.ts.tv_usec) * 1000;
- thdr->tp_snaplen = ___constant_swab32(phdr->ppo.caplen);
- thdr->tp_len = ___constant_swab32(phdr->ppo.len);
+ if (pcap_has_sll_hdr(phdr)) {
+ linux_sll_to_sockaddr(&phdr->h.ppo.sll, sll);
+ sll_len = ___constant_swab32(LINUX_SLL_SIZE);
+ }
+
+ thdr->tp_sec = ___constant_swab32(phdr->h.ppo.ts.tv_sec);
+ thdr->tp_nsec = ___constant_swab32(phdr->h.ppo.ts.tv_usec) * 1000;
+ thdr->tp_snaplen = ___constant_swab32(phdr->h.ppo.caplen) -
+ sll_len;
+ thdr->tp_len = ___constant_swab32(phdr->h.ppo.len) - sll_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;
+ if (pcap_has_sll_hdr(phdr)) {
+ linux_sll_to_sockaddr(&phdr->h.ppo.sll, sll);
+ sll_len = LINUX_SLL_SIZE;
+ }
+
+ thdr->tp_sec = phdr->h.ppn.ts.tv_sec;
+ thdr->tp_nsec = phdr->h.ppn.ts.tv_nsec;
+ thdr->tp_snaplen = phdr->h.ppn.caplen - sll_len;
+ thdr->tp_len = phdr->h.ppn.len - sll_len;
break;

case NSEC_SWAPPED:
- thdr->tp_sec = ___constant_swab32(phdr->ppn.ts.tv_sec);
- thdr->tp_nsec = ___constant_swab32(phdr->ppn.ts.tv_nsec);
- thdr->tp_snaplen = ___constant_swab32(phdr->ppn.caplen);
- thdr->tp_len = ___constant_swab32(phdr->ppn.len);
+ if (pcap_has_sll_hdr(phdr)) {
+ linux_sll_to_sockaddr(&phdr->h.ppo.sll, sll);
+ sll_len = ___constant_swab32(LINUX_SLL_SIZE);
+ }
+
+ thdr->tp_sec = ___constant_swab32(phdr->h.ppn.ts.tv_sec);
+ thdr->tp_nsec = ___constant_swab32(phdr->h.ppn.ts.tv_nsec);
+ thdr->tp_snaplen = ___constant_swab32(phdr->h.ppn.caplen) -
+ sll_len;
+ thdr->tp_len = ___constant_swab32(phdr->h.ppn.len) - sll_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;
+ thdr->tp_sec = phdr->h.ppk.ts.tv_sec;
+ thdr->tp_nsec = phdr->h.ppk.ts.tv_usec * 1000;
+ thdr->tp_snaplen = phdr->h.ppk.caplen;
+ thdr->tp_len = phdr->h.ppk.len;
if (sll) {
- sll->sll_ifindex = phdr->ppk.ifindex;
- sll->sll_protocol = phdr->ppk.protocol;
- sll->sll_pkttype = phdr->ppk.pkttype;
+ sll->sll_ifindex = phdr->h.ppk.ifindex;
+ sll->sll_protocol = phdr->h.ppk.protocol;
+ sll->sll_pkttype = phdr->h.ppk.pkttype;
}
break;

case KUZNETZOV_SWAPPED:
- thdr->tp_sec = ___constant_swab32(phdr->ppk.ts.tv_sec);
- thdr->tp_nsec = ___constant_swab32(phdr->ppk.ts.tv_usec) * 1000;
- thdr->tp_snaplen = ___constant_swab32(phdr->ppk.caplen);
- thdr->tp_len = ___constant_swab32(phdr->ppk.len);
+ thdr->tp_sec = ___constant_swab32(phdr->h.ppk.ts.tv_sec);
+ thdr->tp_nsec = ___constant_swab32(phdr->h.ppk.ts.tv_usec) * 1000;
+ thdr->tp_snaplen = ___constant_swab32(phdr->h.ppk.caplen);
+ thdr->tp_len = ___constant_swab32(phdr->h.ppk.len);
if (sll) {
- sll->sll_ifindex = ___constant_swab32(phdr->ppk.ifindex);
- sll->sll_protocol = ___constant_swab16(phdr->ppk.protocol);
- sll->sll_pkttype = phdr->ppk.pkttype;
+ sll->sll_ifindex = ___constant_swab32(phdr->h.ppk.ifindex);
+ sll->sll_protocol = ___constant_swab16(phdr->h.ppk.protocol);
+ sll->sll_pkttype = phdr->h.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;
+ thdr->tp_sec = phdr->h.ppb.ts.tv_sec;
+ thdr->tp_nsec = phdr->h.ppb.ts.tv_nsec;
+ thdr->tp_snaplen = phdr->h.ppb.caplen;
+ thdr->tp_len = phdr->h.ppb.len;
if (sll) {
- sll->sll_ifindex = phdr->ppb.ifindex;
- sll->sll_protocol = phdr->ppb.protocol;
- sll->sll_hatype = phdr->ppb.hatype;
- sll->sll_pkttype = phdr->ppb.pkttype;
+ sll->sll_ifindex = phdr->h.ppb.ifindex;
+ sll->sll_protocol = phdr->h.ppb.protocol;
+ sll->sll_hatype = phdr->h.ppb.hatype;
+ sll->sll_pkttype = phdr->h.ppb.pkttype;
}
break;

case BORKMANN_SWAPPED:
- thdr->tp_sec = ___constant_swab32(phdr->ppb.ts.tv_sec);
- thdr->tp_nsec = ___constant_swab32(phdr->ppb.ts.tv_nsec);
- thdr->tp_snaplen = ___constant_swab32(phdr->ppb.caplen);
- thdr->tp_len = ___constant_swab32(phdr->ppb.len);
+ thdr->tp_sec = ___constant_swab32(phdr->h.ppb.ts.tv_sec);
+ thdr->tp_nsec = ___constant_swab32(phdr->h.ppb.ts.tv_nsec);
+ thdr->tp_snaplen = ___constant_swab32(phdr->h.ppb.caplen);
+ thdr->tp_len = ___constant_swab32(phdr->h.ppb.len);
if (sll) {
- sll->sll_ifindex = ___constant_swab16(phdr->ppb.ifindex);
- sll->sll_protocol = ___constant_swab16(phdr->ppb.protocol);
- sll->sll_hatype = phdr->ppb.hatype;
- sll->sll_pkttype = phdr->ppb.pkttype;
+ sll->sll_ifindex = ___constant_swab16(phdr->h.ppb.ifindex);
+ sll->sll_protocol = ___constant_swab16(phdr->h.ppb.protocol);
+ sll->sll_hatype = phdr->h.ppb.hatype;
+ sll->sll_pkttype = phdr->h.ppb.pkttype;
}
break;

@@ -659,6 +758,7 @@ static const bool pcap_supported_linktypes[LINKTYPE_MAX] __maybe_unused = {
[LINKTYPE_IEEE802_15_4_LINUX] = true,
[LINKTYPE_INFINIBAND] = true,
[LINKTYPE_NETLINK] = true,
+ [LINKTYPE_LINUX_SLL] = true,
};

static inline void pcap_validate_header(const struct pcap_filehdr *hdr)
diff --git a/pcap_mm.c b/pcap_mm.c
index f7b248e..b6a350d 100644
--- a/pcap_mm.c
+++ b/pcap_mm.c
@@ -56,7 +56,7 @@ static ssize_t pcap_mm_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
if ((off_t) (ptr_va_curr - ptr_va_start) + hdrsize + len > map_size)
__pcap_mmap_write_need_remap(fd);

- fmemcpy(ptr_va_curr, &phdr->raw, hdrsize);
+ fmemcpy(ptr_va_curr, &phdr->h.raw, hdrsize);
ptr_va_curr += hdrsize;
fmemcpy(ptr_va_curr, packet, len);
ptr_va_curr += len;
@@ -72,8 +72,9 @@ static ssize_t pcap_mm_read(int fd __maybe_unused, pcap_pkthdr_t *phdr,
if (unlikely((off_t) (ptr_va_curr + hdrsize - ptr_va_start) > (off_t) map_size))
return -EIO;

- fmemcpy(&phdr->raw, ptr_va_curr, hdrsize);
+ fmemcpy(&phdr->h.raw, ptr_va_curr, hdrsize);
ptr_va_curr += hdrsize;
+
hdrlen = pcap_get_length(phdr, type);

if (unlikely((off_t) (ptr_va_curr + hdrlen - ptr_va_start) > (off_t) map_size))
diff --git a/pcap_rw.c b/pcap_rw.c
index b6be922..e6ebc94 100644
--- a/pcap_rw.c
+++ b/pcap_rw.c
@@ -22,7 +22,7 @@ static ssize_t pcap_rw_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
{
ssize_t ret, hdrsize = pcap_get_hdr_length(phdr, type), hdrlen = 0;

- ret = write_or_die(fd, &phdr->raw, hdrsize);
+ ret = write_or_die(fd, &phdr->h.raw, hdrsize);
if (unlikely(ret != hdrsize))
panic("Failed to write pkt header!\n");

@@ -42,7 +42,7 @@ static ssize_t pcap_rw_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
{
ssize_t ret, hdrsize = pcap_get_hdr_length(phdr, type), hdrlen = 0;

- ret = read_or_die(fd, &phdr->raw, hdrsize);
+ ret = read_or_die(fd, &phdr->h.raw, hdrsize);
if (unlikely(ret != hdrsize))
return -EIO;

diff --git a/pcap_sg.c b/pcap_sg.c
index 80c2c5d..00793fe 100644
--- a/pcap_sg.c
+++ b/pcap_sg.c
@@ -33,7 +33,7 @@ static ssize_t pcap_sg_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
iov_slot = 0;
}

- fmemcpy(iov[iov_slot].iov_base, &phdr->raw, hdrsize);
+ fmemcpy(iov[iov_slot].iov_base, &phdr->h.raw, hdrsize);
iov[iov_slot].iov_len = hdrsize;

fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len, packet, len);
@@ -57,7 +57,7 @@ static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, pcap_pkthdr_t *phdr,

bug_on(offset + remainder != hdrsize);

- fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, offset);
+ fmemcpy(&phdr->h.raw, iov[iov_slot].iov_base + iov_off_rd, offset);
iov_off_rd = 0;
iov_slot++;

@@ -68,7 +68,7 @@ static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, pcap_pkthdr_t *phdr,
return -EIO;
}

- fmemcpy(&phdr->raw + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
+ fmemcpy(&phdr->h.raw + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
iov_off_rd += remainder;

return hdrsize;
@@ -111,7 +111,7 @@ static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen;

if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrsize)) {
- fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, hdrsize);
+ fmemcpy(&phdr->h.raw, iov[iov_slot].iov_base + iov_off_rd, hdrsize);
iov_off_rd += hdrsize;
} else {
ret = __pcap_sg_inter_iov_hdr_read(fd, phdr, hdrsize);

Vadim Kochan

unread,
Jun 15, 2015, 9:11:43 PM6/15/15
to netsn...@googlegroups.com, Vadim Kochan
From: Vadim Kochan <vad...@gmail.com>

Added dissector_sll.c which uses sockaddr_ll to lookup & print
higher L3 layer protocol.

This dissector is mapped by LINKTYPE_LINUX_SLL link type.

Sample output of dissected Netlink & Ethernet packets.
Truncated manually some longer lines by "...":

> nlmon0 20 1434193547s.717131169ns #6
[ Linux "cooked" Pkt Type 4 (outgoing), If Type 824 (netlink), Addr Len 0, Src (), Proto 0x0 ]
[ NLMSG Family 0 (routing), Len 20, Type 0x0003 (DONE)...

> wlp3s0 52 1434194181s.436224709ns #9
[ Linux "cooked" Pkt Type 4 (outgoing), If Type 1 (ether), Addr Len 6, Src (XX:XX:XX:XX:XX:XX), Proto 0x800 ]
[ IPv4 Addr (XXX.XXX.XXX.XXX => 212.42.76.253), Proto (6), TTL (64), TOS (0), ...
), CSum (0x1ef5) is ok ]
[ Geo (local => Ukraine) ]
[ TCP Port (45849 => 443 (https)), SN (0x1744209), AN (0x46ca9611), DataOff (8) ...
[ Chr .....w.Rj).. ]
[ Hex XX XX XX XX XX XX XX XX XX XX XX XX ]

Signed-off-by: Vadim Kochan <vad...@gmail.com>
---
dev.c | 2 +-
dev.h | 4 +-
dissector.c | 12 +++++-
dissector.h | 2 +-
dissector_sll.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++
dissector_sll.h | 18 ++++++++
netsniff-ng.c | 12 +++---
netsniff-ng/Makefile | 1 +
pcap_io.h | 9 +++-
pkt_buff.h | 2 +-
proto_nlmsg.c | 4 +-
11 files changed, 162 insertions(+), 17 deletions(-)
create mode 100644 dissector_sll.c
create mode 100644 dissector_sll.h

diff --git a/dev.c b/dev.c
index a29b4c1..c28fa0e 100644
--- a/dev.c
+++ b/dev.c
@@ -376,7 +376,7 @@ const char *device_type2str(uint16_t type)
}

/* Taken from iproute2 ll_addr_n2a func */
-const char *device_addr2str(const char *addr, int alen, int type,
+const char *device_addr2str(const unsigned char *addr, int alen, int type,
char *buf, int blen)
{
int i, l;
diff --git a/dev.h b/dev.h
index 6aa770d..4f987f8 100644
--- a/dev.h
+++ b/dev.h
@@ -16,6 +16,6 @@ extern u32 device_bitrate(const char *ifname);
extern short device_enter_promiscuous_mode(const char *ifname);
extern void device_leave_promiscuous_mode(const char *ifname, short oldflags);
extern const char *device_type2str(uint16_t type);
-extern const char *device_addr2str(const char *addr, int alen, int type,
- char *buf, int blen);
+extern const char *device_addr2str(const unsigned char *addr, int alen,
+ int type, char *buf, int blen);
#endif /* DEV_H */
+ case LINKTYPE_LINUX_SLL:
+ case ___constant_swab32(LINKTYPE_LINUX_SLL):
index 0000000..e2e5bfa
--- /dev/null
+++ b/dissector_sll.c
@@ -0,0 +1,113 @@
+ case LINKTYPE_NETLINK:
+ case ___constant_swab32(LINKTYPE_NETLINK):
diff --git a/netsniff-ng.c b/netsniff-ng.c
index 1f7c5a5..23fcedc 100644
--- a/netsniff-ng.c
+++ b/netsniff-ng.c
@@ -321,7 +321,7 @@ static void pcap_to_xmit(struct ctx *ctx)

dissector_entry_point(out, hdr->tp_h.tp_snaplen,
ctx->link_type, ctx->print_mode,
- hdr->s_ll.sll_protocol);
+ &hdr->s_ll);

kernel_may_pull_from_tx(&hdr->tp_h);

@@ -472,7 +472,7 @@ static void receive_to_xmit(struct ctx *ctx)

dissector_entry_point(in, hdr_in->tp_h.tp_snaplen,
ctx->link_type, ctx->print_mode,
- hdr_in->s_ll.sll_protocol);
+ &hdr_in->s_ll);

if (frame_count_max != 0) {
if (frame_count >= frame_count_max) {
@@ -667,7 +667,7 @@ static void read_pcap(struct ctx *ctx)

dissector_entry_point(out, fm.tp_h.tp_snaplen,
ctx->link_type, ctx->print_mode,
- fm.s_ll.sll_protocol);
+ &fm.s_ll);

if (is_out_pcap) {
size_t pcap_len = pcap_get_length(&phdr, ctx->magic);
@@ -936,7 +936,7 @@ static void walk_t3_block(struct block_desc *pbd, struct ctx *ctx,
hdr, ctx->print_mode, true, *frame_count);

dissector_entry_point(packet, hdr->tp_snaplen, ctx->link_type,
- ctx->print_mode, sll->sll_protocol);
+ ctx->print_mode, sll);
next:
hdr = (void *) ((uint8_t *) hdr + hdr->tp_next_offset);
sll = (void *) ((uint8_t *) hdr + TPACKET_ALIGN(sizeof(*hdr)));
@@ -1077,7 +1077,7 @@ static void recv_only_or_dump(struct ctx *ctx)

dissector_entry_point(packet, hdr->tp_h.tp_snaplen,
ctx->link_type, ctx->print_mode,
- hdr->s_ll.sll_protocol);
+ &hdr->s_ll);

if (frame_count_max != 0) {
if (unlikely(frame_count >= frame_count_max)) {
@@ -1532,7 +1532,7 @@ int main(int argc, char **argv)
setup_rfmon_mac80211_dev(&ctx, &ctx.device_in);

if (!ctx.link_type)
- ctx.link_type = pcap_devtype_to_linktype(ctx.device_in);
+ ctx.link_type = pcap_dev_to_linktype(ctx.device_in);

if (!ctx.device_out) {
ctx.dump = 0;
diff --git a/netsniff-ng/Makefile b/netsniff-ng/Makefile
index 92990ff..33701a4 100644
--- a/netsniff-ng/Makefile
+++ b/netsniff-ng/Makefile
@@ -12,6 +12,7 @@ netsniff-ng-libs += -lGeoIP \
endif

netsniff-ng-objs = dissector.o \
+ dissector_sll.o \
dissector_eth.o \
dissector_80211.o \
dissector_netlink.o \
diff --git a/pcap_io.h b/pcap_io.h
index 4c4ec95..f0541b4 100644
--- a/pcap_io.h
+++ b/pcap_io.h
@@ -168,9 +168,9 @@ static inline uint16_t tp_to_pcap_tsource(uint32_t status)
return 0;
}

-static inline int pcap_devtype_to_linktype(const char *ifname)
+static inline int pcap_devtype_to_linktype(int dev_type)
{
- switch (device_type(ifname)) {
+ switch (dev_type) {
case ARPHRD_TUNNEL:
case ARPHRD_TUNNEL6:
case ARPHRD_LOOPBACK:
@@ -210,6 +210,11 @@ static inline int pcap_devtype_to_linktype(const char *ifname)
}
}

+static inline int pcap_dev_to_linktype(const char *ifname)
+{
+ return pcap_devtype_to_linktype(device_type(ifname));
+}
+
static inline bool pcap_has_sll_hdr(pcap_pkthdr_t *phdr)
{
switch (phdr->link_type) {

Vadim Kochan

unread,
Jun 16, 2015, 4:33:01 AM6/16/15
to Daniel Borkmann, Vadim Kochan, netsn...@googlegroups.com, tkla...@distanz.ch
OK, I reworked to new series v2 where I did not touch I/O pcap modules
only in few lines because of adding "h" union to keep all kinds of pcap
hdrs in pcap_pkthdr_t.

I did some testing:
- default pcap sniffing,
- --coked options used,
- only netlink interface,
- radiotap (-R option),
- different I/O types,
- opening netsniff-ng's pcap in wireshark & vice-versa,

But did not test the case when TX from pcap to DEV.

The main change is to adding SLL hdr struct at the end of default & nsec
pcap types, so it was only needed to make right len & caplen
modifications, so it was not needed to add additional pcap types.

Regards,

Daniel Borkmann

unread,
Jun 18, 2015, 4:45:37 AM6/18/15
to netsn...@googlegroups.com, Vadim Kochan
I've started splitting this into smaller digestible chunks,
couple of more evenings and it should be done from my side.
Thanks for your patience.

Vadim Kochan

unread,
Jun 18, 2015, 4:56:01 AM6/18/15
to Daniel Borkmann, netsn...@googlegroups.com, Vadim Kochan
Yes I was pulling these changes last night, I will try to follow this
way in the future too, anyway you can ask me for that if I forget.

Thanks,

Vadim Kochan

unread,
Jun 18, 2015, 5:43:34 AM6/18/15
to Daniel Borkmann, netsn...@googlegroups.com, Vadim Kochan
On Thu, Jun 18, 2015 at 10:45:29AM +0200, Daniel Borkmann wrote:
But implementation now is OK in the last original patch series v2 ?

Daniel Borkmann

unread,
Jun 18, 2015, 5:49:28 AM6/18/15
to netsn...@googlegroups.com, Vadim Kochan
The only missing piece from your first patch I need to go through
is the pcap i/o parts. I wanted to check if two new dummy types
are possible (where we'd have transparent mapping - so it would be
semantically the same as this patch), whether they result in a
smaller code diff and would have lesser impact on the fast path.
If that's the case, I'd go for that, if not I will take the current
remaining piece. Will let you know.

Thanks,
Daniel

Daniel Borkmann

unread,
Jun 19, 2015, 4:47:58 PM6/19/15
to netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
Okay, here it goes. I tested this with capturing from netsniff-ng,
reading via Wireshark and capturing from Wireshark and reading via
netsniff-ng.

Seems fine, please double check it.

All in all this should have less overhead and result in smaller
code diff. Apart from that, the pcap_io.h might need some cleanups
anyway.

[PATCH] pcap_io: add cooked mode support

Originally submitted by Vadim in a different form, he wrote:

Use Linux "cooked" header for Netlink interface automatically or
as replacement of L2 header if "--cooked" option is specified:

http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html

'Cooked headers' makes sense to use for default or nsec pcap
types which does not contain protocol info.

Added new LINKTYPE_LINUX_SLL which indicates pcap file with
Linux "cooked" header as L2 layer header. This pcap file is
compatible with Wireshark's "cooked" header & vice-versa.

Signed-off-by: Vadim Kochan <vad...@gmail.com>
Signed-off-by: Daniel Borkmann <dan...@iogearbox.net>
---
netsniff-ng.c | 17 ++++++
pcap_io.h | 192 +++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 172 insertions(+), 37 deletions(-)

diff --git a/netsniff-ng.c b/netsniff-ng.c
index 0a9c620..e593b9d 100644
--- a/netsniff-ng.c
+++ b/netsniff-ng.c
@@ -1519,6 +1519,23 @@ int main(int argc, char **argv)

if (!ctx.link_type)
ctx.link_type = pcap_dev_to_linktype(ctx.device_in);
+ if (link_has_sll_hdr(ctx.link_type)) {
+ switch (ctx.magic) {
+ case ORIGINAL_TCPDUMP_MAGIC:
+ ctx.magic = ORIGINAL_TCPDUMP_MAGIC_LL;
+ break;
+ case NSEC_TCPDUMP_MAGIC:
+ ctx.magic = NSEC_TCPDUMP_MAGIC_LL;
+ break;
+ case ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC):
+ ctx.magic = ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC_LL);
+ break;
+ case ___constant_swab32(NSEC_TCPDUMP_MAGIC):
+ ctx.magic = ___constant_swab32(NSEC_TCPDUMP_MAGIC_LL);
+ break;
+ }
+ }
+

if (!ctx.device_out) {
ctx.dump = 0;
diff --git a/pcap_io.h b/pcap_io.h
index 497e453..5beccf9 100644
--- a/pcap_io.h
+++ b/pcap_io.h
@@ -27,6 +27,8 @@
#define TCPDUMP_MAGIC 0xa1b2c3d4
#define ORIGINAL_TCPDUMP_MAGIC TCPDUMP_MAGIC
#define NSEC_TCPDUMP_MAGIC 0xa1b23c4d
+#define ORIGINAL_TCPDUMP_MAGIC_LL 0xb1b2c3d4 /* Internal dummy just for mapping */
+#define NSEC_TCPDUMP_MAGIC_LL 0xb1b23c4d /* Internal dummy just for mapping */
#define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34
#define BORKMANN_TCPDUMP_MAGIC 0xa1e2cb12

@@ -78,6 +80,20 @@ struct pcap_pkthdr_ns {
uint32_t len;
};

+struct pcap_pkthdr_ll {
+ struct pcap_timeval ts;
+ uint32_t caplen;
+ uint32_t len;
+ struct pcap_ll ll;
+};
+
+struct pcap_pkthdr_ns_ll {
+ struct pcap_timeval_ns ts;
+ uint32_t caplen;
+ uint32_t len;
+ struct pcap_ll ll;
+};
+
struct pcap_pkthdr_kuz {
struct pcap_timeval ts;
uint32_t caplen;
@@ -99,21 +115,27 @@ struct pcap_pkthdr_bkm {
};

typedef union {
- struct pcap_pkthdr ppo;
- struct pcap_pkthdr_ns ppn;
- struct pcap_pkthdr_kuz ppk;
- struct pcap_pkthdr_bkm ppb;
- uint8_t raw;
+ struct pcap_pkthdr ppo;
+ struct pcap_pkthdr_ns ppn;
+ struct pcap_pkthdr_ll ppo_ll;
+ struct pcap_pkthdr_ns_ll ppn_ll;
+ struct pcap_pkthdr_kuz ppk;
+ struct pcap_pkthdr_bkm ppb;
+ uint8_t raw;
} pcap_pkthdr_t;

enum pcap_type {
DEFAULT = ORIGINAL_TCPDUMP_MAGIC,
NSEC = NSEC_TCPDUMP_MAGIC,
+ DEFAULT_LL = ORIGINAL_TCPDUMP_MAGIC_LL,
+ NSEC_LL = NSEC_TCPDUMP_MAGIC_LL,
KUZNETZOV = KUZNETZOV_TCPDUMP_MAGIC,
BORKMANN = BORKMANN_TCPDUMP_MAGIC,

DEFAULT_SWAPPED = ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC),
NSEC_SWAPPED = ___constant_swab32(NSEC_TCPDUMP_MAGIC),
+ DEFAULT_LL_SWAPPED = ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC_LL),
+ NSEC_LL_SWAPPED = ___constant_swab32(NSEC_TCPDUMP_MAGIC_LL),
KUZNETZOV_SWAPPED = ___constant_swab32(KUZNETZOV_TCPDUMP_MAGIC),
BORKMANN_SWAPPED = ___constant_swab32(BORKMANN_TCPDUMP_MAGIC),
};
@@ -244,6 +266,19 @@ static inline int pcap_devtype_to_linktype(int dev_type)
}
}

+static inline bool link_has_sll_hdr(uint32_t link_type)
+{
+ switch (link_type) {
+ case LINKTYPE_NETLINK:
+ case LINKTYPE_LINUX_SLL:
+ case ___constant_swab32(LINKTYPE_NETLINK):
+ case ___constant_swab32(LINKTYPE_LINUX_SLL):
+ return true;
+ default:
+ return false;
+ }
+}
+
static inline int pcap_dev_to_linktype(const char *ifname)
{
return pcap_devtype_to_linktype(device_type(ifname));
@@ -287,20 +322,24 @@ static inline bool pcap_magic_is_swapped(uint32_t magic)
static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, enum pcap_type type)
{
switch (type) {
-#define CASE_RET_CAPLEN(what, member, swap) \
+#define CASE_RET_CAPLEN(what, member, swap, extra) \
case (what): \
return (swap ? ___constant_swab32(phdr->member.caplen) : \
- phdr->member.caplen)
-
- CASE_RET_CAPLEN(DEFAULT, ppo, 0);
- CASE_RET_CAPLEN(NSEC, ppn, 0);
- CASE_RET_CAPLEN(KUZNETZOV, ppk, 0);
- CASE_RET_CAPLEN(BORKMANN, ppb, 0);
-
- CASE_RET_CAPLEN(DEFAULT_SWAPPED, ppo, 1);
- CASE_RET_CAPLEN(NSEC_SWAPPED, ppn, 1);
- CASE_RET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1);
- CASE_RET_CAPLEN(BORKMANN_SWAPPED, ppb, 1);
+ phdr->member.caplen) - extra
+
+ CASE_RET_CAPLEN(DEFAULT, ppo, 0, 0);
+ CASE_RET_CAPLEN(NSEC, ppn, 0, 0);
+ CASE_RET_CAPLEN(DEFAULT_LL, ppo_ll, 0, sizeof(struct pcap_ll));
+ CASE_RET_CAPLEN(NSEC_LL, ppn_ll, 0, sizeof(struct pcap_ll));
+ CASE_RET_CAPLEN(KUZNETZOV, ppk, 0, 0);
+ CASE_RET_CAPLEN(BORKMANN, ppb, 0, 0);
+
+ CASE_RET_CAPLEN(DEFAULT_SWAPPED, ppo, 1, 0);
+ CASE_RET_CAPLEN(NSEC_SWAPPED, ppn, 1, 0);
+ CASE_RET_CAPLEN(DEFAULT_LL_SWAPPED, ppo_ll, 1, sizeof(struct pcap_ll));
+ CASE_RET_CAPLEN(NSEC_LL_SWAPPED, ppn_ll, 1, sizeof(struct pcap_ll));
+ CASE_RET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1, 0);
+ CASE_RET_CAPLEN(BORKMANN_SWAPPED, ppb, 1, 0);

default:
bug();
@@ -317,11 +356,15 @@ static inline void pcap_set_length(pcap_pkthdr_t *phdr, enum pcap_type type, u32

CASE_SET_CAPLEN(DEFAULT, ppo, 0);
CASE_SET_CAPLEN(NSEC, ppn, 0);
+ CASE_SET_CAPLEN(DEFAULT_LL, ppo_ll, 0);
+ CASE_SET_CAPLEN(NSEC_LL, ppn_ll, 0);
CASE_SET_CAPLEN(KUZNETZOV, ppk, 0);
CASE_SET_CAPLEN(BORKMANN, ppb, 0);

CASE_SET_CAPLEN(DEFAULT_SWAPPED, ppo, 1);
CASE_SET_CAPLEN(NSEC_SWAPPED, ppn, 1);
+ CASE_SET_CAPLEN(DEFAULT_LL_SWAPPED, ppo_ll, 1);
+ CASE_SET_CAPLEN(NSEC_LL_SWAPPED, ppn_ll, 1);
CASE_SET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1);
CASE_SET_CAPLEN(BORKMANN_SWAPPED, ppb, 1);

@@ -339,11 +382,15 @@ static inline u32 pcap_get_hdr_length(pcap_pkthdr_t *phdr, enum pcap_type type)

CASE_RET_HDRLEN(DEFAULT, ppo);
CASE_RET_HDRLEN(NSEC, ppn);
+ CASE_RET_HDRLEN(DEFAULT_LL, ppo_ll);
+ CASE_RET_HDRLEN(NSEC_LL, ppn_ll);
CASE_RET_HDRLEN(KUZNETZOV, ppk);
CASE_RET_HDRLEN(BORKMANN, ppb);

CASE_RET_HDRLEN(DEFAULT_SWAPPED, ppo);
CASE_RET_HDRLEN(NSEC_SWAPPED, ppn);
+ CASE_RET_HDRLEN(DEFAULT_LL_SWAPPED, ppo_ll);
+ CASE_RET_HDRLEN(NSEC_LL_SWAPPED, ppn_ll);
CASE_RET_HDRLEN(KUZNETZOV_SWAPPED, ppk);
CASE_RET_HDRLEN(BORKMANN_SWAPPED, ppb);

@@ -354,25 +401,7 @@ static inline u32 pcap_get_hdr_length(pcap_pkthdr_t *phdr, enum pcap_type type)

static inline u32 pcap_get_total_length(pcap_pkthdr_t *phdr, enum pcap_type type)
{
- switch (type) {
-#define CASE_RET_TOTLEN(what, member, swap) \
- case (what): \
- return ((swap ? ___constant_swab32(phdr->member.caplen) : \
- phdr->member.caplen) + sizeof(phdr->member))
-
- CASE_RET_TOTLEN(DEFAULT, ppo, 0);
- CASE_RET_TOTLEN(NSEC, ppn, 0);
- CASE_RET_TOTLEN(KUZNETZOV, ppk, 0);
- CASE_RET_TOTLEN(BORKMANN, ppb, 0);
-
- CASE_RET_TOTLEN(DEFAULT_SWAPPED, ppo, 1);
- CASE_RET_TOTLEN(NSEC_SWAPPED, ppn, 1);
- CASE_RET_TOTLEN(KUZNETZOV_SWAPPED, ppk, 1);
- CASE_RET_TOTLEN(BORKMANN_SWAPPED, ppb, 1);
-
- default:
- bug();
- }
+ return pcap_get_hdr_length(phdr, type) + pcap_get_length(phdr, type);
}

static inline void
@@ -383,31 +412,55 @@ __tpacket_hdr_to_pcap_pkthdr(uint32_t sec, uint32_t nsec, uint32_t snaplen,
{
switch (type) {
case DEFAULT:
+ case DEFAULT_LL:
phdr->ppo.ts.tv_sec = sec;
phdr->ppo.ts.tv_usec = nsec / 1000;
phdr->ppo.caplen = snaplen;
phdr->ppo.len = len;
+ if (type == DEFAULT_LL) {
+ phdr->ppo.caplen += sizeof(struct pcap_ll);
+ phdr->ppo.len += sizeof(struct pcap_ll);
+ sockaddr_to_ll(sll, &phdr->ppo_ll.ll);
+ }
break;

case DEFAULT_SWAPPED:
+ case DEFAULT_LL_SWAPPED:
phdr->ppo.ts.tv_sec = ___constant_swab32(sec);
phdr->ppo.ts.tv_usec = ___constant_swab32(nsec / 1000);
phdr->ppo.caplen = ___constant_swab32(snaplen);
phdr->ppo.len = ___constant_swab32(len);
+ if (type == DEFAULT_LL_SWAPPED) {
+ phdr->ppo.caplen = ___constant_swab32(snaplen + sizeof(struct pcap_ll));
+ phdr->ppo.len = ___constant_swab32(len + sizeof(struct pcap_ll));
+ sockaddr_to_ll(sll, &phdr->ppo_ll.ll);
+ }
break;

case NSEC:
+ case NSEC_LL:
phdr->ppn.ts.tv_sec = sec;
phdr->ppn.ts.tv_nsec = nsec;
phdr->ppn.caplen = snaplen;
phdr->ppn.len = len;
+ if (type == NSEC_LL) {
+ phdr->ppn.caplen += sizeof(struct pcap_ll);
+ phdr->ppn.len += sizeof(struct pcap_ll);
+ sockaddr_to_ll(sll, &phdr->ppn_ll.ll);
+ }
break;

case NSEC_SWAPPED:
+ case NSEC_LL_SWAPPED:
phdr->ppn.ts.tv_sec = ___constant_swab32(sec);
phdr->ppn.ts.tv_nsec = ___constant_swab32(nsec);
phdr->ppn.caplen = ___constant_swab32(snaplen);
phdr->ppn.len = ___constant_swab32(len);
+ if (type == NSEC_LL_SWAPPED) {
+ phdr->ppn.caplen = ___constant_swab32(snaplen + sizeof(struct pcap_ll));
+ phdr->ppn.len = ___constant_swab32(len + sizeof(struct pcap_ll));
+ sockaddr_to_ll(sll, &phdr->ppn_ll.ll);
+ }
break;

case KUZNETZOV:
@@ -492,31 +545,59 @@ static inline void pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr,
{
switch (type) {
case DEFAULT:
+ case DEFAULT_LL:
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;
+ if (type == DEFAULT_LL) {
+ thdr->tp_snaplen -= sizeof(struct pcap_ll);
+ thdr->tp_len -= sizeof(struct pcap_ll);
+ if (sll)
+ ll_to_sockaddr(&phdr->ppo_ll.ll, sll);
+ }
break;

case DEFAULT_SWAPPED:
+ case DEFAULT_LL_SWAPPED:
thdr->tp_sec = ___constant_swab32(phdr->ppo.ts.tv_sec);
thdr->tp_nsec = ___constant_swab32(phdr->ppo.ts.tv_usec) * 1000;
thdr->tp_snaplen = ___constant_swab32(phdr->ppo.caplen);
thdr->tp_len = ___constant_swab32(phdr->ppo.len);
+ if (type == DEFAULT_LL_SWAPPED) {
+ thdr->tp_snaplen -= sizeof(struct pcap_ll);
+ thdr->tp_len -= sizeof(struct pcap_ll);
+ if (sll)
+ ll_to_sockaddr(&phdr->ppo_ll.ll, sll);
+ }
break;

case NSEC:
+ case NSEC_LL:
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;
+ if (type == NSEC_LL) {
+ thdr->tp_snaplen -= sizeof(struct pcap_ll);
+ thdr->tp_len -= sizeof(struct pcap_ll);
+ if (sll)
+ ll_to_sockaddr(&phdr->ppn_ll.ll, sll);
+ }
break;

case NSEC_SWAPPED:
+ case NSEC_LL_SWAPPED:
thdr->tp_sec = ___constant_swab32(phdr->ppn.ts.tv_sec);
thdr->tp_nsec = ___constant_swab32(phdr->ppn.ts.tv_nsec);
thdr->tp_snaplen = ___constant_swab32(phdr->ppn.caplen);
thdr->tp_len = ___constant_swab32(phdr->ppn.len);
+ if (type == NSEC_LL_SWAPPED) {
+ thdr->tp_snaplen -= sizeof(struct pcap_ll);
+ thdr->tp_len -= sizeof(struct pcap_ll);
+ if (sll)
+ ll_to_sockaddr(&phdr->ppn_ll.ll, sll);
+ }
break;

case KUZNETZOV:
@@ -682,6 +763,24 @@ static inline void pcap_prepare_header(struct pcap_filehdr *hdr, uint32_t magic,
{
bool swapped = pcap_magic_is_swapped(magic);

+ /* As *_LL types are just internal, we need to remap pcap
+ * magics to actually valid types.
+ */
+ switch (magic) {
+ case ORIGINAL_TCPDUMP_MAGIC_LL:
+ magic = ORIGINAL_TCPDUMP_MAGIC;
+ break;
+ case NSEC_TCPDUMP_MAGIC_LL:
+ magic = NSEC_TCPDUMP_MAGIC;
+ break;
+ case ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC_LL):
+ magic = ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC);
+ break;
+ case ___constant_swab32(NSEC_TCPDUMP_MAGIC_LL):
+ magic = ___constant_swab32(NSEC_TCPDUMP_MAGIC);
+ break;
+ }
+
hdr->magic = magic;
hdr->version_major = swapped ? ___constant_swab16(PCAP_VERSION_MAJOR) : PCAP_VERSION_MAJOR;
hdr->version_minor = swapped ? ___constant_swab16(PCAP_VERSION_MINOR) : PCAP_VERSION_MINOR;
@@ -716,9 +815,10 @@ static const bool pcap_supported_linktypes[LINKTYPE_MAX] __maybe_unused = {
[LINKTYPE_IEEE802_15_4_LINUX] = true,
[LINKTYPE_INFINIBAND] = true,
[LINKTYPE_NETLINK] = true,
+ [LINKTYPE_LINUX_SLL] = true,
};

-static inline void pcap_validate_header(const struct pcap_filehdr *hdr)
+static inline void pcap_validate_header(struct pcap_filehdr *hdr)
{
bool good = false;
uint32_t linktype;
@@ -737,6 +837,24 @@ static inline void pcap_validate_header(const struct pcap_filehdr *hdr)
if (unlikely(hdr->version_minor != PCAP_VERSION_MINOR) &&
___constant_swab16(hdr->version_minor) != PCAP_VERSION_MINOR)
panic("This file has an invalid pcap minor version (must be %d)\n", PCAP_VERSION_MINOR);
+
+ /* Remap to internal *_LL types in case of LINKTYPE_LINUX_SLL. */
+ if (linktype == LINKTYPE_LINUX_SLL) {
+ switch (hdr->magic) {
+ case ORIGINAL_TCPDUMP_MAGIC:
+ hdr->magic = ORIGINAL_TCPDUMP_MAGIC_LL;
+ break;
+ case NSEC_TCPDUMP_MAGIC:
+ hdr->magic = NSEC_TCPDUMP_MAGIC_LL;
+ break;
+ case ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC):
+ hdr->magic = ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC_LL);
+ break;
+ case ___constant_swab32(NSEC_TCPDUMP_MAGIC):
+ hdr->magic = ___constant_swab32(NSEC_TCPDUMP_MAGIC_LL);
+ break;
+ }
+ }
}

static int pcap_generic_pull_fhdr(int fd, uint32_t *magic,
--
1.9.3


Vadim Kochan

unread,
Jun 19, 2015, 4:59:56 PM6/19/15
to netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
should not link_has_sll_hdr() be used here ?

Daniel Borkmann

unread,
Jun 19, 2015, 5:14:02 PM6/19/15
to netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
On 06/19/2015 10:58 PM, Vadim Kochan wrote:
> On Fri, Jun 19, 2015 at 10:47:49PM +0200, Daniel Borkmann wrote:
...
>> @@ -737,6 +837,24 @@ static inline void pcap_validate_header(const struct pcap_filehdr *hdr)
>> if (unlikely(hdr->version_minor != PCAP_VERSION_MINOR) &&
>> ___constant_swab16(hdr->version_minor) != PCAP_VERSION_MINOR)
>> panic("This file has an invalid pcap minor version (must be %d)\n", PCAP_VERSION_MINOR);
>> +
>> + /* Remap to internal *_LL types in case of LINKTYPE_LINUX_SLL. */
>> + if (linktype == LINKTYPE_LINUX_SLL) {
> should not link_has_sll_hdr() be used here ?

Why? At this point, when reading a pcap file, basic validation has already
been done and linktype is in host endianess. In netsniff-ng, we write out
the pcap header as LINKTYPE_LINUX_SLL in case of Netlink.

In case some other source doesn't use LINKTYPE_LINUX_SLL but LINKTYPE_NETLINK,
we actually need not to assume cooked format.

Vadim Kochan

unread,
Jun 19, 2015, 5:38:59 PM6/19/15
to netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
Never applied patches from emails, I tried to do in mutt by saving as
attachments or mbox, I even cut till 'diff' line but with no luck to
apply this. May be you can suggest some work flow with mutt for
patches via email ?

Vadim Kochan

unread,
Jun 19, 2015, 5:50:17 PM6/19/15
to Daniel Borkmann, netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
My understanding is that linktype might be set to LINKTYPE_NETLINK if it
was sniffed only from Netlink interface which uses the same sll header
format but with ignoring few fields - address & address len.

Daniel Borkmann

unread,
Jun 19, 2015, 5:59:40 PM6/19/15
to netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
On 06/19/2015 11:37 PM, Vadim Kochan wrote:
...
> Never applied patches from emails, I tried to do in mutt by saving as
> attachments or mbox, I even cut till 'diff' line but with no luck to
> apply this. May be you can suggest some work flow with mutt for
> patches via email ?

Ok, so here's both as an attachment, also your dissector on top,
which works fine for me.

(I usually save the whole source and git am it.)
0001-pcap_io-add-cooked-mode-support.patch
0002-netsniff-ng-Add-dissector-for-Linux-cooked-packets.patch

Vadim Kochan

unread,
Jun 19, 2015, 6:13:33 PM6/19/15
to Daniel Borkmann, netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
> From 045e9395ca9c2971ab7f7a886f5d6b4cf679c7fd Mon Sep 17 00:00:00 2001
> Message-Id: <045e9395ca9c2971ab7f7a886f5d6b4...@iogearbox.net>
> From: Daniel Borkmann <dan...@iogearbox.net>
> Date: Fri, 19 Jun 2015 00:30:31 +0200
> Subject: [PATCH 1/2] pcap_io: add cooked mode support
> From 42afc1ba23f232de744a8212e15f8bfbb72bee03 Mon Sep 17 00:00:00 2001
> Message-Id: <42afc1ba23f232de744a8212e15f8bf...@iogearbox.net>
> In-Reply-To: <045e9395ca9c2971ab7f7a886f5d6b4...@iogearbox.net>
> References: <045e9395ca9c2971ab7f7a886f5d6b4...@iogearbox.net>
> From: Vadim Kochan <vad...@gmail.com>
> Date: Tue, 16 Jun 2015 04:10:19 +0300
> Subject: [PATCH 2/2] netsniff-ng: Add dissector for Linux "cooked" packets
>
> Added dissector_sll.c which uses sockaddr_ll to lookup & print
> higher L3 layer protocol.
>
> This dissector is mapped by LINKTYPE_LINUX_SLL link type.
>
> Sample output of dissected Netlink & Ethernet packets.
> Truncated manually some longer lines by "...":
>
> > nlmon0 20 1434193547s.717131169ns #6
> [ Linux "cooked" Pkt Type 4 (outgoing), If Type 824 (netlink), Addr Len 0, Src (), Proto 0x0 ]
> [ NLMSG Family 0 (routing), Len 20, Type 0x0003 (DONE)...
>
> > wlp3s0 52 1434194181s.436224709ns #9
> [ Linux "cooked" Pkt Type 4 (outgoing), If Type 1 (ether), Addr Len 6, Src (XX:XX:XX:XX:XX:XX), Proto 0x800 ]
> [ IPv4 Addr (XXX.XXX.XXX.XXX => 212.42.76.253), Proto (6), TTL (64), TOS (0), ...
> ), CSum (0x1ef5) is ok ]
> [ Geo (local => Ukraine) ]
> [ TCP Port (45849 => 443 (https)), SN (0x1744209), AN (0x46ca9611), DataOff (8) ...
> [ Chr .....w.Rj).. ]
> [ Hex XX XX XX XX XX XX XX XX XX XX XX XX ]
>
> Signed-off-by: Vadim Kochan <vad...@gmail.com>
> Signed-off-by: Daniel Borkmann <dan...@iogearbox.net>
> ---
> dissector.c | 12 +++++-
> dissector.h | 2 +-
> dissector_sll.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++
> dissector_sll.h | 18 ++++++++
> netsniff-ng.c | 10 ++---
> netsniff-ng/Makefile | 1 +
> pkt_buff.h | 2 +-
> proto_nlmsg.c | 4 +-
> 8 files changed, 151 insertions(+), 11 deletions(-)
> create mode 100644 dissector_sll.c
> create mode 100644 dissector_sll.h
>
> + case LINKTYPE_LINUX_SLL:
> + case LINKTYPE_NETLINK:
> diff --git a/netsniff-ng.c b/netsniff-ng.c
> index e593b9d..91356ba 100644
> --- a/netsniff-ng.c
> +++ b/netsniff-ng.c
> @@ -318,7 +318,7 @@ static void pcap_to_xmit(struct ctx *ctx)
>
> dissector_entry_point(out, hdr->tp_h.tp_snaplen,
> ctx->link_type, ctx->print_mode,
> - hdr->s_ll.sll_protocol);
> + &hdr->s_ll);
>
> kernel_may_pull_from_tx(&hdr->tp_h);
>
> @@ -469,7 +469,7 @@ static void receive_to_xmit(struct ctx *ctx)
>
> dissector_entry_point(in, hdr_in->tp_h.tp_snaplen,
> ctx->link_type, ctx->print_mode,
> - hdr_in->s_ll.sll_protocol);
> + &hdr_in->s_ll);
>
> if (frame_count_max != 0) {
> if (frame_count >= frame_count_max) {
> @@ -662,7 +662,7 @@ static void read_pcap(struct ctx *ctx)
>
> dissector_entry_point(out, fm.tp_h.tp_snaplen,
> ctx->link_type, ctx->print_mode,
> - fm.s_ll.sll_protocol);
> + &fm.s_ll);
>
> if (is_out_pcap) {
> size_t pcap_len = pcap_get_length(&phdr, ctx->magic);
> @@ -929,7 +929,7 @@ static void walk_t3_block(struct block_desc *pbd, struct ctx *ctx,
> hdr, ctx->print_mode, true, *frame_count);
>
> dissector_entry_point(packet, hdr->tp_snaplen, ctx->link_type,
> - ctx->print_mode, sll->sll_protocol);
> + ctx->print_mode, sll);
> next:
> hdr = (void *) ((uint8_t *) hdr + hdr->tp_next_offset);
> sll = (void *) ((uint8_t *) hdr + TPACKET_ALIGN(sizeof(*hdr)));
> @@ -1064,7 +1064,7 @@ static void recv_only_or_dump(struct ctx *ctx)
>
> dissector_entry_point(packet, hdr->tp_h.tp_snaplen,
> ctx->link_type, ctx->print_mode,
> - hdr->s_ll.sll_protocol);
> + &hdr->s_ll);
>
> if (frame_count_max != 0) {
> if (unlikely(frame_count >= frame_count_max)) {
> diff --git a/netsniff-ng/Makefile b/netsniff-ng/Makefile
> index 92990ff..33701a4 100644
> --- a/netsniff-ng/Makefile
> +++ b/netsniff-ng/Makefile
> @@ -12,6 +12,7 @@ netsniff-ng-libs += -lGeoIP \
> endif
>
> netsniff-ng-objs = dissector.o \
> + dissector_sll.o \
> dissector_eth.o \
> dissector_80211.o \
> dissector_netlink.o \
> diff --git a/pkt_buff.h b/pkt_buff.h
> index 28872ef..30b999e 100644
> --- a/pkt_buff.h
> +++ b/pkt_buff.h
> @@ -21,7 +21,7 @@ struct pkt_buff {
>
> struct protocol *dissector;
> uint32_t link_type;
> - uint16_t proto;
> + struct sockaddr_ll *sll;
> };
>
> static inline struct pkt_buff *pkt_alloc(uint8_t *packet, unsigned int len)
> diff --git a/proto_nlmsg.c b/proto_nlmsg.c
> index 5018adf..44ef328 100644
> --- a/proto_nlmsg.c
> +++ b/proto_nlmsg.c
> @@ -740,7 +740,7 @@ static void nlmsg(struct pkt_buff *pkt)
> struct nlmsghdr *hdr = (struct nlmsghdr *) pkt_pull(pkt, sizeof(*hdr));
>
> while (hdr) {
> - nlmsg_print(ntohs(pkt->proto), hdr);
> + nlmsg_print(ntohs(pkt->sll->sll_protocol), hdr);
>
> if (!pkt_pull(pkt, NLMSG_PAYLOAD(hdr, 0)))
> break;
> @@ -755,7 +755,7 @@ static void nlmsg(struct pkt_buff *pkt)
> static void nlmsg_less(struct pkt_buff *pkt)
> {
> struct nlmsghdr *hdr = (struct nlmsghdr *) pkt_pull(pkt, sizeof(*hdr));
> - uint16_t family = ntohs(pkt->proto);
> + uint16_t family = ntohs(pkt->sll->sll_protocol);
> char type[32];
>
> if (hdr == NULL)
> --
> 1.9.3
>

Thank you!

So I tested only Netlink linktype and after:

$ sudo netsniff-ng/netsniff-ng -i nl0 -n 10 -o /tmp/nl0.pcap

netsniff-ng can't dissect it normaly from pcap file:

$ sudo netsniff-ng/netsniff-ng -i /tmp/nl0.pcap

and after fixing this:

> + /* Remap to internal *_LL types in case of LINKTYPE_LINUX_SLL. */
> + if (linktype == LINKTYPE_LINUX_SLL) {
> + switch (hdr->magic) {
> + case ORIGINAL_TCPDUMP_MAGIC:
> + hdr->magic = ORIGINAL_TCPDUMP_MAGIC_LL;
> + break;
> + case NSEC_TCPDUMP_MAGIC:
> + hdr->magic = NSEC_TCPDUMP_MAGIC_LL;
> + break;
> + case ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC):
> + hdr->magic = ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC_LL);
> + break;
> + case ___constant_swab32(NSEC_TCPDUMP_MAGIC):
> + hdr->magic = ___constant_swab32(NSEC_TCPDUMP_MAGIC_LL);
> + break;
> + }
> + }

by adding "|| linktype == LINKTYPE_LINUX_SLL)" I got dissected Netlink
messages.

Also may be it is better to get this 'switch' out from validation
function, just but semantic meaning of this function which should just
validate but not change something valuable.

Daniel Borkmann

unread,
Jun 19, 2015, 6:13:47 PM6/19/15
to netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
You mean from Wireshark? That it sets LINKTYPE_NETLINK in the pcap header,
although it has an LINKTYPE_LINUX_SLL-header in front of netlink dgrams?

Vadim Kochan

unread,
Jun 19, 2015, 6:18:01 PM6/19/15
to Daniel Borkmann, netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
Sorry .... I meant I added LINKTYPE_NETLINK checking too, and it fixed
dissecting.

Daniel Borkmann

unread,
Jun 19, 2015, 6:27:48 PM6/19/15
to Vadim Kochan, netsn...@googlegroups.com, tkla...@distanz.ch
On 06/20/2015 12:16 AM, Vadim Kochan wrote:
> On Sat, Jun 20, 2015 at 01:12:06AM +0300, Vadim Kochan wrote:
>> On Fri, Jun 19, 2015 at 11:59:32PM +0200, Daniel Borkmann wrote:
>>> On 06/19/2015 11:37 PM, Vadim Kochan wrote:
...
>> by adding "|| linktype == LINKTYPE_LINUX_SLL)" I got dissected Netlink
>> messages.
>>
>> Also may be it is better to get this 'switch' out from validation
>> function, just but semantic meaning of this function which should just
>> validate but not change something valuable.
>
> Sorry .... I meant I added LINKTYPE_NETLINK checking too, and it fixed
> dissecting.

Ok, good point, thanks! I have pushed it out for now. If you have any
further cleanups on top of this, feel free to submit.

I also applied your sll dissector patch.

Thanks for your patience,
Daniel

Vadim Kochan

unread,
Jun 19, 2015, 6:39:44 PM6/19/15
to Daniel Borkmann, Vadim Kochan, netsn...@googlegroups.com, tkla...@distanz.ch
Regarding cleanups ... what do you think about change pcap_pkthdr_t to:

typedef struct {
union {
struct pcap_pkthdr ppo;
struct pcap_pkthdr_ns ppn;
struct pcap_pkthdr_ll ppo_ll;
struct pcap_pkthdr_ns_ll ppn_ll;
struct pcap_pkthdr_kuz ppk;
struct pcap_pkthdr_bkm ppb;
uint8_t raw;
} h;
pcap_type_t type;
} pcap_pkthdr_t;

which will allow to remove 'type' argument from I/O & other pcap functions ... and
makes calling of these functions shorter ...

Daniel Borkmann

unread,
Jun 19, 2015, 6:44:47 PM6/19/15
to netsn...@googlegroups.com, Vadim Kochan, tkla...@distanz.ch
On 06/20/2015 12:38 AM, Vadim Kochan wrote:
...
> Regarding cleanups ... what do you think about change pcap_pkthdr_t to:
>
> typedef struct {
> union {
> struct pcap_pkthdr ppo;
> struct pcap_pkthdr_ns ppn;
> struct pcap_pkthdr_ll ppo_ll;
> struct pcap_pkthdr_ns_ll ppn_ll;
> struct pcap_pkthdr_kuz ppk;
> struct pcap_pkthdr_bkm ppb;
> uint8_t raw;
> } h;
> pcap_type_t type;
> } pcap_pkthdr_t;
>
> which will allow to remove 'type' argument from I/O & other pcap functions ... and
> makes calling of these functions shorter ...

Seems okay with me, but depends on how the actual code looks eventually. ;)
Reply all
Reply to author
Forward
0 new messages