コード例 #1
0
ファイル: detect-engine-payload.c プロジェクト: norg/suricata
/**
 *  \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);
}
コード例 #2
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);
}
コード例 #3
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);
}
コード例 #4
0
ファイル: detect-engine-hmd.c プロジェクト: gcordrey/suricata
/**
 * \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);
}
コード例 #5
0
ファイル: detect-http-start.c プロジェクト: gozzy/suricata
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;
}
コード例 #6
0
ファイル: detect-base64-data.c プロジェクト: P1sec/suricata
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;
}
コード例 #7
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;
}
コード例 #8
0
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;
}
コード例 #9
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 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;
    }
}
コード例 #10
0
ファイル: detect-engine-payload.c プロジェクト: norg/suricata
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);
}
コード例 #11
0
ファイル: detect-dns-query.c プロジェクト: gozzy/suricata
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;
}
コード例 #12
0
ファイル: detect-engine-tls.c プロジェクト: P1sec/suricata
/** \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;
}
コード例 #13
0
/**
 * \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);
    }
}
コード例 #14
0
/**
 * \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);
}