/* Copyright (C) 2007-2013 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 the pcre keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "pkt-var.h" #include "flow-var.h" #include "flow-util.h" #include "detect-pcre.h" #include "detect-flowvar.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-sigorder.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "util-var-name.h" #include "util-unittest-helper.h" #include "util-debug.h" #include "util-unittest.h" #include "util-print.h" #include "util-pool.h" #include "conf.h" #include "app-layer.h" #include "app-layer-htp.h" #include "stream.h" #include "stream-tcp.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "util-pages.h" /* pcre named substring capture supports only 32byte names, A-z0-9 plus _ * and needs to start with non-numeric. */ #define PARSE_CAPTURE_REGEX "\\(\\?P\\<([A-z]+)\\_([A-z0-9_]+)\\>" #define PARSE_REGEX "(?ctx; if (pe->flags & DETECT_PCRE_RELATIVE) { ptr = payload + det_ctx->buffer_offset; len = payload_len - det_ctx->buffer_offset; } else { ptr = payload; len = payload_len; } int start_offset = 0; if (det_ctx->pcre_match_start_offset != 0) { start_offset = (payload + det_ctx->pcre_match_start_offset - ptr); } /* run the actual pcre detection */ ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, start_offset, 0, ov, MAX_SUBSTRINGS); SCLogDebug("ret %d (negating %s)", ret, (pe->flags & DETECT_PCRE_NEGATE) ? "set" : "not set"); if (ret == PCRE_ERROR_NOMATCH) { if (pe->flags & DETECT_PCRE_NEGATE) { /* regex didn't match with negate option means we * consider it a match */ ret = 1; } else { ret = 0; } } else if (ret >= 0) { if (pe->flags & DETECT_PCRE_NEGATE) { /* regex matched but we're negated, so not * considering it a match */ ret = 0; } else { /* regex matched and we're not negated, * considering it a match */ SCLogDebug("ret %d pe->idx %u", ret, pe->idx); /* see if we need to do substring capturing. */ if (ret > 1 && pe->idx != 0) { uint8_t x; for (x = 0; x < pe->idx; x++) { SCLogDebug("capturing %u", x); const char *str_ptr; ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+1, &str_ptr); if (unlikely(ret == 0)) continue; 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_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], (uint8_t *)str_ptr, capture_len, DETECT_VAR_TYPE_PKT_POSTMATCH); } else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f != NULL) { /* store max 64k. Errors are ignored */ capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; (void)DetectVarStoreMatch(det_ctx, pe->capids[x], (uint8_t *)str_ptr, capture_len, DETECT_VAR_TYPE_FLOW_POSTMATCH); } } } /* update offset for pcre RELATIVE */ det_ctx->buffer_offset = (ptr + ov[1]) - payload; det_ctx->pcre_match_start_offset = (ptr + ov[0] + 1) - payload; ret = 1; } } else { SCLogDebug("pcre had matching error"); ret = 0; } SCReturnInt(ret); } static int DetectPcreSetList(int list, int set) { if (list != DETECT_SM_LIST_NOTSET) { SCLogError(SC_ERR_INVALID_SIGNATURE, "only one pcre option to specify a buffer type is allowed"); return -1; } return set; } static int DetectPcreHasUpperCase(const char *re) { size_t len = strlen(re); int is_meta = 0; for (size_t i = 0; i < len; i++) { if (is_meta) { is_meta = 0; } else if (re[i] == '\\') { is_meta = 1; } else if (isupper((unsigned char)re[i])) { return 1; } } return 0; } static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, int *sm_list, char *capture_names, size_t capture_names_size) { int ec; const char *eb; int eo; int opts = 0; DetectPcreData *pd = NULL; char *op = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int check_host_header = 0; char op_str[64] = ""; uint8_t negate = 0; while (*regexstr != '\0' && isspace((unsigned char)*regexstr)) { regexstr++; } if (*regexstr == '!') { negate = 1; regexstr++; } int cut_capture = 0; char *fcap = strstr(regexstr, "flow:"); char *pcap = strstr(regexstr, "pkt:"); /* take the size of the whole input as buffer size for the regex we will * extract below. Add 1 to please Coverity's alloc_strlen test. */ size_t slen = strlen(regexstr) + 1; if (fcap || pcap) { SCLogDebug("regexstr %s", regexstr); if (fcap && !pcap) cut_capture = fcap - regexstr; else if (pcap && !fcap) cut_capture = pcap - regexstr; else cut_capture = MIN((pcap - regexstr), (fcap - regexstr)); SCLogDebug("cut_capture %d", cut_capture); if (cut_capture > 1) { int offset = cut_capture - 1; while (offset) { SCLogDebug("regexstr[offset] %c", regexstr[offset]); if (regexstr[offset] == ',' || regexstr[offset] == ' ') { offset--; } else break; } if (cut_capture == (offset + 1)) { SCLogDebug("missing separators, assume it's part of the regex"); } else { slen = offset + 1; strlcpy(capture_names, regexstr+cut_capture, capture_names_size); if (capture_names[strlen(capture_names)-1] == '"') capture_names[strlen(capture_names)-1] = '\0'; } } } char re[slen]; ret = pcre_exec(parse_regex, parse_regex_study, regexstr, slen, 0, 0, ov, MAX_SUBSTRINGS); if (ret <= 0) { SCLogError(SC_ERR_PCRE_MATCH, "pcre parse error: %s", regexstr); goto error; } res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, re, slen); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); return NULL; } if (ret > 2) { res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, op_str, sizeof(op_str)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); return NULL; } op = op_str; } //printf("ret %" PRId32 " re \'%s\', op \'%s\'\n", ret, re, op); pd = SCMalloc(sizeof(DetectPcreData)); if (unlikely(pd == NULL)) goto error; memset(pd, 0, sizeof(DetectPcreData)); if (negate) pd->flags |= DETECT_PCRE_NEGATE; if (op != NULL) { while (*op) { SCLogDebug("regex option %c", *op); switch (*op) { case 'A': opts |= PCRE_ANCHORED; break; case 'E': opts |= PCRE_DOLLAR_ENDONLY; break; case 'G': opts |= PCRE_UNGREEDY; break; case 'i': opts |= PCRE_CASELESS; pd->flags |= DETECT_PCRE_CASELESS; break; case 'm': opts |= PCRE_MULTILINE; break; case 's': opts |= PCRE_DOTALL; break; case 'x': opts |= PCRE_EXTENDED; break; case 'O': pd->flags |= DETECT_PCRE_MATCH_LIMIT; break; case 'B': /* snort's option */ if (*sm_list != DETECT_SM_LIST_NOTSET) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'B' inconsistent with chosen buffer"); goto error; } pd->flags |= DETECT_PCRE_RAWBYTES; break; case 'R': /* snort's option */ pd->flags |= DETECT_PCRE_RELATIVE; break; /* buffer selection */ case 'U': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'U' inconsistent with 'B'"); goto error; } int list = DetectBufferTypeGetByName("http_uri"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'V': { if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'V' inconsistent with 'B'"); goto error; } int list = DetectBufferTypeGetByName("http_user_agent"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'W': { if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'W' inconsistent with 'B'"); goto error; } int list = DetectBufferTypeGetByName("http_host"); *sm_list = DetectPcreSetList(*sm_list, list); check_host_header = 1; break; } case 'Z': { if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'Z' inconsistent with 'B'"); goto error; } int list = DetectBufferTypeGetByName("http_raw_host"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'H': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'H' inconsistent with 'B'"); goto error; } int list = DetectBufferTypeGetByName("http_header"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'I': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'I' inconsistent with 'B'"); goto error; } int list = DetectBufferTypeGetByName("http_raw_uri"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'D': { /* snort's option */ int list = DetectBufferTypeGetByName("http_raw_header"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'M': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'M' inconsistent with 'B'"); goto error; } int list = DetectBufferTypeGetByName("http_method"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'C': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'C' inconsistent with 'B'"); goto error; } int list = DetectBufferTypeGetByName("http_cookie"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'P': { /* snort's option (http request body inspection) */ int list = DetectBufferTypeGetByName("http_client_body"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'Q': { int list = DetectBufferTypeGetByName("file_data"); /* suricata extension (http response body inspection) */ *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'Y': { /* snort's option */ int list = DetectBufferTypeGetByName("http_stat_msg"); *sm_list = DetectPcreSetList(*sm_list, list); break; } case 'S': { /* snort's option */ int list = DetectBufferTypeGetByName("http_stat_code"); *sm_list = DetectPcreSetList(*sm_list, list); break; } default: SCLogError(SC_ERR_UNKNOWN_REGEX_MOD, "unknown regex modifier '%c'", *op); goto error; } op++; } } if (*sm_list == -1) goto error; SCLogDebug("DetectPcreParse: \"%s\"", re); /* host header */ if (check_host_header) { if (pd->flags & DETECT_PCRE_CASELESS) { SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http host pcre(\"W\") " "specified along with \"i(caseless)\" modifier. " "Since the hostname buffer we match against " "is actually lowercase, having a " "nocase is redundant."); } else if (DetectPcreHasUpperCase(re)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre host(\"W\") " "specified has an uppercase char. " "Since the hostname buffer we match against " "is actually lowercase, please specify an " "all lowercase based pcre."); goto error; } } /* Try to compile as if all (...) groups had been meant as (?:...), * which is the common case in most rules. * If we fail because a capture group is later referenced (e.g., \1), * PCRE will let us know. */ if (capture_names == NULL || strlen(capture_names) == 0) opts |= PCRE_NO_AUTO_CAPTURE; pd->re = pcre_compile2(re, opts, &ec, &eb, &eo, NULL); if (pd->re == NULL && ec == 15) { // reference to non-existent subpattern opts &= ~PCRE_NO_AUTO_CAPTURE; pd->re = pcre_compile(re, opts, &eb, &eo, NULL); } if (pd->re == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed " "at offset %" PRId32 ": %s", regexstr, eo, eb); goto error; } int options = 0; #ifdef PCRE_HAVE_JIT if (pcre_use_jit) options |= PCRE_STUDY_JIT_COMPILE; #endif pd->sd = pcre_study(pd->re, options, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb); goto error; } #ifdef PCRE_HAVE_JIT int jit = 0; ret = pcre_fullinfo(pd->re, pd->sd, PCRE_INFO_JIT, &jit); if (ret != 0 || jit != 1) { /* warning, so we won't print the sig after this. Adding * file and line to the message so the admin can figure * out what sig this is about */ SCLogDebug("PCRE JIT compiler does not support: %s. " "Falling back to regular PCRE handling (%s:%d)", regexstr, de_ctx->rule_file, de_ctx->rule_line); } #endif /*PCRE_HAVE_JIT*/ if (pd->sd == NULL) pd->sd = (pcre_extra *) SCCalloc(1,sizeof(pcre_extra)); if (pd->sd) { if(pd->flags & DETECT_PCRE_MATCH_LIMIT) { if(pcre_match_limit >= -1) { pd->sd->match_limit = pcre_match_limit; pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT; } #ifndef NO_PCRE_MATCH_RLIMIT if(pcre_match_limit_recursion >= -1) { pd->sd->match_limit_recursion = pcre_match_limit_recursion; pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; } #endif /* NO_PCRE_MATCH_RLIMIT */ } else { pd->sd->match_limit = SC_MATCH_LIMIT_DEFAULT; pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT; #ifndef NO_PCRE_MATCH_RLIMIT pd->sd->match_limit_recursion = SC_MATCH_LIMIT_RECURSION_DEFAULT; pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; #endif /* NO_PCRE_MATCH_RLIMIT */ } } else { goto error; } return pd; error: if (pd != NULL && pd->re != NULL) pcre_free(pd->re); if (pd != NULL && pd->sd != NULL) pcre_free_study(pd->sd); if (pd) SCFree(pd); return NULL; } /** \internal * \brief check if we need to extract capture settings and set them up if needed */ static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd, char *capture_names) { int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; memset(&ov, 0, sizeof(ov)); char type_str[16] = ""; char *orig_right_edge = regexstr + strlen(regexstr); 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); ret = pcre_fullinfo(pd->re, pd->sd, PCRE_INFO_CAPTURECOUNT, &capture_cnt); SCLogDebug("ret %d capture_cnt %d", ret, capture_cnt); if (ret == 0 && capture_cnt && strlen(capture_names) > 0) { char *ptr = NULL; while ((name_array[name_idx] = strtok_r(name_idx == 0 ? capture_names : NULL, " ,", &ptr))){ if (name_idx > capture_cnt) { SCLogError(SC_ERR_VAR_LIMIT, "more pkt/flow " "var capture names than capturing substrings"); return -1; } SCLogDebug("name '%s'", name_array[name_idx]); 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++; } else if (strncmp(name_array[name_idx], "pkt:", 4) == 0) { pd->capids[pd->idx] = VarNameStoreSetupAdd(name_array[name_idx]+4, VAR_TYPE_PKT_VAR); pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR; SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]); pd->idx++; } else { SCLogError(SC_ERR_VAR_LIMIT, " pkt/flow " "var capture names must start with 'pkt:' or 'flow:'"); return -1; } name_idx++; if (name_idx >= DETECT_PCRE_CAPTURE_MAX) break; } } /* take the size of the whole input as buffer size for the string we will * extract below. Add 1 to please Coverity's alloc_strlen test. */ size_t cap_buffer_len = strlen(regexstr) + 1; char capture_str[cap_buffer_len]; memset(capture_str, 0x00, cap_buffer_len); if (de_ctx == NULL) goto error; while (1) { SCLogDebug("\'%s\'", regexstr); ret = pcre_exec(parse_capture_regex, parse_capture_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 3) { return 0; } res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, type_str, sizeof(type_str)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, capture_str, cap_buffer_len); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } if (strlen(capture_str) == 0 || strlen(type_str) == 0) { goto error; } SCLogDebug("type \'%s\'", type_str); SCLogDebug("capture \'%s\'", capture_str); if (pd->idx >= DETECT_PCRE_CAPTURE_MAX) { SCLogError(SC_ERR_VAR_LIMIT, "rule can have maximally %d pkt/flow " "var captures", DETECT_PCRE_CAPTURE_MAX); return -1; } if (strcmp(type_str, "pkt") == 0) { pd->capids[pd->idx] = VarNameStoreSetupAdd((char *)capture_str, VAR_TYPE_PKT_VAR); pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR; SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]); pd->idx++; } else if (strcmp(type_str, "flow") == 0) { pd->capids[pd->idx] = VarNameStoreSetupAdd((char *)capture_str, VAR_TYPE_FLOW_VAR); pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR; pd->idx++; } //SCLogNotice("pd->capname %s", pd->capname); regexstr += ov[1]; if (regexstr >= orig_right_edge) break; } return 0; error: return -1; } static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexstr) { SCEnter(); DetectPcreData *pd = NULL; SigMatch *sm = NULL; int ret = -1; int parsed_sm_list = DETECT_SM_LIST_NOTSET; char capture_names[1024] = ""; pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list, capture_names, sizeof(capture_names)); if (pd == NULL) goto error; if (DetectPcreParseCapture(regexstr, de_ctx, pd, capture_names) < 0) goto error; int sm_list = -1; if (s->init_data->list != DETECT_SM_LIST_NOTSET) { s->flags |= SIG_FLAG_APPLAYER; sm_list = s->init_data->list; } else { switch(parsed_sm_list) { case DETECT_SM_LIST_NOTSET: sm_list = DETECT_SM_LIST_PMATCH; break; default: sm_list = parsed_sm_list; break; } } if (sm_list == -1) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_PCRE; sm->ctx = (void *)pd; SigMatchAppendSMToList(s, sm, sm_list); uint8_t x; for (x = 0; x < pd->idx; x++) { if (DetectFlowvarPostMatchSetup(s, pd->capids[x]) < 0) goto error_nofree; } if (!(pd->flags & DETECT_PCRE_RELATIVE)) goto okay; /* errors below shouldn't free pd */ SigMatch *prev_pm = DetectGetLastSMByListPtr(s, sm->prev, DETECT_CONTENT, DETECT_PCRE, -1); if (s->init_data->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre with /R (relative) needs " "preceeding match in the same buffer"); goto error_nofree; /* null is allowed when we use a sticky buffer */ } else if (prev_pm == NULL) goto okay; if (prev_pm->type == DETECT_CONTENT) { DetectContentData *cd = (DetectContentData *)prev_pm->ctx; cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } else if (prev_pm->type == DETECT_PCRE) { DetectPcreData *tmp = (DetectPcreData *)prev_pm->ctx; tmp->flags |= DETECT_PCRE_RELATIVE_NEXT; } okay: ret = 0; SCReturnInt(ret); error: DetectPcreFree(pd); error_nofree: SCReturnInt(ret); } static void DetectPcreFree(void *ptr) { if (ptr == NULL) return; DetectPcreData *pd = (DetectPcreData *)ptr; if (pd->re != NULL) pcre_free(pd->re); if (pd->sd != NULL) pcre_free_study(pd->sd); SCFree(pd); return; } #ifdef UNITTESTS /* UNITTESTS */ static int g_file_data_buffer_id = 0; static int g_http_header_buffer_id = 0; static int g_dce_stub_data_buffer_id = 0; /** * \test DetectPcreParseTest01 make sure we don't allow invalid opts 7. */ static int DetectPcreParseTest01 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/blah/7"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest02 make sure we don't allow invalid opts Ui$. */ static int DetectPcreParseTest02 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/blah/Ui$"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest03 make sure we don't allow invalid opts UZi. */ static int DetectPcreParseTest03 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/blah/UNi"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest04 make sure we allow escaped " */ static int DetectPcreParseTest04 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/b\\\"lah/i"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest05 make sure we parse pcre with no opts */ static int DetectPcreParseTest05 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/b(l|a)h/"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest06 make sure we parse pcre with smi opts */ static int DetectPcreParseTest06 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/b(l|a)h/smi"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest07 make sure we parse pcre with /Ui opts */ static int DetectPcreParseTest07 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/blah/Ui"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest08 make sure we parse pcre with O opts */ static int DetectPcreParseTest08 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/b(l|a)h/O"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest09 make sure we parse pcre with a content * that has slashes */ static int DetectPcreParseTest09 (void) { DetectPcreData *pd = NULL; char *teststring = "/lala\\\\/"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); PASS; } /** * \test Test pcre option for dce sig(yeah I'm bored of writing test titles). */ int DetectPcreParseTest10(void) { Signature *s = SigAlloc(); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); s->alproto = ALPROTO_DCERPC; FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); FAIL_IF_NOT(s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); s = SigAlloc(); FAIL_IF_NULL(s); /* failure since we have no preceding content/pcre/bytejump */ FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); FAIL_IF_NOT(s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); DetectEngineCtxFree(de_ctx); PASS; } /** * \test Test pcre option for dce sig. */ int DetectPcreParseTest11(void) { DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/R; sid:1;)"); FAIL_IF(de_ctx == NULL); s = de_ctx->sig_list; FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL); FAIL_IF_NOT(s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/R; sid:1;)"); FAIL_IF_NULL(s->next); s = s->next; FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL); FAIL_IF_NOT(s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/RB; sid:1;)"); FAIL_IF(s->next == NULL); s = s->next; FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL); FAIL_IF_NOT(s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; FAIL_IF(!(data->flags & DETECT_PCRE_RAWBYTES) || !(data->flags & DETECT_PCRE_RELATIVE)); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; pcre:/bamboo/; sid:1;)"); FAIL_IF(s->next == NULL); s = s->next; FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] != NULL); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); PASS; } /** * \test Test pcre option with file data. pcre is relative to file_data, * so relative flag should be unset. */ static int DetectPcreParseTest12(void) { DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; pcre:/abc/R; sid:1;)"); FAIL_IF (de_ctx->sig_list == NULL); s = de_ctx->sig_list; FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id] == NULL); FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); PASS; } /** * \test Test pcre option with file data. */ static int DetectPcreParseTest13(void) { DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"abc\"; pcre:/def/R; sid:1;)"); FAIL_IF(de_ctx->sig_list == NULL); s = de_ctx->sig_list; FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id] == NULL); FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE)); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); PASS; } /** * \test Test pcre option with file data. */ static int DetectPcreParseTest14(void) { DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; pcre:/def/; sid:1;)"); FAIL_IF(de_ctx->sig_list == NULL); s = de_ctx->sig_list; FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id] == NULL); FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || data->flags & DETECT_PCRE_RELATIVE); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with pcre relative method */ int DetectPcreParseTest15(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_method\"; " "content:\"GET\"; " "http_method; pcre:\"/abc/RM\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with pcre relative cookie */ int DetectPcreParseTest16(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_cookie\"; " "content:\"test\"; " "http_cookie; pcre:\"/abc/RC\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with pcre relative raw header */ int DetectPcreParseTest17(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_raw_header\"; " "flow:to_server; content:\"test\"; " "http_raw_header; pcre:\"/abc/RD\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with pcre relative header */ int DetectPcreParseTest18(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_header\"; " "content:\"test\"; " "http_header; pcre:\"/abc/RH\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with pcre relative client-body */ int DetectPcreParseTest19(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relativie http_client_body\"; " "content:\"test\"; " "http_client_body; pcre:\"/abc/RP\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with pcre relative raw uri */ int DetectPcreParseTest20(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_uri\"; " "content:\"test\"; " "http_raw_uri; pcre:\"/abc/RI\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with pcre relative uricontent */ int DetectPcreParseTest21(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative uricontent\"; " "uricontent:\"test\"; " "pcre:\"/abc/RU\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with pcre relative http_uri */ int DetectPcreParseTest22(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_uri\"; " "content:\"test\"; " "http_uri; pcre:\"/abc/RU\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with inconsistent pcre relative */ int DetectPcreParseTest23(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre relative\"; " "content:\"GET\"; " "http_cookie; pcre:\"/abc/RM\"; sid:1;)"); FAIL_IF_NOT_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with inconsistent pcre modifiers */ int DetectPcreParseTest24(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/UI\"; sid:1;)"); FAIL_IF_NOT_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with inconsistent pcre modifiers */ int DetectPcreParseTest25(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/DH\"; sid:1;)"); FAIL_IF_NOT_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Check a signature with inconsistent pcre modifiers */ static int DetectPcreParseTest26(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/F\"; sid:1;)"); FAIL_IF_NOT_NULL(de_ctx->sig_list); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } /** \test Bug 1098 */ static int DetectPcreParseTest27(void) { DetectEngineCtx *de_ctx = NULL; FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any 80 " "(content:\"baduricontent\"; http_raw_uri; " "pcre:\"/^[a-z]{5}\\.html/R\"; sid:2; rev:2;)"); FAIL_IF_NOT(de_ctx->sig_list == NULL); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); PASS; } static int DetectPcreTestSig01(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&f, 0, sizeof(f)); memset(&th_v, 0, sizeof(th_v)); memset(&ssn, 0, sizeof(TcpSession)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_HTTP; p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/^gEt/i\"; pcre:\"/\\/two\\//U\"; pcre:\"/GET \\/two\\//\"; pcre:\"/\\s+HTTP/R\"; sid:1;)"); FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER | STREAM_START, buf, buflen); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 1) == 1); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); PASS; } static int DetectPcreTestSig02(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; Flow f; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); FLOW_INITIALIZE(&f); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; pcre_match_limit = 100; pcre_match_limit_recursion = 100; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/two/O\"; sid:2;)"); FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 2) == 1); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); PASS; } /** * \test DetectPcreTestSig03Real negation test ! outside of "" this sig should not match */ static int DetectPcreTestSig03(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"GET\"; pcre:!\"/two/\"; sid:1;)"); FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); PASS; } /** * \test Check the signature with pcre modifier P (match with L7 to http body data) */ static int DetectPcreModifPTest04(void) { uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "X-Powered-By: PHP/5.2.5\r\n" "P3P: CP=\"NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM\"\r\n" "Expires: Mon, 1 Jan 2001 00:00:00 GMT\r\n" "Last-Modified: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" "Pragma: no-cache\r\n" "Keep-Alive: timeout=15, max=100\r\n" "Connection: Keep-Alive\r\n" "Transfer-Encoding: chunked\r\n" "Content-Type: text/html; charset=utf-8\r\n" "\r\n" "15" "\r\n" "flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"Pcre modifier P\"; pcre:\"/DOCTYPE/P\"; " "sid:1;)"); FAIL_IF(s == NULL); s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"" "Pcre modifier P (no match)\"; pcre:\"/blah/P\"; sid:2;)"); FAIL_IF(s->next == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!(PacketAlertCheck(p, 1))); FAIL_IF(PacketAlertCheck(p, 2)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); PASS; } /** * \test Check the signature with pcre modifier P (match with L7 to http body data) * over fragmented chunks (DOCTYPE fragmented) */ static int DetectPcreModifPTest05(void) { uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "X-Powered-By: PHP/5.2.5\r\n" "P3P: CP=\"NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM\"\r\n" "Expires: Mon, 1 Jan 2001 00:00:00 GMT\r\n" "Last-Modified: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" "Pragma: no-cache\r\n" "Keep-Alive: timeout=15, max=100\r\n" "Connection: Keep-Alive\r\n" "Transfer-Encoding: chunked\r\n" "Content-Type: text/html; charset=utf-8\r\n" "\r\n" "15" "\r\n" "flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"Pcre modifier P\"; pcre:\"/DOC/P\"; " "sid:1;)"); FAIL_IF(s == NULL); s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"" "Pcre modifier P (no match)\"; pcre:\"/DOCTYPE/P\"; sid:2;)"); FAIL_IF(s->next == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); HtpState *http_state = f.alstate; FAIL_IF(http_state == NULL); FAIL_IF(PacketAlertCheck(p1, 1)); FAIL_IF(PacketAlertCheck(p1, 2)); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); FAIL_IF(!(PacketAlertCheck(p2, 1))); FAIL_IF(!(PacketAlertCheck(p2, 2))); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); PASS; } int DetectPcreTestSig06() { uint8_t *buf = (uint8_t *) "lalala lalala\\ lala\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/ lalala\\\\/\"; sid:1;)"; if (UTHPacketMatchSig(p, sig) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** \test anchored pcre */ int DetectPcreTestSig07() { uint8_t *buf = (uint8_t *) "lalala\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)"; FAIL_IF(UTHPacketMatchSig(p, sig) == 0); if (p != NULL) UTHFreePacket(p); PASS; } /** \test anchored pcre */ int DetectPcreTestSig08() { /* test it also without ending in a newline "\n" */ uint8_t *buf = (uint8_t *) "lalala"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)"; FAIL_IF(UTHPacketMatchSig(p, sig) == 0); if (p != NULL) UTHFreePacket(p); PASS; } /** \test Check the signature working to alert when cookie modifier is * passed to pcre */ static int DetectPcreTestSig09(void) { Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; pcre:\"/dummy/C\"; " " sid:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); PASS; } /** \test Check the signature working to alert when cookie modifier is * passed to a negated pcre */ static int DetectPcreTestSig10(void) { Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; pcre:!\"/dummy/C\"; " " sid:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); PASS; } /** \test Check the signature working to alert when method modifier is * passed to pcre */ static int DetectPcreTestSig11(void) { Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP method\"; pcre:\"/POST/M\"; " " sid:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); PASS; } /** \test Check the signature working to alert when method modifier is * passed to a negated pcre */ static int DetectPcreTestSig12(void) { Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP method\"; pcre:!\"/POST/M\"; " " sid:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); PASS; } /** \test Check the signature working to alert when header modifier is * passed to pcre */ static int DetectPcreTestSig13(void) { Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP header\"; pcre:\"/User[-_]Agent[:]?\\sMozilla/H\"; " " sid:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); PASS; } /** \test Check the signature working to alert when header modifier is * passed to a negated pcre */ static int DetectPcreTestSig14(void) { Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: IEXPLORER/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP header\"; pcre:!\"/User-Agent[:]?\\s+Mozilla/H\"; " " sid:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); PASS; } /** \test Check the signature working to alert when cookie and relative modifiers are * passed to pcre */ static int DetectPcreTestSig15(void) { Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy 1234\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"pcre relative HTTP cookie\"; content:\"dummy\";" " http_cookie; pcre:\"/1234/RC\"; " " sid:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); PASS; } /** \test Check the signature working to alert when method and relative modifiers are * passed to pcre */ static int DetectPcreTestSig16(void) { Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy 1234\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"pcre relative HTTP method\"; content:\"PO\";" " http_method; pcre:\"/ST/RM\"; " " sid:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); PASS; } /** \test Test tracking of body chunks per transactions (on requests) */ static int DetectPcreTxBodyChunksTest01(void) { Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Body one!!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); AppLayerHtpEnableRequestBodyCallback(); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); FAIL_IF(r != 0); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); FAIL_IF(r != 0); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); FAIL_IF(r != 0); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); FAIL_IF(r != 0); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); FAIL_IF(r != 0); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); FAIL_IF(r != 0); /* Now we should have 2 transactions, each with it's own list * of request body chunks (let's test it) */ HtpState *htp_state = f.alstate; FAIL_IF(htp_state == NULL); /* hardcoded check of the transactions and it's client body chunks */ FAIL_IF(AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2); htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 0); htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 1); HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); FAIL_IF(htud == NULL); HtpBodyChunk *cur = htud->request_body.first; FAIL_IF(htud->request_body.first == NULL); FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); htud = (HtpTxUserData *) htp_tx_get_user_data(t2); cur = htud->request_body.first; FAIL_IF(htud->request_body.first == NULL); FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); FLOWLOCK_UNLOCK(&f); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); PASS; } /** \test test pcre P modifier with multiple pipelined http transactions */ static int DetectPcreTxBodyChunksTest02(void) { Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Body one!!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); FAIL_IF(s == NULL); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!(PacketAlertCheck(p, 1))); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))); p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!(PacketAlertCheck(p, 2))); p->alerts.cnt = 0; HtpState *htp_state = f.alstate; FAIL_IF(htp_state == NULL); /* hardcoded check of the transactions and it's client body chunks */ FAIL_IF(AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2); htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 0); htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 1); HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); HtpBodyChunk *cur = htud->request_body.first; FAIL_IF(htud->request_body.first == NULL); FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); htud = (HtpTxUserData *) htp_tx_get_user_data(t2); cur = htud->request_body.first; FAIL_IF(htud->request_body.first == NULL); FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); PASS; } /** \test multiple http transactions and body chunks of request handling */ static int DetectPcreTxBodyChunksTest03(void) { Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Body one!!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); FAIL_IF(s == NULL); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!(PacketAlertCheck(p, 1))); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))); p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF(!(PacketAlertCheck(p, 2))); p->alerts.cnt = 0; HtpState *htp_state = f.alstate; FAIL_IF(htp_state == NULL); FAIL_IF(AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); PASS; } /** * \test flowvar capture on http buffer */ static int DetectPcreFlowvarCapture01(void) { uint8_t uabuf1[] = "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13"; uint32_t ualen1 = sizeof(uabuf1) - 1; /* minus the \0 */ uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "\r\n" "flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; sid:1;)"); FAIL_IF(s == NULL); FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || s->sm_lists[g_http_header_buffer_id]->next == NULL || s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); DetectPcreData *pd = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); FAIL_IF(!(PacketAlertCheck(p1, 1))); FlowVar *fv = FlowVarGet(&f, pd->capids[0]); FAIL_IF(fv == NULL); FAIL_IF(fv->data.fv_str.value_len != ualen1); if (memcmp(fv->data.fv_str.value, uabuf1, ualen1) != 0) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("buffer mismatch: "); FAIL; } if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); PASS; } /** * \test flowvar capture on http buffer, capture overwrite */ static int DetectPcreFlowvarCapture02(void) { uint8_t uabuf1[] = "Apache"; uint32_t ualen1 = sizeof(uabuf1) - 1; /* minus the \0 */ uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "\r\n" "flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:1; sid:1;)"); FAIL_IF(s == NULL); FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || s->sm_lists[g_http_header_buffer_id]->next == NULL || s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:3; sid:2;)"); FAIL_IF(s == NULL); FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || s->sm_lists[g_http_header_buffer_id]->next == NULL || s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; FAIL_IF(pd1->capids[0] != pd2->capids[0]); SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); FAIL_IF(!(PacketAlertCheck(p1, 1))); FlowVar *fv = FlowVarGet(&f, pd1->capids[0]); FAIL_IF(fv == NULL); if (fv->data.fv_str.value_len != ualen1) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("%u != %u: ", fv->data.fv_str.value_len, ualen1); FAIL; } if (memcmp(fv->data.fv_str.value, uabuf1, ualen1) != 0) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("buffer mismatch: "); FAIL; } if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); PASS; } /** * \test flowvar capture on http buffer, capture overwrite + no matching sigs, so flowvars should not be set. */ static int DetectPcreFlowvarCapture03(void) { uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "\r\n" "flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:1; sid:1;)"); FAIL_IF(s == NULL); FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || s->sm_lists[g_http_header_buffer_id]->next == NULL || s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:3; sid:2;)"); FAIL_IF(s == NULL); FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || s->sm_lists[g_http_header_buffer_id]->next == NULL || s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; FAIL_IF(pd1->capids[0] != pd2->capids[0]); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); FLOWLOCK_WRLOCK(&f); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); FAIL_IF(r != 0); FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; FAIL_IF(http_state == NULL); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); FAIL_IF(PacketAlertCheck(p1, 1)); FlowVar *fv = FlowVarGet(&f, pd1->capids[0]); FAIL_IF(fv != NULL); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); PASS; } /** * \brief Test parsing of pcre's with the W modifier set. */ static int DetectPcreParseHttpHost(void) { DetectPcreData *pd = NULL; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list, NULL, 0); FAIL_IF(pd == NULL); DetectPcreFree(pd); list = DETECT_SM_LIST_NOTSET; pd = DetectPcreParse(de_ctx, "/dOmain\\.com/W", &list, NULL, 0); FAIL_IF(pd != NULL); /* Uppercase meta characters are valid. */ list = DETECT_SM_LIST_NOTSET; pd = DetectPcreParse(de_ctx, "/domain\\D+\\.com/W", &list, NULL, 0); FAIL_IF(pd == NULL); DetectPcreFree(pd); /* This should not parse as the first \ escapes the second \, then * we have a D. */ list = DETECT_SM_LIST_NOTSET; pd = DetectPcreParse(de_ctx, "/\\\\Ddomain\\.com/W", &list, NULL, 0); FAIL_IF(pd != NULL); DetectEngineCtxFree(de_ctx); PASS; } /** * \brief Test parsing of capture extension */ static int DetectPcreParseCaptureTest(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " "(content:\"Server: \"; http_header; pcre:\"/(.*)\\r\\n/HR, flow:somecapture\"; content:\"xyz\"; http_header; sid:1;)"); FAIL_IF(s == NULL); s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " "(content:\"Server: \"; http_header; pcre:\"/(flow:.*)\\r\\n/HR\"; content:\"xyz\"; http_header; sid:2;)"); FAIL_IF(s == NULL); s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " "(content:\"Server: \"; http_header; pcre:\"/([a-z]+)([0-9]+)\\r\\n/HR, flow:somecapture, pkt:anothercap\"; content:\"xyz\"; http_header; sid:3;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); uint32_t capid = VarNameStoreLookupByName("somecapture", VAR_TYPE_FLOW_VAR); FAIL_IF (capid != 1); capid = VarNameStoreLookupByName("anothercap", VAR_TYPE_PKT_VAR); FAIL_IF (capid != 2); DetectEngineCtxFree(de_ctx); PASS; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectPcre */ static void DetectPcreRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01); UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02); UtRegisterTest("DetectPcreParseTest03", DetectPcreParseTest03); UtRegisterTest("DetectPcreParseTest04", DetectPcreParseTest04); UtRegisterTest("DetectPcreParseTest05", DetectPcreParseTest05); UtRegisterTest("DetectPcreParseTest06", DetectPcreParseTest06); UtRegisterTest("DetectPcreParseTest07", DetectPcreParseTest07); UtRegisterTest("DetectPcreParseTest08", DetectPcreParseTest08); UtRegisterTest("DetectPcreParseTest09", DetectPcreParseTest09); UtRegisterTest("DetectPcreParseTest10", DetectPcreParseTest10); UtRegisterTest("DetectPcreParseTest11", DetectPcreParseTest11); UtRegisterTest("DetectPcreParseTest12", DetectPcreParseTest12); UtRegisterTest("DetectPcreParseTest13", DetectPcreParseTest13); UtRegisterTest("DetectPcreParseTest14", DetectPcreParseTest14); UtRegisterTest("DetectPcreParseTest15", DetectPcreParseTest15); UtRegisterTest("DetectPcreParseTest16", DetectPcreParseTest16); UtRegisterTest("DetectPcreParseTest17", DetectPcreParseTest17); UtRegisterTest("DetectPcreParseTest18", DetectPcreParseTest18); UtRegisterTest("DetectPcreParseTest19", DetectPcreParseTest19); UtRegisterTest("DetectPcreParseTest20", DetectPcreParseTest20); UtRegisterTest("DetectPcreParseTest21", DetectPcreParseTest21); UtRegisterTest("DetectPcreParseTest22", DetectPcreParseTest22); UtRegisterTest("DetectPcreParseTest23", DetectPcreParseTest23); UtRegisterTest("DetectPcreParseTest24", DetectPcreParseTest24); UtRegisterTest("DetectPcreParseTest25", DetectPcreParseTest25); UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26); UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27); UtRegisterTest("DetectPcreTestSig01 -- pcre test", DetectPcreTestSig01); UtRegisterTest("DetectPcreTestSig02 -- pcre test", DetectPcreTestSig02); UtRegisterTest("DetectPcreTestSig03 -- negated pcre test", DetectPcreTestSig03); UtRegisterTest("DetectPcreModifPTest04 -- Modifier P", DetectPcreModifPTest04); UtRegisterTest("DetectPcreModifPTest05 -- Modifier P fragmented", DetectPcreModifPTest05); UtRegisterTest("DetectPcreTestSig06", DetectPcreTestSig06); UtRegisterTest("DetectPcreTestSig07 -- anchored pcre", DetectPcreTestSig07); UtRegisterTest("DetectPcreTestSig08 -- anchored pcre", DetectPcreTestSig08); UtRegisterTest("DetectPcreTestSig09 -- Cookie modifier", DetectPcreTestSig09); UtRegisterTest("DetectPcreTestSig10 -- negated Cookie modifier", DetectPcreTestSig10); UtRegisterTest("DetectPcreTestSig11 -- Method modifier", DetectPcreTestSig11); UtRegisterTest("DetectPcreTestSig12 -- negated Method modifier", DetectPcreTestSig12); UtRegisterTest("DetectPcreTestSig13 -- Header modifier", DetectPcreTestSig13); UtRegisterTest("DetectPcreTestSig14 -- negated Header modifier", DetectPcreTestSig14); UtRegisterTest("DetectPcreTestSig15 -- relative Cookie modifier", DetectPcreTestSig15); UtRegisterTest("DetectPcreTestSig16 -- relative Method modifier", DetectPcreTestSig16); UtRegisterTest("DetectPcreTxBodyChunksTest01", DetectPcreTxBodyChunksTest01); UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest02); UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest03); UtRegisterTest("DetectPcreFlowvarCapture01 -- capture for http_header", DetectPcreFlowvarCapture01); UtRegisterTest("DetectPcreFlowvarCapture02 -- capture for http_header", DetectPcreFlowvarCapture02); UtRegisterTest("DetectPcreFlowvarCapture03 -- capture for http_header", DetectPcreFlowvarCapture03); UtRegisterTest("DetectPcreParseHttpHost", DetectPcreParseHttpHost); UtRegisterTest("DetectPcreParseCaptureTest", DetectPcreParseCaptureTest); #endif /* UNITTESTS */ }