int (*StateGetProgress)(void *alstate, uint8_t direction);
uint64_t (*StateGetTxCnt)(void *alstate);
void *(*StateGetTx)(void *alstate, uint64_t tx_id);
+ AppLayerGetTxIteratorFunc StateGetTxIterator;
int (*StateGetProgressCompletionStatus)(uint8_t direction);
int (*StateGetEventInfo)(const char *event_name,
int *event_id, AppLayerEventType *event_type);
SCReturn;
}
+void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto,
+ AppLayerGetTxIteratorFunc Func)
+{
+ SCEnter();
+ alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxIterator = Func;
+ SCReturn;
+}
+
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto,
int (*StateGetProgressCompletionStatus)(uint8_t direction))
{
SCReturn;
}
+/** \brief default tx iterator
+ *
+ * Used if the app layer parser doesn't register its own iterator.
+ * Simply walks the tx_id space until it finds a tx. Uses 'state' to
+ * keep track of where it left off.
+ *
+ * \retval txptr or NULL if no more txs in list
+ */
+static AppLayerGetTxIterTuple AppLayerDefaultGetTxIterator(
+ const uint8_t ipproto, const AppProto alproto,
+ void *alstate, uint64_t min_tx_id, uint64_t max_tx_id,
+ AppLayerGetTxIterState *state)
+{
+ uint64_t ustate = *(uint64_t *)state;
+ uint64_t tx_id = MAX(min_tx_id, ustate);
+ for ( ; tx_id < max_tx_id; tx_id++) {
+ void *tx_ptr = AppLayerParserGetTx(ipproto, alproto, alstate, tx_id);
+ if (tx_ptr != NULL) {
+ ustate = tx_id + 1;
+ *state = *(AppLayerGetTxIterState *)&ustate;
+ AppLayerGetTxIterTuple tuple = {
+ .tx_ptr = tx_ptr,
+ .tx_id = tx_id,
+ .has_next = (tx_id + 1 < max_tx_id),
+ };
+ SCLogDebug("tulpe: %p/%"PRIu64"/%s", tuple.tx_ptr, tuple.tx_id,
+ tuple.has_next ? "true" : "false");
+ return tuple;
+ }
+ }
+
+ AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
+ return no_tuple;
+}
+
+AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto,
+ const AppProto alproto)
+{
+ AppLayerGetTxIteratorFunc Func =
+ alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxIterator;
+ return Func ? Func : AppLayerDefaultGetTxIterator;
+}
+
void AppLayerParserSetTxLogged(uint8_t ipproto, AppProto alproto,
void *alstate, void *tx, LoggerId logger)
{
const uint8_t ipproto = f->proto;
const AppProto alproto = f->alproto;
+ AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto);
+ AppLayerGetTxIterState state;
+ memset(&state, 0, sizeof(state));
+
SCLogDebug("called: %s, tag_txs_as_inspected %s",direction==0?"toserver":"toclient",
tag_txs_as_inspected?"true":"false");
/* mark all txs as inspected if the applayer progress is
* at the 'end state'. */
- for (; idx < total_txs; idx++) {
- void *tx = AppLayerParserGetTx(ipproto, alproto, alstate, idx);
- if (tx == NULL)
- continue;
+ while (1) {
+ AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, idx, total_txs, &state);
+ if (ires.tx_ptr == NULL)
+ break;
+
+ void *tx = ires.tx_ptr;
+ idx = ires.tx_id;
+
int state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags);
- if (state_progress >= state_done_progress) {
- if (tag_txs_as_inspected) {
- uint64_t detect_flags = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx, flags);
- if ((detect_flags & APP_LAYER_TX_INSPECTED_FLAG) == 0) {
- detect_flags |= APP_LAYER_TX_INSPECTED_FLAG;
- AppLayerParserSetTxDetectFlags(ipproto, alproto, tx, flags, detect_flags);
- SCLogDebug("%p/%"PRIu64" in-order tx is done for direction %s. Flag %016"PRIx64,
- tx, idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", detect_flags);
- }
+ if (state_progress < state_done_progress)
+ break;
+
+ if (tag_txs_as_inspected) {
+ uint64_t detect_flags = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx, flags);
+ if ((detect_flags & APP_LAYER_TX_INSPECTED_FLAG) == 0) {
+ detect_flags |= APP_LAYER_TX_INSPECTED_FLAG;
+ AppLayerParserSetTxDetectFlags(ipproto, alproto, tx, flags, detect_flags);
+ SCLogDebug("%p/%"PRIu64" in-order tx is done for direction %s. Flag %016"PRIx64,
+ tx, idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", detect_flags);
}
- continue;
- } else
+ }
+ if (!ires.has_next)
break;
}
pstate->inspect_id[direction] = idx;
/* if necessary we flag all txs that are complete as 'inspected'
* also move inspect_id forward. */
if (tag_txs_as_inspected) {
- for (; idx < total_txs; idx++) {
- bool check_inspect_id = false;
- void *tx = AppLayerParserGetTx(ipproto, alproto, alstate, idx);
- if (tx == NULL) {
- check_inspect_id = true;
- } else {
- int state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags);
- if (state_progress >= state_done_progress) {
- uint64_t detect_flags = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx, flags);
- if ((detect_flags & APP_LAYER_TX_INSPECTED_FLAG) == 0) {
- detect_flags |= APP_LAYER_TX_INSPECTED_FLAG;
- AppLayerParserSetTxDetectFlags(ipproto, alproto, tx, flags, detect_flags);
- SCLogDebug("%p/%"PRIu64" out of order tx is done for direction %s. Flag %016"PRIx64,
- tx, idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", detect_flags);
- check_inspect_id = true;
- }
- }
+ /* continue at idx */
+ while (1) {
+ AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, idx, total_txs, &state);
+ if (ires.tx_ptr == NULL)
+ break;
+
+ void *tx = ires.tx_ptr;
+ /* if we got a higher id than the minimum we requested, we
+ * skipped a bunch of 'null-txs'. Lets see if we can up the
+ * inspect tracker */
+ if (ires.tx_id > idx && pstate->inspect_id[direction] == idx) {
+ pstate->inspect_id[direction] = ires.tx_id;
}
- if (check_inspect_id) {
- SCLogDebug("%p/%"PRIu64" out of order tx. Update inspect_id? %"PRIu64, tx, idx, pstate->inspect_id[direction]);
+ idx = ires.tx_id;
+
+ const int state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags);
+ if (state_progress < state_done_progress)
+ break;
+
+ uint64_t detect_flags = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx, flags);
+ if ((detect_flags & APP_LAYER_TX_INSPECTED_FLAG) == 0) {
+ detect_flags |= APP_LAYER_TX_INSPECTED_FLAG;
+ AppLayerParserSetTxDetectFlags(ipproto, alproto, tx, flags, detect_flags);
+ SCLogDebug("%p/%"PRIu64" out of order tx is done for direction %s. Flag %016"PRIx64,
+ tx, idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", detect_flags);
+
+ SCLogDebug("%p/%"PRIu64" out of order tx. Update inspect_id? %"PRIu64,
+ tx, idx, pstate->inspect_id[direction]);
if (pstate->inspect_id[direction]+1 == idx)
pstate->inspect_id[direction] = idx;
}
+ if (!ires.has_next)
+ break;
}
}
const int tx_end_state_ts = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER);
const int tx_end_state_tc = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT);
- SCLogDebug("checking %"PRIu64" txs from offset %"PRIu64, total_txs, min);
- for (uint64_t i = min ; i < total_txs; i++) {
- void * const tx = AppLayerParserGetTx(ipproto, alproto, alstate, i);
- if (tx == NULL) {
- SCLogDebug("%p/%"PRIu64" skipping: no tx", tx, i);
- goto wrap_up;
- }
+ AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto);
+ AppLayerGetTxIterState state;
+ memset(&state, 0, sizeof(state));
+ uint64_t i = min;
+ uint64_t new_min = min;
+
+ while (1) {
+ AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, i, total_txs, &state);
+ if (ires.tx_ptr == NULL)
+ break;
+
+ void *tx = ires.tx_ptr;
+ i = ires.tx_id;
+
SCLogDebug("%p/%"PRIu64" checking", tx, i);
const int tx_progress_tc = AppLayerParserGetStateProgress(ipproto, alproto, tx, STREAM_TOCLIENT);
if (tx_progress_tc < tx_end_state_tc) {
SCLogDebug("%p/%"PRIu64" skipping: tc parser not done", tx, i);
- continue;
+ goto next;
}
const int tx_progress_ts = AppLayerParserGetStateProgress(ipproto, alproto, tx, STREAM_TOSERVER);
if (tx_progress_ts < tx_end_state_ts) {
SCLogDebug("%p/%"PRIu64" skipping: ts parser not done", tx, i);
- continue;
+ goto next;
}
if (f->sgh_toserver != NULL) {
uint64_t detect_flags_ts = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx, STREAM_TOSERVER);
if (!(detect_flags_ts & APP_LAYER_TX_INSPECTED_FLAG)) {
SCLogDebug("%p/%"PRIu64" skipping: TS inspect not done: ts:%"PRIx64,
tx, i, detect_flags_ts);
- continue;
+ goto next;
}
}
if (f->sgh_toclient != NULL) {
if (!(detect_flags_tc & APP_LAYER_TX_INSPECTED_FLAG)) {
SCLogDebug("%p/%"PRIu64" skipping: TC inspect not done: tc:%"PRIx64,
tx, i, detect_flags_tc);
- continue;
+ goto next;
}
}
if (logger_expectation != 0) {
if (tx_logged != logger_expectation) {
SCLogDebug("%p/%"PRIu64" skipping: logging not done: want:%"PRIx32", have:%"PRIx32,
tx, i, logger_expectation, tx_logged);
- continue;
+ goto next;
}
}
/* if we are here, the tx can be freed. */
p->StateTransactionFree(alstate, i);
SCLogDebug("%p/%"PRIu64" freed", tx, i);
- wrap_up:
- /* see if this tx is actually in order. If so, we need to bring all
- * trackers up to date. */
- SCLogDebug("%p/%"PRIu64" update f->alparser->min_id? %"PRIu64, tx, i, alparser->min_id);
- if (i == alparser->min_id) {
- uint64_t next_id = i + 1;
- alparser->min_id = next_id;
- alparser->inspect_id[0] = MAX(alparser->inspect_id[0], next_id);
- alparser->inspect_id[1] = MAX(alparser->inspect_id[1], next_id);
- alparser->log_id = MAX(alparser->log_id, next_id);
- SCLogDebug("%p/%"PRIu64" updated f->alparser->min_id %"PRIu64, tx, i, alparser->min_id);
- }
+
+ /* if this tx was the minimum, up the minimum */
+ if (i == new_min)
+ new_min = i + 1;
+
+next:
+ if (!ires.has_next)
+ break;
+ }
+
+ /* see if we need to bring all trackers up to date. */
+ SCLogDebug("update f->alparser->min_id? %"PRIu64, alparser->min_id);
+ if (new_min > alparser->min_id) {
+ const uint64_t next_id = new_min;
+ alparser->min_id = next_id;
+ alparser->inspect_id[0] = MAX(alparser->inspect_id[0], next_id);
+ alparser->inspect_id[1] = MAX(alparser->inspect_id[1], next_id);
+ alparser->log_id = MAX(alparser->log_id, next_id);
+ SCLogDebug("updated f->alparser->min_id %"PRIu64, alparser->min_id);
}
}
* \brief get a DetectTransaction object
* \retval struct filled with relevant info or all nulls/0s
*/
-static DetectTransaction GetTx(const uint8_t ipproto, const AppProto alproto,
- void *alstate, const uint64_t tx_id, const int tx_end_state,
+static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alproto,
+ void *alstate, const uint64_t tx_id, void *tx_ptr, const int tx_end_state,
const uint8_t flow_flags)
{
- void *tx_ptr = AppLayerParserGetTx(ipproto, alproto, alstate, tx_id);
- if (tx_ptr == NULL) {
- DetectTransaction no_tx = { NULL, 0, NULL, 0, 0, 0, 0, 0, };
- return no_tx;
- }
const uint64_t detect_flags = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx_ptr, flow_flags);
if (detect_flags & APP_LAYER_TX_INSPECTED_FLAG) {
SCLogDebug("%"PRIu64" tx already fully inspected for %s. Flags %016"PRIx64,
uint64_t tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flow_flags);
const int tx_end_state = AppLayerParserGetStateProgressCompletionStatus(alproto, flow_flags);
- for ( ; tx_id < total_txs; tx_id++) {
- DetectTransaction tx = GetTx(ipproto, alproto,
- alstate, tx_id, tx_end_state, flow_flags);
+ 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;
+
+ DetectTransaction tx = GetDetectTx(ipproto, alproto,
+ alstate, ires.tx_id, ires.tx_ptr, tx_end_state, flow_flags);
if (tx.tx_ptr == NULL) {
SCLogDebug("%p/%"PRIu64" no transaction to inspect",
tx.tx_ptr, tx_id);
- continue;
+ goto next;
}
uint32_t array_idx = 0;
AppLayerParserSetTxDetectFlags(ipproto, alproto, tx.tx_ptr,
flow_flags, new_detect_flags);
}
+next:
+ if (!ires.has_next)
+ break;
}
}