Skip to content

Commit 15b6f2a

Browse files
Jason Ishjasonish
authored andcommitted
rust/ffi: add flow accessors to flow wrapper
Ticket: OISF#8599
1 parent 6d948dd commit 15b6f2a

2 files changed

Lines changed: 108 additions & 1 deletion

File tree

examples/plugins/rust/src/mod.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,32 @@ fn log_eve_wrapped(
9898
jb.set_string("example", "eve-callback")?;
9999
jb.set_string("has_flow", if f.is_some() { "true" } else { "false" })?;
100100

101-
// If we have a flow, log something from flow storage.
101+
// If we have a flow, show the `Flow` wrapper accessors and log something
102+
// from flow storage.
102103
if let Some(f) = f {
104+
let src_ip = f
105+
.source_address()
106+
.map(|addr| addr.to_string())
107+
.unwrap_or_else(|| "<unknown>".to_string());
108+
let dst_ip = f
109+
.destination_address()
110+
.map(|addr| addr.to_string())
111+
.unwrap_or_else(|| "<unknown>".to_string());
112+
let toserver = f.to_server_packet_count();
113+
let toclient = f.to_client_packet_count();
114+
115+
jb.open_object("flow_accessors")?;
116+
jb.set_string("src_ip", &src_ip)?;
117+
jb.set_uint("src_port", f.source_port() as u64)?;
118+
jb.set_string("dest_ip", &dst_ip)?;
119+
jb.set_uint("dest_port", f.destination_port() as u64)?;
120+
jb.set_uint("ip_proto", f.ip_protocol() as u64)?;
121+
jb.set_uint("app_proto", f.app_protocol() as u64)?;
122+
jb.set_uint("toserver_pkts", toserver as u64)?;
123+
jb.set_uint("toclient_pkts", toclient as u64)?;
124+
jb.set_uint("last_seen", f.last_time().as_secs())?;
125+
jb.close()?;
126+
103127
if let Some(state) = flow_storage.get(f) {
104128
jb.set_uint("flow_packets", state.packets)?;
105129
}

rust/ffi/src/flow.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
use std::ffi::CString;
1919
use std::marker::PhantomData;
20+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2021
use std::os::raw::c_void;
22+
use std::time::Duration;
2123

2224
use suricata_sys::sys::{
2325
self, Packet, SCFlowGetStorageById, SCFlowRegisterFinishCallback, SCFlowRegisterInitCallback,
@@ -58,6 +60,87 @@ impl<'a> Flow<'a> {
5860
fn as_mut_ptr(&mut self) -> *mut sys::Flow {
5961
self.flow
6062
}
63+
64+
/// Return the time of the last flow update as a `Duration` since the epoch.
65+
pub fn last_time(&self) -> Duration {
66+
let mut secs: u64 = 0;
67+
let mut usecs: u64 = 0;
68+
unsafe {
69+
sys::SCFlowGetLastTimeAsParts(self.as_ptr(), &mut secs, &mut usecs);
70+
}
71+
Duration::new(secs, usecs as u32 * 1000)
72+
}
73+
74+
/// Return the flow flags.
75+
pub fn flags(&self) -> u64 {
76+
unsafe { sys::SCFlowGetFlags(self.as_ptr()) }
77+
}
78+
79+
/// Return true if the flow is IPv4.
80+
pub fn is_ipv4(&self) -> bool {
81+
unsafe { sys::SCFlowIsIPv4(self.as_ptr()) }
82+
}
83+
84+
/// Return true if the flow is IPv6.
85+
pub fn is_ipv6(&self) -> bool {
86+
unsafe { sys::SCFlowIsIPv6(self.as_ptr()) }
87+
}
88+
89+
/// Return the flow IP protocol.
90+
pub fn ip_protocol(&self) -> u8 {
91+
unsafe { sys::SCFlowGetIPProtocol(self.as_ptr()) }
92+
}
93+
94+
/// Return the flow app-layer protocol.
95+
pub fn app_protocol(&self) -> sys::AppProto {
96+
unsafe { sys::SCFlowGetAppProtocol(self.as_ptr()) }
97+
}
98+
99+
/// Return the flow source port.
100+
pub fn source_port(&self) -> u16 {
101+
unsafe { sys::SCFlowGetSourcePort(self.as_ptr()) }
102+
}
103+
104+
/// Return the flow destination port.
105+
pub fn destination_port(&self) -> u16 {
106+
unsafe { sys::SCFlowGetDestinationPort(self.as_ptr()) }
107+
}
108+
109+
/// Return the flow source address.
110+
pub fn source_address(&self) -> Option<IpAddr> {
111+
let ptr = unsafe { sys::SCFlowGetSourceAddress(self.as_ptr()) };
112+
self.address_from_ptr(ptr)
113+
}
114+
115+
/// Return the flow destination address.
116+
pub fn destination_address(&self) -> Option<IpAddr> {
117+
let ptr = unsafe { sys::SCFlowGetDestinationAddress(self.as_ptr()) };
118+
self.address_from_ptr(ptr)
119+
}
120+
121+
/// Return the number of packets seen to-server.
122+
pub fn to_server_packet_count(&self) -> u32 {
123+
unsafe { sys::SCFlowGetToServerPacketCount(self.as_ptr()) }
124+
}
125+
126+
/// Return the number of packets seen to-client.
127+
pub fn to_client_packet_count(&self) -> u32 {
128+
unsafe { sys::SCFlowGetToClientPacketCount(self.as_ptr()) }
129+
}
130+
131+
fn address_from_ptr(&self, ptr: *const sys::SCFlowAddress) -> Option<IpAddr> {
132+
let address = unsafe { ptr.as_ref()? };
133+
let bytes = unsafe { address.address.address_un_data8 };
134+
if self.is_ipv4() {
135+
Some(IpAddr::V4(Ipv4Addr::new(
136+
bytes[0], bytes[1], bytes[2], bytes[3],
137+
)))
138+
} else if self.is_ipv6() {
139+
Some(IpAddr::V6(Ipv6Addr::from(bytes)))
140+
} else {
141+
None
142+
}
143+
}
61144
}
62145

63146
/// A typed handle to a per-flow storage slot.

0 commit comments

Comments
 (0)