/src/suricata7/rust/src/core.rs
Line | Count | Source |
1 | | /* Copyright (C) 2017 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | //! This module exposes items from the core "C" code to Rust. |
19 | | |
20 | | use std; |
21 | | use crate::filecontainer::*; |
22 | | use crate::debug_validate_fail; |
23 | | |
24 | | /// Opaque C types. |
25 | | pub enum DetectEngineState {} |
26 | | pub enum AppLayerDecoderEvents {} |
27 | | |
28 | | #[repr(C)] |
29 | | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
30 | | #[allow(non_camel_case_types)] |
31 | | pub enum AppLayerEventType { |
32 | | APP_LAYER_EVENT_TYPE_TRANSACTION = 1, |
33 | | APP_LAYER_EVENT_TYPE_PACKET = 2, |
34 | | } |
35 | | |
36 | | pub const STREAM_START: u8 = 0x01; |
37 | | pub const STREAM_EOF: u8 = 0x02; |
38 | | pub const STREAM_TOSERVER: u8 = 0x04; |
39 | | pub const STREAM_TOCLIENT: u8 = 0x08; |
40 | | pub const STREAM_GAP: u8 = 0x10; |
41 | | pub const STREAM_DEPTH: u8 = 0x20; |
42 | | pub const STREAM_MIDSTREAM:u8 = 0x40; |
43 | | pub const DIR_BOTH: u8 = 0b0000_1100; |
44 | | const DIR_TOSERVER: u8 = 0b0000_0100; |
45 | | const DIR_TOCLIENT: u8 = 0b0000_1000; |
46 | | |
47 | | #[repr(C)] |
48 | | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
49 | | pub enum Direction { |
50 | | ToServer = 0x04, |
51 | | ToClient = 0x08, |
52 | | } |
53 | | |
54 | | impl Direction { |
55 | | /// Return true if the direction is to server. |
56 | 32.7M | pub fn is_to_server(&self) -> bool { |
57 | 32.7M | matches!(self, Self::ToServer) |
58 | 32.7M | } |
59 | | |
60 | | /// Return true if the direction is to client. |
61 | 32.7M | pub fn is_to_client(&self) -> bool { |
62 | 32.7M | matches!(self, Self::ToClient) |
63 | 32.7M | } |
64 | | } |
65 | | |
66 | | impl Default for Direction { |
67 | 405k | fn default() -> Self { Direction::ToServer } |
68 | | } |
69 | | |
70 | | impl std::fmt::Display for Direction { |
71 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
72 | 0 | match self { |
73 | 0 | Self::ToServer => write!(f, "toserver"), |
74 | 0 | Self::ToClient => write!(f, "toclient"), |
75 | | } |
76 | 0 | } |
77 | | } |
78 | | |
79 | | impl From<u8> for Direction { |
80 | 31.3M | fn from(d: u8) -> Self { |
81 | 31.3M | if d & (DIR_TOSERVER | DIR_TOCLIENT) == (DIR_TOSERVER | DIR_TOCLIENT) { |
82 | 0 | debug_validate_fail!("Both directions are set"); |
83 | 0 | Direction::ToServer |
84 | 31.3M | } else if d & DIR_TOSERVER != 0 { |
85 | 14.9M | Direction::ToServer |
86 | 16.4M | } else if d & DIR_TOCLIENT != 0 { |
87 | 16.4M | Direction::ToClient |
88 | | } else { |
89 | 0 | debug_validate_fail!("Unknown direction!!"); |
90 | 0 | Direction::ToServer |
91 | | } |
92 | 31.3M | } |
93 | | } |
94 | | |
95 | | impl From<Direction> for u8 { |
96 | 1.57G | fn from(d: Direction) -> u8 { |
97 | 1.57G | d as u8 |
98 | 1.57G | } |
99 | | } |
100 | | |
101 | | // Application layer protocol identifiers (app-layer-protos.h) |
102 | | pub type AppProto = u16; |
103 | | |
104 | | pub const ALPROTO_UNKNOWN : AppProto = 0; |
105 | | pub static mut ALPROTO_FAILED : AppProto = 0; // updated during init |
106 | | |
107 | | pub const IPPROTO_TCP : u8 = 6; |
108 | | pub const IPPROTO_UDP : u8 = 17; |
109 | | |
110 | | /* |
111 | | macro_rules!BIT_U8 { |
112 | | ($x:expr) => (1 << $x); |
113 | | } |
114 | | */ |
115 | | macro_rules!BIT_U16 { |
116 | | ($x:expr) => (1 << $x); |
117 | | } |
118 | | |
119 | | macro_rules!BIT_U32 { |
120 | | ($x:expr) => (1 << $x); |
121 | | } |
122 | | |
123 | | macro_rules!BIT_U64 { |
124 | | ($x:expr) => (1 << $x); |
125 | | } |
126 | | |
127 | | // Flow flags |
128 | | pub const FLOW_DIR_REVERSED: u32 = BIT_U32!(26); |
129 | | |
130 | | // Defined in app-layer-protos.h |
131 | | /// cbindgen:ignore |
132 | | extern "C" { |
133 | | pub fn StringToAppProto(proto_name: *const u8) -> AppProto; |
134 | | } |
135 | | |
136 | | // |
137 | | // Function types for calls into C. |
138 | | // |
139 | | |
140 | | #[allow(non_snake_case)] |
141 | | pub type SCLogMessageFunc = |
142 | | extern "C" fn(level: std::os::raw::c_int, |
143 | | filename: *const std::os::raw::c_char, |
144 | | line: std::os::raw::c_uint, |
145 | | function: *const std::os::raw::c_char, |
146 | | subsystem: *const std::os::raw::c_char, |
147 | | message: *const std::os::raw::c_char) -> std::os::raw::c_int; |
148 | | |
149 | | pub type DetectEngineStateFreeFunc = |
150 | | extern "C" fn(state: *mut DetectEngineState); |
151 | | |
152 | | pub type AppLayerParserTriggerRawStreamReassemblyFunc = |
153 | | extern "C" fn (flow: *const Flow, direction: i32); |
154 | | pub type AppLayerDecoderEventsSetEventRawFunc = |
155 | | extern "C" fn (events: *mut *mut AppLayerDecoderEvents, |
156 | | event: u8); |
157 | | |
158 | | pub type AppLayerDecoderEventsFreeEventsFunc = |
159 | | extern "C" fn (events: *mut *mut AppLayerDecoderEvents); |
160 | | |
161 | | pub enum StreamingBufferConfig {} |
162 | | |
163 | | // Opaque flow type (defined in C) |
164 | | pub enum HttpRangeContainerBlock {} |
165 | | |
166 | | pub type SCHttpRangeFreeBlock = extern "C" fn ( |
167 | | c: *mut HttpRangeContainerBlock); |
168 | | pub type SCHTPFileCloseHandleRange = extern "C" fn ( |
169 | | sbcfg: &StreamingBufferConfig, |
170 | | fc: *mut FileContainer, |
171 | | flags: u16, |
172 | | c: *mut HttpRangeContainerBlock, |
173 | | data: *const u8, |
174 | | data_len: u32) -> bool; |
175 | | pub type SCFileOpenFileWithId = extern "C" fn ( |
176 | | file_container: &FileContainer, |
177 | | sbcfg: &StreamingBufferConfig, |
178 | | track_id: u32, |
179 | | name: *const u8, name_len: u16, |
180 | | data: *const u8, data_len: u32, |
181 | | flags: u16) -> i32; |
182 | | pub type SCFileCloseFileById = extern "C" fn ( |
183 | | file_container: &FileContainer, |
184 | | sbcfg: &StreamingBufferConfig, |
185 | | track_id: u32, |
186 | | data: *const u8, data_len: u32, |
187 | | flags: u16) -> i32; |
188 | | pub type SCFileAppendDataById = extern "C" fn ( |
189 | | file_container: &FileContainer, |
190 | | sbcfg: &StreamingBufferConfig, |
191 | | track_id: u32, |
192 | | data: *const u8, data_len: u32) -> i32; |
193 | | pub type SCFileAppendGAPById = extern "C" fn ( |
194 | | file_container: &FileContainer, |
195 | | sbcfg: &StreamingBufferConfig, |
196 | | track_id: u32, |
197 | | data: *const u8, data_len: u32) -> i32; |
198 | | pub type SCFileContainerRecycle = extern "C" fn ( |
199 | | file_container: &FileContainer, |
200 | | sbcfg: &StreamingBufferConfig); |
201 | | |
202 | | // A Suricata context that is passed in from C. This is alternative to |
203 | | // using functions from Suricata directly, so they can be wrapped so |
204 | | // Rust unit tests will still compile when they are not linked |
205 | | // directly to the real function. |
206 | | // |
207 | | // This might add a little too much complexity to keep pure Rust test |
208 | | // cases working. |
209 | | #[allow(non_snake_case)] |
210 | | #[repr(C)] |
211 | | pub struct SuricataContext { |
212 | | pub SCLogMessage: SCLogMessageFunc, |
213 | | DetectEngineStateFree: DetectEngineStateFreeFunc, |
214 | | AppLayerDecoderEventsSetEventRaw: AppLayerDecoderEventsSetEventRawFunc, |
215 | | AppLayerDecoderEventsFreeEvents: AppLayerDecoderEventsFreeEventsFunc, |
216 | | pub AppLayerParserTriggerRawStreamReassembly: AppLayerParserTriggerRawStreamReassemblyFunc, |
217 | | |
218 | | pub HttpRangeFreeBlock: SCHttpRangeFreeBlock, |
219 | | pub HTPFileCloseHandleRange: SCHTPFileCloseHandleRange, |
220 | | |
221 | | pub FileOpenFile: SCFileOpenFileWithId, |
222 | | pub FileCloseFile: SCFileCloseFileById, |
223 | | pub FileAppendData: SCFileAppendDataById, |
224 | | pub FileAppendGAP: SCFileAppendGAPById, |
225 | | pub FileContainerRecycle: SCFileContainerRecycle, |
226 | | |
227 | | pub AppLayerRegisterParser: extern "C" fn(parser: *const crate::applayer::RustParser, alproto: AppProto) -> std::os::raw::c_int, |
228 | | } |
229 | | |
230 | | #[allow(non_snake_case)] |
231 | | #[repr(C)] |
232 | | pub struct SuricataFileContext { |
233 | | pub files_sbcfg: &'static StreamingBufferConfig, |
234 | | } |
235 | | |
236 | | /// cbindgen:ignore |
237 | | extern "C" { |
238 | | pub fn SCGetContext() -> &'static mut SuricataContext; |
239 | | pub fn SCLogGetLogLevel() -> i32; |
240 | | } |
241 | | |
242 | | pub static mut SC: Option<&'static SuricataContext> = None; |
243 | | |
244 | 37 | pub fn init_ffi(context: &'static SuricataContext) |
245 | | { |
246 | 37 | unsafe { |
247 | 37 | SC = Some(context); |
248 | 37 | ALPROTO_FAILED = StringToAppProto("failed\0".as_ptr()); |
249 | 37 | } |
250 | 37 | } |
251 | | |
252 | | #[no_mangle] |
253 | 37 | pub extern "C" fn rs_init(context: &'static SuricataContext) |
254 | | { |
255 | 37 | init_ffi(context); |
256 | 37 | } |
257 | | |
258 | | /// DetectEngineStateFree wrapper. |
259 | 20.4k | pub fn sc_detect_engine_state_free(state: *mut DetectEngineState) |
260 | | { |
261 | | unsafe { |
262 | 20.4k | if let Some(c) = SC { |
263 | 20.4k | (c.DetectEngineStateFree)(state); |
264 | 20.4k | } |
265 | | } |
266 | 20.4k | } |
267 | | |
268 | | /// AppLayerParserTriggerRawStreamReassembly wrapper |
269 | 8.13M | pub fn sc_app_layer_parser_trigger_raw_stream_reassembly(flow: *const Flow, direction: i32) { |
270 | | unsafe { |
271 | 8.13M | if let Some(c) = SC { |
272 | 8.13M | (c.AppLayerParserTriggerRawStreamReassembly)(flow, direction); |
273 | 8.13M | } |
274 | | } |
275 | 8.13M | } |
276 | | |
277 | | /// AppLayerDecoderEventsSetEventRaw wrapper. |
278 | 47.2M | pub fn sc_app_layer_decoder_events_set_event_raw( |
279 | 47.2M | events: *mut *mut AppLayerDecoderEvents, event: u8) |
280 | | { |
281 | | unsafe { |
282 | 47.2M | if let Some(c) = SC { |
283 | 47.2M | (c.AppLayerDecoderEventsSetEventRaw)(events, event); |
284 | 47.2M | } |
285 | | } |
286 | 47.2M | } |
287 | | |
288 | | /// AppLayerDecoderEventsFreeEvents wrapper. |
289 | 38.4M | pub fn sc_app_layer_decoder_events_free_events( |
290 | 38.4M | events: *mut *mut AppLayerDecoderEvents) |
291 | | { |
292 | | unsafe { |
293 | 38.4M | if let Some(c) = SC { |
294 | 38.4M | (c.AppLayerDecoderEventsFreeEvents)(events); |
295 | 38.4M | } |
296 | | } |
297 | 38.4M | } |
298 | | |
299 | | /// Opaque flow type (defined in C) |
300 | | pub enum Flow {} |
301 | | |
302 | | // Extern functions operating on Flow. |
303 | | /// cbindgen:ignore |
304 | | extern "C" { |
305 | | pub fn FlowGetLastTimeAsParts(flow: &Flow, secs: *mut u64, usecs: *mut u64); |
306 | | pub fn FlowGetFlags(flow: &Flow) -> u32; |
307 | | pub fn FlowGetSourcePort(flow: &Flow) -> u16; |
308 | | pub fn FlowGetDestinationPort(flow: &Flow) -> u16; |
309 | | } |
310 | | |
311 | | /// Rust implementation of Flow. |
312 | | impl Flow { |
313 | | |
314 | | /// Return the time of the last flow update as a `Duration` |
315 | | /// since the epoch. |
316 | 6.38M | pub fn get_last_time(&mut self) -> std::time::Duration { |
317 | | unsafe { |
318 | 6.38M | let mut secs: u64 = 0; |
319 | 6.38M | let mut usecs: u64 = 0; |
320 | 6.38M | FlowGetLastTimeAsParts(self, &mut secs, &mut usecs); |
321 | 6.38M | std::time::Duration::new(secs, usecs as u32 * 1000) |
322 | | } |
323 | 6.38M | } |
324 | | |
325 | | /// Return the flow flags. |
326 | 11 | pub fn get_flags(&self) -> u32 { |
327 | 11 | unsafe { FlowGetFlags(self) } |
328 | 11 | } |
329 | | |
330 | | /// Return flow ports |
331 | 11 | pub fn get_ports(&self) -> (u16, u16) { |
332 | 11 | unsafe { (FlowGetSourcePort(self), FlowGetDestinationPort(self)) } |
333 | 11 | } |
334 | | } |
335 | | |
336 | | #[cfg(test)] |
337 | | mod test { |
338 | | use super::*; |
339 | | |
340 | | #[test] |
341 | | fn test_direction() { |
342 | | assert!(Direction::ToServer.is_to_server()); |
343 | | assert!(!Direction::ToServer.is_to_client()); |
344 | | |
345 | | assert!(Direction::ToClient.is_to_client()); |
346 | | assert!(!Direction::ToClient.is_to_server()); |
347 | | } |
348 | | } |