29.4.10. Flow Life Cycle Callbacks
Flow lifecycle callbacks let plugins and library users observe when Suricata initializes a flow, updates a flow with a packet, and finishes with a flow.
These callbacks are useful for maintaining plugin state that follows the lifetime of a Suricata flow. For example, a plugin can allocate per-flow state from the init callback, update it as packets are seen, and perform final accounting from the finish callback.
29.4.10.1. C API
29.4.10.1.1. Flow Init Callback
The init callback is called when Suricata initializes a flow.
/** \brief Function type for flow initialization callbacks.
*
* Once registered with SCFlowRegisterInitCallback, this function will
* be called every time a flow is initialized, or in other words,
* every time Suricata picks up a flow.
*
* \param tv The ThreadVars data structure for the thread creating the
* flow.
* \param f The newly initialized flow.
* \param p The packet related to creating the new flow.
* \param user The user data provided during callback registration.
*/
typedef void (*SCFlowInitCallbackFn)(ThreadVars *tv, Flow *f, const Packet *p, void *user);
Register an init callback with SCFlowRegisterInitCallback.
/** \brief Register a flow init callback.
*
* Register a user provided function to be called every time a flow is
* initialized for use.
*
* \param fn Pointer to function to be called
* \param user Additional user data to be passed to callback
*
* \returns true if callback was registered, otherwise false if the
* callback could not be registered due to memory allocation error.
*/
bool SCFlowRegisterInitCallback(SCFlowInitCallbackFn fn, void *user);
29.4.10.1.2. Flow Update Callback
The update callback is called when Suricata updates a flow with a packet.
/** \brief Function type for flow update callbacks.
*
* Once registered with SCFlowRegisterUpdateCallback, this function
* will be called every time a flow is updated by a packet (basically
* everytime a packet is seen on a flow).
*
* \param tv The ThreadVars data structure for the thread updating the
* flow.
* \param f The flow being updated.
* \param p The packet responsible for the flow update.
* \param user The user data provided during callback registration.
*/
typedef void (*SCFlowUpdateCallbackFn)(ThreadVars *tv, Flow *f, Packet *p, void *user);
Register an update callback with SCFlowRegisterUpdateCallback.
/** \brief Register a flow update callback.
*
* Register a user provided function to be called everytime a flow is
* updated.
*
* \param fn Pointer to function to be called
* \param user Additional user data to be passed to callback
*
* \returns true if callback was registered, otherwise false if the
* callback could not be registered due to memory allocation error.
*/
bool SCFlowRegisterUpdateCallback(SCFlowUpdateCallbackFn fn, void *user);
29.4.10.1.3. Flow Finish Callback
The finish callback is called when Suricata is done with a flow.
/** \brief Function type for flow finish callbacks.
*
* Once registered with SCFlowRegisterFinshCallback, this function
* will be called when Suricata is done with a flow.
*
* \param tv The ThreadVars data structure for the thread finishing
* the flow.
* \param f The flow being finshed.
* \param user The user data provided during callback registration.
*/
typedef void (*SCFlowFinishCallbackFn)(ThreadVars *tv, Flow *f, void *user);
Register a finish callback with SCFlowRegisterFinishCallback.
bool SCFlowRegisterFinishCallback(SCFlowFinishCallbackFn fn, void *user);
29.4.10.1.4. Example
static void ExampleFlowInit(ThreadVars *tv, Flow *f, const Packet *p, void *user)
{
SCLogNotice("flow initialized: %p", f);
}
static void ExampleFlowUpdate(ThreadVars *tv, Flow *f, Packet *p, void *user)
{
SCLogNotice("flow updated: %p packet: %p", f, p);
}
static void ExampleFlowFinish(ThreadVars *tv, Flow *f, void *user)
{
SCLogNotice("flow finished: %p", f);
}
static void ExampleInit(void)
{
SCFlowRegisterInitCallback(ExampleFlowInit, NULL);
SCFlowRegisterUpdateCallback(ExampleFlowUpdate, NULL);
SCFlowRegisterFinishCallback(ExampleFlowFinish, NULL);
}
29.4.10.2. Rust API
In Rust, use the suricata_ffi::flow module:
flow::register_init_callbackflow::register_update_callbackflow::register_finish_callback
The Rust wrappers register closures or function items and return
Result<(), &'static str>.
use suricata_ffi::flow::{self, Flow, Packet};
use suricata_ffi::thread::ThreadVars;
use suricata_ffi::SCLogNotice;
fn flow_init(_tv: &mut ThreadVars, f: *mut Flow, _p: *const Packet) {
SCLogNotice!("flow initialized: {:p}", f);
}
fn flow_update(_tv: &mut ThreadVars, f: *mut Flow, p: *mut Packet) {
SCLogNotice!("flow updated: {:p} packet: {:p}", f, p);
}
fn flow_finish(_tv: &mut ThreadVars, f: *mut Flow) {
SCLogNotice!("flow finished: {:p}", f);
}
fn register_flow_callbacks() -> Result<(), &'static str> {
flow::register_init_callback(flow_init)?;
flow::register_update_callback(flow_update)?;
flow::register_finish_callback(flow_finish)?;
Ok(())
}
The raw pointers passed into callbacks are only valid for the duration of the callback invocation and must not be stored. Rust callbacks must not panic.