18.3.4. Flow
Flows are exposed to Lua scripts with the suricata.flow
library. To use it, the script must require it. For example:
local flow = require("suricata.flow")
Following are the functions currently available for acessing Flow details.
18.3.4.1. Initialization
18.3.4.1.1. get
Init the flow for use in the script. The flow is the current one the engine is processing.
f = flow.get()
18.3.4.2. Time
18.3.4.2.1. timestamps
Get timestamps of the first and the last packets from the flow, as seconds and microseconds since 1970-01-01 00:00:00 UTC, returning 4 numbers:
f = flow.get()
local start_sec, start_usec, last_sec, last_usec = f:timestamps()
18.3.4.2.2. timestring_legacy
Get the timestamp of the first packet from the flow, as a string in the format: 11/24/2009-18:57:25.179869. This is the format used by fast.log, http.log and other legacy outputs.
f = flow.get()
print f:timestring_legacy()
18.3.4.2.3. timestring_iso8601
Get the timestamp of the first packet from the flow, as a string in the format: 2015-10-06T15:16:43.136733+0000. This is the format used by EVE outputs.
f = flow.get()
print f:timestring_iso8601()
18.3.4.3. Ports and Addresses
18.3.4.4. tuple
Using the tuple method, the IP version (4 or 6), src IP and dest IP (as string), IP protocol (int), and ports (ints) are retrieved.
The protocol value comes from the IP header. See further https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml .
f = flow.get()
ipver, srcip, dstip, proto, sp, dp = f:tuple()
18.3.4.5. App Layer Protocols
18.3.4.5.1. app_layer_proto
Get alproto from the flow as a string. If an alproto is not (yet) known, it returns "unknown".
Returns 5 values: <alproto>, <alproto_ts>, <alproto_tc>, <alproto_orig>, <alproto_expect>.
Example:
f = flow.get()
alproto, alproto_ts, alproto_tc, alproto_orig, alproto_expect = f:app_layer_proto()
orig and expect are used when changing and upgrading protocols. In an SMTP STARTTLS case, orig would normally be set to "smtp" and expect to "tls".
18.3.4.6. Misc
18.3.4.6.1. has_alerts
Returns true if the flow has alerts.
f = flow.get()
alerted = f:has_alerts()
18.3.4.6.2. id
Get the flow id. Note that simply printing the id
will likely result in
printing a scientific notation. To avoid that, simply do:
f = flow.get()
id = f:id()
id_str = string.format("%.0f", id)
print ("Flow ID: " .. id_str .."\n")
18.3.4.6.3. stats
Get the packet and byte counts (for both directions), as 4 numbers, per flow.
f = flow.get()
tscnt, tsbytes, tccnt, tcbytes = f:stats()
18.3.4.7. Example
A simple log
function for a script to output Flow details if the flow
triggered an alert:
function log(args)
local f = flow.get()
ts = f:timestring_iso8601()
has_alerts = f:has_alerts()
ipver, srcip, dstip, proto, sp, dp = f:tuple()
alproto, alproto_ts, alproto_tc, alproto_orig, alproto_expect = f:app_layer_proto()
start_sec, start_usec, last_sec, last_usec = f:timestamps()
id = f:id()
if has_alerts then
file:write ("[**] Start time " .. ts .. " [**] -> alproto " .. alproto .. " [**] " .. proto .. " [**] alerted: true\n[**] First packet: " .. start_sec .." [**] Last packet: " .. last_sec .. " [**] Flow id: " .. id .. "\n")
file:flush()
end
end
For complete scripts using these and other lua functions, the Suricata-verify can be a good resource: https://github.com/OISF/suricata-verify/tree/master/tests .