static uint16_t SignatureGetMpmPatternLen(const Signature *s, const int list) { if (s->sm_lists[list] != NULL && s->mpm_sm != NULL && SigMatchListSMBelongsTo(s, s->mpm_sm) == list) { DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; return cd->content_len; } return 0; }
static void EngineAnalysisRulesPrintFP(Signature *s) { DetectContentData *fp_cd = NULL; SigMatch *mpm_sm = s->mpm_sm; if (mpm_sm != NULL) { fp_cd = (DetectContentData *)mpm_sm->ctx; } if (fp_cd == NULL) { return; } uint16_t patlen = fp_cd->content_len; uint8_t *pat = SCMalloc(fp_cd->content_len + 1); if (unlikely(pat == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memcpy(pat, fp_cd->content, fp_cd->content_len); pat[fp_cd->content_len] = '\0'; if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { SCFree(pat); patlen = fp_cd->fp_chop_len; pat = SCMalloc(fp_cd->fp_chop_len + 1); if (unlikely(pat == NULL)) { exit(EXIT_FAILURE); } memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len); pat[fp_cd->fp_chop_len] = '\0'; fprintf(rule_engine_analysis_FD, " Fast Pattern \""); PrintRawUriFp(rule_engine_analysis_FD, pat, patlen); } else { fprintf(rule_engine_analysis_FD, " Fast Pattern \""); PrintRawUriFp(rule_engine_analysis_FD, pat, patlen); } SCFree(pat); fprintf(rule_engine_analysis_FD, "\" on \""); int list_type = SigMatchListSMBelongsTo(s, mpm_sm); if (list_type == DETECT_SM_LIST_PMATCH) { int payload = 0; int stream = 0; if (SignatureHasPacketContent(s)) payload = 1; if (SignatureHasStreamContent(s)) stream = 1; fprintf(rule_engine_analysis_FD, "%s", payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream"); } else if (list_type == DETECT_SM_LIST_UMATCH) fprintf(rule_engine_analysis_FD, "http uri content"); else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(rule_engine_analysis_FD, "http raw uri content"); else if (list_type == DETECT_SM_LIST_HHDMATCH) fprintf(rule_engine_analysis_FD, "http header content"); else if (list_type == DETECT_SM_LIST_HRHDMATCH) fprintf(rule_engine_analysis_FD, "http raw header content"); else if (list_type == DETECT_SM_LIST_HMDMATCH) fprintf(rule_engine_analysis_FD, "http method content"); else if (list_type == DETECT_SM_LIST_HCDMATCH) fprintf(rule_engine_analysis_FD, "http cookie content"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(rule_engine_analysis_FD, "http client body content"); else if (list_type == DETECT_SM_LIST_HSBDMATCH) fprintf(rule_engine_analysis_FD, "http server body content"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) fprintf(rule_engine_analysis_FD, "http stat code content"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) fprintf(rule_engine_analysis_FD, "http stat msg content"); else if (list_type == DETECT_SM_LIST_HUADMATCH) fprintf(rule_engine_analysis_FD, "http user agent content"); else if (list_type == DETECT_SM_LIST_DNSQUERY_MATCH) fprintf(rule_engine_analysis_FD, "dns query name content"); fprintf(rule_engine_analysis_FD, "\" buffer.\n"); return; }
/** \brief Setup within pattern (content/uricontent) modifier. * * \todo apply to uricontent * * \retval 0 ok * \retval -1 error, sig needs to be invalidated */ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withinstr) { char *str = withinstr; char dubbed = 0; SigMatch *pm = NULL; /* strip "'s */ if (withinstr[0] == '\"' && withinstr[strlen(withinstr)-1] == '\"') { str = SCStrdup(withinstr+1); if (str == NULL) goto error; str[strlen(withinstr)-2] = '\0'; dubbed = 1; } /* if we still haven't found that the sig is related to DCERPC, * it's a direct entry into Signature->[DETECT_SM_LIST_PMATCH] */ if (s->alproto == ALPROTO_DCERPC) { SigMatch *dcem = NULL; SigMatch *dm = NULL; SigMatch *pm1 = NULL; SigMatch *pm1_ots = NULL; SigMatch *pm2_ots = NULL; dcem = SigMatchGetLastSMFromLists(s, 6, DETECT_DCE_IFACE, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_DCE_OPNUM, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_DCE_STUB_DATA, s->sm_lists_tail[DETECT_SM_LIST_AMATCH]); pm1_ots = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm1_ots != NULL && pm1_ots->prev != NULL) { pm2_ots = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, pm1_ots->prev, DETECT_PCRE, pm1_ots->prev, DETECT_BYTEJUMP, pm1_ots->prev); } dm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm1 = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (dm == NULL && pm1 == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"within\" requires a " "preceding content keyword"); goto error; } if (dm == NULL) { if (pm2_ots == NULL) { if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1 and we continue this way */ pm = pm1; } } else if (pm2_ots->idx > dcem->idx) { /* within is against pm1, pm = pm1; */ pm = pm1; } else if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1 and we continue this way */ pm = pm1; } } else { if (pm1 == NULL) { /* within is against dm and continue this way */ pm = dm; } else if (dm->idx > pm1->idx) { /* within is against dm */ pm = dm; } else if (pm2_ots == NULL || pm2_ots->idx < dcem->idx) { /* trasnfer pm1 to dmatch list and pm = pm1 */ SigMatchTransferSigMatchAcrossLists(pm1, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1, pm = pm1 */ pm = pm1; } } } else { pm = SigMatchGetLastSMFromLists(s, 24, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "\"within\" requires " "preceeding content, uricontent, http_client_body, " "http_server_body, http_header, http_raw_header, " "http_method, http_cookie, http_raw_uri, " "http_stat_msg, http_stat_code or http_user_agent " "option"); if (dubbed) SCFree(str); return -1; } } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (pm->type) { case DETECT_CONTENT: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "content error"); goto error; } if (cd->flags & DETECT_CONTENT_NEGATED) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "negated keyword set along with a fast_pattern"); goto error; } } else { if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "keyword set along with a fast_pattern:only"); goto error; } } if (cd->flags & DETECT_CONTENT_DEPTH || cd->flags & DETECT_CONTENT_OFFSET) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative keyword " "with a non-relative keyword for the same content" ); goto error; } if (str[0] != '-' && isalpha(str[0])) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var " "seen in within - %s\n", str); goto error; } cd->within = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_WITHIN_BE; } else { cd->within = strtol(str, NULL, 10); if (cd->within < (int32_t)cd->content_len) { SCLogError(SC_ERR_WITHIN_INVALID, "within argument \"%"PRIi32"\" is " "less than the content length \"%"PRIu32"\" which is invalid, since " "this will never match. Invalidating signature", cd->within, cd->content_len); goto error; } } cd->flags |= DETECT_CONTENT_WITHIN; pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, pm->prev, DETECT_PCRE, pm->prev, DETECT_BYTEJUMP, pm->prev); if (pm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("content relative without a previous content based " "keyword. Holds good only in the case of DCERPC " "alproto like now."); } else { //SCLogError(SC_ERR_INVALID_SIGNATURE, "No related " // "previous-previous content or pcre keyword"); //goto error; ; } } else { switch (pm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "content error"); goto error; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "previous keyword " "has a fast_pattern:only; set. Can't " "have relative keywords around a fast_pattern " "only content"); goto error; } break; case DETECT_PCRE: pe = (DetectPcreData *) pm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre error"); goto error; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: SCLogDebug("no setting relative_next for bytejump. We " "have no use for it"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "unsupported type %d", pm->type); break; } } break; default: SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two " "preceeding content or uricontent options"); goto error; } if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; }
int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) { char *str = offsetstr; char dubbed = 0; SigMatch *pm = NULL; /* strip "'s */ if (offsetstr[0] == '\"' && offsetstr[strlen(offsetstr)-1] == '\"') { str = SCStrdup(offsetstr+1); if (unlikely(str == NULL)) goto error; str[strlen(offsetstr)-2] = '\0'; dubbed = 1; } switch (s->alproto) { case ALPROTO_DCERPC: /* add to the latest "content" keyword from either dmatch or pmatch */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs " "preceding content option for dcerpc sig"); if (dubbed) SCFree(str); return -1; } break; default: pm = SigMatchGetLastSMFromLists(s, 24, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs " "preceding content or uricontent option, http_client_body, " "http_header, http_raw_header, http_method, " "http_cookie, http_raw_uri, http_stat_msg, " "http_stat_code or http_user_agent option"); if (dubbed) SCFree(str); return -1; } break; } /* we can remove this switch now with the unified structure */ DetectContentData *cd = NULL; switch (pm->type) { case DETECT_CONTENT: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); if (dubbed) SCFree(str); return -1; } if (cd->flags & DETECT_CONTENT_NEGATED) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "negated keyword set along with a fast_pattern"); goto error; } } else { if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "keyword set along with a fast_pattern:only;"); goto error; } } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative keyword " "with a non-relative keyword for the same content." ); goto error; } if (cd->flags & DETECT_CONTENT_OFFSET) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple offsets for the same content. "); goto error; } if (str[0] != '-' && isalpha((unsigned char)str[0])) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var " "seen in offset - %s\n", str); goto error; } cd->offset = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_OFFSET_BE; } else { cd->offset = (uint32_t)atoi(str); if (cd->depth != 0) { if (cd->depth < cd->content_len) { SCLogDebug("depth increased to %"PRIu32" to match pattern len", cd->content_len); cd->depth = cd->content_len; } /* Updating the depth as is relative to the offset */ cd->depth += cd->offset; } } cd->flags |= DETECT_CONTENT_OFFSET; break; default: SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs a preceding" " content keyword"); goto error; } if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; }
/** * \brief This function is used to add the parsed isdataatdata into the current * signature. * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param isdataatstr pointer to the user provided isdataat options * * \retval 0 on Success * \retval -1 on Failure */ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatstr) { DetectIsdataatData *idad = NULL; SigMatch *sm = NULL; SigMatch *dm = NULL; SigMatch *pm = NULL; SigMatch *prev_pm = NULL; char *offset = NULL; idad = DetectIsdataatParse(isdataatstr, &offset); if (idad == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_ISDATAAT; sm->ctx = (void *)idad; if (s->alproto == ALPROTO_DCERPC && (idad->flags & ISDATAAT_RELATIVE)) { pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); if (pm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (dm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (pm->idx > dm->idx) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } prev_pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, sm->prev, DETECT_BYTEJUMP, sm->prev, DETECT_PCRE, sm->prev); if (prev_pm == NULL) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is a dce alproto sig."); if (offset != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in isdataat - %s", offset); goto error; } return 0; } } else if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { if (idad->flags & ISDATAAT_RELATIVE) { pm = SigMatchGetLastSMFromLists(s, 10, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); if (pm == NULL) { idad->flags &= ~ISDATAAT_RELATIVE; } s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } else { s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } if (pm == NULL) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is a file_data sig."); if (offset != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in isdataat - %s", offset); goto error; } return 0; } prev_pm = pm; } else { if (!(idad->flags & ISDATAAT_RELATIVE)) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); if (offset != NULL) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, SigMatchListSMBelongsTo(s, sm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in isdataat - %s\n", offset); goto error; } DetectIsdataatData *isdd = sm->ctx; isdd->dataat = ((DetectByteExtractData *)bed_sm->ctx)->local_id; isdd->flags |= ISDATAAT_OFFSET_BE; SCFree(offset); } return 0; } pm = SigMatchGetLastSMFromLists(s, 66, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "isdataat relative seen " "without a previous content uricontent, " "http_client_body, http_header, http_raw_header, " "http_method, http_cookie, http_raw_uri, " "http_stat_msg, http_stat_code, byte_test, " "byte_extract, byte_jump, http_user_agent, " "http_host or http_raw_host keyword"); goto error; } else { int list_type = SigMatchListSMBelongsTo(s, pm); if (list_type == -1) { goto error; } SigMatchAppendSMToList(s, sm, list_type); } /* else - if (pm == NULL) */ prev_pm = pm; } if (offset != NULL) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, SigMatchListSMBelongsTo(s, sm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in isdataat - %s\n", offset); goto error; } DetectIsdataatData *isdd = sm->ctx; isdd->dataat = ((DetectByteExtractData *)bed_sm->ctx)->local_id; isdd->flags |= ISDATAAT_OFFSET_BE; SCFree(offset); } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (prev_pm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)prev_pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; break; case DETECT_PCRE: pe = (DetectPcreData *)prev_pm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: case DETECT_BYTETEST: case DETECT_BYTE_EXTRACT: SCLogDebug("Do nothing for byte_jump, byte_test, byte_extract"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } /* switch */ return 0; error: return -1; }
MpmStore *MpmStorePrepareBuffer2(DetectEngineCtx *de_ctx, SigGroupHead *sgh, AppLayerMpms *am) { const Signature *s = NULL; uint32_t sig; uint32_t cnt = 0; uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1; uint8_t sids_array[max_sid]; memset(sids_array, 0x00, max_sid); SCLogDebug("handling %s direction %s for list %d", am->name, am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", am->sm_list); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; if (s->mpm_sm == NULL) continue; int list = SigMatchListSMBelongsTo(s, s->mpm_sm); if (list < 0) continue; if ((s->flags & am->direction) == 0) continue; if (list != am->sm_list) continue; sids_array[s->num / 8] |= 1 << (s->num % 8); cnt++; } if (cnt == 0) return NULL; MpmStore lookup = { sids_array, max_sid, am->direction, MPMB_MAX, am->sm_list, 0, NULL}; MpmStore *result = MpmStoreLookup(de_ctx, &lookup); if (result == NULL) { SCLogDebug("new unique mpm for %s %s: %u patterns", am->name, am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", cnt); MpmStore *copy = SCCalloc(1, sizeof(MpmStore)); if (copy == NULL) return NULL; uint8_t *sids = SCCalloc(1, max_sid); if (sids == NULL) { SCFree(copy); return NULL; } memcpy(sids, sids_array, max_sid); copy->sid_array = sids; copy->sid_array_size = max_sid; copy->buffer = MPMB_MAX; copy->direction = am->direction; copy->sm_list = am->sm_list; copy->sgh_mpm_context = am->sgh_mpm_context; MpmStoreSetup(de_ctx, copy); MpmStoreAdd(de_ctx, copy); return copy; } else { return result; } return NULL; }
/** * \brief This function is used to add the parsed isdataatdata into the current * signature. * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param isdataatstr pointer to the user provided isdataat options * * \retval 0 on Success * \retval -1 on Failure */ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatstr) { DetectIsdataatData *idad = NULL; SigMatch *sm = NULL; SigMatch *dm = NULL; SigMatch *pm = NULL; SigMatch *prev_pm = NULL; idad = DetectIsdataatParse(isdataatstr); if (idad == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_ISDATAAT; sm->ctx = (void *)idad; if (s->alproto == ALPROTO_DCERPC && idad->flags & ISDATAAT_RELATIVE) { pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); if (pm == NULL) { SigMatchAppendDcePayload(s, sm); } else if (dm == NULL) { SigMatchAppendDcePayload(s, sm); } else if (pm->idx > dm->idx) { SigMatchAppendPayload(s, sm); } else { SigMatchAppendDcePayload(s, sm); } prev_pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, sm->prev, DETECT_BYTEJUMP, sm->prev, DETECT_PCRE, sm->prev); } else { pm = SigMatchGetLastSMFromLists(s, 30, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_URICONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_AL_HTTP_CLIENT_BODY, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_AL_HTTP_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_AL_HTTP_RAW_HEADER, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_AL_HTTP_METHOD, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_AL_HTTP_COOKIE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { if (idad->flags & ISDATAAT_RELATIVE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "isdataat relative seen " "without a previous content uricontent, " "http_client_body, http_header, http_raw_header, " "http_method or http_cookie keyword"); goto error; } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } } else { int list_type; if (pm->type == DETECT_PCRE || pm->type == DETECT_BYTEJUMP) { list_type = SigMatchListSMBelongsTo(s, pm); if (list_type == -1) { goto error; } } else { switch (pm->type) { case DETECT_CONTENT: list_type = DETECT_SM_LIST_PMATCH; break; case DETECT_URICONTENT: list_type = DETECT_SM_LIST_UMATCH; break; case DETECT_AL_HTTP_CLIENT_BODY: list_type = DETECT_SM_LIST_HCBDMATCH; break; case DETECT_AL_HTTP_RAW_HEADER: list_type = DETECT_SM_LIST_HRHDMATCH; break; case DETECT_AL_HTTP_HEADER: list_type = DETECT_SM_LIST_HHDMATCH; break; case DETECT_AL_HTTP_METHOD: list_type = DETECT_SM_LIST_HMDMATCH; break; case DETECT_AL_HTTP_COOKIE: list_type = DETECT_SM_LIST_HCDMATCH; break; } /* switch */ } /* else */ SigMatchAppendSMToList(s, sm, list_type); } /* else - if (pm == NULL) */ prev_pm = pm; } if (!(idad->flags & ISDATAAT_RELATIVE)) { return 0; } if (prev_pm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is a dce alproto sig."); return 0; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "No preceding content, pcre, " "uricontent, http_client_body, http_header, " "http_raw_header, http_method or http_cookie keyword"); goto error; } } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (prev_pm->type) { case DETECT_CONTENT: case DETECT_URICONTENT: case DETECT_AL_HTTP_CLIENT_BODY: case DETECT_AL_HTTP_HEADER: case DETECT_AL_HTTP_RAW_HEADER: case DETECT_AL_HTTP_METHOD: case DETECT_AL_HTTP_COOKIE: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)prev_pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; break; case DETECT_PCRE: pe = (DetectPcreData *)prev_pm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: SCLogDebug("Do nothing for bytejump"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } /* switch */ return 0; error: //if (idad != NULL) // DetectIsdataatFree(idad); //if (sm != NULL) // SCFree(sm); return -1; }
int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) { char *str = offsetstr; char dubbed = 0; SigMatch *pm = NULL; int ret = -1; /* strip "'s */ if (offsetstr[0] == '\"' && offsetstr[strlen(offsetstr)-1] == '\"') { str = SCStrdup(offsetstr+1); if (unlikely(str == NULL)) goto end; str[strlen(offsetstr) - 2] = '\0'; dubbed = 1; } /* retrive the sm to apply the depth against */ if (s->list != DETECT_SM_LIST_NOTSET) { pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); } else { pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); } if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs " "preceding content, uricontent option, http_client_body, " "http_server_body, http_header option, http_raw_header option, " "http_method option, http_cookie, http_raw_uri, " "http_stat_msg, http_stat_code, http_user_agent or " "file_data/dce_stub_data sticky buffer options"); goto end; } /* verify other conditions */ DetectContentData *cd = (DetectContentData *)pm->ctx; if (cd->flags & DETECT_CONTENT_OFFSET) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple offsets for the same content. "); goto end; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative " "keyword like within/distance with a absolute " "relative keyword like depth/offset for the same " "content." ); goto end; } if (cd->flags & DETECT_CONTENT_NEGATED && cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "negated keyword set along with a fast_pattern"); goto end; } if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "keyword set along with a fast_pattern:only;"); goto end; } if (str[0] != '-' && isalpha((unsigned char)str[0])) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var " "seen in offset - %s\n", str); goto end; } cd->offset = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_OFFSET_BE; } else { cd->offset = (uint32_t)atoi(str); if (cd->depth != 0) { if (cd->depth < cd->content_len) { SCLogDebug("depth increased to %"PRIu32" to match pattern len", cd->content_len); cd->depth = cd->content_len; } /* Updating the depth as is relative to the offset */ cd->depth += cd->offset; } } cd->flags |= DETECT_CONTENT_OFFSET; ret = 0; end: if (dubbed) SCFree(str); return ret; }
static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depthstr) { char *str = depthstr; char dubbed = 0; SigMatch *pm = NULL; DetectContentData *cd = NULL; /* strip "'s */ if (depthstr[0] == '\"' && depthstr[strlen(depthstr) - 1] == '\"') { str = SCStrdup(depthstr + 1); if (str == NULL) goto error; str[strlen(depthstr) - 2] = '\0'; dubbed = 1; } switch (s->alproto) { case ALPROTO_DCERPC: /* add to the latest content keyword from either dmatch or pmatch */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " "preceding content option for dcerpc sig"); if (dubbed) SCFree(str); return -1; } break; default: pm = SigMatchGetLastSMFromLists(s, 24, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " "preceding content, uricontent option, http_client_body, " "http_server_body, http_header option, http_raw_header option, " "http_method option, http_cookie, http_raw_uri, " "http_stat_msg, http_stat_code or http_user_agent option"); if (dubbed) SCFree(str); return -1; } break; } /* i swear we will clean this up :). Use a single version for all. Using * separate versions for all now, to avoiding breaking any code */ switch (pm->type) { case DETECT_CONTENT: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); if (dubbed) SCFree(str); return -1; } if (cd->flags & DETECT_CONTENT_NEGATED) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "negated keyword set along with a fast_pattern"); goto error; } } else { if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "keyword set along with a fast_pattern:only;"); goto error; } } if (cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative keyword " "with a non-relative keyword for the same content." ); goto error; } if (cd->flags & DETECT_CONTENT_DEPTH) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple depths for the same content."); goto error; } if (str[0] != '-' && isalpha(str[0])) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var " "seen in depth - %s\n", str); goto error; } cd->depth = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_DEPTH_BE; } else { cd->depth = (uint32_t)atoi(str); if (cd->depth < cd->content_len) { uint32_t content_len = cd->content_len; SCLogError(SC_ERR_INVALID_SIGNATURE, "depth - %"PRIu16 " smaller than content length - %"PRIu32, cd->depth, content_len); goto error; } /* Now update the real limit, as depth is relative to the offset */ cd->depth += cd->offset; } cd->flags |= DETECT_CONTENT_DEPTH; break; default: SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceding " "content (or uricontent) option"); goto error; } if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; }
static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { uint32_t bytes = 0; uint32_t offset = 0; uint8_t relative = 0; DetectBase64Decode *data = NULL; int sm_list; SigMatch *sm = NULL; SigMatch *pm = NULL; if (str != NULL) { if (!DetectBase64DecodeParse(str, &bytes, &offset, &relative)) { goto error; } } data = SCCalloc(1, sizeof(DetectBase64Decode)); if (unlikely(data == NULL)) { goto error; } data->bytes = bytes; data->offset = offset; data->relative = relative; if (s->list != DETECT_SM_LIST_NOTSET) { sm_list = s->list; #if 0 if (data->relative) { pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[sm_list], DETECT_PCRE, s->sm_lists_tail[sm_list]); } #endif } else { /* Copied from detect-isdataat.c. */ pm = SigMatchGetLastSMFromLists(s, 168, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { sm_list = SigMatchListSMBelongsTo(s, pm); if (sm_list < 0) { goto error; } } } sm = SigMatchAlloc(); if (sm == NULL) { goto error; } sm->type = DETECT_BASE64_DECODE; sm->ctx = (SigMatchCtx *)data; SigMatchAppendSMToList(s, sm, sm_list); if (!data->bytes) { data->bytes = BASE64_DECODE_MAX; } if (data->bytes > de_ctx->base64_decode_max_len) { de_ctx->base64_decode_max_len = data->bytes; } return 0; error: if (data != NULL) { SCFree(data); } return -1; }
int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { DetectBytejumpData *data = NULL; SigMatch *sm = NULL; char *offset = NULL; data = DetectBytejumpParse(optstr, &offset); if (data == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_BYTEJUMP; sm->ctx = (void *)data; /* check bytejump modifiers against the signature alproto. In case they conflict * chuck out invalid signature */ if (data->flags & DETECT_BYTEJUMP_DCE) { if (s->alproto != ALPROTO_DCERPC) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " "bytetest with dce enabled"); goto error; } if ( (data->flags & DETECT_BYTEJUMP_STRING) || (data->flags & DETECT_BYTEJUMP_LITTLE) || (data->flags & DETECT_BYTEJUMP_BIG) || (data->flags & DETECT_BYTEJUMP_BEGIN) || (data->base == DETECT_BYTEJUMP_BASE_DEC) || (data->base == DETECT_BYTEJUMP_BASE_HEX) || (data->base == DETECT_BYTEJUMP_BASE_OCT) ) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " "DCERPC rule holds an invalid modifier for bytejump."); goto error; } } if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { if (data->flags & DETECT_BYTEJUMP_RELATIVE) { SigMatch *prev_sm = NULL; prev_sm = SigMatchGetLastSMFromLists(s, 8, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); if (prev_sm == NULL) { data->flags &= ~DETECT_BYTEJUMP_RELATIVE; } s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } else { s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } } else if (s->alproto == ALPROTO_DCERPC && (data->flags & DETECT_BYTEJUMP_RELATIVE)) { SigMatch *pm = NULL; SigMatch *dm = NULL; pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); if (pm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (dm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (pm->idx > dm->idx) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } if (offset != NULL) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, SigMatchListSMBelongsTo(s, sm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in byte_jump - %s\n", offset); goto error; } DetectBytejumpData *bjd = sm->ctx; bjd->offset = ((DetectByteExtractData *)bed_sm->ctx)->local_id; bjd->flags |= DETECT_BYTEJUMP_OFFSET_BE; SCFree(offset); } if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { return 0; } if ( !(data->flags & DETECT_BYTEJUMP_RELATIVE)) { return(0); } SigMatch *prev_sm = NULL; prev_sm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, sm->prev, DETECT_BYTEJUMP, sm->prev, DETECT_PCRE, sm->prev); if (prev_sm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is an alproto sig."); return 0; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "No preceding content " "or uricontent or pcre option"); return -1; } } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (prev_sm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)prev_sm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; break; case DETECT_PCRE: pe = (DetectPcreData *)prev_sm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: SCLogDebug("No setting relative_next for bytejump. We " "have no use for it"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } /* switch */ return 0; error: if (data != NULL) DetectBytejumpFree(data); if (sm != NULL) SCFree(sm); return -1; }
/** \brief Get MpmStore for a built-in buffer type * */ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum MpmBuiltinBuffers buf) { const Signature *s = NULL; uint32_t sig; uint32_t cnt = 0; int direction = 0; uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1; uint8_t sids_array[max_sid]; memset(sids_array, 0x00, max_sid); int sgh_mpm_context = 0; switch (buf) { case MPMB_TCP_PKT_TS: case MPMB_TCP_PKT_TC: sgh_mpm_context = de_ctx->sgh_mpm_context_proto_tcp_packet; break; case MPMB_TCP_STREAM_TS: case MPMB_TCP_STREAM_TC: sgh_mpm_context = de_ctx->sgh_mpm_context_stream; break; case MPMB_UDP_TS: case MPMB_UDP_TC: sgh_mpm_context = de_ctx->sgh_mpm_context_proto_udp_packet; break; case MPMB_OTHERIP: sgh_mpm_context = de_ctx->sgh_mpm_context_proto_other_packet; break; default: break; } switch(buf) { case MPMB_TCP_PKT_TS: case MPMB_TCP_STREAM_TS: case MPMB_UDP_TS: direction = SIG_FLAG_TOSERVER; break; case MPMB_TCP_PKT_TC: case MPMB_TCP_STREAM_TC: case MPMB_UDP_TC: direction = SIG_FLAG_TOCLIENT; break; case MPMB_OTHERIP: direction = (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER); break; case MPMB_MAX: BUG_ON(1); break; } for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; if (s->mpm_sm == NULL) continue; int list = SigMatchListSMBelongsTo(s, s->mpm_sm); if (list < 0) continue; if (list != DETECT_SM_LIST_PMATCH) continue; switch (buf) { case MPMB_TCP_PKT_TS: case MPMB_TCP_PKT_TC: if (SignatureHasPacketContent(s) == 1) { sids_array[s->num / 8] |= 1 << (s->num % 8); cnt++; } break; case MPMB_TCP_STREAM_TS: case MPMB_TCP_STREAM_TC: if (SignatureHasStreamContent(s) == 1) { sids_array[s->num / 8] |= 1 << (s->num % 8); cnt++; } break; case MPMB_UDP_TS: case MPMB_UDP_TC: sids_array[s->num / 8] |= 1 << (s->num % 8); cnt++; break; case MPMB_OTHERIP: sids_array[s->num / 8] |= 1 << (s->num % 8); cnt++; break; default: break; } } if (cnt == 0) return NULL; MpmStore lookup = { sids_array, max_sid, direction, buf, DETECT_SM_LIST_PMATCH, 0, NULL}; MpmStore *result = MpmStoreLookup(de_ctx, &lookup); if (result == NULL) { MpmStore *copy = SCCalloc(1, sizeof(MpmStore)); if (copy == NULL) return NULL; uint8_t *sids = SCCalloc(1, max_sid); if (sids == NULL) { SCFree(copy); return NULL; } memcpy(sids, sids_array, max_sid); copy->sid_array = sids; copy->sid_array_size = max_sid; copy->buffer = buf; copy->direction = direction; copy->sm_list = DETECT_SM_LIST_PMATCH; copy->sgh_mpm_context = sgh_mpm_context; MpmStoreSetup(de_ctx, copy); MpmStoreAdd(de_ctx, copy); return copy; } else { return result; } }
void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) { const Signature *s = NULL; uint32_t sig; int dir = 0; if (ms->buffer != MPMB_MAX) { BUG_ON(ms->sm_list != DETECT_SM_LIST_PMATCH); switch (ms->buffer) { /* TS is 1 */ case MPMB_TCP_PKT_TS: case MPMB_TCP_STREAM_TS: case MPMB_UDP_TS: dir = 1; break; /* TC is 0 */ default: case MPMB_UDP_TC: case MPMB_TCP_STREAM_TC: case MPMB_TCP_PKT_TC: case MPMB_OTHERIP: /**< use 0 for other */ dir = 0; break; } } else { BUG_ON(ms->sm_list == DETECT_SM_LIST_PMATCH); BUG_ON(ms->direction == 0); BUG_ON(ms->direction == (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)); if (ms->direction == SIG_FLAG_TOSERVER) dir = 1; else dir = 0; } ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, ms->sgh_mpm_context, dir); MpmInitCtx(ms->mpm_ctx, de_ctx->mpm_matcher); /* add the patterns */ for (sig = 0; sig < (ms->sid_array_size * 8); sig++) { if (ms->sid_array[sig / 8] & (1 << (sig % 8))) { s = de_ctx->sig_array[sig]; if (s == NULL) continue; if (s->mpm_sm == NULL) continue; int list = SigMatchListSMBelongsTo(s, s->mpm_sm); if (list < 0) continue; if (list != ms->sm_list) continue; if ((s->flags & ms->direction) == 0) continue; SCLogDebug("adding %u", s->id); const DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; int skip = 0; /* negated logic: if mpm match can't be used to be sure about this * pattern, we have to inspect the rule fully regardless of mpm * match. So in this case there is no point of adding it at all. * The non-mpm list entry for the sig will make sure the sig is * inspected. */ if ((cd->flags & DETECT_CONTENT_NEGATED) && !(DETECT_CONTENT_MPM_IS_CONCLUSIVE(cd))) { skip = 1; SCLogDebug("not adding negated mpm as it's not 'single'"); } if (!skip) { PopulateMpmHelperAddPatternToPktCtx(ms->mpm_ctx, cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); } } } if (ms->mpm_ctx != NULL) { if (ms->mpm_ctx->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, ms->mpm_ctx); ms->mpm_ctx = NULL; } else { if (ms->sgh_mpm_context == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { if (mpm_table[ms->mpm_ctx->mpm_type].Prepare != NULL) { mpm_table[ms->mpm_ctx->mpm_type].Prepare(ms->mpm_ctx); } } } } }
/** * \brief Figured out the FP and their respective content ids for all the * sigs in the engine. * * \param de_ctx Detection engine context. * * \retval 0 On success. * \retval -1 On failure. */ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) { uint32_t struct_total_size = 0; uint32_t content_total_size = 0; Signature *s = NULL; /* Count the amount of memory needed to store all the structures * and the content of those structures. This will over estimate the * true size, since duplicates are removed below, but counted here. */ for (s = de_ctx->sig_list; s != NULL; s = s->next) { RetrieveFPForSig(s); if (s->mpm_sm != NULL) { DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; struct_total_size += sizeof(DetectFPAndItsId); content_total_size += cd->content_len; } } /* array hash buffer - i've run out of ideas to name it */ uint8_t *ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size)); if (unlikely(ahb == NULL)) return -1; uint8_t *content = NULL; uint8_t content_len = 0; PatIntId max_id = 0; DetectFPAndItsId *struct_offset = (DetectFPAndItsId *)ahb; uint8_t *content_offset = ahb + struct_total_size; for (s = de_ctx->sig_list; s != NULL; s = s->next) { if (s->mpm_sm != NULL) { int sm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); BUG_ON(sm_list == -1); DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; DetectFPAndItsId *dup = (DetectFPAndItsId *)ahb; if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { content = cd->content + cd->fp_chop_offset; content_len = cd->fp_chop_len; } else { content = cd->content; content_len = cd->content_len; } uint32_t flags = cd->flags & DETECT_CONTENT_NOCASE; /* Check for content already found on the same list */ for (; dup != struct_offset; dup++) { if (dup->content_len != content_len) continue; if (dup->sm_list != sm_list) continue; if (dup->flags != flags) continue; /* Check for pattern matching a duplicate. Use case insensitive matching * for case insensitive patterns. */ if (flags & DETECT_CONTENT_NOCASE) { if (SCMemcmpLowercase(dup->content, content, content_len) != 0) continue; } else { /* Case sensitive matching */ if (SCMemcmp(dup->content, content, content_len) != 0) continue; } /* Found a match with a previous pattern. */ break; } if (dup != struct_offset) { /* Exited for-loop before the end, so found an existing match. * Use its ID. */ cd->id = dup->id; continue; } /* Not found, so new content. Give it a new ID and add it * to the array. Copy the content at the end of the * content array. */ struct_offset->id = max_id++; cd->id = struct_offset->id; struct_offset->content_len = content_len; struct_offset->sm_list = sm_list; struct_offset->content = content_offset; struct_offset->flags = flags; content_offset += content_len; if (flags & DETECT_CONTENT_NOCASE) { /* Need to store case-insensitive patterns as lower case * because SCMemcmpLowercase() above assumes that all * patterns are stored lower case so that it doesn't * need to relower its first argument. */ memcpy_tolower(struct_offset->content, content, content_len); } else { memcpy(struct_offset->content, content, content_len); } struct_offset++; } /* if (s->mpm_sm != NULL) */ } /* for */ de_ctx->max_fp_id = max_id; SCFree(ahb); return 0; }
void EngineAnalysisFP(Signature *s, char *line) { int fast_pattern_set = 0; int fast_pattern_only_set = 0; int fast_pattern_chop_set = 0; DetectContentData *fp_cd = NULL; SigMatch *mpm_sm = s->mpm_sm; if (mpm_sm != NULL) { fp_cd = (DetectContentData *)mpm_sm->ctx; if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN) { fast_pattern_set = 1; if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { fast_pattern_only_set = 1; } else if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { fast_pattern_chop_set = 1; } } } fprintf(fp_engine_analysis_FD, "== Sid: %u ==\n", s->id); fprintf(fp_engine_analysis_FD, "%s\n", line); fprintf(fp_engine_analysis_FD, " Fast Pattern analysis:\n"); if (fp_cd == NULL) { fprintf(fp_engine_analysis_FD, " No content present\n"); fprintf(fp_engine_analysis_FD, "\n"); return; } fprintf(fp_engine_analysis_FD, " Fast pattern matcher: "); int list_type = SigMatchListSMBelongsTo(s, mpm_sm); if (list_type == DETECT_SM_LIST_PMATCH) fprintf(fp_engine_analysis_FD, "content\n"); else if (list_type == DETECT_SM_LIST_UMATCH) fprintf(fp_engine_analysis_FD, "http uri content\n"); else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(fp_engine_analysis_FD, "http raw uri content\n"); else if (list_type == DETECT_SM_LIST_HHDMATCH) fprintf(fp_engine_analysis_FD, "http header content\n"); else if (list_type == DETECT_SM_LIST_HRHDMATCH) fprintf(fp_engine_analysis_FD, "http raw header content\n"); else if (list_type == DETECT_SM_LIST_HMDMATCH) fprintf(fp_engine_analysis_FD, "http method content\n"); else if (list_type == DETECT_SM_LIST_HCDMATCH) fprintf(fp_engine_analysis_FD, "http cookie content\n"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(fp_engine_analysis_FD, "http client body content\n"); else if (list_type == DETECT_SM_LIST_HSBDMATCH) fprintf(fp_engine_analysis_FD, "http server body content\n"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) fprintf(fp_engine_analysis_FD, "http stat code content\n"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) fprintf(fp_engine_analysis_FD, "http stat msg content\n"); else if (list_type == DETECT_SM_LIST_HUADMATCH) fprintf(fp_engine_analysis_FD, "http user agent content\n"); int flags_set = 0; fprintf(fp_engine_analysis_FD, " Flags:"); if (fp_cd->flags & DETECT_CONTENT_OFFSET) { fprintf(fp_engine_analysis_FD, " Offset"); flags_set = 1; } if (fp_cd->flags & DETECT_CONTENT_DEPTH) { fprintf(fp_engine_analysis_FD, " Depth"); flags_set = 1; } if (fp_cd->flags & DETECT_CONTENT_WITHIN) { fprintf(fp_engine_analysis_FD, " Within"); flags_set = 1; } if (fp_cd->flags & DETECT_CONTENT_DISTANCE) { fprintf(fp_engine_analysis_FD, " Distance"); flags_set = 1; } if (fp_cd->flags & DETECT_CONTENT_NOCASE) { fprintf(fp_engine_analysis_FD, " Nocase"); flags_set = 1; } if (fp_cd->flags & DETECT_CONTENT_NEGATED) { fprintf(fp_engine_analysis_FD, " Negated"); flags_set = 1; } if (flags_set == 0) fprintf(fp_engine_analysis_FD, " None"); fprintf(fp_engine_analysis_FD, "\n"); fprintf(fp_engine_analysis_FD, " Fast pattern set: %s\n", fast_pattern_set ? "yes" : "no"); fprintf(fp_engine_analysis_FD, " Fast pattern only set: %s\n", fast_pattern_only_set ? "yes" : "no"); fprintf(fp_engine_analysis_FD, " Fast pattern chop set: %s\n", fast_pattern_chop_set ? "yes" : "no"); if (fast_pattern_chop_set) { fprintf(fp_engine_analysis_FD, " Fast pattern offset, length: %u, %u\n", fp_cd->fp_chop_offset, fp_cd->fp_chop_len); } uint16_t patlen = fp_cd->content_len; uint8_t *pat = SCMalloc(fp_cd->content_len + 1); if (unlikely(pat == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memcpy(pat, fp_cd->content, fp_cd->content_len); pat[fp_cd->content_len] = '\0'; fprintf(fp_engine_analysis_FD, " Original content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); if (fast_pattern_chop_set) { SCFree(pat); patlen = fp_cd->fp_chop_len; pat = SCMalloc(fp_cd->fp_chop_len + 1); if (unlikely(pat == NULL)) { exit(EXIT_FAILURE); } memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len); pat[fp_cd->fp_chop_len] = '\0'; fprintf(fp_engine_analysis_FD, " Final content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); } else { fprintf(fp_engine_analysis_FD, " Final content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); } SCFree(pat); fprintf(fp_engine_analysis_FD, "\n"); return; }
void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const Packet *p) { json_t *js = CreateJSONHeader(p, 0, "inspectedrules"); if (js == NULL) return; json_t *ir = json_object(); if (ir == NULL) return; json_object_set_new(ir, "rule_group_id", json_integer(det_ctx->sgh->id)); json_object_set_new(ir, "rule_cnt", json_integer(det_ctx->match_array_cnt)); json_t *js_array = json_array(); uint32_t x; for (x = 0; x < det_ctx->match_array_cnt; x++) { const Signature *s = det_ctx->match_array[x]; if (s == NULL) continue; json_t *js_sig = json_object(); if (unlikely(js == NULL)) continue; json_object_set_new(js_sig, "sig_id", json_integer(s->id)); json_object_set_new(js_sig, "mpm", (s->mpm_sm != NULL) ? json_true() : json_false()); if (s->mpm_sm != NULL) { char orig[256] = ""; char chop[256] = ""; DumpFp(s->mpm_sm, orig, sizeof(orig), chop, sizeof(chop)); json_object_set_new(js_sig, "mpm_buffer", json_string(DetectListToHumanString(SigMatchListSMBelongsTo(s, s->mpm_sm)))); json_object_set_new(js_sig, "mpm_pattern", json_string(orig)); if (strlen(chop) > 0) { json_object_set_new(js_sig, "mpm_pattern_chop", json_string(chop)); } } json_array_append_new(js_array, js_sig); } json_object_set_new(ir, "rules", js_array); json_object_set_new(js, "inspectedrules", ir); const char *filename = "packet_inspected_rules.json"; const char *log_dir = ConfigGetLogDirectory(); char log_path[PATH_MAX] = ""; snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename); MemBuffer *mbuf = NULL; mbuf = MemBufferCreateNew(4096); BUG_ON(mbuf == NULL); OutputJSONMemBufferWrapper wrapper = { .buffer = &mbuf, .expand_by = 4096, }; int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| JSON_ESCAPE_SLASH); if (r != 0) { SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object"); } else { MemBufferWriteString(mbuf, "\n"); SCMutexLock(&g_rule_dump_write_m); FILE *fp = fopen(log_path, "a"); if (fp != NULL) { MemBufferPrintToFPAsString(mbuf, fp); fclose(fp); SCMutexUnlock(&g_rule_dump_write_m); } } MemBufferFree(mbuf); json_object_clear(js); json_decref(js); }
/** * \brief Prints analysis of loaded rules. * * Warns if potential rule issues are detected. For example, * warns if a rule uses a construct that may perform poorly, * e.g. pcre without content or with http_method content only; * warns if a rule uses a construct that may not be consistent with intent, * e.g. client side ports only, http and content without any http_* modifiers, etc. * * \param s Pointer to the signature. */ void EngineAnalysisRules(Signature *s, char *line) { uint32_t rule_bidirectional = 0; uint32_t rule_pcre = 0; uint32_t rule_pcre_http = 0; uint32_t rule_content = 0; uint32_t rule_flow = 0; uint32_t rule_flags = 0; uint32_t rule_flow_toserver = 0; uint32_t rule_flow_toclient = 0; uint32_t rule_flow_nostream = 0; uint32_t rule_ipv4_only = 0; uint32_t rule_ipv6_only = 0; uint32_t rule_flowbits = 0; uint32_t rule_flowint = 0; //uint32_t rule_flowvar = 0; uint32_t rule_content_http = 0; uint32_t rule_content_offset_depth = 0; uint32_t list_id = 0; uint32_t rule_warning = 0; uint32_t raw_http_buf = 0; uint32_t norm_http_buf = 0; uint32_t stream_buf = 0; uint32_t packet_buf = 0; uint32_t http_header_buf = 0; uint32_t http_uri_buf = 0; uint32_t http_method_buf = 0; uint32_t http_cookie_buf = 0; uint32_t http_client_body_buf = 0; uint32_t http_server_body_buf = 0; uint32_t http_stat_code_buf = 0; uint32_t http_stat_msg_buf = 0; uint32_t http_raw_header_buf = 0; uint32_t http_raw_uri_buf = 0; uint32_t http_ua_buf = 0; uint32_t warn_pcre_no_content = 0; uint32_t warn_pcre_http_content = 0; uint32_t warn_pcre_http = 0; uint32_t warn_content_http_content = 0; uint32_t warn_content_http = 0; uint32_t warn_tcp_no_flow = 0; uint32_t warn_client_ports = 0; uint32_t warn_direction = 0; uint32_t warn_method_toclient = 0; uint32_t warn_method_serverbody = 0; uint32_t warn_pcre_method = 0; uint32_t warn_encoding_norm_http_buf = 0; uint32_t warn_offset_depth_pkt_stream = 0; uint32_t warn_offset_depth_alproto = 0; uint32_t warn_non_alproto_fp_for_alproto_sig = 0; if (s->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; } if (s->flags & SIG_FLAG_REQUIRE_PACKET) { packet_buf += 1; } if (s->flags & SIG_FLAG_REQUIRE_STREAM) { stream_buf += 1; } if (s->proto.flags & DETECT_PROTO_IPV4) { rule_ipv4_only += 1; } if (s->proto.flags & DETECT_PROTO_IPV6) { rule_ipv6_only += 1; } for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { SigMatch *sm = NULL; for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_PCRE) { if (list_id == DETECT_SM_LIST_HCBDMATCH) { rule_pcre_http += 1; http_client_body_buf += 1; raw_http_buf += 1; } else if (list_id == DETECT_SM_LIST_UMATCH) { rule_pcre_http += 1; norm_http_buf += 1; http_uri_buf += 1; } else if (list_id == DETECT_SM_LIST_HHDMATCH) { rule_pcre_http += 1; norm_http_buf += 1; http_header_buf += 1; } else if (list_id == DETECT_SM_LIST_HCDMATCH) { rule_pcre_http += 1; norm_http_buf += 1; http_cookie_buf += 1; } else if (list_id == DETECT_SM_LIST_HSBDMATCH) { rule_pcre_http += 1; http_server_body_buf += 1; raw_http_buf += 1; } else if (list_id == DETECT_SM_LIST_HRHDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_raw_header_buf += 1; } else if (list_id == DETECT_SM_LIST_HMDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_method_buf += 1; } else if (list_id == DETECT_SM_LIST_HRUDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_raw_uri_buf += 1; } else if (list_id == DETECT_SM_LIST_HSMDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_stat_msg_buf += 1; } else if (list_id == DETECT_SM_LIST_HSCDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_stat_code_buf += 1; } else if (list_id == DETECT_SM_LIST_HUADMATCH) { rule_pcre_http += 1; norm_http_buf += 1; http_ua_buf += 1; } else { rule_pcre += 1; } } else if (sm->type == DETECT_CONTENT) { if (list_id == DETECT_SM_LIST_UMATCH || list_id == DETECT_SM_LIST_HHDMATCH || list_id == DETECT_SM_LIST_HCDMATCH) { rule_content_http += 1; norm_http_buf += 1; DetectContentData *cd = (DetectContentData *)sm->ctx; if (cd != NULL && PerCentEncodingMatch(cd->content, cd->content_len) > 0) { warn_encoding_norm_http_buf += 1; rule_warning += 1; } if (list_id == DETECT_SM_LIST_UMATCH) { http_uri_buf += 1; } else if (list_id == DETECT_SM_LIST_HHDMATCH) { http_header_buf += 1; } else if (list_id == DETECT_SM_LIST_HCDMATCH) { http_cookie_buf += 1; } } else if (list_id == DETECT_SM_LIST_HCBDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_client_body_buf += 1; } else if (list_id == DETECT_SM_LIST_HSBDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_server_body_buf += 1; } else if (list_id == DETECT_SM_LIST_HRHDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_raw_header_buf += 1; } else if (list_id == DETECT_SM_LIST_HRUDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_raw_uri_buf += 1; } else if (list_id == DETECT_SM_LIST_HSMDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_stat_msg_buf += 1; } else if (list_id == DETECT_SM_LIST_HSCDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_stat_code_buf += 1; } else if (list_id == DETECT_SM_LIST_HMDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_method_buf += 1; } else if (list_id == DETECT_SM_LIST_PMATCH) { rule_content += 1; DetectContentData *cd = (DetectContentData *)sm->ctx; if (cd->flags & (DETECT_CONTENT_OFFSET | DETECT_CONTENT_DEPTH)) { rule_content_offset_depth++; } } } else if (sm->type == DETECT_FLOW) { rule_flow += 1; if ((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { rule_flow_toserver = 1; } else if ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) { rule_flow_toclient = 1; } DetectFlowData *fd = (DetectFlowData *)sm->ctx; if (fd != NULL) { if (fd->flags & FLOW_PKT_NOSTREAM) rule_flow_nostream = 1; } } else if (sm->type == DETECT_FLOWBITS) { if (list_id == DETECT_SM_LIST_MATCH) { rule_flowbits += 1; } } else if (sm->type == DETECT_FLOWINT) { if (list_id == DETECT_SM_LIST_MATCH) { rule_flowint += 1; } } else if (sm->type == DETECT_FLAGS) { DetectFlagsData *fd = (DetectFlagsData *)sm->ctx; if (fd != NULL) { rule_flags = 1; } } } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */ } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */ if (rule_pcre > 0 && rule_content == 0 && rule_content_http == 0) { rule_warning += 1; warn_pcre_no_content = 1; } if (rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0) { rule_warning += 1; warn_pcre_http_content = 1; } else if (s->alproto == ALPROTO_HTTP && rule_pcre > 0 && rule_pcre_http == 0) { rule_warning += 1; warn_pcre_http = 1; } if (rule_content > 0 && rule_content_http > 0) { rule_warning += 1; warn_content_http_content = 1; } if (s->alproto == ALPROTO_HTTP && rule_content > 0 && rule_content_http == 0) { rule_warning += 1; warn_content_http = 1; } if (rule_content == 1) { //todo: warning if content is weak, separate warning for pcre + weak content } if (rule_flow == 0 && rule_flags == 0 && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP) && (rule_content || rule_content_http || rule_pcre || rule_pcre_http || rule_flowbits)) { rule_warning += 1; warn_tcp_no_flow = 1; } if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient) && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) { if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY)) || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))) { rule_warning += 1; warn_client_ports = 1; } } if (rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)) { rule_warning += 1; warn_direction = 1; } if (http_method_buf) { if (rule_flow && rule_flow_toclient) { rule_warning += 1; warn_method_toclient = 1; } if (http_server_body_buf) { rule_warning += 1; warn_method_serverbody = 1; } if (rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)) { rule_warning += 1; warn_pcre_method = 1; } } if (rule_content_offset_depth > 0 && stream_buf && packet_buf) { rule_warning += 1; warn_offset_depth_pkt_stream = 1; } if (rule_content_offset_depth > 0 && !stream_buf && packet_buf && s->alproto != ALPROTO_UNKNOWN) { rule_warning += 1; warn_offset_depth_alproto = 1; } if (s->mpm_sm != NULL && s->alproto == ALPROTO_HTTP && SigMatchListSMBelongsTo(s, s->mpm_sm) == DETECT_SM_LIST_PMATCH) { rule_warning += 1; warn_non_alproto_fp_for_alproto_sig = 1; } if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) { fprintf(rule_engine_analysis_FD, "== Sid: %u ==\n", s->id); fprintf(rule_engine_analysis_FD, "%s\n", line); if (s->flags & SIG_FLAG_IPONLY) fprintf(rule_engine_analysis_FD, " Rule is ip only.\n"); if (rule_ipv6_only) fprintf(rule_engine_analysis_FD, " Rule is IPv6 only.\n"); if (rule_ipv4_only) fprintf(rule_engine_analysis_FD, " Rule is IPv4 only.\n"); if (packet_buf) fprintf(rule_engine_analysis_FD, " Rule matches on packets.\n"); if (!rule_flow_nostream && stream_buf && (rule_flow || rule_flowbits || rule_content || rule_pcre)) { fprintf(rule_engine_analysis_FD, " Rule matches on reassembled stream.\n"); } if (http_uri_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http uri buffer.\n"); if (http_header_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http header buffer.\n"); if (http_cookie_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http cookie buffer.\n"); if (http_raw_uri_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http raw uri buffer.\n"); if (http_raw_header_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http raw header buffer.\n"); if (http_method_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http method buffer.\n"); if (http_server_body_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http server body buffer.\n"); if (http_client_body_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http client body buffer.\n"); if (http_stat_msg_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http stat msg buffer.\n"); if (http_stat_code_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http stat code buffer.\n"); if (http_ua_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http user agent buffer.\n"); if (s->alproto != ALPROTO_UNKNOWN) { fprintf(rule_engine_analysis_FD, " App layer protocol is %s.\n", AppProtoToString(s->alproto)); } if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) { fprintf(rule_engine_analysis_FD, " Rule contains %d content options, %d http content options, %d pcre options, and %d pcre options with http modifiers.\n", rule_content, rule_content_http, rule_pcre, rule_pcre_http); } /* print fast pattern info */ EngineAnalysisRulesPrintFP(s); /* this is where the warnings start */ if (warn_pcre_no_content /*rule_pcre > 0 && rule_content == 0 && rule_content_http == 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses pcre without a content option present.\n" " -Consider adding a content to improve performance of this rule.\n"); } if (warn_pcre_http_content /*rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses content options with http_* and pcre options without http modifiers.\n" " -Consider adding http pcre modifier.\n"); } else if (warn_pcre_http /*s->alproto == ALPROTO_HTTP && rule_pcre > 0 && rule_pcre_http == 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule app layer protocol is http, but pcre options do not have http modifiers.\n" " -Consider adding http pcre modifiers.\n"); } if (warn_content_http_content /*rule_content > 0 && rule_content_http > 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule contains content with http_* and content without http_*.\n" " -Consider adding http content modifiers.\n"); } if (warn_content_http /*s->alproto == ALPROTO_HTTP && rule_content > 0 && rule_content_http == 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule app layer protocol is http, but content options do not have http_* modifiers.\n" " -Consider adding http content modifiers.\n"); } if (rule_content == 1) { //todo: warning if content is weak, separate warning for pcre + weak content } if (warn_encoding_norm_http_buf) { fprintf(rule_engine_analysis_FD, " Warning: Rule may contain percent encoded content for a normalized http buffer match.\n"); } if (warn_tcp_no_flow /*rule_flow == 0 && rule_flow == 0 && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP)*/) { fprintf(rule_engine_analysis_FD, " Warning: TCP rule without a flow or flags option.\n" " -Consider adding flow or flags to improve performance of this rule.\n"); } if (warn_client_ports /*rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient) && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY)) || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule contains ports or port variables only on the client side.\n" " -Flow direction possibly inconsistent with rule.\n"); } if (warn_direction /*rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule is bidirectional and has a flow option with a specific direction.\n"); } if (warn_method_toclient /*http_method_buf && rule_flow && rule_flow_toclient*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses content or pcre for http_method with flow:to_client or from_server\n"); } if (warn_method_serverbody /*http_method_buf && http_server_body_buf*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses content or pcre for http_method with content or pcre for http_server_body.\n"); } if (warn_pcre_method /*http_method_buf && rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses pcre with only a http_method content; possible performance issue.\n"); } if (warn_offset_depth_pkt_stream) { fprintf(rule_engine_analysis_FD, " Warning: Rule has depth" "/offset with raw content keywords. Please note the " "offset/depth will be checked against both packet " "payloads and stream. If you meant to have the offset/" "depth checked against just the payload, you can update " "the signature as \"alert tcp-pkt...\"\n"); } if (warn_offset_depth_alproto) { fprintf(rule_engine_analysis_FD, " Warning: Rule has " "offset/depth set along with a match on a specific " "app layer protocol - %d. This can lead to FNs if we " "have a offset/depth content match on a packet payload " "before we can detect the app layer protocol for the " "flow.\n", s->alproto); } if (warn_non_alproto_fp_for_alproto_sig) { fprintf(rule_engine_analysis_FD, " Warning: Rule app layer " "protocol is http, but the fast_pattern is set on the raw " "stream. Consider adding fast_pattern over a http " "buffer for increased performance."); } if (rule_warning == 0) { fprintf(rule_engine_analysis_FD, " No warnings for this rule.\n"); } fprintf(rule_engine_analysis_FD, "\n"); } return; }
static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr) { SigMatch *sm = NULL; SigMatch *prev_pm = NULL; DetectBytejumpData *data = NULL; char *offset = NULL; int ret = -1; data = DetectBytejumpParse(optstr, &offset); if (data == NULL) goto error; int sm_list; if (s->init_data->list != DETECT_SM_LIST_NOTSET) { sm_list = s->init_data->list; if (data->flags & DETECT_BYTEJUMP_RELATIVE) { prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (data->flags & DETECT_BYTEJUMP_DCE) { if (data->flags & DETECT_BYTEJUMP_RELATIVE) { prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { sm_list = SigMatchListSMBelongsTo(s, prev_pm); if (sm_list < 0) goto error; } } else { sm_list = DETECT_SM_LIST_PMATCH; } if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) goto error; } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) { prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { sm_list = SigMatchListSMBelongsTo(s, prev_pm); if (sm_list < 0) goto error; } } else { sm_list = DETECT_SM_LIST_PMATCH; } if (data->flags & DETECT_BYTEJUMP_DCE) { if ((data->flags & DETECT_BYTEJUMP_STRING) || (data->flags & DETECT_BYTEJUMP_LITTLE) || (data->flags & DETECT_BYTEJUMP_BIG) || (data->flags & DETECT_BYTEJUMP_BEGIN) || (data->base == DETECT_BYTEJUMP_BASE_DEC) || (data->base == DETECT_BYTEJUMP_BASE_HEX) || (data->base == DETECT_BYTEJUMP_BASE_OCT) ) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " "A byte_jump keyword with dce holds other invalid modifiers."); goto error; } } if (offset != NULL) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in byte_jump - %s\n", offset); goto error; } data->offset = ((DetectByteExtractData *)bed_sm->ctx)->local_id; data->flags |= DETECT_BYTEJUMP_OFFSET_BE; SCFree(offset); } sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_BYTEJUMP; sm->ctx = (SigMatchCtx *)data; SigMatchAppendSMToList(s, sm, sm_list); if (!(data->flags & DETECT_BYTEJUMP_RELATIVE)) goto okay; 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 *pd = (DetectPcreData *)prev_pm->ctx; pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } okay: ret = 0; return ret; error: DetectBytejumpFree(data); return ret; }