/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 | | } |