|
|
2cd29a |
From e80ed31b6e3ab778a7e0dd53348f488a91456cfc Mon Sep 17 00:00:00 2001
|
|
|
2cd29a |
From: Michal Sekletar <msekleta@redhat.com>
|
|
|
2cd29a |
Date: Fri, 31 Oct 2014 15:19:54 +0100
|
|
|
2cd29a |
Subject: [PATCH 2/2] Use BPF extensions in compiled filters
|
|
|
2cd29a |
|
|
|
2cd29a |
libpcap will generate BPF filter code which uses BPF extensions if target
|
|
|
2cd29a |
platform supports them. Currently supported BPF extensions are vlan_tci and
|
|
|
2cd29a |
vlan_pr.
|
|
|
2cd29a |
|
|
|
2cd29a |
Also to properly handle such filters when filtering in userspace libpcap now
|
|
|
2cd29a |
employs bpf_filter1.
|
|
|
2cd29a |
|
|
|
2cd29a |
(cherry picked from 04660eb1e56102e2369473cae2538e4d3d263607)
|
|
|
2cd29a |
|
|
|
2cd29a |
Conflicts:
|
|
|
2cd29a |
pcap-linux.c
|
|
|
2cd29a |
---
|
|
|
2cd29a |
gencode.c | 110 +++++++++++++++++++++++++++++++++++++++++++++--------------
|
|
|
2cd29a |
pcap-linux.c | 23 +++++++++----
|
|
|
2cd29a |
2 files changed, 102 insertions(+), 31 deletions(-)
|
|
|
2cd29a |
|
|
|
2cd29a |
diff --git a/gencode.c b/gencode.c
|
|
|
2cd29a |
index d58ea30..2ff725e 100644
|
|
|
2cd29a |
--- a/gencode.c
|
|
|
2cd29a |
+++ b/gencode.c
|
|
|
2cd29a |
@@ -58,6 +58,7 @@ static const char rcsid[] _U_ =
|
|
|
2cd29a |
|
|
|
2cd29a |
#include <netinet/in.h>
|
|
|
2cd29a |
#include <arpa/inet.h>
|
|
|
2cd29a |
+#include <errno.h>
|
|
|
2cd29a |
|
|
|
2cd29a |
#endif /* WIN32 */
|
|
|
2cd29a |
|
|
|
2cd29a |
@@ -135,9 +136,9 @@ static pcap_t *bpf_pcap;
|
|
|
2cd29a |
|
|
|
2cd29a |
/* Hack for updating VLAN, MPLS, and PPPoE offsets. */
|
|
|
2cd29a |
#ifdef WIN32
|
|
|
2cd29a |
-static u_int orig_linktype = (u_int)-1, orig_nl = (u_int)-1, label_stack_depth = (u_int)-1;
|
|
|
2cd29a |
+static u_int orig_linktype = (u_int)-1, orig_nl = (u_int)-1, label_stack_depth = (u_int)-1, vlan_stack_depth = (u_int)-1;
|
|
|
2cd29a |
#else
|
|
|
2cd29a |
-static u_int orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U;
|
|
|
2cd29a |
+static u_int orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U, vlan_stack_depth = -1U;
|
|
|
2cd29a |
#endif
|
|
|
2cd29a |
|
|
|
2cd29a |
/* XXX */
|
|
|
2cd29a |
@@ -962,6 +963,7 @@ init_linktype(p)
|
|
|
2cd29a |
orig_linktype = -1;
|
|
|
2cd29a |
orig_nl = -1;
|
|
|
2cd29a |
label_stack_depth = 0;
|
|
|
2cd29a |
+ vlan_stack_depth = 0;
|
|
|
2cd29a |
|
|
|
2cd29a |
reg_off_ll = -1;
|
|
|
2cd29a |
reg_off_macpl = -1;
|
|
|
2cd29a |
@@ -7861,6 +7863,76 @@ gen_ahostop(eaddr, dir)
|
|
|
2cd29a |
/* NOTREACHED */
|
|
|
2cd29a |
}
|
|
|
2cd29a |
|
|
|
2cd29a |
+#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT)
|
|
|
2cd29a |
+static int skf_ad_vlan_tag_present_supported(int bpf_extensions) {
|
|
|
2cd29a |
+ return bpf_extensions >= SKF_AD_VLAN_TAG_PRESENT;
|
|
|
2cd29a |
+}
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+static struct block *
|
|
|
2cd29a |
+gen_vlan_bpf_extensions(int vlan_num) {
|
|
|
2cd29a |
+ struct block *b0, *b1;
|
|
|
2cd29a |
+ struct slist *s;
|
|
|
2cd29a |
+ int val = 0, len, r;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ len = sizeof(val);
|
|
|
2cd29a |
+ r = getsockopt(bpf_pcap->fd, SOL_SOCKET, SO_BPF_EXTENSIONS, &val, &len;;
|
|
|
2cd29a |
+ if (r < 0)
|
|
|
2cd29a |
+ return NULL;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ if (!skf_ad_vlan_tag_present_supported(val))
|
|
|
2cd29a |
+ return NULL;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ /* generate new filter code based on extracting packet
|
|
|
2cd29a |
+ * metadata */
|
|
|
2cd29a |
+ s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
|
|
|
2cd29a |
+ s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ b0 = new_block(JMP(BPF_JEQ));
|
|
|
2cd29a |
+ b0->stmts = s;
|
|
|
2cd29a |
+ b0->s.k = 1;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ if (vlan_num >= 0) {
|
|
|
2cd29a |
+ s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
|
|
|
2cd29a |
+ s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ b1 = new_block(JMP(BPF_JEQ));
|
|
|
2cd29a |
+ b1->stmts = s;
|
|
|
2cd29a |
+ b1->s.k = (bpf_int32) vlan_num;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ gen_and(b0,b1);
|
|
|
2cd29a |
+ b0 = b1;
|
|
|
2cd29a |
+ }
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ return b0;
|
|
|
2cd29a |
+}
|
|
|
2cd29a |
+#endif
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+static struct block *
|
|
|
2cd29a |
+gen_vlan_no_bpf_extensions(int vlan_num) {
|
|
|
2cd29a |
+ struct block *b0, *b1;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ /* check for VLAN, including QinQ */
|
|
|
2cd29a |
+ b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
|
|
|
2cd29a |
+ (bpf_int32)ETHERTYPE_8021Q);
|
|
|
2cd29a |
+ b1 = gen_cmp(OR_LINK, off_linktype, BPF_H,
|
|
|
2cd29a |
+ (bpf_int32)ETHERTYPE_8021QINQ);
|
|
|
2cd29a |
+ gen_or(b0,b1);
|
|
|
2cd29a |
+ b0 = b1;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ /* If a specific VLAN is requested, check VLAN id */
|
|
|
2cd29a |
+ if (vlan_num >= 0) {
|
|
|
2cd29a |
+ b1 = gen_mcmp(OR_MACPL, 0, BPF_H,
|
|
|
2cd29a |
+ (bpf_int32)vlan_num, 0x0fff);
|
|
|
2cd29a |
+ gen_and(b0, b1);
|
|
|
2cd29a |
+ b0 = b1;
|
|
|
2cd29a |
+ }
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ off_macpl += 4;
|
|
|
2cd29a |
+ off_linktype += 4;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ return b0;
|
|
|
2cd29a |
+}
|
|
|
2cd29a |
+
|
|
|
2cd29a |
/*
|
|
|
2cd29a |
* support IEEE 802.1Q VLAN trunk over ethernet
|
|
|
2cd29a |
*/
|
|
|
2cd29a |
@@ -7912,36 +7984,24 @@ gen_vlan(vlan_num)
|
|
|
2cd29a |
case DLT_EN10MB:
|
|
|
2cd29a |
case DLT_NETANALYZER:
|
|
|
2cd29a |
case DLT_NETANALYZER_TRANSPARENT:
|
|
|
2cd29a |
- /* check for VLAN, including QinQ */
|
|
|
2cd29a |
- b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
|
|
|
2cd29a |
- (bpf_int32)ETHERTYPE_8021Q);
|
|
|
2cd29a |
- b1 = gen_cmp(OR_LINK, off_linktype, BPF_H,
|
|
|
2cd29a |
- (bpf_int32)ETHERTYPE_8021QINQ);
|
|
|
2cd29a |
- gen_or(b0,b1);
|
|
|
2cd29a |
- b0 = b1;
|
|
|
2cd29a |
-
|
|
|
2cd29a |
- /* If a specific VLAN is requested, check VLAN id */
|
|
|
2cd29a |
- if (vlan_num >= 0) {
|
|
|
2cd29a |
- b1 = gen_mcmp(OR_MACPL, 0, BPF_H,
|
|
|
2cd29a |
- (bpf_int32)vlan_num, 0x0fff);
|
|
|
2cd29a |
- gen_and(b0, b1);
|
|
|
2cd29a |
- b0 = b1;
|
|
|
2cd29a |
- }
|
|
|
2cd29a |
-
|
|
|
2cd29a |
- off_macpl += 4;
|
|
|
2cd29a |
- off_linktype += 4;
|
|
|
2cd29a |
-#if 0
|
|
|
2cd29a |
- off_nl_nosnap += 4;
|
|
|
2cd29a |
- off_nl += 4;
|
|
|
2cd29a |
+#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT)
|
|
|
2cd29a |
+ if (!vlan_stack_depth) {
|
|
|
2cd29a |
+ b0 = gen_vlan_bpf_extensions(vlan_num);
|
|
|
2cd29a |
+ if (!b0)
|
|
|
2cd29a |
+ b0 = gen_vlan_no_bpf_extensions(vlan_num);
|
|
|
2cd29a |
+ }
|
|
|
2cd29a |
+ else
|
|
|
2cd29a |
#endif
|
|
|
2cd29a |
- break;
|
|
|
2cd29a |
-
|
|
|
2cd29a |
+ b0 = gen_vlan_no_bpf_extensions(vlan_num);
|
|
|
2cd29a |
+ break;
|
|
|
2cd29a |
default:
|
|
|
2cd29a |
bpf_error("no VLAN support for data link type %d",
|
|
|
2cd29a |
linktype);
|
|
|
2cd29a |
/*NOTREACHED*/
|
|
|
2cd29a |
}
|
|
|
2cd29a |
|
|
|
2cd29a |
+ vlan_stack_depth++;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
return (b0);
|
|
|
2cd29a |
}
|
|
|
2cd29a |
|
|
|
2cd29a |
diff --git a/pcap-linux.c b/pcap-linux.c
|
|
|
2cd29a |
index a0e543c..68e6d05 100644
|
|
|
2cd29a |
--- a/pcap-linux.c
|
|
|
2cd29a |
+++ b/pcap-linux.c
|
|
|
2cd29a |
@@ -1475,6 +1475,7 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
|
|
|
2cd29a |
int packet_len, caplen;
|
|
|
2cd29a |
struct pcap_pkthdr pcap_header;
|
|
|
2cd29a |
|
|
|
2cd29a |
+ struct bpf_aux_data aux_data;
|
|
|
2cd29a |
#ifdef HAVE_PF_PACKET_SOCKETS
|
|
|
2cd29a |
/*
|
|
|
2cd29a |
* If this is a cooked device, leave extra room for a
|
|
|
2cd29a |
@@ -1658,6 +1659,11 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
|
|
|
2cd29a |
tag->vlan_tpid = htons(ETH_P_8021Q);
|
|
|
2cd29a |
tag->vlan_tci = htons(aux->tp_vlan_tci);
|
|
|
2cd29a |
|
|
|
2cd29a |
+ /* store vlan tci to bpf_aux_data struct for userland bpf filter */
|
|
|
2cd29a |
+#if defined(TP_STATUS_VLAN_VALID)
|
|
|
2cd29a |
+ aux_data.vlan_tag = htons(aux->tp_vlan_tci) & 0x0fff;
|
|
|
2cd29a |
+ aux_data.vlan_tag_present = (aux->tp_status & TP_STATUS_VLAN_VALID);
|
|
|
2cd29a |
+#endif
|
|
|
2cd29a |
packet_len += VLAN_TAG_LEN;
|
|
|
2cd29a |
}
|
|
|
2cd29a |
}
|
|
|
2cd29a |
@@ -1702,8 +1708,8 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
|
|
|
2cd29a |
|
|
|
2cd29a |
/* Run the packet filter if not using kernel filter */
|
|
|
2cd29a |
if (handlep->filter_in_userland && handle->fcode.bf_insns) {
|
|
|
2cd29a |
- if (bpf_filter(handle->fcode.bf_insns, bp,
|
|
|
2cd29a |
- packet_len, caplen) == 0)
|
|
|
2cd29a |
+ if (bpf_filter1(handle->fcode.bf_insns, bp,
|
|
|
2cd29a |
+ packet_len, caplen, &aux_data) == 0)
|
|
|
2cd29a |
{
|
|
|
2cd29a |
/* rejected by filter */
|
|
|
2cd29a |
return 0;
|
|
|
2cd29a |
@@ -4270,10 +4276,15 @@ static int pcap_handle_packet_mmap(
|
|
|
2cd29a |
snaplen += sizeof(struct sll_header);
|
|
|
2cd29a |
}
|
|
|
2cd29a |
|
|
|
2cd29a |
- if (handlep->filter_in_userland && handle->fcode.bf_insns &&
|
|
|
2cd29a |
- (bpf_filter(handle->fcode.bf_insns, bp,
|
|
|
2cd29a |
- tp_len, snaplen) == 0))
|
|
|
2cd29a |
- return 0;
|
|
|
2cd29a |
+ if (handlep->filter_in_userland && handle->fcode.bf_insns) {
|
|
|
2cd29a |
+ struct bpf_aux_data aux_data;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ aux_data.vlan_tag = tp_vlan_tci & 0x0fff;
|
|
|
2cd29a |
+ aux_data.vlan_tag_present = tp_vlan_tci_valid;
|
|
|
2cd29a |
+
|
|
|
2cd29a |
+ if (bpf_filter1(handle->fcode.bf_insns, bp, tp_len, tp_snaplen, &aux_data) == 0)
|
|
|
2cd29a |
+ return 0;
|
|
|
2cd29a |
+ }
|
|
|
2cd29a |
|
|
|
2cd29a |
if (!linux_check_direction(handle, sll))
|
|
|
2cd29a |
return 0;
|
|
|
2cd29a |
--
|
|
|
2cd29a |
2.4.3
|
|
|
2cd29a |
|