Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/src/detect/mod.rs
Line
Count
Source
1
/* Copyright (C) 2022 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
//! Module for rule parsing.
19
20
pub mod byte_extract;
21
pub mod byte_math;
22
pub mod entropy;
23
pub mod error;
24
pub mod flow;
25
pub mod iprep;
26
pub mod parser;
27
pub mod requires;
28
pub mod stream_size;
29
pub mod transforms;
30
pub mod uint;
31
pub mod float;
32
pub mod uri;
33
pub mod tojson;
34
pub mod vlan;
35
pub mod datasets;
36
37
use std::os::raw::c_int;
38
use std::ffi::CString;
39
40
use suricata_sys::sys::{
41
    DetectEngineCtx, SCDetectHelperKeywordRegister, SCDetectHelperKeywordSetCleanCString,
42
    SCSigTableAppLiteElmt, Signature,
43
};
44
45
/// EnumString trait that will be implemented on enums that
46
/// derive StringEnum.
47
pub trait EnumString<T> {
48
    /// Return the enum variant of the given numeric value.
49
    fn from_u(v: T) -> Option<Self> where Self: Sized;
50
51
    /// Convert the enum variant to the numeric value.
52
    fn into_u(self) -> T;
53
54
    /// Return the string for logging the enum value.
55
    fn to_str(&self) -> &'static str;
56
57
    /// Get an enum variant from parsing a string.
58
    fn from_str(s: &str) -> Option<Self> where Self: Sized;
59
}
60
61
/// Rust app-layer light version of SigTableElmt for simple sticky buffer
62
pub struct SigTableElmtStickyBuffer {
63
    /// keyword name
64
    pub name: String,
65
    /// keyword description
66
    pub desc: String,
67
    /// keyword documentation url
68
    pub url: String,
69
    /// function callback to parse and setup keyword in rule
70
    pub setup: unsafe extern "C" fn(
71
        de: *mut DetectEngineCtx,
72
        s: *mut Signature,
73
        raw: *const std::os::raw::c_char,
74
    ) -> c_int,
75
}
76
77
2.14k
pub fn helper_keyword_register_sticky_buffer(kw: &SigTableElmtStickyBuffer) -> u16 {
78
2.14k
    let name = CString::new(kw.name.as_bytes()).unwrap().into_raw();
79
2.14k
    let desc = CString::new(kw.desc.as_bytes()).unwrap().into_raw();
80
2.14k
    let url = CString::new(kw.url.as_bytes()).unwrap().into_raw();
81
2.14k
    let st = SCSigTableAppLiteElmt {
82
2.14k
        name,
83
2.14k
        desc,
84
2.14k
        url,
85
2.14k
        Setup: Some(kw.setup),
86
2.14k
        flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER,
87
2.14k
        AppLayerTxMatch: None,
88
2.14k
        Free: None,
89
2.14k
    };
90
    unsafe {
91
2.14k
        let r = SCDetectHelperKeywordRegister(&st);
92
2.14k
        SCDetectHelperKeywordSetCleanCString(r);
93
2.14k
        return r;
94
    }
95
2.14k
}
96
97
#[repr(C)]
98
#[allow(non_snake_case)]
99
/// Names of SigTableElmt for release by rust
100
pub struct SCSigTableNamesElmt {
101
    /// keyword name
102
    pub name: *mut libc::c_char,
103
    /// keyword description
104
    pub desc: *mut libc::c_char,
105
    /// keyword documentation url
106
    pub url: *mut libc::c_char,
107
}
108
109
#[no_mangle]
110
0
pub unsafe extern "C" fn SCDetectSigMatchNamesFree(kw: &mut SCSigTableNamesElmt) {
111
0
    let _ = CString::from_raw(kw.name);
112
0
    let _ = CString::from_raw(kw.desc);
113
0
    let _ = CString::from_raw(kw.url);
114
0
}
115
116
// TODO bindgen these
117
pub const SIGMATCH_NOOPT: u16 = 1; // BIT_U16(0) in detect.h
118
pub(crate) const SIGMATCH_OPTIONAL_OPT: u16 = 0x10; // BIT_U16(4) in detect.h
119
pub(crate) const SIGMATCH_QUOTES_MANDATORY: u16 = 0x40; // BIT_U16(6) in detect.h
120
pub const SIGMATCH_INFO_STICKY_BUFFER: u16 = 0x200; // BIT_U16(9)
121
pub(crate) const SIGMATCH_SUPPORT_FIREWALL: u16 = 0x1000; // BIT_U16(12)
122
123
#[repr(u8)]
124
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
125
// endian <big|little|dce>
126
pub enum ByteEndian {
127
    BigEndian = 1,
128
    LittleEndian = 2,
129
    EndianDCE = 3,
130
}
131
132
#[repr(u8)]
133
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
134
pub enum ByteBase {
135
    BaseOct = 8,
136
    BaseDec = 10,
137
    BaseHex = 16,
138
}
139
140
5.03k
fn get_string_value(value: &str) -> Option<ByteBase> {
141
5.03k
    let res = match value {
142
5.03k
        "hex" => Some(ByteBase::BaseHex),
143
4.95k
        "oct" => Some(ByteBase::BaseOct),
144
4.95k
        "dec" => Some(ByteBase::BaseDec),
145
0
        _ => None,
146
    };
147
148
5.03k
    res
149
5.03k
}
150
151
276
fn get_endian_value(value: &str) -> Option<ByteEndian> {
152
276
    let res = match value {
153
276
        "big" => Some(ByteEndian::BigEndian),
154
276
        "little" => Some(ByteEndian::LittleEndian),
155
274
        "dce" => Some(ByteEndian::EndianDCE),
156
0
        _ => None,
157
    };
158
159
276
    res
160
276
}
161
162
#[cfg(test)]
163
mod test {
164
    use super::*;
165
    use suricata_derive::EnumStringU8;
166
167
    #[derive(Clone, Debug, PartialEq, EnumStringU8)]
168
    #[repr(u8)]
169
    pub enum TestEnum {
170
        Zero = 0,
171
        BestValueEver = 42,
172
    }
173
174
    #[test]
175
    fn test_enum_string_u8() {
176
        assert_eq!(TestEnum::from_u(0), Some(TestEnum::Zero));
177
        assert_eq!(TestEnum::from_u(1), None);
178
        assert_eq!(TestEnum::from_u(42), Some(TestEnum::BestValueEver));
179
        assert_eq!(TestEnum::Zero.into_u(), 0);
180
        assert_eq!(TestEnum::BestValueEver.into_u(), 42);
181
        assert_eq!(TestEnum::Zero.to_str(), "zero");
182
        assert_eq!(TestEnum::BestValueEver.to_str(), "best_value_ever");
183
        assert_eq!(TestEnum::from_str("zero"), Some(TestEnum::Zero));
184
        assert_eq!(TestEnum::from_str("nope"), None);
185
        assert_eq!(TestEnum::from_str("best_value_ever"), Some(TestEnum::BestValueEver));
186
    }
187
}