mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
7.1 KiB
C
220 lines
7.1 KiB
C
/* Copyright (C) 2024 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
|
|
* Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
#include "detect-vlan.h"
|
|
#include "detect-engine-uint.h"
|
|
#include "detect-parse.h"
|
|
#include "rust.h"
|
|
|
|
static int DetectVlanIdMatch(
|
|
DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx)
|
|
{
|
|
const DetectVlanIdData *vdata = (const DetectVlanIdData *)ctx;
|
|
|
|
if (p->vlan_idx == 0) {
|
|
return 0;
|
|
}
|
|
|
|
switch (vdata->layer) {
|
|
case DETECT_VLAN_ID_ANY:
|
|
for (int i = 0; i < p->vlan_idx; i++) {
|
|
if (DetectU16Match(p->vlan_id[i], &vdata->du16)) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
case DETECT_VLAN_ID_ALL:
|
|
for (int i = 0; i < p->vlan_idx; i++) {
|
|
if (!DetectU16Match(p->vlan_id[i], &vdata->du16)) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
default:
|
|
if (vdata->layer < 0) { // Negative layer values for backward indexing.
|
|
if (((int16_t)p->vlan_idx) + vdata->layer < 0) {
|
|
return 0;
|
|
}
|
|
return DetectU16Match(p->vlan_id[p->vlan_idx + vdata->layer], &vdata->du16);
|
|
} else {
|
|
if (p->vlan_idx < vdata->layer) {
|
|
return 0;
|
|
}
|
|
return DetectU16Match(p->vlan_id[vdata->layer], &vdata->du16);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void DetectVlanIdFree(DetectEngineCtx *de_ctx, void *ptr)
|
|
{
|
|
SCDetectVlanIdFree(ptr);
|
|
}
|
|
|
|
static int DetectVlanIdSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
|
|
{
|
|
DetectVlanIdData *vdata = SCDetectVlanIdParse(rawstr);
|
|
if (vdata == NULL) {
|
|
SCLogError("vlan id invalid %s", rawstr);
|
|
return -1;
|
|
}
|
|
|
|
if (SCSigMatchAppendSMToList(
|
|
de_ctx, s, DETECT_VLAN_ID, (SigMatchCtx *)vdata, DETECT_SM_LIST_MATCH) == NULL) {
|
|
DetectVlanIdFree(de_ctx, vdata);
|
|
return -1;
|
|
}
|
|
s->flags |= SIG_FLAG_REQUIRE_PACKET;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void PrefilterPacketVlanIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
|
|
{
|
|
const PrefilterPacketHeaderCtx *ctx = pectx;
|
|
|
|
DetectVlanIdData vdata;
|
|
vdata.du16.mode = ctx->v1.u8[0];
|
|
vdata.layer = ctx->v1.u8[1];
|
|
vdata.du16.arg1 = ctx->v1.u16[2];
|
|
vdata.du16.arg2 = ctx->v1.u16[3];
|
|
|
|
if (p->vlan_idx == 0)
|
|
return;
|
|
|
|
if (DetectVlanIdMatch(det_ctx, p, NULL, (const SigMatchCtx *)&vdata)) {
|
|
PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
|
|
}
|
|
}
|
|
|
|
static void PrefilterPacketVlanIdSet(PrefilterPacketHeaderValue *v, void *smctx)
|
|
{
|
|
const DetectVlanIdData *a = smctx;
|
|
v->u8[0] = a->du16.mode;
|
|
v->u8[1] = a->layer;
|
|
v->u16[2] = a->du16.arg1;
|
|
v->u16[3] = a->du16.arg2;
|
|
}
|
|
|
|
static bool PrefilterPacketVlanIdCompare(PrefilterPacketHeaderValue v, void *smctx)
|
|
{
|
|
const DetectVlanIdData *a = smctx;
|
|
if (v.u8[0] == a->du16.mode && v.u8[1] == a->layer && v.u16[2] == a->du16.arg1 &&
|
|
v.u16[3] == a->du16.arg2)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static int PrefilterSetupVlanId(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
|
|
{
|
|
return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_VLAN_ID, SIG_MASK_REQUIRE_REAL_PKT,
|
|
PrefilterPacketVlanIdSet, PrefilterPacketVlanIdCompare, PrefilterPacketVlanIdMatch);
|
|
}
|
|
|
|
static bool PrefilterVlanIdIsPrefilterable(const Signature *s)
|
|
{
|
|
return PrefilterIsPrefilterableById(s, DETECT_VLAN_ID);
|
|
}
|
|
|
|
void DetectVlanIdRegister(void)
|
|
{
|
|
sigmatch_table[DETECT_VLAN_ID].name = "vlan.id";
|
|
sigmatch_table[DETECT_VLAN_ID].desc = "match vlan id";
|
|
sigmatch_table[DETECT_VLAN_ID].url = "/rules/vlan-keywords.html#vlan-id";
|
|
sigmatch_table[DETECT_VLAN_ID].Match = DetectVlanIdMatch;
|
|
sigmatch_table[DETECT_VLAN_ID].Setup = DetectVlanIdSetup;
|
|
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)
|
|
{
|
|
SCDetectU8Free(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);
|
|
DetectVlanLayersFree(de_ctx, du8);
|
|
return -1;
|
|
}
|
|
|
|
if (SCSigMatchAppendSMToList(
|
|
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;
|
|
}
|