detect: add vlan.layers keyword

vlan.layers matches on the number of VLAN layers per packet
It is an unsigned 8-bit integer
Valid range = [0-3]
Supports prefiltering

Ticket: #1065
pull/12393/head
Alice Akaki 2 months ago committed by Victor Julien
parent b1c2643c87
commit 078c6469a0

@ -83,3 +83,43 @@ It is also possible to use the vlan.id content as a fast_pattern by using the ``
.. container:: example-rule
alert ip any any -> any any (msg:"Vlan ID is equal to 200 at layer 1"; :example-rule-emphasis:`vlan.id:200,1; prefilter;` sid:1;)
vlan.layers
-----------
Matches based on the number of layers.
Syntax::
vlan.layers: [op]number;
It can be matched exactly, or compared using the ``op`` setting::
vlan.layers:3 # exactly 3 vlan layers
vlan.layers:<3 # less than 3 vlan layers
vlan.layers:>=2 # more or equal to 2 vlan layers
vlan.layers uses :ref:`unsigned 8-bit integer <rules-integer-keywords>`.
The minimum and maximum values that vlan.layers can be are ``0`` and ``3``.
Examples
^^^^^^^^
Example of a signature that would alert if a packet has 0 VLAN layers:
.. container:: example-rule
alert ip any any -> any any (msg:"Packet has 0 vlan layers"; :example-rule-emphasis:`vlan.layers:0;` sid:1;)
Example of a signature that would alert if a packet has more than 1 VLAN layers:
.. container:: example-rule
alert ip any any -> any any (msg:"Packet has more than 1 vlan layer"; :example-rule-emphasis:`vlan.layers:>1;` sid:1;)
It is also possible to use the vlan.layers content as a fast_pattern by using the ``prefilter`` keyword, as shown in the following example.
.. container:: example-rule
alert ip any any -> any any (msg:"Packet has 2 vlan layers"; :example-rule-emphasis:`vlan.layers:2; prefilter;` sid:1;)

@ -728,6 +728,7 @@ void SigTableSetup(void)
DetectFileHandlerRegister();
DetectVlanIdRegister();
DetectVlanLayersRegister();
ScDetectSNMPRegister();
ScDetectDHCPRegister();

@ -334,6 +334,7 @@ enum DetectKeywordId {
DETECT_AL_JA4_HASH,
DETECT_VLAN_ID,
DETECT_VLAN_LAYERS,
/* make sure this stays last */
DETECT_TBLSIZE_STATIC,

@ -139,4 +139,80 @@ void DetectVlanIdRegister(void)
sigmatch_table[DETECT_VLAN_ID].Free = DetectVlanIdFree;
sigmatch_table[DETECT_VLAN_ID].SupportsPrefilter = PrefilterVlanIdIsPrefilterable;
sigmatch_table[DETECT_VLAN_ID].SetupPrefilter = PrefilterSetupVlanId;
}
}
static int DetectVlanLayersMatch(
DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx)
{
uint8_t nb = p->vlan_idx;
const DetectU8Data *du8 = (const DetectU8Data *)ctx;
return DetectU8Match(nb, du8);
}
static void DetectVlanLayersFree(DetectEngineCtx *de_ctx, void *ptr)
{
rs_detect_u8_free(ptr);
}
static int DetectVlanLayersSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
DetectU8Data *du8 = DetectU8Parse(rawstr);
if (du8 == NULL) {
SCLogError("vlan layers invalid %s", rawstr);
return -1;
}
if (du8->arg1 > VLAN_MAX_LAYERS || du8->arg2 > VLAN_MAX_LAYERS) {
SCLogError("number of layers out of range %s", rawstr);
return -1;
}
if (SigMatchAppendSMToList(
de_ctx, s, DETECT_VLAN_LAYERS, (SigMatchCtx *)du8, DETECT_SM_LIST_MATCH) == NULL) {
DetectVlanLayersFree(de_ctx, du8);
return -1;
}
s->flags |= SIG_FLAG_REQUIRE_PACKET;
return 0;
}
static void PrefilterPacketVlanLayersMatch(
DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
{
const PrefilterPacketHeaderCtx *ctx = pectx;
DetectU8Data du8;
du8.mode = ctx->v1.u8[0];
du8.arg1 = ctx->v1.u8[1];
du8.arg2 = ctx->v1.u8[2];
if (DetectVlanLayersMatch(det_ctx, p, NULL, (const SigMatchCtx *)&du8)) {
PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
}
}
static int PrefilterSetupVlanLayers(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
{
return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_VLAN_LAYERS, SIG_MASK_REQUIRE_REAL_PKT,
PrefilterPacketU8Set, PrefilterPacketU8Compare, PrefilterPacketVlanLayersMatch);
}
static bool PrefilterVlanLayersIsPrefilterable(const Signature *s)
{
return PrefilterIsPrefilterableById(s, DETECT_VLAN_LAYERS);
}
void DetectVlanLayersRegister(void)
{
sigmatch_table[DETECT_VLAN_LAYERS].name = "vlan.layers";
sigmatch_table[DETECT_VLAN_LAYERS].desc = "match number of vlan layers";
sigmatch_table[DETECT_VLAN_LAYERS].url = "/rules/vlan-keywords.html#vlan-layers";
sigmatch_table[DETECT_VLAN_LAYERS].Match = DetectVlanLayersMatch;
sigmatch_table[DETECT_VLAN_LAYERS].Setup = DetectVlanLayersSetup;
sigmatch_table[DETECT_VLAN_LAYERS].Free = DetectVlanLayersFree;
sigmatch_table[DETECT_VLAN_LAYERS].SupportsPrefilter = PrefilterVlanLayersIsPrefilterable;
sigmatch_table[DETECT_VLAN_LAYERS].SetupPrefilter = PrefilterSetupVlanLayers;
}

@ -19,5 +19,6 @@
#define SURICATA_DETECT_VLAN_H
void DetectVlanIdRegister(void);
void DetectVlanLayersRegister(void);
#endif /* SURICATA_DETECT_VLAN_H */

Loading…
Cancel
Save