/* Copyright (C) 2007-2010 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 * \author Pablo Rincon * * Flow level variable support for complex detection rules * Supported types atm are String and Integers */ #include "suricata-common.h" #include "threads.h" #include "flow-var.h" #include "flow.h" #include "detect.h" #include "util-debug.h" /* puts a new value into a flowvar */ static void FlowVarUpdateStr(FlowVar *fv, uint8_t *value, uint16_t size) { if (fv->data.fv_str.value) SCFree(fv->data.fv_str.value); fv->data.fv_str.value = value; fv->data.fv_str.value_len = size; } /* puts a new value into a flowvar */ static void FlowVarUpdateInt(FlowVar *fv, uint32_t value) { fv->data.fv_int.value = value; } /** \brief get the flowvar with index 'idx' from the flow * \note flow is not locked by this function, caller is * responsible */ FlowVar *FlowVarGetByKey(Flow *f, const uint8_t *key, uint16_t keylen) { if (f == NULL) return NULL; GenericVar *gv = f->flowvar; for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWVAR && gv->idx == 0) { FlowVar *fv = (FlowVar *)gv; if (fv->keylen == keylen && memcmp(key, fv->key, keylen) == 0) { return fv; } } } return NULL; } /** \brief get the flowvar with index 'idx' from the flow * \note flow is not locked by this function, caller is * responsible */ FlowVar *FlowVarGet(Flow *f, uint32_t idx) { if (f == NULL) return NULL; GenericVar *gv = f->flowvar; for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWVAR && gv->idx == idx) return (FlowVar *)gv; } return NULL; } /* add a flowvar to the flow, or update it */ void FlowVarAddKeyValue(Flow *f, uint8_t *key, uint16_t keysize, uint8_t *value, uint16_t size) { FlowVar *fv = SCCalloc(1, sizeof(FlowVar)); if (unlikely(fv == NULL)) return; fv->type = DETECT_FLOWVAR; fv->datatype = FLOWVAR_TYPE_STR; fv->idx = 0; fv->data.fv_str.value = value; fv->data.fv_str.value_len = size; fv->key = key; fv->keylen = keysize; fv->next = NULL; GenericVarAppend(&f->flowvar, (GenericVar *)fv); } /* add a flowvar to the flow, or update it */ void FlowVarAddIdValue(Flow *f, uint32_t idx, uint8_t *value, uint16_t size) { FlowVar *fv = FlowVarGet(f, idx); if (fv == NULL) { fv = SCCalloc(1, sizeof(FlowVar)); if (unlikely(fv == NULL)) return; fv->type = DETECT_FLOWVAR; fv->datatype = FLOWVAR_TYPE_STR; fv->idx = idx; fv->data.fv_str.value = value; fv->data.fv_str.value_len = size; fv->next = NULL; GenericVarAppend(&f->flowvar, (GenericVar *)fv); } else { FlowVarUpdateStr(fv, value, size); } } /* add a flowvar to the flow, or update it */ void FlowVarAddIntNoLock(Flow *f, uint32_t idx, uint32_t value) { FlowVar *fv = FlowVarGet(f, idx); if (fv == NULL) { fv = SCMalloc(sizeof(FlowVar)); if (unlikely(fv == NULL)) return; fv->type = DETECT_FLOWVAR; fv->datatype = FLOWVAR_TYPE_INT; fv->idx = idx; fv->data.fv_int.value= value; fv->next = NULL; GenericVarAppend(&f->flowvar, (GenericVar *)fv); } else { FlowVarUpdateInt(fv, value); } } /* add a flowvar to the flow, or update it */ void FlowVarAddInt(Flow *f, uint32_t idx, uint32_t value) { FlowVarAddIntNoLock(f, idx, value); } void FlowVarFree(FlowVar *fv) { if (fv == NULL) return; if (fv->datatype == FLOWVAR_TYPE_STR) { if (fv->data.fv_str.value != NULL) SCFree(fv->data.fv_str.value); } SCFree(fv); } void FlowVarPrint(GenericVar *gv) { uint16_t u; if (!SCLogDebugEnabled()) return; if (gv == NULL) return; if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { FlowVar *fv = (FlowVar *)gv; if (fv->datatype == FLOWVAR_TYPE_STR) { SCLogDebug("Name idx \"%" PRIu32 "\", Value \"", fv->idx); for (u = 0; u < fv->data.fv_str.value_len; u++) { if (isprint(fv->data.fv_str.value[u])) SCLogDebug("%c", fv->data.fv_str.value[u]); else SCLogDebug("\\%02X", fv->data.fv_str.value[u]); } SCLogDebug("\", Len \"%" PRIu16 "\"\n", fv->data.fv_str.value_len); } else if (fv->datatype == FLOWVAR_TYPE_INT) { SCLogDebug("Name idx \"%" PRIu32 "\", Value \"%" PRIu32 "\"", fv->idx, fv->data.fv_int.value); } else { SCLogDebug("Unknown data type at flowvars\n"); } } FlowVarPrint(gv->next); }