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.
suricata/src/detect-vlan.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;
}