/** \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; }
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; }
/** * \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); }
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); }
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; }
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; }
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); }
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; }
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; }
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; }