af-packet: add VLAN header when needed in IPS mode

When packet is coming from a real ethernet card, the kernel is
stripping the vlan header and delivering a modified packet so
we need to insert the VLAN header back before sending the packet
on the wire.

To do so, we pass an option to the raw socket to add a reserve
before the packet data. It will get Suricata some head room to
to move the ethernet addresses before there actual place and
and insert the VLAN header in the correct place.

We get VLAN info from the ring buffer as the call of AFPWrite is
always done in the release function so we still have access to the
memory.
pull/2549/head
Eric Leblond 8 years ago committed by Victor Julien
parent f407d77016
commit ecf59be413

@ -1,4 +1,4 @@
/* Copyright (C) 2011-2016 Open Information Security Foundation
/* Copyright (C) 2011-2017 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -662,10 +662,23 @@ int AFPRead(AFPThreadVars *ptv)
SCReturnInt(AFP_READ_OK);
}
TmEcode AFPWritePacket(Packet *p)
/**
* \brief AF packet write function.
*
* This function has to be called before the memory
* related to Packet in ring buffer is released.
*
* \param pointer to Packet
* \param version of capture: TPACKET_V2 or TPACKET_V3
* \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success
*
*/
static TmEcode AFPWritePacket(Packet *p, int version)
{
struct sockaddr_ll socket_address;
int socket;
uint8_t *pstart;
size_t plen;
if (p->afp_v.copy_mode == AFP_COPY_MODE_IPS) {
if (PACKET_TEST_ACTION(p, ACTION_DROP)) {
@ -691,7 +704,31 @@ TmEcode AFPWritePacket(Packet *p)
if (p->afp_v.peer->flags & AFP_SOCK_PROTECT)
SCMutexLock(&p->afp_v.peer->sock_protect);
socket = SC_ATOMIC_GET(p->afp_v.peer->socket);
if (sendto(socket, GET_PKT_DATA(p), GET_PKT_LEN(p), 0,
if (version == TPACKET_V2) {
union thdr h;
h.raw = p->afp_v.relptr;
/* 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) {
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(h.h2->tp_vlan_tci);
} else {
pstart = GET_PKT_DATA(p);
plen = GET_PKT_LEN(p);
}
} 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) {
SCLogWarning(SC_ERR_SOCKET, "Sending packet failed on socket %d: %s",
@ -712,7 +749,7 @@ void AFPReleaseDataFromRing(Packet *p)
/* Need to be in copy mode and need to detect early release
where Ethernet header could not be set (and pseudo packet) */
if ((p->afp_v.copy_mode != AFP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) {
AFPWritePacket(p);
AFPWritePacket(p, TPACKET_V2);
}
if (AFPDerefSocket(p->afp_v.mpeer) == 0)
@ -728,15 +765,17 @@ cleanup:
AFPV_CLEANUP(&p->afp_v);
}
#ifdef HAVE_TPACKET_V3
void AFPReleasePacketV3(Packet *p)
{
/* Need to be in copy mode and need to detect early release
where Ethernet header could not be set (and pseudo packet) */
if ((p->afp_v.copy_mode != AFP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) {
AFPWritePacket(p);
AFPWritePacket(p, TPACKET_V3);
}
PacketFreeOrRelease(p);
}
#endif
void AFPReleasePacket(Packet *p)
{
@ -1686,6 +1725,21 @@ 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;
}
}
/* Allocate RX ring */
#ifdef HAVE_TPACKET_V3
if (ptv->flags & AFP_TPACKET_V3) {

Loading…
Cancel
Save