]> git.ipfire.org Git - people/ms/suricata.git/blobdiff - src/source-af-packet.c
af-packet: refactor VLAN hdr handling
[people/ms/suricata.git] / src / source-af-packet.c
index 3012f618633d276d4d7da20f81a9c8b3a43ba683..aeb9e4bae0fa39fb9ea2996094b45fdf6f5075f3 100644 (file)
@@ -632,10 +632,6 @@ static TmEcode AFPWritePacket(Packet *p, int version)
 {
     struct sockaddr_ll socket_address;
     int socket;
-    uint8_t *pstart;
-    size_t plen;
-    union thdr h;
-    uint16_t vlan_tci = 0;
 
     if (p->afp_v.copy_mode == AFP_COPY_MODE_IPS) {
         if (PacketTestAction(p, ACTION_DROP)) {
@@ -662,42 +658,8 @@ static TmEcode AFPWritePacket(Packet *p, int version)
         SCMutexLock(&p->afp_v.peer->sock_protect);
     socket = SC_ATOMIC_GET(p->afp_v.peer->socket);
 
-    h.raw = p->afp_v.relptr;
-
-    if (version == TPACKET_V2) {
-        /* Copy VLAN header from ring memory. For post june 2011 kernel we test
-         * the flag. It is not defined for older kernel so we go best effort
-         * and test for non zero value of the TCI header. */
-        if (h.h2->tp_status & TP_STATUS_VLAN_VALID || h.h2->tp_vlan_tci) {
-            vlan_tci = h.h2->tp_vlan_tci;
-        }
-    } else {
-#ifdef HAVE_TPACKET_V3
-        if (h.h3->tp_status & TP_STATUS_VLAN_VALID || h.h3->hv1.tp_vlan_tci) {
-            vlan_tci = h.h3->hv1.tp_vlan_tci;
-        }
-#else
-        /* Should not get here */
-        BUG_ON(1);
-#endif
-    }
-
-    if (vlan_tci != 0) {
-        pstart = GET_PKT_DATA(p) - VLAN_HEADER_LEN;
-        plen = GET_PKT_LEN(p) + VLAN_HEADER_LEN;
-        /* move ethernet addresses */
-        memmove(pstart, GET_PKT_DATA(p), 2 * ETH_ALEN);
-        /* write vlan info */
-        *(uint16_t *)(pstart + 2 * ETH_ALEN) = htons(0x8100);
-        *(uint16_t *)(pstart + 2 * ETH_ALEN + 2) = htons(vlan_tci);
-    } else {
-        pstart = GET_PKT_DATA(p);
-        plen = GET_PKT_LEN(p);
-    }
-
-    if (sendto(socket, pstart, plen, 0,
-               (struct sockaddr*) &socket_address,
-               sizeof(struct sockaddr_ll)) < 0) {
+    if (sendto(socket, GET_PKT_DATA(p), GET_PKT_LEN(p), 0, (struct sockaddr *)&socket_address,
+                sizeof(struct sockaddr_ll)) < 0) {
         SCLogWarning(SC_ERR_SOCKET, "Sending packet failed on socket %d: %s",
                   socket,
                   strerror(errno));
@@ -810,6 +772,7 @@ static void AFPReadFromRingSetupPacket(
             (tp_status & TP_STATUS_VLAN_VALID || h.h2->tp_vlan_tci)) {
         p->vlan_id[0] = h.h2->tp_vlan_tci & 0x0fff;
         p->vlan_idx = 1;
+        p->afp_v.vlan_tci = h.h2->tp_vlan_tci;
     }
 
     (void)PacketSetData(p, (unsigned char *)h.raw + h.h2->tp_mac, h.h2->tp_snaplen);
@@ -977,6 +940,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc
             (ppd->tp_status & TP_STATUS_VLAN_VALID || ppd->hv1.tp_vlan_tci)) {
         p->vlan_id[0] = ppd->hv1.tp_vlan_tci & 0x0fff;
         p->vlan_idx = 1;
+        p->afp_v.vlan_tci = ppd->hv1.tp_vlan_tci;
     }
 
     (void)PacketSetData(p, (unsigned char *)ppd + ppd->tp_mac, ppd->tp_snaplen);
@@ -1691,19 +1655,14 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname)
     }
 #endif
 
-    /* Let's reserve head room so we can add the VLAN header in IPS
-     * or TAP mode before write the packet */
-    if (ptv->copy_mode != AFP_COPY_MODE_NONE) {
-        /* Only one vlan is extracted from AFP header so
-         * one VLAN header length is enough. */
-        int reserve = VLAN_HEADER_LEN;
-        if (setsockopt(ptv->socket, SOL_PACKET, PACKET_RESERVE, (void *) &reserve,
-                    sizeof(reserve)) < 0) {
-            SCLogError(SC_ERR_AFP_CREATE,
-                    "Can't activate reserve on packet socket: %s",
-                    strerror(errno));
-            return AFP_FATAL_ERROR;
-        }
+    /* Reserve head room for a VLAN header. One vlan is extracted from AFP header
+     * so one VLAN header length is enough. */
+    int reserve = VLAN_HEADER_LEN;
+    if (setsockopt(ptv->socket, SOL_PACKET, PACKET_RESERVE, (void *)&reserve, sizeof(reserve)) <
+            0) {
+        SCLogError(
+                SC_ERR_AFP_CREATE, "Can't activate reserve on packet socket: %s", strerror(errno));
+        return AFP_FATAL_ERROR;
     }
 
     /* Allocate RX ring */
@@ -2681,6 +2640,34 @@ TmEcode ReceiveAFPThreadDeinit(ThreadVars *tv, void *data)
     SCReturnInt(TM_ECODE_OK);
 }
 
+/** \internal
+ *  \brief add a VLAN header into the raw data for inspection, logging
+ *         and sending out in IPS mode
+ *
+ *  The kernel doesn't provide the first VLAN header the raw packet data,
+ *  but instead feeds it to us through meta data. For logging and IPS
+ *  we need to put it back into the raw data. Luckily there is some head
+ *  room in the original data so its enough to move the ethernet header
+ *  a bit to make space for the VLAN header.
+ */
+static void UpdateRawDataForVLANHdr(Packet *p)
+{
+    if (p->afp_v.vlan_tci != 0) {
+        uint8_t *pstart = GET_PKT_DATA(p) - VLAN_HEADER_LEN;
+        size_t plen = GET_PKT_LEN(p) + VLAN_HEADER_LEN;
+        /* move ethernet addresses */
+        memmove(pstart, GET_PKT_DATA(p), 2 * ETH_ALEN);
+        /* write vlan info */
+        *(uint16_t *)(pstart + 2 * ETH_ALEN) = htons(0x8100);
+        *(uint16_t *)(pstart + 2 * ETH_ALEN + 2) = htons(p->afp_v.vlan_tci);
+
+        /* update the packet raw data pointer to start at the new offset */
+        (void)PacketSetData(p, pstart, plen);
+        /* update ethernet header pointer to point to the new start of the data */
+        p->ethh = (void *)pstart;
+    }
+}
+
 /**
  * \brief This function passes off to link type decoders.
  *
@@ -2694,6 +2681,8 @@ TmEcode ReceiveAFPThreadDeinit(ThreadVars *tv, void *data)
 TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data)
 {
     SCEnter();
+
+    const bool afp_vlan_hdr = p->vlan_idx != 0;
     DecodeThreadVars *dtv = (DecodeThreadVars *)data;
 
     DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p));
@@ -2701,13 +2690,13 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data)
     /* update counters */
     DecodeUpdatePacketCounters(tv, dtv, p);
 
-    /* If suri has set vlan during reading, we increase vlan counter */
-    if (p->vlan_idx) {
-        StatsIncr(tv, dtv->counter_vlan);
-    }
-
     /* call the decoder */
     DecodeLinkLayer(tv, dtv, p->datalink, p, GET_PKT_DATA(p), GET_PKT_LEN(p));
+    /* post-decoding put vlan hdr back into the raw data) */
+    if (afp_vlan_hdr) {
+        StatsIncr(tv, dtv->counter_vlan);
+        UpdateRawDataForVLANHdr(p);
+    }
 
     PacketDecodeFinalize(tv, dtv, p);