/* Copyright (C) 2014-2021 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. */ /** * \file * * \author Victor Julien * * Implements per ippair bits. Actually, not a bit, * but called that way because of Snort's flowbits. * It's a binary storage. * * \todo move away from a linked list implementation * \todo use different datatypes, such as string, int, etc. */ #include "suricata-common.h" #include "threads.h" #include "ippair-bit.h" #include "ippair.h" #include "detect.h" #include "util-var.h" #include "util-debug.h" #include "util-unittest.h" #include "ippair-storage.h" static IPPairStorageId g_ippair_bit_storage_id = { .id = -1 }; /**< IPPair storage id for bits */ static void XBitFreeAll(void *store) { GenericVar *gv = store; GenericVarFree(gv); } void IPPairBitInitCtx(void) { g_ippair_bit_storage_id = IPPairStorageRegister("bit", sizeof(void *), NULL, XBitFreeAll); if (g_ippair_bit_storage_id.id == -1) { FatalError("Can't initiate ippair storage for bits"); } } /* lock before using this */ int IPPairHasBits(IPPair *ippair) { if (ippair == NULL) return 0; return IPPairGetStorageById(ippair, g_ippair_bit_storage_id) ? 1 : 0; } /** \retval 1 ippair timed out wrt xbits * \retval 0 ippair still has active (non-expired) xbits */ int IPPairBitsTimedoutCheck(IPPair *h, SCTime_t ts) { GenericVar *gv = IPPairGetStorageById(h, g_ippair_bit_storage_id); for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_XBITS) { XBit *xb = (XBit *)gv; if (xb->expire > (uint32_t)SCTIME_SECS(ts)) return 0; } } return 1; } /* get the bit with idx from the ippair */ static XBit *IPPairBitGet(IPPair *h, uint32_t idx) { GenericVar *gv = IPPairGetStorageById(h, g_ippair_bit_storage_id); for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_XBITS && gv->idx == idx) { return (XBit *)gv; } } return NULL; } /* add a flowbit to the flow */ static void IPPairBitAdd(IPPair *h, uint32_t idx, uint32_t expire) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) { fb = SCMalloc(sizeof(XBit)); if (unlikely(fb == NULL)) return; fb->type = DETECT_XBITS; fb->idx = idx; fb->next = NULL; fb->expire = expire; GenericVar *gv = IPPairGetStorageById(h, g_ippair_bit_storage_id); GenericVarAppend(&gv, (GenericVar *)fb); IPPairSetStorageById(h, g_ippair_bit_storage_id, gv); // bit already set, lets update it's timer } else { fb->expire = expire; } } static void IPPairBitRemove(IPPair *h, uint32_t idx) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) return; GenericVar *gv = IPPairGetStorageById(h, g_ippair_bit_storage_id); if (gv) { GenericVarRemove(&gv, (GenericVar *)fb); XBitFree(fb); IPPairSetStorageById(h, g_ippair_bit_storage_id, gv); } } void IPPairBitSet(IPPair *h, uint32_t idx, uint32_t expire) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) { IPPairBitAdd(h, idx, expire); } } void IPPairBitUnset(IPPair *h, uint32_t idx) { XBit *fb = IPPairBitGet(h, idx); if (fb != NULL) { IPPairBitRemove(h, idx); } } void IPPairBitToggle(IPPair *h, uint32_t idx, uint32_t expire) { XBit *fb = IPPairBitGet(h, idx); if (fb != NULL) { IPPairBitRemove(h, idx); } else { IPPairBitAdd(h, idx, expire); } } int IPPairBitIsset(IPPair *h, uint32_t idx, uint32_t ts) { XBit *fb = IPPairBitGet(h, idx); if (fb != NULL) { if (fb->expire < ts) { IPPairBitRemove(h, idx); return 0; } return 1; } return 0; } int IPPairBitIsnotset(IPPair *h, uint32_t idx, uint32_t ts) { XBit *fb = IPPairBitGet(h, idx); if (fb == NULL) { return 1; } if (fb->expire < ts) { IPPairBitRemove(h, idx); return 1; } return 0; } /* TESTS */ #ifdef UNITTESTS static int IPPairBitTest01 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0, 0); XBit *fb = IPPairBitGet(h,0); if (fb != NULL) ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest02 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; XBit *fb = IPPairBitGet(h,0); if (fb == NULL) ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest03 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0, 30); XBit *fb = IPPairBitGet(h,0); if (fb == NULL) { printf("fb == NULL although it was just added: "); goto end; } IPPairBitRemove(h, 0); fb = IPPairBitGet(h,0); if (fb != NULL) { printf("fb != NULL although it was just removed: "); goto end; } else { ret = 1; } IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest04 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0,30); IPPairBitAdd(h, 1,30); IPPairBitAdd(h, 2,30); IPPairBitAdd(h, 3,30); XBit *fb = IPPairBitGet(h,0); if (fb != NULL) ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest05 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0,90); IPPairBitAdd(h, 1,90); IPPairBitAdd(h, 2,90); IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,1); if (fb != NULL) ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest06 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0,90); IPPairBitAdd(h, 1,90); IPPairBitAdd(h, 2,90); IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,2); if (fb != NULL) ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest07 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0,90); IPPairBitAdd(h, 1,90); IPPairBitAdd(h, 2,90); IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,3); if (fb != NULL) ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest08 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0,90); IPPairBitAdd(h, 1,90); IPPairBitAdd(h, 2,90); IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,0); if (fb == NULL) goto end; IPPairBitRemove(h,0); fb = IPPairBitGet(h,0); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest09 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0,90); IPPairBitAdd(h, 1,90); IPPairBitAdd(h, 2,90); IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,1); if (fb == NULL) goto end; IPPairBitRemove(h,1); fb = IPPairBitGet(h,1); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest10 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0,90); IPPairBitAdd(h, 1,90); IPPairBitAdd(h, 2,90); IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,2); if (fb == NULL) goto end; IPPairBitRemove(h,2); fb = IPPairBitGet(h,2); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } static int IPPairBitTest11 (void) { int ret = 0; IPPairInitConfig(true); IPPair *h = IPPairAlloc(); if (h == NULL) goto end; IPPairBitAdd(h, 0,90); IPPairBitAdd(h, 1,90); IPPairBitAdd(h, 2,90); IPPairBitAdd(h, 3,90); XBit *fb = IPPairBitGet(h,3); if (fb == NULL) goto end; IPPairBitRemove(h,3); fb = IPPairBitGet(h,3); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; IPPairFree(h); end: IPPairCleanup(); return ret; } #endif /* UNITTESTS */ void IPPairBitRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("IPPairBitTest01", IPPairBitTest01); UtRegisterTest("IPPairBitTest02", IPPairBitTest02); UtRegisterTest("IPPairBitTest03", IPPairBitTest03); UtRegisterTest("IPPairBitTest04", IPPairBitTest04); UtRegisterTest("IPPairBitTest05", IPPairBitTest05); UtRegisterTest("IPPairBitTest06", IPPairBitTest06); UtRegisterTest("IPPairBitTest07", IPPairBitTest07); UtRegisterTest("IPPairBitTest08", IPPairBitTest08); UtRegisterTest("IPPairBitTest09", IPPairBitTest09); UtRegisterTest("IPPairBitTest10", IPPairBitTest10); UtRegisterTest("IPPairBitTest11", IPPairBitTest11); #endif /* UNITTESTS */ }