Пример #1
0
/** \brief active TX retrieval for logging only: so NO detection
 *
 *  If the logger is enabled, we simply return the log_id here.
 *
 *  Otherwise, we go look for the tx id. There probably is no point
 *  in running this function in that case though. With no detection
 *  and no logging, why run a parser in the first place?
 **/
uint64_t AppLayerTransactionGetActiveLogOnly(Flow *f, uint8_t flags)
{
    AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->protomap][f->alproto];

    if (p->logger == TRUE) {
        uint64_t log_id = f->alparser->log_id;
        SCLogDebug("returning %"PRIu64, log_id);
        return log_id;
    }

    /* logger is disabled, return highest 'complete' tx id */
    uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, f->alproto, f->alstate);
    uint64_t idx = AppLayerParserGetTransactionInspectId(f->alparser, flags);
    int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->alproto, flags);
    void *tx;
    int state_progress;

    for (; idx < total_txs; idx++) {
        tx = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, idx);
        if (tx == NULL)
            continue;
        state_progress = AppLayerParserGetStateProgress(f->proto, f->alproto, tx, flags);
        if (state_progress >= state_done_progress)
            continue;
        else
            break;
    }
    SCLogDebug("returning %"PRIu64, idx);
    return idx;
}
Пример #2
0
void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate,
                                           uint8_t ipproto, AppProto alproto, void *alstate,
                                           uint8_t direction)
{
    SCEnter();

    uint8_t dir = (direction & STREAM_TOSERVER) ? 0 : 1;
    uint64_t total_txs = AppLayerParserGetTxCnt(ipproto, alproto, alstate);
    uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, direction);
    int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(ipproto, alproto, direction);
    void *tx;
    int state_progress;

    for (; idx < total_txs; idx++) {
        tx = AppLayerParserGetTx(ipproto, alproto, alstate, idx);
        if (tx == NULL)
            continue;
        state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, direction);
        if (state_progress >= state_done_progress)
            continue;
        else
            break;
    }
    pstate->inspect_id[dir] = idx;

    SCReturn;
}
Пример #3
0
/**
 *  \brief Check if a flow needs forced reassembly, or any other processing
 *
 *  \param f *LOCKED* flow
 *  \param server ptr to int that should be set to 1 or 2 if we return 1
 *  \param client ptr to int that should be set to 1 or 2 if we return 1
 *
 *  \retval 0 no
 *  \retval 1 yes
 */
int FlowForceReassemblyNeedReassembly(Flow *f, int *server, int *client)
{
    TcpSession *ssn;

    if (f == NULL) {
        *server = *client = STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
        SCReturnInt(0);
    }

    /* Get the tcp session for the flow */
    ssn = (TcpSession *)f->protoctx;
    if (ssn == NULL) {
        *server = *client = STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
        SCReturnInt(0);
    }

    *client = StreamNeedsReassembly(ssn, 0);
    *server = StreamNeedsReassembly(ssn, 1);

    /* if state is not fully closed we assume that we haven't fully
     * inspected the app layer state yet */
    if (ssn->state >= TCP_ESTABLISHED && ssn->state != TCP_CLOSED)
    {
        if (*client != STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY)
            *client = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;

        if (*server != STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY)
            *server = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
    }

    /* if app layer still needs some love, push through */
    if (f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL &&
        AppLayerParserProtocolSupportsTxs(f->proto, f->alproto))
    {
        uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, f->alproto, f->alstate);

        if (AppLayerParserGetTransactionActive(f->proto, f->alproto,
                                               f->alparser, STREAM_TOCLIENT) < total_txs)
        {
            if (*server != STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY)
                *server = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
        }
        if (AppLayerParserGetTransactionActive(f->proto, f->alproto,
                                               f->alparser, STREAM_TOSERVER) < total_txs)
        {
            if (*client != STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY)
                *client = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
        }
    }

    /* nothing to do */
    if (*client == STREAM_HAS_UNPROCESSED_SEGMENTS_NONE &&
        *server == STREAM_HAS_UNPROCESSED_SEGMENTS_NONE) {
        SCReturnInt(0);
    }

    SCReturnInt(1);
}
Пример #4
0
int AppLayerParserHasDecoderEvents(uint8_t ipproto, AppProto alproto,
                                   void *alstate, AppLayerParserState *pstate,
                                   uint8_t flags)
{
    SCEnter();

    if (alstate == NULL || pstate == NULL)
        goto not_present;

    AppLayerDecoderEvents *decoder_events;
    uint64_t tx_id;
    uint64_t max_id;

    if (AppLayerParserProtocolIsTxEventAware(ipproto, alproto)) {
        /* fast path if supported by alproto */
        if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasEvents != NULL) {
            if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
                StateHasEvents(alstate) == 1)
            {
                goto present;
            }
        } else {
            /* check each tx */
            tx_id = AppLayerParserGetTransactionInspectId(pstate, flags);
            max_id = AppLayerParserGetTxCnt(ipproto, alproto, alstate);
            for ( ; tx_id < max_id; tx_id++) {
                decoder_events = AppLayerParserGetEventsByTx(ipproto, alproto, alstate, tx_id);
                if (decoder_events && decoder_events->cnt)
                    goto present;
            }
        }
    }

    decoder_events = AppLayerParserGetDecoderEvents(pstate);
    if (decoder_events && decoder_events->cnt)
        goto present;

    /* if we have reached here, we don't have events */
 not_present:
    SCReturnInt(0);
 present:
    SCReturnInt(1);
}
Пример #5
0
static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data)
{
    BUG_ON(thread_data == NULL);
    if (list == NULL) {
        /* No child loggers registered. */
        return TM_ECODE_OK;
    }

    OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data;
    OutputTxLogger *logger = list;
    OutputLoggerThreadStore *store = op_thread_data->store;

    BUG_ON(logger == NULL && store != NULL);
    BUG_ON(logger != NULL && store == NULL);
    BUG_ON(logger == NULL && store == NULL);

    if (p->flow == NULL)
        return TM_ECODE_OK;

    Flow * const f = p->flow;

    AppProto alproto = f->alproto;

    if (AppLayerParserProtocolIsTxAware(p->proto, alproto) == 0)
        goto end;
    if (AppLayerParserProtocolHasLogger(p->proto, alproto) == 0)
        goto end;

    void *alstate = f->alstate;
    if (alstate == NULL) {
        SCLogDebug("no alstate");
        goto end;
    }

    uint64_t total_txs = AppLayerParserGetTxCnt(p->proto, alproto, alstate);
    uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser);

    for (; tx_id < total_txs; tx_id++)
    {
        int logger_not_logged = 0;

        void *tx = AppLayerParserGetTx(p->proto, alproto, alstate, tx_id);
        if (tx == NULL) {
            SCLogDebug("tx is NULL not logging");
            continue;
        }

        int tx_progress_ts = AppLayerParserGetStateProgress(p->proto, alproto,
                tx, FlowGetDisruptionFlags(f, STREAM_TOSERVER));

        int tx_progress_tc = AppLayerParserGetStateProgress(p->proto, alproto,
                tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT));

        SCLogDebug("tx_progress_ts %d tx_progress_tc %d",
                tx_progress_ts, tx_progress_tc);

        // call each logger here (pseudo code)
        logger = list;
        store = op_thread_data->store;
        while (logger && store) {
            BUG_ON(logger->LogFunc == NULL);

            SCLogDebug("logger %p, LogCondition %p, ts_log_progress %d "
                    "tc_log_progress %d", logger, logger->LogCondition,
                    logger->ts_log_progress, logger->tc_log_progress);
            if (logger->alproto == alproto) {
                SCLogDebug("alproto match, logging tx_id %"PRIu64, tx_id);

                if (AppLayerParserGetTxLogged(p->proto, alproto, alstate, tx,
                        logger->id)) {
                    SCLogDebug("logger has already logged this transaction");

                    goto next;
                }

                if (!(AppLayerParserStateIssetFlag(f->alparser,
                                                   APP_LAYER_PARSER_EOF))) {
                    if (logger->LogCondition) {
                        int r = logger->LogCondition(tv, p, alstate, tx, tx_id);
                        if (r == FALSE) {
                            SCLogDebug("conditions not met, not logging");
                            logger_not_logged = 1;
                            goto next;
                        }
                    } else {
                        if (tx_progress_tc < logger->tc_log_progress) {
                            SCLogDebug("progress not far enough, not logging");
                            logger_not_logged = 1;
                            goto next;
                        }

                        if (tx_progress_ts < logger->ts_log_progress) {
                            SCLogDebug("progress not far enough, not logging");
                            logger_not_logged = 1;
                            goto next;
                        }
                    }
                }

                PACKET_PROFILING_LOGGER_START(p, logger->logger_id);
                logger->LogFunc(tv, store->thread_data, p, f, alstate, tx, tx_id);
                PACKET_PROFILING_LOGGER_END(p, logger->logger_id);

                AppLayerParserSetTxLogged(p->proto, alproto, alstate, tx,
                                          logger->id);
            }

next:
            logger = logger->next;
            store = store->next;

            BUG_ON(logger == NULL && store != NULL);
            BUG_ON(logger != NULL && store == NULL);
        }

        if (!logger_not_logged) {
            SCLogDebug("updating log tx_id %"PRIu64, tx_id);
            AppLayerParserSetTransactionLogId(f->alparser);
        }
    }

end:
    return TM_ECODE_OK;
}
Пример #6
0
int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags)
{
    SCLogDebug("called with %p, %d, %p, %02x", f, close, cbdata, iflags);

    HtpState *s = f->alstate;
    if (s != NULL && s->conn != NULL) {
        int tx_progress_done_value_ts =
            AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP,
                                                           ALPROTO_HTTP, STREAM_TOSERVER);
        int tx_progress_done_value_tc =
            AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP,
                                                           ALPROTO_HTTP, STREAM_TOCLIENT);

        // for each tx
        uint64_t tx_id = 0;
        uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, f->alproto, f->alstate);
        SCLogDebug("s->conn %p", s->conn);
        for (tx_id = 0; tx_id < total_txs; tx_id++) { // TODO optimization store log tx
            htp_tx_t *tx = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, tx_id);
            if (tx != NULL) {
                int tx_done = 0;
                int tx_logged = 0;

                int tx_progress_ts = AppLayerParserGetStateProgress(
                        IPPROTO_TCP, ALPROTO_HTTP, tx, FlowGetDisruptionFlags(f, STREAM_TOSERVER));
                if (tx_progress_ts >= tx_progress_done_value_ts) {
                    int tx_progress_tc = AppLayerParserGetStateProgress(
                            IPPROTO_TCP, ALPROTO_HTTP, tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT));
                    if (tx_progress_tc >= tx_progress_done_value_tc) {
                        tx_done = 1;
                    }
                }

                SCLogDebug("tx %p", tx);
                HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
                if (htud != NULL) {
                    SCLogDebug("htud %p", htud);
                    HtpBody *body = NULL;
                    if (iflags & OUTPUT_STREAMING_FLAG_TOCLIENT)
                        body = &htud->request_body;
                    else if (iflags & OUTPUT_STREAMING_FLAG_TOSERVER)
                        body = &htud->response_body;

                    if (body == NULL) {
                        SCLogDebug("no body");
                        goto next;
                    }
                    if (body->first == NULL) {
                        SCLogDebug("no body chunks");
                        goto next;
                    }
                    if (body->last->logged == 1) {
                        SCLogDebug("all logged already");
                        goto next;
                    }

                    // for each chunk
                    HtpBodyChunk *chunk = body->first;
                    for ( ; chunk != NULL; chunk = chunk->next) {
                        if (chunk->logged) {
                            SCLogDebug("logged %d", chunk->logged);
                            continue;
                        }

                        uint8_t flags = iflags | OUTPUT_STREAMING_FLAG_TRANSACTION;
                        if (chunk->stream_offset == 0)
                            flags |= OUTPUT_STREAMING_FLAG_OPEN;
                        /* if we need to close and we're at the last segment in the list
                         * we add the 'close' flag so the logger can close up. */
                        if ((tx_done || close) && chunk->next == NULL) {
                            flags |= OUTPUT_STREAMING_FLAG_CLOSE;
                        }

                        // invoke Streamer
                        Streamer(cbdata, f, chunk->data, (uint32_t)chunk->len, tx_id, flags);
                        //PrintRawDataFp(stdout, chunk->data, chunk->len);
                        chunk->logged = 1;
                        tx_logged = 1;
                    }

                  next:
                    /* if we need to close we need to invoke the Streamer for sure. If we
                     * logged no chunks, we call the Streamer with NULL data so it can
                     * close up. */
                    if (tx_logged == 0 && (close||tx_done)) {
                        Streamer(cbdata, f, NULL, 0, tx_id,
                                OUTPUT_STREAMING_FLAG_CLOSE|OUTPUT_STREAMING_FLAG_TRANSACTION);
                    }
                }
            }
        }
    }


    return 0;
}
Пример #7
0
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto,
                        uint8_t flags, uint8_t *input, uint32_t input_len)
{
    SCEnter();
#ifdef DEBUG_VALIDATION
    BUG_ON(f->protomap != FlowGetProtoMapping(f->proto));
#endif
    AppLayerParserState *pstate = NULL;
    AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->protomap][alproto];
    void *alstate = NULL;
    uint64_t p_tx_cnt = 0;

    /* we don't have the parser registered for this protocol */
    if (p->StateAlloc == NULL)
        goto end;

    /* Do this check before calling AppLayerParse */
    if (flags & STREAM_GAP) {
        SCLogDebug("stream gap detected (missing packets), "
                   "this is not yet supported.");

        if (f->alstate != NULL)
            AppLayerParserStreamTruncated(f->proto, alproto, f->alstate, flags);
        goto error;
    }

    /* Get the parser state (if any) */
    pstate = f->alparser;
    if (pstate == NULL) {
        f->alparser = pstate = AppLayerParserStateAlloc();
        if (pstate == NULL)
            goto error;
    }
    pstate->version++;
    SCLogDebug("app layer parser state version incremented to %"PRIu8,
               pstate->version);

    if (flags & STREAM_EOF)
        AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF);

    alstate = f->alstate;
    if (alstate == NULL) {
        f->alstate = alstate = p->StateAlloc();
        if (alstate == NULL)
            goto error;
        SCLogDebug("alloced new app layer state %p (name %s)",
                   alstate, AppLayerGetProtoName(f->alproto));
    } else {
        SCLogDebug("using existing app layer state %p (name %s))",
                   alstate, AppLayerGetProtoName(f->alproto));
    }

    if (AppLayerParserProtocolIsTxAware(f->proto, alproto)) {
        p_tx_cnt = AppLayerParserGetTxCnt(f->proto, alproto, f->alstate);
    }

    /* invoke the recursive parser, but only on data. We may get empty msgs on EOF */
    if (input_len > 0 || (flags & STREAM_EOF)) {
        /* invoke the parser */
        if (p->Parser[(flags & STREAM_TOSERVER) ? 0 : 1](f, alstate, pstate,
                input, input_len,
                alp_tctx->alproto_local_storage[f->protomap][alproto]) < 0)
        {
            goto error;
        }
    }

    /* set the packets to no inspection and reassembly if required */
    if (pstate->flags & APP_LAYER_PARSER_NO_INSPECTION) {
        AppLayerParserSetEOF(pstate);
        FlowSetNoPayloadInspectionFlag(f);

        if (f->proto == IPPROTO_TCP) {
            StreamTcpDisableAppLayer(f);

            /* Set the no reassembly flag for both the stream in this TcpSession */
            if (pstate->flags & APP_LAYER_PARSER_NO_REASSEMBLY) {
                /* Used only if it's TCP */
                TcpSession *ssn = f->protoctx;
                if (ssn != NULL) {
                    StreamTcpSetSessionNoReassemblyFlag(ssn,
                            flags & STREAM_TOCLIENT ? 1 : 0);
                    StreamTcpSetSessionNoReassemblyFlag(ssn,
                            flags & STREAM_TOSERVER ? 1 : 0);
                }
            }
        }
    }

    /* In cases like HeartBleed for TLS we need to inspect AppLayer but not Payload */
    if (!(f->flags & FLOW_NOPAYLOAD_INSPECTION) && pstate->flags & APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD) {
        FlowSetNoPayloadInspectionFlag(f);
        /* Set the no reassembly flag for both the stream in this TcpSession */
        if (f->proto == IPPROTO_TCP) {
            /* Used only if it's TCP */
            TcpSession *ssn = f->protoctx;
            if (ssn != NULL) {
                StreamTcpSetDisableRawReassemblyFlag(ssn, 0);
                StreamTcpSetDisableRawReassemblyFlag(ssn, 1);
            }
        }
    }

    if (AppLayerParserProtocolIsTxAware(f->proto, alproto)) {
        if (likely(tv)) {
            uint64_t cur_tx_cnt = AppLayerParserGetTxCnt(f->proto, alproto, f->alstate);
            if (cur_tx_cnt > p_tx_cnt) {
                AppLayerIncTxCounter(tv, f, cur_tx_cnt - p_tx_cnt);
            }
        }
    }
    /* next, see if we can get rid of transactions now */
    AppLayerParserTransactionsCleanup(f);

    /* stream truncated, inform app layer */
    if (flags & STREAM_DEPTH)
        AppLayerParserStreamTruncated(f->proto, alproto, alstate, flags);

 end:
    SCReturnInt(0);
 error:
    /* Set the no app layer inspection flag for both
     * the stream in this Flow */
    if (f->proto == IPPROTO_TCP) {
        StreamTcpDisableAppLayer(f);
    }
    AppLayerParserSetEOF(pstate);
    SCReturnInt(-1);
}
Пример #8
0
static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq)
{
    BUG_ON(thread_data == NULL);
    BUG_ON(list == NULL);

    OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data;
    OutputTxLogger *logger = list;
    OutputLoggerThreadStore *store = op_thread_data->store;

    BUG_ON(logger == NULL && store != NULL);
    BUG_ON(logger != NULL && store == NULL);
    BUG_ON(logger == NULL && store == NULL);

    if (p->flow == NULL)
        return TM_ECODE_OK;

    Flow * const f = p->flow;

    FLOWLOCK_WRLOCK(f); /* WRITE lock before we updated flow logged id */
    AppProto alproto = f->alproto;

    if (AppLayerParserProtocolIsTxAware(p->proto, alproto) == 0)
        goto end;
    if (AppLayerParserProtocolHasLogger(p->proto, alproto) == 0)
        goto end;

    void *alstate = f->alstate;
    if (alstate == NULL) {
        SCLogDebug("no alstate");
        goto end;
    }

    uint64_t total_txs = AppLayerParserGetTxCnt(p->proto, alproto, alstate);
    uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser);
    int tx_progress_done_value_ts =
        AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto,
                                                       STREAM_TOSERVER);
    int tx_progress_done_value_tc =
        AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto,
                                                       STREAM_TOCLIENT);
    for (; tx_id < total_txs; tx_id++)
    {
        int proto_logged = 0;

        void *tx = AppLayerParserGetTx(p->proto, alproto, alstate, tx_id);
        if (tx == NULL) {
            SCLogDebug("tx is NULL not logging");
            continue;
        }

        if (!(AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_EOF)))
        {
            int tx_progress = AppLayerParserGetStateProgress(p->proto, alproto,
                                                             tx, FlowGetDisruptionFlags(f, STREAM_TOSERVER));
            if (tx_progress < tx_progress_done_value_ts) {
                SCLogDebug("progress not far enough, not logging");
                break;
            }

            tx_progress = AppLayerParserGetStateProgress(p->proto, alproto,
                                                         tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT));
            if (tx_progress < tx_progress_done_value_tc) {
                SCLogDebug("progress not far enough, not logging");
                break;
            }
        }

        // call each logger here (pseudo code)
        logger = list;
        store = op_thread_data->store;
        while (logger && store) {
            BUG_ON(logger->LogFunc == NULL);

            SCLogDebug("logger %p", logger);
            if (logger->alproto == alproto) {
                SCLogDebug("alproto match, logging tx_id %ju", tx_id);
                PACKET_PROFILING_TMM_START(p, logger->module_id);
                logger->LogFunc(tv, store->thread_data, p, f, alstate, tx, tx_id);
                PACKET_PROFILING_TMM_END(p, logger->module_id);
                proto_logged = 1;
            }

            logger = logger->next;
            store = store->next;

            BUG_ON(logger == NULL && store != NULL);
            BUG_ON(logger != NULL && store == NULL);
        }

        if (proto_logged) {
            SCLogDebug("updating log tx_id %ju", tx_id);
            AppLayerParserSetTransactionLogId(f->alparser);
        }
    }

end:
    FLOWLOCK_UNLOCK(f);
    return TM_ECODE_OK;
}
Пример #9
0
static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data)
{
    BUG_ON(thread_data == NULL);
    if (list == NULL) {
        /* No child loggers registered. */
        return TM_ECODE_OK;
    }

    OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data;
    if (p->flow == NULL)
        return TM_ECODE_OK;

    Flow * const f = p->flow;
    const uint8_t ipproto = f->proto;
    const AppProto alproto = f->alproto;

    if (AppLayerParserProtocolIsTxAware(p->proto, alproto) == 0)
        goto end;
    if (AppLayerParserProtocolHasLogger(p->proto, alproto) == 0)
        goto end;
    const LoggerId logger_expectation = AppLayerParserProtocolGetLoggerBits(p->proto, alproto);
    if (logger_expectation == 0)
        goto end;

    void *alstate = f->alstate;
    if (alstate == NULL) {
        SCLogDebug("no alstate");
        goto end;
    }

    const uint8_t ts_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOSERVER);
    const uint8_t tc_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOCLIENT);
    const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
    uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser);
    uint64_t max_id = tx_id;
    int logged = 0;
    int gap = 0;

    AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto);
    AppLayerGetTxIterState state;
    memset(&state, 0, sizeof(state));

    while (1) {
        AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, tx_id, total_txs, &state);
        if (ires.tx_ptr == NULL)
            break;
        void * const tx = ires.tx_ptr;
        tx_id = ires.tx_id;

        LoggerId tx_logged = AppLayerParserGetTxLogged(f, alstate, tx);
        const LoggerId tx_logged_old = tx_logged;
        SCLogDebug("logger: expect %08x, have %08x", logger_expectation, tx_logged);
        if (tx_logged == logger_expectation) {
            /* tx already fully logged */
            goto next_tx;
        }

        int tx_progress_ts = AppLayerParserGetStateProgress(p->proto, alproto,
                tx, ts_disrupt_flags);
        int tx_progress_tc = AppLayerParserGetStateProgress(p->proto, alproto,
                tx, tc_disrupt_flags);
        SCLogDebug("tx_progress_ts %d tx_progress_tc %d",
                tx_progress_ts, tx_progress_tc);

        const OutputTxLogger *logger = list;
        const OutputLoggerThreadStore *store = op_thread_data->store;
#ifdef DEBUG_VALIDATION
        BUG_ON(logger == NULL && store != NULL);
        BUG_ON(logger != NULL && store == NULL);
        BUG_ON(logger == NULL && store == NULL);
#endif
        while (logger && store) {
            BUG_ON(logger->LogFunc == NULL);

            SCLogDebug("logger %p, LogCondition %p, ts_log_progress %d "
                    "tc_log_progress %d", logger, logger->LogCondition,
                    logger->ts_log_progress, logger->tc_log_progress);
            if (logger->alproto == alproto &&
                (tx_logged_old & (1<<logger->logger_id)) == 0)
            {
                SCLogDebug("alproto match, logging tx_id %"PRIu64, tx_id);

                if (!(AppLayerParserStateIssetFlag(f->alparser,
                                                   APP_LAYER_PARSER_EOF))) {
                    if (logger->LogCondition) {
                        int r = logger->LogCondition(tv, p, alstate, tx, tx_id);
                        if (r == FALSE) {
                            SCLogDebug("conditions not met, not logging");
                            goto next_logger;
                        }
                    } else {
                        if (tx_progress_tc < logger->tc_log_progress) {
                            SCLogDebug("progress not far enough, not logging");
                            goto next_logger;
                        }

                        if (tx_progress_ts < logger->ts_log_progress) {
                            SCLogDebug("progress not far enough, not logging");
                            goto next_logger;
                        }
                    }
                }

                SCLogDebug("Logging tx_id %"PRIu64" to logger %d", tx_id,
                    logger->logger_id);
                PACKET_PROFILING_LOGGER_START(p, logger->logger_id);
                logger->LogFunc(tv, store->thread_data, p, f, alstate, tx, tx_id);
                PACKET_PROFILING_LOGGER_END(p, logger->logger_id);

                tx_logged |= (1<<logger->logger_id);
            }

next_logger:
            logger = logger->next;
            store = store->next;
#ifdef DEBUG_VALIDATION
            BUG_ON(logger == NULL && store != NULL);
            BUG_ON(logger != NULL && store == NULL);
#endif
        }

        if (tx_logged != tx_logged_old) {
            SCLogDebug("logger: storing %08x (was %08x)",
                tx_logged, tx_logged_old);
            AppLayerParserSetTxLogged(p->proto, alproto, alstate, tx,
                    tx_logged);
        }

        /* If all loggers logged set a flag and update the last tx_id
         * that was logged.
         *
         * If not all loggers were logged we flag that there was a gap
         * so any subsequent transactions in this loop don't increase
         * the maximum ID that was logged. */
        if (!gap && tx_logged == logger_expectation) {
            logged = 1;
            max_id = tx_id;
        } else {
            gap = 1;
        }
next_tx:
        if (!ires.has_next)
            break;
        tx_id++;
    }

    /* Update the the last ID that has been logged with all
     * transactions before it. */
    if (logged) {
        SCLogDebug("updating log tx_id %"PRIu64, max_id);
        AppLayerParserSetTransactionLogId(f->alparser, max_id + 1);
    }

end:
    return TM_ECODE_OK;
}
Пример #10
0
static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data)
{
    BUG_ON(thread_data == NULL);
    if (list == NULL) {
        /* No child loggers registered. */
        return TM_ECODE_OK;
    }

    OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data;
    if (p->flow == NULL)
        return TM_ECODE_OK;

    Flow * const f = p->flow;
    const AppProto alproto = f->alproto;

    if (AppLayerParserProtocolIsTxAware(p->proto, alproto) == 0)
        goto end;
    if (AppLayerParserProtocolHasLogger(p->proto, alproto) == 0)
        goto end;

    void *alstate = f->alstate;
    if (alstate == NULL) {
        SCLogDebug("no alstate");
        goto end;
    }

    const uint8_t ts_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOSERVER);
    const uint8_t tc_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOCLIENT);
    const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
    uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser);
    uint64_t max_id = tx_id;
    int logged = 0;
    int gap = 0;

    for (; tx_id < total_txs; tx_id++)
    {
        /* Track the number of loggers, of the eligible loggers that
         * actually logged this transaction. They all must have logged
         * before the transaction is considered logged. */
        int number_of_loggers = 0;
        int loggers_that_logged = 0;

        void *tx = AppLayerParserGetTx(p->proto, alproto, alstate, tx_id);
        if (tx == NULL) {
            SCLogDebug("tx is NULL not logging");
            continue;
        }

        int tx_progress_ts = AppLayerParserGetStateProgress(p->proto, alproto,
                tx, ts_disrupt_flags);

        int tx_progress_tc = AppLayerParserGetStateProgress(p->proto, alproto,
                tx, tc_disrupt_flags);

        SCLogDebug("tx_progress_ts %d tx_progress_tc %d",
                tx_progress_ts, tx_progress_tc);

        const OutputTxLogger *logger = list;
        const OutputLoggerThreadStore *store = op_thread_data->store;
#ifdef DEBUG_VALIDATION
        BUG_ON(logger == NULL && store != NULL);
        BUG_ON(logger != NULL && store == NULL);
        BUG_ON(logger == NULL && store == NULL);
#endif
        while (logger && store) {
            BUG_ON(logger->LogFunc == NULL);

            SCLogDebug("logger %p, LogCondition %p, ts_log_progress %d "
                    "tc_log_progress %d", logger, logger->LogCondition,
                    logger->ts_log_progress, logger->tc_log_progress);
            if (logger->alproto == alproto) {
                SCLogDebug("alproto match, logging tx_id %"PRIu64, tx_id);

                number_of_loggers++;

                if (AppLayerParserGetTxLogged(f, alstate, tx, logger->id)) {
                    SCLogDebug("logger has already logged this transaction");
                    loggers_that_logged++;
                    goto next;
                }

                if (!(AppLayerParserStateIssetFlag(f->alparser,
                                                   APP_LAYER_PARSER_EOF))) {
                    if (logger->LogCondition) {
                        int r = logger->LogCondition(tv, p, alstate, tx, tx_id);
                        if (r == FALSE) {
                            SCLogDebug("conditions not met, not logging");
                            goto next;
                        }
                    } else {
                        if (tx_progress_tc < logger->tc_log_progress) {
                            SCLogDebug("progress not far enough, not logging");
                            goto next;
                        }

                        if (tx_progress_ts < logger->ts_log_progress) {
                            SCLogDebug("progress not far enough, not logging");
                            goto next;
                        }
                    }
                }

                SCLogDebug("Logging tx_id %"PRIu64" to logger %d", tx_id,
                    logger->logger_id);
                PACKET_PROFILING_LOGGER_START(p, logger->logger_id);
                logger->LogFunc(tv, store->thread_data, p, f, alstate, tx, tx_id);
                PACKET_PROFILING_LOGGER_END(p, logger->logger_id);

                AppLayerParserSetTxLogged(p->proto, alproto, alstate, tx,
                                          logger->id);
                loggers_that_logged++;
            }

next:
            logger = logger->next;
            store = store->next;
#ifdef DEBUG_VALIDATION
            BUG_ON(logger == NULL && store != NULL);
            BUG_ON(logger != NULL && store == NULL);
#endif
        }

        /* If all loggers logged set a flag and update the last tx_id
         * that was logged.
         *
         * If not all loggers were logged we flag that there was a gap
         * so any subsequent transactions in this loop don't increase
         * the maximum ID that was logged. */
        if (!gap && loggers_that_logged == number_of_loggers) {
            logged = 1;
            max_id = tx_id;
        } else {
            gap = 1;
        }
    }

    /* Update the the last ID that has been logged with all
     * transactions before it. */
    if (logged) {
        SCLogDebug("updating log tx_id %"PRIu64, max_id);
        AppLayerParserSetTransactionLogId(f->alparser, max_id + 1);
    }

end:
    return TM_ECODE_OK;
}