af-packet: Ignore outgoing packets on loopback interfaces

When reading a loopback interface, packets are received twice: Once as
outgoing packets and once as incoming packets.

Libpcap ignores outgoing packets. With current versions of Suricata, sniffing
a single http://localhost:80 request over lo using the af-packet source
minimally shows two syn packets, two synacks and twice as many packets in
the stats entries than you'd expect when running tcpdump or Wireshark.
pull/8815/head
Arne Welzel 2 years ago committed by Victor Julien
parent cd7d6e651a
commit 51aef3c230

@ -327,6 +327,9 @@ typedef struct AFPThreadVars_
int promisc;
/* bitmask of ignored ssl_pkttypes */
uint32_t pkttype_filter_mask;
int down_count;
uint16_t cluster_id;
@ -853,6 +856,25 @@ static inline int AFPReadFromRingWaitForPacket(AFPThreadVars *ptv)
return AFP_READ_OK;
}
/**
* \brief AF packet frame ignore logic
*
* Given a sockaddr_ll of a frame, use the pkttype_filter_mask to decide if the
* frame should be ignored. Protect from undefined behavior if there's ever
* a sll_pkttype that would shift by too much. At this point, only outgoing
* packets (4) are ignored. The highest value in if_linux.h is PACKET_KERNEL (7),
* this extra check is being overly cautious.
*
* \retval true if the frame should be ignored
*/
static inline bool AFPShouldIgnoreFrame(AFPThreadVars *ptv, const struct sockaddr_ll *sll)
{
if (unlikely(sll->sll_pkttype > 31))
return false;
return (ptv->pkttype_filter_mask & BIT_U32(sll->sll_pkttype)) != 0;
}
/**
* \brief AF packet read function for ring
*
@ -898,6 +920,12 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
goto next_frame;
}
const struct sockaddr_ll *sll =
(const struct sockaddr_ll *)((uint8_t *)h.h2 +
TPACKET_ALIGN(sizeof(struct tpacket2_hdr)));
if (unlikely(AFPShouldIgnoreFrame(ptv, sll)))
goto next_frame;
Packet *p = PacketGetFromQueueOrAlloc();
if (p == NULL) {
return AFPSuriFailure(ptv, h);
@ -990,6 +1018,12 @@ static inline int AFPWalkBlock(AFPThreadVars *ptv, struct tpacket_block_desc *pb
uint8_t *ppd = (uint8_t *)pbd + pbd->hdr.bh1.offset_to_first_pkt;
for (int i = 0; i < num_pkts; ++i) {
const struct sockaddr_ll *sll =
(const struct sockaddr_ll *)(ppd + TPACKET_ALIGN(sizeof(struct tpacket3_hdr)));
if (unlikely(AFPShouldIgnoreFrame(ptv, sll))) {
ppd = ppd + ((struct tpacket3_hdr *)ppd)->tp_next_offset;
continue;
}
int ret = AFPParsePacketV3(ptv, pbd, (struct tpacket3_hdr *)ppd);
switch (ret) {
case AFP_READ_OK:
@ -1877,6 +1911,10 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose)
goto socket_err;
}
/* ignore outgoing packets on loopback interfaces */
if (if_flags & IFF_LOOPBACK)
ptv->pkttype_filter_mask |= BIT_U32(PACKET_OUTGOING);
if (ptv->promisc != 0) {
/* Force promiscuous mode */
memset(&sock_params, 0, sizeof(sock_params));

Loading…
Cancel
Save