Coverage Report

Created: 2026-05-16 07:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/conf.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
//! Module for retrieving configuration details.
19
20
use std::os::raw::c_char;
21
use std::os::raw::c_void;
22
use std::os::raw::c_int;
23
use std::ffi::{CString, CStr};
24
use std::ptr;
25
use std::str;
26
use nom7::{
27
    character::complete::{multispace0, not_line_ending},
28
    sequence::{preceded, tuple},
29
    number::complete::double,
30
    combinator::verify,
31
    IResult,
32
};
33
34
/// cbindgen:ignore
35
extern "C" {
36
    fn ConfGet(key: *const c_char, res: *mut *const c_char) -> i8;
37
    fn ConfGetChildValue(conf: *const c_void, key: *const c_char,
38
                         vptr: *mut *const c_char) -> i8;
39
    fn ConfGetChildValueBool(conf: *const c_void, key: *const c_char,
40
                             vptr: *mut c_int) -> i8;
41
    fn ConfGetNode(key: *const c_char) -> *const c_void;
42
}
43
44
34
pub fn conf_get_node(key: &str) -> Option<ConfNode> {
45
34
    let key = if let Ok(key) = CString::new(key) {
46
34
        key
47
    } else {
48
0
        return None;
49
    };
50
51
34
    let node = unsafe { ConfGetNode(key.as_ptr()) };
52
34
    if node.is_null() {
53
1
        None
54
    } else {
55
33
        Some(ConfNode::wrap(node))
56
    }
57
34
}
58
59
// Return the string value of a configuration value.
60
2.00k
pub fn conf_get(key: &str) -> Option<&str> {
61
2.00k
    let mut vptr: *const c_char = ptr::null_mut();
62
63
    unsafe {
64
2.00k
        let s = CString::new(key).unwrap();
65
2.00k
        if ConfGet(s.as_ptr(), &mut vptr) != 1 {
66
            SCLogDebug!("Failed to find value for key {}", key);
67
1.97k
            return None;
68
33
        }
69
    }
70
71
33
    if vptr.is_null() {
72
0
        return None;
73
33
    }
74
75
33
    let value = str::from_utf8(unsafe{
76
33
        CStr::from_ptr(vptr).to_bytes()
77
33
    }).unwrap();
78
79
33
    return Some(value);
80
2.00k
}
81
82
// Return the value of key as a boolean. A value that is not set is
83
// the same as having it set to false.
84
34
pub fn conf_get_bool(key: &str) -> bool {
85
34
    if let Some("1" | "yes" | "true" | "on") = conf_get(key) {
86
33
        return true;
87
1
    }
88
89
1
    return false;
90
34
}
91
92
/// Wrap a Suricata ConfNode and expose some of its methods with a
93
/// Rust friendly interface.
94
pub struct ConfNode {
95
    pub conf: *const c_void,
96
}
97
98
impl ConfNode {
99
100
35
    pub fn wrap(conf: *const c_void) -> Self {
101
35
        return Self { conf }
102
35
    }
103
104
0
    pub fn get_child_value(&self, key: &str) -> Option<&str> {
105
0
        let mut vptr: *const c_char = ptr::null_mut();
106
107
        unsafe {
108
0
            let s = CString::new(key).unwrap();
109
0
            if ConfGetChildValue(self.conf,
110
0
                                 s.as_ptr(),
111
0
                                 &mut vptr) != 1 {
112
0
                return None;
113
0
            }
114
        }
115
116
0
        if vptr.is_null() {
117
0
            return None;
118
0
        }
119
120
0
        let value = str::from_utf8(unsafe{
121
0
            CStr::from_ptr(vptr).to_bytes()
122
0
        }).unwrap();
123
124
0
        return Some(value);
125
0
    }
126
127
2
    pub fn get_child_bool(&self, key: &str) -> bool {
128
2
        let mut vptr: c_int = 0;
129
130
        unsafe {
131
2
            let s = CString::new(key).unwrap();
132
2
            if ConfGetChildValueBool(self.conf,
133
2
                                     s.as_ptr(),
134
2
                                     &mut vptr) != 1 {
135
0
                return false;
136
2
            }
137
        }
138
139
2
        if vptr == 1 {
140
2
            return true;
141
0
        }
142
0
        return false;
143
2
    }
144
}
145
146
const BYTE: u64       = 1;
147
const KILOBYTE: u64   = 1024;
148
const MEGABYTE: u64   = 1_048_576;
149
const GIGABYTE: u64   = 1_073_741_824;
150
151
/// Helper function to retrieve memory unit from a string slice
152
///
153
/// Return value: u64
154
///
155
/// # Arguments
156
///
157
/// * `unit` - A string slice possibly containing memory unit
158
0
fn get_memunit(unit: &str) -> u64 {
159
0
    let unit = &unit.to_lowercase()[..];
160
0
    match unit {
161
0
        "b"     => { BYTE }
162
0
        "kb"    => { KILOBYTE }
163
0
        "mb"    => { MEGABYTE }
164
0
        "gb"    => { GIGABYTE }
165
0
        _       => { 0 }
166
    }
167
0
}
168
169
/// Parses memory units from human readable form to machine readable
170
///
171
/// Return value:
172
///     Result => Ok(u64)
173
///            => Err(error string)
174
///
175
/// # Arguments
176
///
177
/// * `arg` - A string slice that holds the value parsed from the config
178
0
pub fn get_memval(arg: &str) -> Result<u64, &'static str> {
179
0
    let arg = arg.trim();
180
    let val: f64;
181
    let mut unit: &str;
182
0
    let mut parser = tuple((preceded(multispace0, double),
183
0
                        preceded(multispace0, verify(not_line_ending, |c: &str| c.len() < 3))));
184
0
    let r: IResult<&str, (f64, &str)> = parser(arg);
185
0
    if let Ok(r) = r {
186
0
        val = (r.1).0;
187
0
        unit = (r.1).1;
188
0
    } else {
189
0
        return Err("Error parsing the memory value");
190
    }
191
0
    if unit.is_empty() {
192
0
        unit = "B";
193
0
    }
194
0
    let unit = get_memunit(unit);
195
0
    if unit == 0 {
196
0
        return Err("Invalid memory unit");
197
0
    }
198
0
    let res = val * unit as f64;
199
0
    Ok(res as u64)
200
0
}
201
202
#[cfg(test)]
203
mod tests {
204
    use super::*;
205
206
    #[test]
207
    fn test_memval_nospace() {
208
        let s = "10";
209
        let res = 10 ;
210
        assert_eq!(Ok(10), get_memval(s));
211
212
        let s = "10kb";
213
        assert_eq!(Ok(res * KILOBYTE), get_memval(s));
214
215
        let s = "10Kb";
216
        assert_eq!(Ok(res * KILOBYTE), get_memval(s));
217
218
        let s = "10KB";
219
        assert_eq!(Ok(res * KILOBYTE), get_memval(s));
220
221
        let s = "10mb";
222
        assert_eq!(Ok(res * MEGABYTE), get_memval(s));
223
224
        let s = "10gb";
225
        assert_eq!(Ok(res * GIGABYTE), get_memval(s));
226
    }
227
228
    #[test]
229
    fn test_memval_space_start() {
230
        let s = " 10";
231
        let res = 10 ;
232
        assert_eq!(Ok(res), get_memval(s));
233
234
        let s = " 10Kb";
235
        assert_eq!(Ok(res * KILOBYTE), get_memval(s));
236
237
        let s = "     10mb";
238
        assert_eq!(Ok(res * MEGABYTE), get_memval(s));
239
240
        let s = "        10Gb";
241
        assert_eq!(Ok(res * GIGABYTE), get_memval(s));
242
243
        let s = "   30b";
244
        assert_eq!(Ok(30), get_memval(s));
245
    }
246
247
    #[test]
248
    fn test_memval_space_end() {
249
        let s = " 10                  ";
250
        let res = 10 ;
251
        assert_eq!(Ok(res), get_memval(s));
252
253
        let s = "10Kb    ";
254
        assert_eq!(Ok(res * KILOBYTE), get_memval(s));
255
256
        let s = "10mb            ";
257
        assert_eq!(Ok(res * MEGABYTE), get_memval(s));
258
259
        let s = "        10Gb           ";
260
        assert_eq!(Ok(res * GIGABYTE), get_memval(s));
261
262
        let s = "   30b                    ";
263
        assert_eq!(Ok(30), get_memval(s));
264
    }
265
266
    #[test]
267
    fn test_memval_space_in_bw() {
268
        let s = " 10                  ";
269
        let res = 10 ;
270
        assert_eq!(Ok(res), get_memval(s));
271
272
        let s = "10 Kb    ";
273
        assert_eq!(Ok(res * KILOBYTE), get_memval(s));
274
275
        let s = "10 mb";
276
        assert_eq!(Ok(res * MEGABYTE), get_memval(s));
277
278
        let s = "        10 Gb           ";
279
        assert_eq!(Ok(res * GIGABYTE), get_memval(s));
280
281
        let s = "30 b";
282
        assert_eq!(Ok(30), get_memval(s));
283
    }
284
285
    #[test]
286
    fn test_memval_float_val() {
287
        let s = " 10.5                  ";
288
        assert_eq!(Ok(10), get_memval(s));
289
290
        let s = "10.8Kb    ";
291
        assert_eq!(Ok((10.8 * KILOBYTE as f64) as u64), get_memval(s));
292
293
        let s = "10.4 mb            ";
294
        assert_eq!(Ok((10.4 * MEGABYTE as f64) as u64), get_memval(s));
295
296
        let s = "        10.5Gb           ";
297
        assert_eq!(Ok((10.5 * GIGABYTE as f64) as u64), get_memval(s));
298
299
        let s = "   30.0 b                    ";
300
        assert_eq!(Ok(30), get_memval(s));
301
    }
302
303
    #[test]
304
    fn test_memval_erroneous_val() {
305
        let s = "5eb";
306
        assert!(get_memval(s).is_err());
307
308
        let s = "5 1kb";
309
        assert!(get_memval(s).is_err());
310
311
        let s = "61k b";
312
        assert!(get_memval(s).is_err());
313
314
        let s = "8 8 k b";
315
        assert!(get_memval(s).is_err());
316
    }
317
}