From: Victor Julien Date: Thu, 4 Nov 2021 09:00:17 +0000 (+0100) Subject: af-packet: refactor VLAN hdr handling X-Git-Tag: suricata-7.0.0-beta1~1168 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2fab3ff0e851da759fd1d7214f8f89eea9054e18;p=thirdparty%2Fsuricata.git af-packet: refactor VLAN hdr handling Update the packet payload after decode, instead of during IPS send. This means the updates happen in the capture thread, and the VLAN header is available to logging as well. Ticket: #4805. --- diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 3012f61863..aeb9e4bae0 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -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); diff --git a/src/source-af-packet.h b/src/source-af-packet.h index 4065699130..e8929f40cc 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -148,6 +148,7 @@ typedef struct AFPPacketVars_ */ AFPPeer *mpeer; uint8_t copy_mode; + uint16_t vlan_tci; #ifdef HAVE_PACKET_EBPF int v4_map_fd; int v6_map_fd; @@ -156,21 +157,25 @@ typedef struct AFPPacketVars_ } AFPPacketVars; #ifdef HAVE_PACKET_EBPF -#define AFPV_CLEANUP(afpv) do { \ - (afpv)->relptr = NULL; \ - (afpv)->copy_mode = 0; \ - (afpv)->peer = NULL; \ - (afpv)->mpeer = NULL; \ - (afpv)->v4_map_fd = -1; \ - (afpv)->v6_map_fd = -1; \ -} while(0) +#define AFPV_CLEANUP(afpv) \ + do { \ + (afpv)->relptr = NULL; \ + (afpv)->copy_mode = 0; \ + (afpv)->vlan_tci = 0; \ + (afpv)->peer = NULL; \ + (afpv)->mpeer = NULL; \ + (afpv)->v4_map_fd = -1; \ + (afpv)->v6_map_fd = -1; \ + } while (0) #else -#define AFPV_CLEANUP(afpv) do { \ - (afpv)->relptr = NULL; \ - (afpv)->copy_mode = 0; \ - (afpv)->peer = NULL; \ - (afpv)->mpeer = NULL; \ -} while(0) +#define AFPV_CLEANUP(afpv) \ + do { \ + (afpv)->relptr = NULL; \ + (afpv)->copy_mode = 0; \ + (afpv)->vlan_tci = 0; \ + (afpv)->peer = NULL; \ + (afpv)->mpeer = NULL; \ + } while (0) #endif /**