int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *output_ctx, int tc_log_progress, int ts_log_progress, TxLoggerCondition LogCondition) { int module_id = TmModuleGetIdByName(name); if (module_id < 0) return -1; OutputTxLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; memset(op, 0x00, sizeof(*op)); op->alproto = alproto; op->LogFunc = LogFunc; op->LogCondition = LogCondition; op->output_ctx = output_ctx; op->name = name; op->module_id = (TmmId) module_id; if (tc_log_progress) { op->tc_log_progress = tc_log_progress; } else { op->tc_log_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT); } if (ts_log_progress) { op->ts_log_progress = ts_log_progress; } else { op->ts_log_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER); } if (list == NULL) { op->id = 1; list = op; } else { OutputTxLogger *t = list; while (t->next) t = t->next; if (t->id * 2 > UINT32_MAX) { SCLogError(SC_ERR_FATAL, "Too many loggers registered."); exit(EXIT_FAILURE); } op->id = t->id * 2; t->next = op; } SCLogDebug("OutputRegisterTxLogger happy"); return 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; }
/** \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; }
int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *output_ctx, int tc_log_progress, int ts_log_progress, TxLoggerCondition LogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, void (*ThreadExitPrintStats)(ThreadVars *, void *)) { if (!(AppLayerParserIsTxAware(alproto))) { SCLogNotice("%s logger not enabled: protocol %s is disabled", name, AppProtoToString(alproto)); return -1; } OutputTxLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; memset(op, 0x00, sizeof(*op)); op->alproto = alproto; op->LogFunc = LogFunc; op->LogCondition = LogCondition; op->output_ctx = output_ctx; op->name = name; op->logger_id = id; op->ThreadInit = ThreadInit; op->ThreadDeinit = ThreadDeinit; op->ThreadExitPrintStats = ThreadExitPrintStats; if (tc_log_progress < 0) { op->tc_log_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT); } else { op->tc_log_progress = tc_log_progress; } if (ts_log_progress < 0) { op->ts_log_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER); } else { op->ts_log_progress = ts_log_progress; } if (list == NULL) { op->id = 1; list = op; } else { OutputTxLogger *t = list; while (t->next) t = t->next; if (t->id * 2 > UINT32_MAX) { SCLogError(SC_ERR_FATAL, "Too many loggers registered."); exit(EXIT_FAILURE); } op->id = t->id * 2; t->next = op; } SCLogDebug("OutputRegisterTxLogger happy"); return 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; }
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; }