/** * \brief Do the content inspection & validation for a signature * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param f flow (for pcre flowvar storage) * \param p Packet * * \retval 0 no match * \retval 1 match */ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, Packet *p) { SCEnter(); int r = 0; if (s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL) { SCReturnInt(0); } #ifdef DEBUG det_ctx->payload_persig_cnt++; det_ctx->payload_persig_size += p->payload_len; #endif det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; det_ctx->replist = NULL; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[DETECT_SM_LIST_PMATCH], f, p->payload, p->payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD, p); if (r == 1) { SCReturnInt(1); } SCReturnInt(0); }
/** * \brief Do the content inspection & validation for a signature for a stream chunk * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param f flow (for pcre flowvar storage) * \param payload ptr to the payload to inspect * \param payload_len length of the payload * * \retval 0 no match * \retval 1 match * * \todo we might also pass the packet to this function for the pktvar * storage. Only, would that be right? We're not inspecting data * from the current packet here. */ int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t *payload, uint32_t payload_len) { SCEnter(); int r = 0; if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { SCReturnInt(0); } det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], f, payload, payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, NULL); //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], NULL, f, payload, payload_len); //det_ctx->flags &= ~DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM; if (r == 1) { SCReturnInt(1); } SCReturnInt(0); }
/** * \brief Do the content inspection & validation for a signature * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param f flow (for pcre flowvar storage) * \param flags app layer flags * \param state App layer state * \param p Packet * * \retval 0 no match * \retval 1 match */ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, Packet *p) { SCEnter(); int r = 0; if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { SCReturnInt(0); } det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; det_ctx->replist = NULL; //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], f, p->payload, p->payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD, p); //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], p, f, p->payload, p->payload_len); //det_ctx->flags &= ~DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; if (r == 1) { SCReturnInt(1); } SCReturnInt(0); }
/** * \brief Do the http_method content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpMethod(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate) { SCEnter(); int r = 0; HtpState *htp_state = NULL; htp_tx_t *tx = NULL; int idx; FLOWLOCK_RDLOCK(f); htp_state = (HtpState *)alstate; if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL || tx->request_method == NULL) continue; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HMDMATCH], f, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method), DETECT_ENGINE_CONTENT_INSPECTION_MODE_HMD, NULL); //r = DoInspectHttpMethod(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HMDMATCH], //(uint8_t *)bstr_ptr(tx->request_method), //bstr_len(tx->request_method)); if (r == 1) { break; } } end: FLOWLOCK_UNLOCK(f); SCReturnInt(r); }
static int InspectEngineHttpStart( DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { const int list_id = engine->sm_list; InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); if (buffer->inspect == NULL) { SCLogDebug("setting up inspect buffer %d", list_id); /* if prefilter didn't already run, we need to consider transformations */ const DetectEngineTransforms *transforms = NULL; if (!engine->mpm) { transforms = engine->v2.transforms; } uint32_t rawdata_len = 0; uint8_t *rawdata = GetBufferForTX(txv, tx_id, det_ctx, f, flags, &rawdata_len); if (rawdata_len == 0) { SCLogDebug("no data"); goto end; } /* setup buffer and apply transforms */ InspectionBufferSetup(buffer, rawdata, rawdata_len); InspectionBufferApplyTransforms(buffer, transforms); } const uint32_t data_len = buffer->inspect_len; const uint8_t *data = buffer->inspect; const uint64_t offset = buffer->inspect_offset; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, (uint8_t *)data, data_len, offset, DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; end: if (flags & STREAM_TOSERVER) { if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } else { if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_RESPONSE_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; }
int DetectBase64DataDoMatch(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f) { if (det_ctx->base64_decoded_len) { return DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_BASE64_DATA], f, det_ctx->base64_decoded, det_ctx->base64_decoded_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } return 0; }
int DetectEngineInspectTemplateBuffer(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { TemplateTransaction *tx = (TemplateTransaction *)txv; int ret = 0; if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { ret = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, tx->request_buffer, tx->request_buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { ret = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, tx->response_buffer, tx->response_buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); } SCLogNotice("Returning %d.", ret); return ret; }
int DetectEngineInspectSMTPFiledata(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { SMTPState *smtp_state = (SMTPState *)alstate; FileContainer *ffc = smtp_state->files_ts; int r = 0; int match = 0; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; const uint8_t *buffer = 0; if (ffc != NULL) { File *file = ffc->head; for (; file != NULL; file = file->next) { buffer = DetectEngineSMTPGetBufferForTX(tx_id, de_ctx, det_ctx, f, file, flags, &buffer_len, &stream_start_offset); if (buffer_len == 0) goto end; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; match = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_FILEDATA], f, (uint8_t *)buffer, buffer_len, stream_start_offset, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (match == 1) r = 1; } } end: if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; }
/** * \brief Do the content inspection & validation for a signature * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param sm SigMatch to inspect * \param f Flow * \param flags app layer flags * \param state App layer state * * \retval 0 no match. * \retval 1 match. * \retval 2 Sig can't match. */ int DetectEngineInspectHttpResponseLine(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->response_line == NULL) { if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_RESPONSE_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; #if 0 PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx->response_line), bstr_len(tx->response_line)); #endif /* run the inspection against the buffer */ int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HTTP_RESLINEMATCH], f, bstr_ptr(tx->response_line), bstr_len(tx->response_line), 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) { return DETECT_ENGINE_INSPECT_SIG_MATCH; } else { return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } }
static int StreamContentInspectEngineFunc(void *cb_data, const uint8_t *data, const uint32_t data_len) { SCEnter(); int r = 0; struct StreamContentInspectEngineData *smd = cb_data; #ifdef DEBUG smd->det_ctx->stream_persig_cnt++; smd->det_ctx->stream_persig_size += data_len; #endif smd->det_ctx->buffer_offset = 0; smd->det_ctx->discontinue_matching = 0; smd->det_ctx->inspection_recursion_counter = 0; r = DetectEngineContentInspection(smd->de_ctx, smd->det_ctx, smd->s, smd->smd, smd->f, (uint8_t *)data, data_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, NULL); if (r == 1) { SCReturnInt(1); } SCReturnInt(0); }
static int DetectEngineInspectDnsQuery( DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { int local_id = 0; const DetectEngineTransforms *transforms = NULL; if (!engine->mpm) { transforms = engine->v2.transforms; } while(1) { struct DnsQueryGetDataArgs cbdata = { local_id, txv, }; InspectionBuffer *buffer = DnsQueryGetData(det_ctx, transforms, f, &cbdata, engine->sm_list, false); if (buffer == NULL || buffer->inspect == NULL) break; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; const int match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); if (match == 1) { return DETECT_ENGINE_INSPECT_SIG_MATCH; } local_id++; } return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; }
/** \brief Do the content inspection and validation for a signature * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param sm SigMatch to inspect * \param f Flow * \param flags App layer flags * \param state App layer state * * \retval 0 No match * \retval 1 Match */ int DetectEngineInspectTlsSni(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *buffer; uint16_t buffer_len; int cnt = 0; SSLState *ssl_state = (SSLState *)alstate; if (ssl_state->client_connp.sni == NULL) return 0; buffer = (uint8_t *)ssl_state->client_connp.sni; buffer_len = strlen(ssl_state->client_connp.sni); cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_TLSSNI_MATCH], f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); return cnt; }
/** * \brief Run the actual payload match functions * * The following keywords are inspected: * - content, including all the http and dce modified contents * - isdaatat * - pcre * - bytejump * - bytetest * - byte_extract * - urilen * - * * All keywords are evaluated against the buffer with buffer_len. * * For accounting the last match in relative matching the * det_ctx->buffer_offset int is used. * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param sm SigMatch to inspect * \param f Flow (for pcre flowvar storage) * \param buffer Ptr to the buffer to inspect * \param buffer_len Length of the payload * \param stream_start_offset Indicates the start of the current buffer in * the whole buffer stream inspected. This * applies if the current buffer is inspected * in chunks. * \param inspection_mode Refers to the engine inspection mode we are currently * inspecting. Can be payload, stream, one of the http * buffer inspection modes or dce inspection mode. * \param data Used to send some custom data. For example in * payload inspection mode, data contains packet ptr, * and under dce inspection mode, contains dce state. * * \retval 0 no match * \retval 1 match */ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, uint8_t inspection_mode, void *data) { SCEnter(); KEYWORD_PROFILING_START; det_ctx->inspection_recursion_counter++; if (det_ctx->inspection_recursion_counter == de_ctx->inspection_recursion_limit) { det_ctx->discontinue_matching = 1; KEYWORD_PROFILING_END(det_ctx, sm->type, 0); SCReturnInt(0); } if (sm == NULL || buffer_len == 0) { KEYWORD_PROFILING_END(det_ctx, sm->type, 0); SCReturnInt(0); } /* \todo unify this which is phase 2 of payload inspection unification */ if (sm->type == DETECT_CONTENT) { DetectContentData *cd = (DetectContentData *)sm->ctx; SCLogDebug("inspecting content %"PRIu32" buffer_len %"PRIu32, cd->id, buffer_len); /* we might have already have this content matched by the mpm. * (if there is any other reason why we'd want to avoid checking * it here, please fill it in) */ //if (cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED) { // goto match; //} /* rule parsers should take care of this */ #ifdef DEBUG BUG_ON(cd->depth != 0 && cd->depth <= cd->offset); #endif /* search for our pattern, checking the matches recursively. * if we match we look for the next SigMatch as well */ uint8_t *found = NULL; uint32_t offset = 0; uint32_t depth = buffer_len; uint32_t prev_offset = 0; /**< used in recursive searching */ uint32_t prev_buffer_offset = det_ctx->buffer_offset; do { if ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN)) { SCLogDebug("det_ctx->buffer_offset %"PRIu32, det_ctx->buffer_offset); offset = prev_buffer_offset; depth = buffer_len; int distance = cd->distance; if (cd->flags & DETECT_CONTENT_DISTANCE) { if (cd->flags & DETECT_CONTENT_DISTANCE_BE) { distance = det_ctx->bj_values[cd->distance]; } if (distance < 0 && (uint32_t)(abs(distance)) > offset) offset = 0; else offset += distance; SCLogDebug("cd->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32, distance, offset, depth); } if (cd->flags & DETECT_CONTENT_WITHIN) { if (cd->flags & DETECT_CONTENT_WITHIN_BE) { if ((int32_t)depth > (int32_t)(prev_buffer_offset + det_ctx->bj_values[cd->within] + distance)) { depth = prev_buffer_offset + det_ctx->bj_values[cd->within] + distance; } } else { if ((int32_t)depth > (int32_t)(prev_buffer_offset + cd->within + distance)) { depth = prev_buffer_offset + cd->within + distance; } SCLogDebug("cd->within %"PRIi32", det_ctx->buffer_offset %"PRIu32", depth %"PRIu32, cd->within, prev_buffer_offset, depth); } if (stream_start_offset != 0 && prev_buffer_offset == 0) { if (depth <= stream_start_offset) { goto no_match; } else if (depth >= (stream_start_offset + buffer_len)) { ; } else { depth = depth - stream_start_offset; } } } if (cd->flags & DETECT_CONTENT_DEPTH_BE) { if ((det_ctx->bj_values[cd->depth] + prev_buffer_offset) < depth) { depth = prev_buffer_offset + det_ctx->bj_values[cd->depth]; } } else { if (cd->depth != 0) { if ((cd->depth + prev_buffer_offset) < depth) { depth = prev_buffer_offset + cd->depth; } SCLogDebug("cd->depth %"PRIu32", depth %"PRIu32, cd->depth, depth); } } if (cd->flags & DETECT_CONTENT_OFFSET_BE) { if (det_ctx->bj_values[cd->offset] > offset) offset = det_ctx->bj_values[cd->offset]; } else { if (cd->offset > offset) { offset = cd->offset; SCLogDebug("setting offset %"PRIu32, offset); } } } else { /* implied no relative matches */ /* set depth */ if (cd->flags & DETECT_CONTENT_DEPTH_BE) { depth = det_ctx->bj_values[cd->depth]; } else { if (cd->depth != 0) { depth = cd->depth; } } if (stream_start_offset != 0 && cd->flags & DETECT_CONTENT_DEPTH) { if (depth <= stream_start_offset) { goto no_match; } else if (depth >= (stream_start_offset + buffer_len)) { ; } else { depth = depth - stream_start_offset; } } /* set offset */ if (cd->flags & DETECT_CONTENT_OFFSET_BE) offset = det_ctx->bj_values[cd->offset]; else offset = cd->offset; prev_buffer_offset = 0; } /* update offset with prev_offset if we're searching for * matches after the first occurence. */ SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, offset, prev_offset); if (prev_offset != 0) offset = prev_offset; SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth); if (depth > buffer_len) depth = buffer_len; /* if offset is bigger than depth we can never match on a pattern. * We can however, "match" on a negated pattern. */ if (offset > depth || depth == 0) { if (cd->flags & DETECT_CONTENT_NEGATED) { goto match; } else { goto no_match; } } uint8_t *sbuffer = buffer + offset; uint32_t sbuffer_len = depth - offset; uint32_t match_offset = 0; SCLogDebug("sbuffer_len %"PRIu32, sbuffer_len); #ifdef DEBUG BUG_ON(sbuffer_len > buffer_len); #endif /* \todo Add another optimization here. If cd->content_len is * greater than sbuffer_len found is anyways NULL */ /* do the actual search */ if (cd->flags & DETECT_CONTENT_NOCASE) found = BoyerMooreNocase(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx->bmGs, cd->bm_ctx->bmBc); else found = BoyerMoore(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx->bmGs, cd->bm_ctx->bmBc); /* next we evaluate the result in combination with the * negation flag. */ SCLogDebug("found %p cd negated %s", found, cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); if (found == NULL && !(cd->flags & DETECT_CONTENT_NEGATED)) { goto no_match; } else if (found == NULL && (cd->flags & DETECT_CONTENT_NEGATED)) { goto match; } else if (found != NULL && (cd->flags & DETECT_CONTENT_NEGATED)) { SCLogDebug("content %"PRIu32" matched at offset %"PRIu32", but negated so no match", cd->id, match_offset); /* don't bother carrying recursive matches now, for preceding * relative keywords */ if (DETECT_CONTENT_IS_SINGLE(cd)) det_ctx->discontinue_matching = 1; goto no_match; } else { match_offset = (uint32_t)((found - buffer) + cd->content_len); SCLogDebug("content %"PRIu32" matched at offset %"PRIu32"", cd->id, match_offset); det_ctx->buffer_offset = match_offset; /* Match branch, add replace to the list if needed */ if (cd->flags & DETECT_CONTENT_REPLACE) { if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) { /* we will need to replace content if match is confirmed */ det_ctx->replist = DetectReplaceAddToList(det_ctx->replist, found, cd); } else { SCLogWarning(SC_ERR_INVALID_VALUE, "Can't modify payload without packet"); } } if (!(cd->flags & DETECT_CONTENT_RELATIVE_NEXT)) { SCLogDebug("no relative match coming up, so this is a match"); goto match; } /* bail out if we have no next match. Technically this is an * error, as the current cd has the DETECT_CONTENT_RELATIVE_NEXT * flag set. */ if (sm->next == NULL) { goto no_match; } SCLogDebug("content %"PRIu32, cd->id); KEYWORD_PROFILING_END(det_ctx, sm->type, 1); /* see if the next buffer keywords match. If not, we will * search for another occurence of this content and see * if the others match then until we run out of matches */ int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } if (det_ctx->discontinue_matching) goto no_match; /* set the previous match offset to the start of this match + 1 */ prev_offset = (match_offset - (cd->content_len - 1)); SCLogDebug("trying to see if there is another match after prev_offset %"PRIu32, prev_offset); } } while(1); } else if (sm->type == DETECT_ISDATAAT) { SCLogDebug("inspecting isdataat"); DetectIsdataatData *id = (DetectIsdataatData *)sm->ctx; if (id->flags & ISDATAAT_RELATIVE) { if (det_ctx->buffer_offset + id->dataat > buffer_len) { SCLogDebug("det_ctx->buffer_offset + id->dataat %"PRIu32" > %"PRIu32, det_ctx->buffer_offset + id->dataat, buffer_len); if (id->flags & ISDATAAT_NEGATED) goto match; goto no_match; } else { SCLogDebug("relative isdataat match"); if (id->flags & ISDATAAT_NEGATED) goto no_match; goto match; } } else { if (id->dataat < buffer_len) { SCLogDebug("absolute isdataat match"); if (id->flags & ISDATAAT_NEGATED) goto no_match; goto match; } else { SCLogDebug("absolute isdataat mismatch, id->isdataat %"PRIu32", buffer_len %"PRIu32"", id->dataat, buffer_len); if (id->flags & ISDATAAT_NEGATED) goto match; goto no_match; } } } else if (sm->type == DETECT_PCRE) { SCLogDebug("inspecting pcre"); DetectPcreData *pe = (DetectPcreData *)sm->ctx; uint32_t prev_buffer_offset = det_ctx->buffer_offset; uint32_t prev_offset = 0; int r = 0; det_ctx->pcre_match_start_offset = 0; do { Packet *p = NULL; if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) p = (Packet *)data; r = DetectPcrePayloadMatch(det_ctx, s, sm, p, f, buffer, buffer_len); if (r == 0) { goto no_match; } if (!(pe->flags & DETECT_PCRE_RELATIVE_NEXT)) { SCLogDebug("no relative match coming up, so this is a match"); goto match; } KEYWORD_PROFILING_END(det_ctx, sm->type, 1); /* save it, in case we need to do a pcre match once again */ prev_offset = det_ctx->pcre_match_start_offset; /* see if the next payload keywords match. If not, we will * search for another occurence of this pcre and see * if the others match, until we run out of matches */ r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } if (det_ctx->discontinue_matching) goto no_match; det_ctx->buffer_offset = prev_buffer_offset; det_ctx->pcre_match_start_offset = prev_offset; } while (1); } else if (sm->type == DETECT_BYTETEST) { DetectBytetestData *btd = (DetectBytetestData *)sm->ctx; uint8_t flags = btd->flags; int32_t offset = btd->offset; uint64_t value = btd->value; if (flags & DETECT_BYTETEST_OFFSET_BE) { offset = det_ctx->bj_values[offset]; } if (flags & DETECT_BYTETEST_VALUE_BE) { value = det_ctx->bj_values[value]; } /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if (flags & DETECT_BYTETEST_DCE) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ flags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ? DETECT_BYTETEST_LITTLE: 0); } if (DetectBytetestDoMatch(det_ctx, s, sm, buffer, buffer_len, flags, offset, value) != 1) { goto no_match; } goto match; } else if (sm->type == DETECT_BYTEJUMP) { DetectBytejumpData *bjd = (DetectBytejumpData *)sm->ctx; uint8_t flags = bjd->flags; int32_t offset = bjd->offset; if (flags & DETECT_BYTEJUMP_OFFSET_BE) { offset = det_ctx->bj_values[offset]; } /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if (flags & DETECT_BYTEJUMP_DCE) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ flags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ? DETECT_BYTEJUMP_LITTLE: 0); } if (DetectBytejumpDoMatch(det_ctx, s, sm, buffer, buffer_len, flags, offset) != 1) { goto no_match; } goto match; } else if (sm->type == DETECT_BYTE_EXTRACT) { DetectByteExtractData *bed = (DetectByteExtractData *)sm->ctx; uint8_t endian = bed->endian; /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if ((bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) && endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ endian |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] == 0x10) ? DETECT_BYTE_EXTRACT_ENDIAN_LITTLE : DETECT_BYTE_EXTRACT_ENDIAN_BIG); } if (DetectByteExtractDoMatch(det_ctx, sm, s, buffer, buffer_len, &det_ctx->bj_values[bed->local_id], endian) != 1) { goto no_match; } goto match; /* we should never get here, but bail out just in case */ } else if (sm->type == DETECT_AL_URILEN) { SCLogDebug("inspecting uri len"); int r = 0; DetectUrilenData *urilend = (DetectUrilenData *) sm->ctx; switch (urilend->mode) { case DETECT_URILEN_EQ: if (buffer_len == urilend->urilen1) r = 1; break; case DETECT_URILEN_LT: if (buffer_len < urilend->urilen1) r = 1; break; case DETECT_URILEN_GT: if (buffer_len > urilend->urilen1) r = 1; break; case DETECT_URILEN_RA: if (buffer_len > urilend->urilen1 && buffer_len < urilend->urilen2) { r = 1; } break; } if (r == 1) { goto match; } det_ctx->discontinue_matching = 0; goto no_match; #ifdef HAVE_LUAJIT } else if (sm->type == DETECT_LUAJIT) { /* for flowvar gets and sets we need to know the flow's lock status */ int need_flow_lock = 0; if (inspection_mode <= DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM) need_flow_lock = 1; if (DetectLuajitMatchBuffer(det_ctx, s, sm, buffer, buffer_len, det_ctx->buffer_offset, f, need_flow_lock) != 1) { goto no_match; } goto match; #endif } else { SCLogDebug("sm->type %u", sm->type); #ifdef DEBUG BUG_ON(1); #endif } no_match: KEYWORD_PROFILING_END(det_ctx, sm->type, 0); SCReturnInt(0); match: /* this sigmatch matched, inspect the next one. If it was the last, * the buffer portion of the signature matched. */ if (sm->next != NULL) { KEYWORD_PROFILING_END(det_ctx, sm->type, 1); int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); SCReturnInt(r); } else { KEYWORD_PROFILING_END(det_ctx, sm->type, 1); SCReturnInt(1); } }
/** * \brief Run the actual payload match functions * * The following keywords are inspected: * - content, including all the http and dce modified contents * - isdaatat * - pcre * - bytejump * - bytetest * - byte_extract * - urilen * - * * All keywords are evaluated against the buffer with buffer_len. * * For accounting the last match in relative matching the * det_ctx->buffer_offset int is used. * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param sm SigMatch to inspect * \param f Flow (for pcre flowvar storage) * \param buffer Ptr to the buffer to inspect * \param buffer_len Length of the payload * \param stream_start_offset Indicates the start of the current buffer in * the whole buffer stream inspected. This * applies if the current buffer is inspected * in chunks. * \param inspection_mode Refers to the engine inspection mode we are currently * inspecting. Can be payload, stream, one of the http * buffer inspection modes or dce inspection mode. * \param data Used to send some custom data. For example in * payload inspection mode, data contains packet ptr, * and under dce inspection mode, contains dce state. * * \retval 0 no match * \retval 1 match */ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, uint8_t flags, uint8_t inspection_mode, void *data) { SCEnter(); KEYWORD_PROFILING_START; det_ctx->inspection_recursion_counter++; if (det_ctx->inspection_recursion_counter == de_ctx->inspection_recursion_limit) { det_ctx->discontinue_matching = 1; KEYWORD_PROFILING_END(det_ctx, smd->type, 0); SCReturnInt(0); } if (smd == NULL || buffer_len == 0) { KEYWORD_PROFILING_END(det_ctx, smd->type, 0); SCReturnInt(0); } /* \todo unify this which is phase 2 of payload inspection unification */ if (smd->type == DETECT_CONTENT) { DetectContentData *cd = (DetectContentData *)smd->ctx; SCLogDebug("inspecting content %"PRIu32" buffer_len %"PRIu32, cd->id, buffer_len); /* we might have already have this content matched by the mpm. * (if there is any other reason why we'd want to avoid checking * it here, please fill it in) */ //if (cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED) { // goto match; //} /* rule parsers should take care of this */ #ifdef DEBUG BUG_ON(cd->depth != 0 && cd->depth <= cd->offset); #endif /* search for our pattern, checking the matches recursively. * if we match we look for the next SigMatch as well */ uint8_t *found = NULL; uint32_t offset = 0; uint32_t depth = buffer_len; uint32_t prev_offset = 0; /**< used in recursive searching */ uint32_t prev_buffer_offset = det_ctx->buffer_offset; do { if ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN)) { SCLogDebug("det_ctx->buffer_offset %"PRIu32, det_ctx->buffer_offset); offset = prev_buffer_offset; depth = buffer_len; int distance = cd->distance; if (cd->flags & DETECT_CONTENT_DISTANCE) { if (cd->flags & DETECT_CONTENT_DISTANCE_BE) { distance = det_ctx->bj_values[cd->distance]; } if (distance < 0 && (uint32_t)(abs(distance)) > offset) offset = 0; else offset += distance; SCLogDebug("cd->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32, distance, offset, depth); } if (cd->flags & DETECT_CONTENT_WITHIN) { if (cd->flags & DETECT_CONTENT_WITHIN_BE) { if ((int32_t)depth > (int32_t)(prev_buffer_offset + det_ctx->bj_values[cd->within] + distance)) { depth = prev_buffer_offset + det_ctx->bj_values[cd->within] + distance; } } else { if ((int32_t)depth > (int32_t)(prev_buffer_offset + cd->within + distance)) { depth = prev_buffer_offset + cd->within + distance; } SCLogDebug("cd->within %"PRIi32", det_ctx->buffer_offset %"PRIu32", depth %"PRIu32, cd->within, prev_buffer_offset, depth); } if (stream_start_offset != 0 && prev_buffer_offset == 0) { if (depth <= stream_start_offset) { goto no_match; } else if (depth >= (stream_start_offset + buffer_len)) { ; } else { depth = depth - stream_start_offset; } } } if (cd->flags & DETECT_CONTENT_DEPTH_BE) { if ((det_ctx->bj_values[cd->depth] + prev_buffer_offset) < depth) { depth = prev_buffer_offset + det_ctx->bj_values[cd->depth]; } } else { if (cd->depth != 0) { if ((cd->depth + prev_buffer_offset) < depth) { depth = prev_buffer_offset + cd->depth; } SCLogDebug("cd->depth %"PRIu32", depth %"PRIu32, cd->depth, depth); } } if (cd->flags & DETECT_CONTENT_OFFSET_BE) { if (det_ctx->bj_values[cd->offset] > offset) offset = det_ctx->bj_values[cd->offset]; } else { if (cd->offset > offset) { offset = cd->offset; SCLogDebug("setting offset %"PRIu32, offset); } } } else { /* implied no relative matches */ /* set depth */ if (cd->flags & DETECT_CONTENT_DEPTH_BE) { depth = det_ctx->bj_values[cd->depth]; } else { if (cd->depth != 0) { depth = cd->depth; } } if (stream_start_offset != 0 && cd->flags & DETECT_CONTENT_DEPTH) { if (depth <= stream_start_offset) { goto no_match; } else if (depth >= (stream_start_offset + buffer_len)) { ; } else { depth = depth - stream_start_offset; } } /* set offset */ if (cd->flags & DETECT_CONTENT_OFFSET_BE) offset = det_ctx->bj_values[cd->offset]; else offset = cd->offset; prev_buffer_offset = 0; } /* update offset with prev_offset if we're searching for * matches after the first occurence. */ SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, offset, prev_offset); if (prev_offset != 0) offset = prev_offset; SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth); if (depth > buffer_len) depth = buffer_len; /* if offset is bigger than depth we can never match on a pattern. * We can however, "match" on a negated pattern. */ if (offset > depth || depth == 0) { if (cd->flags & DETECT_CONTENT_NEGATED) { goto match; } else { goto no_match; } } uint8_t *sbuffer = buffer + offset; uint32_t sbuffer_len = depth - offset; uint32_t match_offset = 0; SCLogDebug("sbuffer_len %"PRIu32, sbuffer_len); #ifdef DEBUG BUG_ON(sbuffer_len > buffer_len); #endif if (cd->flags & DETECT_CONTENT_ENDS_WITH && depth < buffer_len) { SCLogDebug("depth < buffer_len while DETECT_CONTENT_ENDS_WITH is set. Can't possibly match."); found = NULL; } else if (cd->content_len > sbuffer_len) { found = NULL; } else { /* do the actual search */ found = SpmScan(cd->spm_ctx, det_ctx->spm_thread_ctx, sbuffer, sbuffer_len); } /* next we evaluate the result in combination with the * negation flag. */ SCLogDebug("found %p cd negated %s", found, cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); if (found == NULL && !(cd->flags & DETECT_CONTENT_NEGATED)) { if ((cd->flags & (DETECT_CONTENT_DISTANCE|DETECT_CONTENT_WITHIN)) == 0) { /* independent match from previous matches, so failure is fatal */ det_ctx->discontinue_matching = 1; } goto no_match; } else if (found == NULL && (cd->flags & DETECT_CONTENT_NEGATED)) { goto match; } else if (found != NULL && (cd->flags & DETECT_CONTENT_NEGATED)) { SCLogDebug("content %"PRIu32" matched at offset %"PRIu32", but negated so no match", cd->id, match_offset); /* don't bother carrying recursive matches now, for preceding * relative keywords */ if (DETECT_CONTENT_IS_SINGLE(cd)) det_ctx->discontinue_matching = 1; goto no_match; } else { match_offset = (uint32_t)((found - buffer) + cd->content_len); SCLogDebug("content %"PRIu32" matched at offset %"PRIu32"", cd->id, match_offset); det_ctx->buffer_offset = match_offset; if ((cd->flags & DETECT_CONTENT_ENDS_WITH) == 0 || match_offset == buffer_len) { /* Match branch, add replace to the list if needed */ if (cd->flags & DETECT_CONTENT_REPLACE) { if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) { /* we will need to replace content if match is confirmed */ det_ctx->replist = DetectReplaceAddToList(det_ctx->replist, found, cd); } else { SCLogWarning(SC_ERR_INVALID_VALUE, "Can't modify payload without packet"); } } /* if this is the last match we're done */ if (smd->is_last) { goto match; } SCLogDebug("content %"PRIu32, cd->id); KEYWORD_PROFILING_END(det_ctx, smd->type, 1); /* see if the next buffer keywords match. If not, we will * search for another occurence of this content and see * if the others match then until we run out of matches */ int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, f, buffer, buffer_len, stream_start_offset, flags, inspection_mode, data); if (r == 1) { SCReturnInt(1); } SCLogDebug("no match for 'next sm'"); if (det_ctx->discontinue_matching) { SCLogDebug("'next sm' said to discontinue this right now"); goto no_match; } /* no match and no reason to look for another instance */ if ((cd->flags & DETECT_CONTENT_WITHIN_NEXT) == 0) { SCLogDebug("'next sm' does not depend on me, so we can give up"); det_ctx->discontinue_matching = 1; goto no_match; } SCLogDebug("'next sm' depends on me %p, lets see what we can do (flags %u)", cd, cd->flags); } /* set the previous match offset to the start of this match + 1 */ prev_offset = (match_offset - (cd->content_len - 1)); SCLogDebug("trying to see if there is another match after prev_offset %"PRIu32, prev_offset); } } while(1); } else if (smd->type == DETECT_ISDATAAT) { SCLogDebug("inspecting isdataat"); const DetectIsdataatData *id = (DetectIsdataatData *)smd->ctx; uint32_t dataat = id->dataat; if (id->flags & ISDATAAT_OFFSET_BE) { uint64_t be_value = det_ctx->bj_values[dataat]; if (be_value >= 100000000) { if ((id->flags & ISDATAAT_NEGATED) == 0) { SCLogDebug("extracted value %"PRIu64" very big: no match", be_value); goto no_match; } SCLogDebug("extracted value way %"PRIu64" very big: match", be_value); goto match; } dataat = (uint32_t)be_value; SCLogDebug("isdataat: using value %u from byte_extract local_id %u", dataat, id->dataat); } if (id->flags & ISDATAAT_RELATIVE) { if (det_ctx->buffer_offset + dataat > buffer_len) { SCLogDebug("det_ctx->buffer_offset + dataat %"PRIu32" > %"PRIu32, det_ctx->buffer_offset + dataat, buffer_len); if (id->flags & ISDATAAT_NEGATED) goto match; goto no_match; } else { SCLogDebug("relative isdataat match"); if (id->flags & ISDATAAT_NEGATED) goto no_match; goto match; } } else { if (dataat < buffer_len) { SCLogDebug("absolute isdataat match"); if (id->flags & ISDATAAT_NEGATED) goto no_match; goto match; } else { SCLogDebug("absolute isdataat mismatch, id->isdataat %"PRIu32", buffer_len %"PRIu32"", dataat, buffer_len); if (id->flags & ISDATAAT_NEGATED) goto match; goto no_match; } } } else if (smd->type == DETECT_PCRE) { SCLogDebug("inspecting pcre"); DetectPcreData *pe = (DetectPcreData *)smd->ctx; uint32_t prev_buffer_offset = det_ctx->buffer_offset; uint32_t prev_offset = 0; int r = 0; det_ctx->pcre_match_start_offset = 0; do { Packet *p = NULL; if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) p = (Packet *)data; r = DetectPcrePayloadMatch(det_ctx, s, smd, p, f, buffer, buffer_len); if (r == 0) { goto no_match; } if (!(pe->flags & DETECT_PCRE_RELATIVE_NEXT)) { SCLogDebug("no relative match coming up, so this is a match"); goto match; } KEYWORD_PROFILING_END(det_ctx, smd->type, 1); /* save it, in case we need to do a pcre match once again */ prev_offset = det_ctx->pcre_match_start_offset; /* see if the next payload keywords match. If not, we will * search for another occurence of this pcre and see * if the others match, until we run out of matches */ r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, f, buffer, buffer_len, stream_start_offset, flags, inspection_mode, data); if (r == 1) { SCReturnInt(1); } if (det_ctx->discontinue_matching) goto no_match; det_ctx->buffer_offset = prev_buffer_offset; det_ctx->pcre_match_start_offset = prev_offset; } while (1); } else if (smd->type == DETECT_BYTETEST) { DetectBytetestData *btd = (DetectBytetestData *)smd->ctx; uint8_t btflags = btd->flags; int32_t offset = btd->offset; uint64_t value = btd->value; if (btflags & DETECT_BYTETEST_OFFSET_BE) { offset = det_ctx->bj_values[offset]; } if (btflags & DETECT_BYTETEST_VALUE_BE) { value = det_ctx->bj_values[value]; } /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if (btflags & DETECT_BYTETEST_DCE && data != NULL) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ btflags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ? DETECT_BYTETEST_LITTLE: 0); } if (DetectBytetestDoMatch(det_ctx, s, smd->ctx, buffer, buffer_len, btflags, offset, value) != 1) { goto no_match; } goto match; } else if (smd->type == DETECT_BYTEJUMP) { DetectBytejumpData *bjd = (DetectBytejumpData *)smd->ctx; uint8_t bjflags = bjd->flags; int32_t offset = bjd->offset; if (bjflags & DETECT_BYTEJUMP_OFFSET_BE) { offset = det_ctx->bj_values[offset]; } /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if (bjflags & DETECT_BYTEJUMP_DCE && data != NULL) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ bjflags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ? DETECT_BYTEJUMP_LITTLE: 0); } if (DetectBytejumpDoMatch(det_ctx, s, smd->ctx, buffer, buffer_len, bjflags, offset) != 1) { goto no_match; } goto match; } else if (smd->type == DETECT_BYTE_EXTRACT) { DetectByteExtractData *bed = (DetectByteExtractData *)smd->ctx; uint8_t endian = bed->endian; /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if ((bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) && endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE && data != NULL) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ endian |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] == 0x10) ? DETECT_BYTE_EXTRACT_ENDIAN_LITTLE : DETECT_BYTE_EXTRACT_ENDIAN_BIG); } if (DetectByteExtractDoMatch(det_ctx, smd, s, buffer, buffer_len, &det_ctx->bj_values[bed->local_id], endian) != 1) { goto no_match; } goto match; } else if (smd->type == DETECT_BSIZE) { bool eof = (flags & DETECT_CI_FLAGS_END); const uint64_t data_size = buffer_len + stream_start_offset; int r = DetectBsizeMatch(smd->ctx, data_size, eof); if (r < 0) { det_ctx->discontinue_matching = 1; goto no_match; } else if (r == 0) { goto no_match; } goto match; } else if (smd->type == DETECT_AL_URILEN) { SCLogDebug("inspecting uri len"); int r = 0; DetectUrilenData *urilend = (DetectUrilenData *) smd->ctx; switch (urilend->mode) { case DETECT_URILEN_EQ: if (buffer_len == urilend->urilen1) r = 1; break; case DETECT_URILEN_LT: if (buffer_len < urilend->urilen1) r = 1; break; case DETECT_URILEN_GT: if (buffer_len > urilend->urilen1) r = 1; break; case DETECT_URILEN_RA: if (buffer_len > urilend->urilen1 && buffer_len < urilend->urilen2) { r = 1; } break; } if (r == 1) { goto match; } det_ctx->discontinue_matching = 0; goto no_match; #ifdef HAVE_LUA } else if (smd->type == DETECT_LUA) { SCLogDebug("lua starting"); if (DetectLuaMatchBuffer(det_ctx, s, smd, buffer, buffer_len, det_ctx->buffer_offset, f) != 1) { SCLogDebug("lua no_match"); goto no_match; } SCLogDebug("lua match"); goto match; #endif /* HAVE_LUA */ } else if (smd->type == DETECT_BASE64_DECODE) { if (DetectBase64DecodeDoMatch(det_ctx, s, smd, buffer, buffer_len)) { if (s->sm_arrays[DETECT_SM_LIST_BASE64_DATA] != NULL) { KEYWORD_PROFILING_END(det_ctx, smd->type, 1); if (DetectBase64DataDoMatch(de_ctx, det_ctx, s, f)) { /* Base64 is a terminal list. */ goto final_match; } } } } else { SCLogDebug("sm->type %u", smd->type); #ifdef DEBUG BUG_ON(1); #endif } no_match: KEYWORD_PROFILING_END(det_ctx, smd->type, 0); SCReturnInt(0); match: /* this sigmatch matched, inspect the next one. If it was the last, * the buffer portion of the signature matched. */ if (!smd->is_last) { KEYWORD_PROFILING_END(det_ctx, smd->type, 1); int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, f, buffer, buffer_len, stream_start_offset, flags, inspection_mode, data); SCReturnInt(r); } final_match: KEYWORD_PROFILING_END(det_ctx, smd->type, 1); SCReturnInt(1); }