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.
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