Skip to content

Commit

Permalink
decode/tunnel: improve tunnel handling
Browse files Browse the repository at this point in the history
Give each packet explicit tunnel type `ttype`: none, root, child.

Assigning happens when a (tunnel) packet is set up and is thread
safe.
  • Loading branch information
victorjulien committed Mar 13, 2024
1 parent 9bc42e3 commit 6066c4d
Show file tree
Hide file tree
Showing 16 changed files with 95 additions and 70 deletions.
35 changes: 19 additions & 16 deletions src/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,13 +335,15 @@ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *pare
p->livedev = parent->livedev;

/* set the root ptr to the lowest layer */
if (parent->root != NULL)
if (parent->root != NULL) {
p->root = parent->root;
else
BUG_ON(parent->ttype != PacketTunnelChild);
} else {
p->root = parent;

parent->ttype = PacketTunnelRoot;
}
/* tell new packet it's part of a tunnel */
SET_TUNNEL_PKT(p);
p->ttype = PacketTunnelChild;

ret = DecodeTunnel(tv, dtv, p, GET_PKT_DATA(p),
GET_PKT_LEN(p), proto);
Expand All @@ -351,18 +353,15 @@ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *pare
{
/* Not a (valid) tunnel packet */
SCLogDebug("tunnel packet is invalid");

p->root = NULL;
UNSET_TUNNEL_PKT(p);
TmqhOutputPacketpool(tv, p);
SCReturnPtr(NULL, "Packet");
}


/* tell parent packet it's part of a tunnel */
SET_TUNNEL_PKT(parent);

/* increment tunnel packet refcnt in the root packet */
/* Update tunnel settings in parent */
if (parent->root == NULL) {
parent->ttype = PacketTunnelRoot;
}
TUNNEL_INCR_PKT_TPR(p);

/* disable payload (not packet) inspection on the parent, as the payload
Expand Down Expand Up @@ -397,10 +396,15 @@ Packet *PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, u
}

/* set the root ptr to the lowest layer */
if (parent->root != NULL)
if (parent->root != NULL) {
p->root = parent->root;
else
BUG_ON(parent->ttype != PacketTunnelChild);
} else {
p->root = parent;
// we set parent->ttype later
}
/* tell new packet it's part of a tunnel */
p->ttype = PacketTunnelChild;

/* copy packet and set length, proto */
if (pkt && len) {
Expand All @@ -410,8 +414,6 @@ Packet *PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, u
p->ts = parent->ts;
p->datalink = DLT_RAW;
p->tenant_id = parent->tenant_id;
/* tell new packet it's part of a tunnel */
SET_TUNNEL_PKT(p);
memcpy(&p->vlan_id[0], &parent->vlan_id[0], sizeof(p->vlan_id));
p->vlan_idx = parent->vlan_idx;
p->livedev = parent->livedev;
Expand All @@ -426,7 +428,8 @@ Packet *PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, u
void PacketDefragPktSetupParent(Packet *parent)
{
/* tell parent packet it's part of a tunnel */
SET_TUNNEL_PKT(parent);
if (parent->ttype == PacketTunnelNone)
parent->ttype = PacketTunnelRoot;

/* increment tunnel packet refcnt in the root packet */
TUNNEL_INCR_PKT_TPR(parent);
Expand Down
58 changes: 44 additions & 14 deletions src/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,12 @@ enum PacketDropReason {
PKT_DROP_REASON_MAX,
};

enum PacketTunnelType {
PacketTunnelNone,
PacketTunnelRoot,
PacketTunnelChild,
};

/* forward declaration since Packet struct definition requires this */
struct PacketQueue_;

Expand Down Expand Up @@ -472,6 +478,9 @@ typedef struct Packet_
* hash size still */
uint32_t flow_hash;

/* tunnel type: none, root or child */
enum PacketTunnelType ttype;

SCTime_t ts;

union {
Expand Down Expand Up @@ -618,7 +627,7 @@ typedef struct Packet_
/* enum PacketDropReason::PKT_DROP_REASON_* as uint8_t for compactness */
uint8_t drop_reason;

/* has tunnel been verdicted? */
/** has verdict on this tunneled packet been issued? */
bool tunnel_verdicted;

/* tunnel/encapsulation handling */
Expand Down Expand Up @@ -649,8 +658,8 @@ typedef struct Packet_
/** lock to protect access to:
* - tunnel_rtv_cnt
* - tunnel_tpr_cnt
* - nfq_v.mark
* - flags
* - tunnel_verdicted
* - nfq_v.mark (if p->ttype != PacketTunnelNone)
*/
SCSpinlock tunnel_lock;
} persistent;
Expand Down Expand Up @@ -799,13 +808,14 @@ static inline void TUNNEL_INCR_PKT_TPR(Packet *p)
#define TUNNEL_PKT_RTV(p) ((p)->root ? (p)->root->tunnel_rtv_cnt : (p)->tunnel_rtv_cnt)
#define TUNNEL_PKT_TPR(p) ((p)->root ? (p)->root->tunnel_tpr_cnt : (p)->tunnel_tpr_cnt)

#define IS_TUNNEL_PKT(p) (((p)->flags & PKT_TUNNEL))
#define SET_TUNNEL_PKT(p) ((p)->flags |= PKT_TUNNEL)
#define UNSET_TUNNEL_PKT(p) ((p)->flags &= ~PKT_TUNNEL)
#define IS_TUNNEL_ROOT_PKT(p) (IS_TUNNEL_PKT(p) && (p)->root == NULL)

#define IS_TUNNEL_PKT_VERDICTED(p) (p)->tunnel_verdicted
#define SET_TUNNEL_PKT_VERDICTED(p) (p)->tunnel_verdicted = true
static inline bool PacketTunnelIsVerdicted(const Packet *p)
{
return p->tunnel_verdicted;
}
static inline void PacketTunnelSetVerdicted(Packet *p)
{
p->tunnel_verdicted = true;
}

enum DecodeTunnelProto {
DECODE_TUNNEL_ETHERNET,
Expand Down Expand Up @@ -1017,8 +1027,7 @@ void DecodeUnregisterCounters(void);
depth reached. */
#define PKT_STREAM_NOPCAPLOG BIT_U32(12)

#define PKT_TUNNEL BIT_U32(13)
// vacancy
// vacancy 2x

/** Packet checksum is not computed (TX packet for example) */
#define PKT_IGNORE_CHECKSUM BIT_U32(15)
Expand Down Expand Up @@ -1094,6 +1103,26 @@ static inline void DecodeSetNoPacketInspectionFlag(Packet *p)
p->flags |= PKT_NOPACKET_INSPECTION;
}

static inline bool PacketIsTunnelRoot(const Packet *p)
{
return (p->ttype == PacketTunnelRoot);
}

static inline bool PacketIsTunnelChild(const Packet *p)
{
return (p->ttype == PacketTunnelChild);
}

static inline bool PacketIsTunnel(const Packet *p)
{
return (p->ttype != PacketTunnelNone);
}

static inline bool PacketIsNotTunnel(const Packet *p)
{
return (p->ttype == PacketTunnelNone);
}

/** \brief return true if *this* packet needs to trigger a verdict.
*
* If we have the root packet, and we have none outstanding,
Expand All @@ -1113,10 +1142,11 @@ static inline bool VerdictTunnelPacket(Packet *p)
SCLogDebug("tunnel: outstanding %u", outstanding);

/* if there are packets outstanding, we won't verdict this one */
if (IS_TUNNEL_ROOT_PKT(p) && !IS_TUNNEL_PKT_VERDICTED(p) && !outstanding) {
if (PacketIsTunnelRoot(p) && !PacketTunnelIsVerdicted(p) && !outstanding) {
// verdict
SCLogDebug("root %p: verdict", p);
} else if (!IS_TUNNEL_ROOT_PKT(p) && outstanding == 1 && p->root && IS_TUNNEL_PKT_VERDICTED(p->root)) {
} else if (PacketIsTunnelChild(p) && outstanding == 1 && p->root &&
PacketTunnelIsVerdicted(p->root)) {
// verdict
SCLogDebug("tunnel %p: verdict", p);
} else {
Expand Down
10 changes: 2 additions & 8 deletions src/defrag.c
Original file line number Diff line number Diff line change
Expand Up @@ -873,10 +873,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker,
r = Defrag4Reassemble(tv, tracker, p);
if (r != NULL && tv != NULL && dtv != NULL) {
StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled);
if (DecodeIPV4(tv, dtv, r, (void *)r->ip4h,
IPV4_GET_IPLEN(r)) != TM_ECODE_OK) {

UNSET_TUNNEL_PKT(r);
if (DecodeIPV4(tv, dtv, r, (void *)r->ip4h, IPV4_GET_IPLEN(r)) != TM_ECODE_OK) {
r->root = NULL;
TmqhOutputPacketpool(tv, r);
r = NULL;
Expand All @@ -890,10 +887,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker,
if (r != NULL && tv != NULL && dtv != NULL) {
StatsIncr(tv, dtv->counter_defrag_ipv6_reassembled);
if (DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h,
IPV6_GET_PLEN(r) + IPV6_HEADER_LEN)
!= TM_ECODE_OK) {

UNSET_TUNNEL_PKT(r);
IPV6_GET_PLEN(r) + IPV6_HEADER_LEN) != TM_ECODE_OK) {
r->root = NULL;
TmqhOutputPacketpool(tv, r);
r = NULL;
Expand Down
2 changes: 1 addition & 1 deletion src/detect-mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p,
#ifdef NFQ
const DetectMarkData *nf_data = (const DetectMarkData *)ctx;
if (nf_data->mask) {
if (!(IS_TUNNEL_PKT(p))) {
if (PacketIsNotTunnel(p)) {
/* coverity[missing_lock] */
p->nfq_v.mark = (nf_data->mark & nf_data->mask)
| (p->nfq_v.mark & ~(nf_data->mask));
Expand Down
10 changes: 5 additions & 5 deletions src/log-pcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ static bool PcapLogCondition(ThreadVars *tv, void *thread_data, const Packet *p)
return false;
}

if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
if (p->ttype == PacketTunnelChild) {
return false;
}
return true;
Expand Down Expand Up @@ -379,7 +379,7 @@ static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p)
PCAPLOG_PROFILE_START;

int datalink = p->datalink;
if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
if (p->ttype == PacketTunnelChild) {
Packet *real_p = p->root;
datalink = real_p->datalink;
}
Expand Down Expand Up @@ -588,7 +588,7 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
pl->pkt_cnt++;
pl->h->ts.tv_sec = SCTIME_SECS(p->ts);
pl->h->ts.tv_usec = SCTIME_USECS(p->ts);
if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
if (p->ttype == PacketTunnelChild) {
rp = p->root;
pl->h->caplen = GET_PKT_LEN(rp);
pl->h->len = GET_PKT_LEN(rp);
Expand Down Expand Up @@ -666,7 +666,7 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
/* PcapLogDumpSegment has written over the PcapLogData variables so need to update */
pl->h->ts.tv_sec = SCTIME_SECS(p->ts);
pl->h->ts.tv_usec = SCTIME_USECS(p->ts);
if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
if (p->ttype == PacketTunnelChild) {
rp = p->root;
pl->h->caplen = GET_PKT_LEN(rp);
pl->h->len = GET_PKT_LEN(rp);
Expand All @@ -679,7 +679,7 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
}
}

if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
if (p->ttype == PacketTunnelChild) {
rp = p->root;
#ifdef HAVE_LIBLZ4
ret = PcapWrite(pl, comp, GET_PKT_DATA(rp), len);
Expand Down
2 changes: 1 addition & 1 deletion src/output-json-alert.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p)
/* alert */
AlertJsonHeader(json_output_ctx, p, pa, jb, json_output_ctx->flags, &addr, xff_buffer);

if (IS_TUNNEL_PKT(p)) {
if (PacketIsTunnel(p)) {
AlertJsonTunnel(p, jb);
}

Expand Down
1 change: 1 addition & 0 deletions src/packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ void PacketReinit(Packet *p)
p->vlan_id[0] = 0;
p->vlan_id[1] = 0;
p->vlan_idx = 0;
p->ttype = PacketTunnelNone;
SCTIME_INIT(p->ts);
p->datalink = 0;
p->drop_reason = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/respond-reject.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ static TmEcode RespondRejectFunc(ThreadVars *tv, Packet *p, void *data)
return TM_ECODE_OK;
}

if (IS_TUNNEL_PKT(p)) {
if (PacketIsTunnel(p)) {
return TM_ECODE_OK;
}

Expand Down
4 changes: 2 additions & 2 deletions src/source-af-packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -2194,7 +2194,7 @@ static int AFPBypassCallback(Packet *p)
/* Bypassing tunneled packets is currently not supported
* because we can't discard the inner packet only due to
* primitive parsing in eBPF */
if (IS_TUNNEL_PKT(p)) {
if (PacketIsTunnel(p)) {
return 0;
}
if (PKT_IS_IPV4(p)) {
Expand Down Expand Up @@ -2349,7 +2349,7 @@ static int AFPXDPBypassCallback(Packet *p)
/* Bypassing tunneled packets is currently not supported
* because we can't discard the inner packet only due to
* primitive parsing in eBPF */
if (IS_TUNNEL_PKT(p)) {
if (PacketIsTunnel(p)) {
return 0;
}
if (PKT_IS_IPV4(p)) {
Expand Down
7 changes: 3 additions & 4 deletions src/source-ipfw.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,9 +614,8 @@ TmEcode VerdictIPFW(ThreadVars *tv, Packet *p, void *data)
}

/* This came from NFQ.
* if this is a tunnel packet we check if we are ready to verdict
* already. */
if (IS_TUNNEL_PKT(p)) {
* If this is a tunnel packet we check if we are ready to verdict already. */
if (PacketIsTunnel(p)) {
bool verdict = VerdictTunnelPacket(p);

/* don't verdict if we are not ready */
Expand All @@ -628,7 +627,7 @@ TmEcode VerdictIPFW(ThreadVars *tv, Packet *p, void *data)
/* no tunnel, verdict normally */
SCLogDebug("Setting verdict on non-tunnel");
retval = IPFWSetVerdict(tv, ptv, p);
} /* IS_TUNNEL_PKT end */
}

SCReturnInt(retval);
}
Expand Down
4 changes: 2 additions & 2 deletions src/source-nfq.c
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ static void NFQReleasePacket(Packet *p)
*/
static int NFQBypassCallback(Packet *p)
{
if (IS_TUNNEL_PKT(p)) {
if (PacketIsTunnel(p)) {
/* real tunnels may have multiple flows inside them, so bypass can't
* work for those. Rebuilt packets from IP fragments are fine. */
if (p->flags & PKT_REBUILT_FRAGMENT) {
Expand Down Expand Up @@ -1186,7 +1186,7 @@ TmEcode VerdictNFQ(ThreadVars *tv, Packet *p, void *data)
{
/* if this is a tunnel packet we check if we are ready to verdict
* already. */
if (IS_TUNNEL_PKT(p)) {
if (p->ttype != PacketTunnelNone) {
SCLogDebug("tunnel pkt: %p/%p %s", p, p->root, p->root ? "upper layer" : "root");
bool verdict = VerdictTunnelPacket(p);
/* don't verdict if we are not ready */
Expand Down
2 changes: 1 addition & 1 deletion src/source-pfring.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ static int PfringBypassCallback(Packet *p)
}

/* Bypassing tunneled packets is currently not supported */
if (IS_TUNNEL_PKT(p)) {
if (PacketIsTunnel(p)) {
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion src/source-windivert.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ static TmEcode WinDivertVerdictHelper(ThreadVars *tv, Packet *p)

/* we can't verdict tunnel packets without ensuring all encapsulated
* packets are verdicted */
if (IS_TUNNEL_PKT(p)) {
if (PacketIsTunnel(p)) {
bool finalVerdict = VerdictTunnelPacket(p);
if (!finalVerdict) {
SCReturnInt(TM_ECODE_OK);
Expand Down
2 changes: 1 addition & 1 deletion src/stream-tcp-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ static void StreamTcpSegmentAddPacketData(
return;
}

if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
if (PacketIsTunnelChild(p)) {
Packet *rp = p->root;
StreamTcpSegmentAddPacketDataDo(seg, rp, p);
} else {
Expand Down
Loading

0 comments on commit 6066c4d

Please sign in to comment.