mirror of
https://github.com/OISF/suricata.git
synced 2026-10-11 22:09:53 +00:00
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
This commit is contained in:
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,
|
||||
|
||||
+77
-1
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user