From: Victor Julien Date: Sat, 5 Nov 2016 13:02:39 +0000 (-0400) Subject: pktvars: same name pktvars, key-value vars X-Git-Tag: suricata-4.0.0-beta1~321 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=996112edf5712f593c87dc8741c59ce65b73e07f;p=thirdparty%2Fsuricata.git pktvars: same name pktvars, key-value vars --- diff --git a/src/decode.h b/src/decode.h index 6d0ad53ee7..d732ce9038 100644 --- a/src/decode.h +++ b/src/decode.h @@ -302,8 +302,10 @@ typedef struct PktVar_ { struct PktVar_ *next; /* right now just implement this as a list, * in the long run we have thing of something * faster. */ - uint8_t *value; + uint16_t key_len; uint16_t value_len; + uint8_t *key; + uint8_t *value; } PktVar; #ifdef PROFILING diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index b0c30d4099..9f84811a12 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -193,9 +193,29 @@ error: return -1; } +/** \brief Store flowvar in det_ctx so we can exec it post-match */ +int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *det_ctx, + uint8_t *key, uint16_t key_len, + uint8_t *buffer, uint16_t len, int type) +{ + DetectVarList *fs = SCCalloc(1, sizeof(*fs)); + if (unlikely(fs == NULL)) + return -1; + + fs->len = len; + fs->type = type; + fs->buffer = buffer; + fs->key = key; + fs->key_len = key_len; + + fs->next = det_ctx->varlist; + det_ctx->varlist = fs; + return 0; +} /** \brief Store flowvar in det_ctx so we can exec it post-match */ -int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, uint32_t idx, +int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, + uint32_t idx, uint8_t *buffer, uint16_t len, int type) { DetectVarList *fs = det_ctx->varlist; @@ -211,7 +231,7 @@ int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, uint32_t idx, } if (fs == NULL) { - fs = SCMalloc(sizeof(*fs)); + fs = SCCalloc(1, sizeof(*fs)); if (unlikely(fs == NULL)) return -1; @@ -278,7 +298,7 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, prev = NULL; fs = det_ctx->varlist; while (fs != NULL) { - if (fd->idx == fs->idx) { + if (fd->idx == 0 || fd->idx == fs->idx) { SCLogDebug("adding to the flow %u:", fs->idx); //PrintRawDataFp(stdout, fs->buffer, fs->len); @@ -286,8 +306,20 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, FlowVarAddStrNoLock(p->flow, fs->idx, fs->buffer, fs->len); /* memory at fs->buffer is now the responsibility of * the flowvar code. */ + } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && fs->key && p) { + /* pkt key/value */ + if (PktVarAddKeyValue(p, (uint8_t *)fs->key, fs->key_len, + (uint8_t *)fs->buffer, fs->len) == -1) + { + SCFree(fs->key); + SCFree(fs->buffer); + /* the rest of fs is freed below */ + } } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && p) { - PktVarAdd(p, fs->idx, fs->buffer, fs->len); + if (PktVarAdd(p, fs->idx, fs->buffer, fs->len) == -1) { + SCFree(fs->buffer); + /* the rest of fs is freed below */ + } } if (fs == det_ctx->varlist) { diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index 59edfc80bc..f919c3b031 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -36,7 +36,10 @@ typedef struct DetectFlowvarData_ { void DetectFlowvarRegister (void); int DetectFlowvarPostMatchSetup(Signature *s, uint32_t idx); -int DetectVarStoreMatch(DetectEngineThreadCtx *, uint32_t, uint8_t *, uint16_t, int); +int DetectVarStoreMatch(DetectEngineThreadCtx *, + uint32_t, uint8_t *, uint16_t, int); +int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *, + uint8_t *, uint16_t, uint8_t *, uint16_t, int); /* For use only by DetectFlowvarProcessList() */ void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p); diff --git a/src/detect-pcre.c b/src/detect-pcre.c index b4ed145715..661a254a3e 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -230,7 +230,23 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, SCLogDebug("data %p/%u, type %u id %u p %p", str_ptr, ret, pe->captypes[x], pe->capids[x], p); - if (pe->captypes[x] == VAR_TYPE_PKT_VAR) { + if (pe->captypes[x] == VAR_TYPE_PKT_VAR_KV) { + /* get the value, as first capture is the key */ + const char *str_ptr2; + int ret2 = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+2, &str_ptr2); + if (unlikely(ret2 == 0)) { + break; + } + /* key length is limited to 256 chars */ + uint16_t key_len = (ret < 0xff) ? (uint16_t)ret : 0xff; + capture_len = (ret2 < 0xffff) ? (uint16_t)ret2 : 0xffff; + + (void)DetectVarStoreMatchKeyValue(det_ctx, + (uint8_t *)str_ptr, key_len, + (uint8_t *)str_ptr2, capture_len, + DETECT_VAR_TYPE_PKT_POSTMATCH); + + } else if (pe->captypes[x] == VAR_TYPE_PKT_VAR) { /* store max 64k. Errors are ignored */ capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; (void)DetectVarStoreMatch(det_ctx, pe->capids[x], @@ -665,6 +681,7 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec char *name_array[DETECT_PCRE_CAPTURE_MAX] = { NULL }; int name_idx = 0; int capture_cnt = 0; + int key = 0; SCLogDebug("regexstr %s, pd %p", regexstr, pd); @@ -681,7 +698,25 @@ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, Detec } SCLogDebug("name '%s'", name_array[name_idx]); - if (strncmp(name_array[name_idx], "flow:", 5) == 0) { + if (strcmp(name_array[name_idx], "pkt:key") == 0) { + key = 1; + SCLogDebug("key-value/key"); + + pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR_KV; + SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]); + pd->idx++; + + } else if (key == 1 && strcmp(name_array[name_idx], "pkt:value") == 0) { + SCLogDebug("key-value/value"); + key = 0; + + /* kv error conditions */ + } else if (key == 0 && strcmp(name_array[name_idx], "pkt:value") == 0) { + return -1; + } else if (key == 1) { + return -1; + + } else if (strncmp(name_array[name_idx], "flow:", 5) == 0) { pd->capids[pd->idx] = VarNameStoreSetupAdd(name_array[name_idx]+5, VAR_TYPE_FLOW_VAR); pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR; pd->idx++; diff --git a/src/detect.h b/src/detect.h index 2394ab442e..023b931da4 100644 --- a/src/detect.h +++ b/src/detect.h @@ -500,7 +500,9 @@ typedef struct DetectReplaceList_ { typedef struct DetectVarList_ { uint32_t idx; /**< flowvar name idx */ uint16_t len; /**< data len */ + uint16_t key_len; int type; /**< type of store candidate POSTMATCH or ALWAYS */ + uint8_t *key; uint8_t *buffer; /**< alloc'd buffer, may be freed by post-match, post-non-match */ struct DetectVarList_ *next; diff --git a/src/output-json.c b/src/output-json.c index 7aa7a23aa7..7db6262d33 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -102,23 +102,44 @@ static void JsonAddPacketvars(const Packet *p, json_t *js_vars) json_t *js_pktvars = NULL; PktVar *pv = p->pktvar; while (pv != NULL) { - const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); - if (varname) { + if (pv->key || pv->id > 0) { if (js_pktvars == NULL) { - js_pktvars = json_object(); + js_pktvars = json_array(); if (js_pktvars == NULL) break; } + json_t *js_pair = json_object(); + if (js_pair == NULL) { + break; + } - uint32_t len = pv->value_len; - uint8_t printable_buf[len + 1]; - uint32_t offset = 0; - PrintStringsToBuffer(printable_buf, &offset, - sizeof(printable_buf), - pv->value, pv->value_len); - - json_object_set_new(js_pktvars, varname, - json_string((char *)printable_buf)); + if (pv->key != NULL) { + uint32_t offset = 0; + uint8_t keybuf[pv->key_len + 1]; + PrintStringsToBuffer(keybuf, &offset, + sizeof(keybuf), + pv->key, pv->key_len); + uint32_t len = pv->value_len; + uint8_t printable_buf[len + 1]; + offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + pv->value, pv->value_len); + json_object_set_new(js_pair, (char *)keybuf, + json_string((char *)printable_buf)); + } else { + const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); + uint32_t len = pv->value_len; + uint8_t printable_buf[len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + pv->value, pv->value_len); + + json_object_set_new(js_pair, varname, + json_string((char *)printable_buf)); + } + json_array_append_new(js_pktvars, js_pair); } pv = pv->next; } diff --git a/src/pkt-var.c b/src/pkt-var.c index 333f2977bd..a81af35e1a 100644 --- a/src/pkt-var.c +++ b/src/pkt-var.c @@ -34,15 +34,6 @@ #include "pkt-var.h" #include "util-debug.h" -/* puts a new value into a pktvar */ -static void PktVarUpdate(PktVar *pv, uint8_t *value, uint16_t size) -{ - if (pv->value) - SCFree(pv->value); - pv->value = value; - pv->value_len = size; -} - /* get the pktvar with name 'name' from the pkt * * name is a normal string*/ @@ -58,37 +49,63 @@ PktVar *PktVarGet(Packet *p, uint32_t id) return NULL; } -/* add a pktvar to the pkt, or update it */ -void PktVarAdd(Packet *p, uint32_t id, uint8_t *value, uint16_t size) +/** + * \brief add a key-value pktvar to the pkt + * \retval r 0 ok, -1 error + */ +int PktVarAddKeyValue(Packet *p, uint8_t *key, uint16_t ksize, uint8_t *value, uint16_t size) { - //printf("Adding packet var \"%s\" with value(%" PRId32 ") \"%s\"\n", name, size, value); + PktVar *pv = SCCalloc(1, sizeof(PktVar)); + if (unlikely(pv == NULL)) + return -1; - PktVar *pv = PktVarGet(p, id); - if (pv == NULL) { - pv = SCMalloc(sizeof(PktVar)); - if (unlikely(pv == NULL)) - return; + pv->key = key; + pv->key_len = ksize; + pv->value = value; + pv->value_len = size; - pv->id = id; - pv->value = value; - pv->value_len = size; - pv->next = NULL; + PktVar *tpv = p->pktvar; + if (p->pktvar == NULL) + p->pktvar = pv; + else { + while(tpv) { + if (tpv->next == NULL) { + tpv->next = pv; + return 0; + } + tpv = tpv->next; + } + } + return 0; +} + +/** + * \brief add a key-value pktvar to the pkt + * \retval r 0 ok, -1 error + */ +int PktVarAdd(Packet *p, uint32_t id, uint8_t *value, uint16_t size) +{ + PktVar *pv = SCCalloc(1, sizeof(PktVar)); + if (unlikely(pv == NULL)) + return -1; + + pv->id = id; + pv->value = value; + pv->value_len = size; - PktVar *tpv = p->pktvar; - if (p->pktvar == NULL) - p->pktvar = pv; - else { - while(tpv) { - if (tpv->next == NULL) { - tpv->next = pv; - return; - } - tpv = tpv->next; + PktVar *tpv = p->pktvar; + if (p->pktvar == NULL) + p->pktvar = pv; + else { + while(tpv) { + if (tpv->next == NULL) { + tpv->next = pv; + return 0; } + tpv = tpv->next; } - } else { - PktVarUpdate(pv, value, size); } + return 0; } void PktVarFree(PktVar *pv) @@ -96,6 +113,8 @@ void PktVarFree(PktVar *pv) if (pv == NULL) return; + if (pv->key != NULL) + SCFree(pv->key); if (pv->value != NULL) SCFree(pv->value); PktVar *pv_next = pv->next; diff --git a/src/pkt-var.h b/src/pkt-var.h index cfdd6f5aee..0a261c9ffa 100644 --- a/src/pkt-var.h +++ b/src/pkt-var.h @@ -24,7 +24,8 @@ #ifndef __PKT_VAR_H__ #define __PKT_VAR_H__ -void PktVarAdd(Packet *, uint32_t id, uint8_t *, uint16_t); +int WARN_UNUSED PktVarAddKeyValue(Packet *, uint8_t *, uint16_t, uint8_t *, uint16_t); +int WARN_UNUSED PktVarAdd(Packet *, uint32_t id, uint8_t *, uint16_t); PktVar *PktVarGet(Packet *, uint32_t id); void PktVarFree(PktVar *); diff --git a/src/util-var.h b/src/util-var.h index 3deeaf7479..ac9de2d3fb 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -30,6 +30,7 @@ enum VarTypes { VAR_TYPE_PKT_BIT, VAR_TYPE_PKT_INT, VAR_TYPE_PKT_VAR, + VAR_TYPE_PKT_VAR_KV, // key-value VAR_TYPE_FLOW_BIT, VAR_TYPE_FLOW_INT,