/* 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; }