From 189b521239a2be4da2da833f9fd5b2474e4a9464 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 19 Dec 2017 20:17:39 +0100 Subject: [PATCH] pfring: fix vlan handling issues When Suricata was monitoring traffic with a single vlan layer, the stats and output instead showed 2. This was caused by the raw packets PF_RING feeds Suricata would hold the vlan header, but the code assumed that the header was stripped and the vlan_id passed to Suricata through PF_RING's extended_hdr.parsed_pkt. This patch adds the following logic: Check vlan id from the parser packet PF_RING prepared. PF_RING sets the vlan_id based on its own parsing or based on the hardware offload. It gives no indication on where the vlan_id came from, so we rely on the vlan_offset field. If it's 0, we assume the PF_RING parser did not see the vlan header and got it from the hardware offload. In this case we will use this information directly, as we won't get a raw vlan header later. If PF_RING did set the offset, we do the parsing in the Suricata decoder so that we have full control. PF_RING *should* put back the vlan header in all cases, and also set the vlan_offset field, but as a extra precaution keep the check described above. Bug #2355. --- src/source-pfring.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/source-pfring.c b/src/source-pfring.c index 4eb9f79338..a4591337ac 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -255,11 +255,23 @@ static inline void PfringProcessPacket(void *user, struct pfring_pkthdr *h, Pack * so that is what we do here. */ p->datalink = LINKTYPE_ETHERNET; - /* get vlan id from header. Check on vlan_id not null even if comment in - * header announce NO_VLAN is used when there is no VLAN. But NO_VLAN - * is not defined nor used in PF_RING code. And vlan_id is set to 0 - * in PF_RING kernel code when there is no VLAN. */ - if ((!ptv->vlan_disabled) && h->extended_hdr.parsed_pkt.vlan_id) { + /* In the past, we needed this vlan handling in cases + * where the vlan header was stripped from the raw packet. + * With modern (at least >= 6) versions of PF_RING, the + * 'copy_data_to_ring' function (kernel/pf_ring.c) makes + * sure that if the hardware stripped the vlan header, + * it is put back by PF_RING. + * + * PF_RING should put it back in all cases, but as a extra + * precaution keep the check here. If the vlan header is + * part of the raw packet, the vlan_offset will be set. + * So is it is not set, use the parsed info from PF_RING's + * extended header. + */ + if ((!ptv->vlan_disabled) && + h->extended_hdr.parsed_pkt.offset.vlan_offset == 0 && + h->extended_hdr.parsed_pkt.vlan_id) + { p->vlan_id[0] = h->extended_hdr.parsed_pkt.vlan_id & 0x0fff; p->vlan_idx = 1; p->vlanh[0] = NULL;