diff options
Diffstat (limited to '')
-rw-r--r-- | rust/src/conf.rs | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/rust/src/conf.rs b/rust/src/conf.rs new file mode 100644 index 0000000..50acf6c --- /dev/null +++ b/rust/src/conf.rs @@ -0,0 +1,322 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +//! Module for retrieving configuration details. + +use std::os::raw::c_char; +use std::os::raw::c_void; +use std::os::raw::c_int; +use std::ffi::{CString, CStr}; +use std::ptr; +use std::str; +use nom7::{ + character::complete::{multispace0, not_line_ending}, + sequence::{preceded, tuple}, + number::complete::double, + combinator::verify, + IResult, +}; + +extern { + fn ConfGet(key: *const c_char, res: *mut *const c_char) -> i8; + fn ConfGetChildValue(conf: *const c_void, key: *const c_char, + vptr: *mut *const c_char) -> i8; + fn ConfGetChildValueBool(conf: *const c_void, key: *const c_char, + vptr: *mut c_int) -> i8; + fn ConfGetNode(key: *const c_char) -> *const c_void; +} + +pub fn conf_get_node(key: &str) -> Option<ConfNode> { + let key = if let Ok(key) = CString::new(key) { + key + } else { + return None; + }; + + let node = unsafe { ConfGetNode(key.as_ptr()) }; + if node.is_null() { + None + } else { + Some(ConfNode::wrap(node)) + } +} + +// Return the string value of a configuration value. +pub fn conf_get(key: &str) -> Option<&str> { + let mut vptr: *const c_char = ptr::null_mut(); + + unsafe { + let s = CString::new(key).unwrap(); + if ConfGet(s.as_ptr(), &mut vptr) != 1 { + SCLogDebug!("Failed to find value for key {}", key); + return None; + } + } + + if vptr.is_null() { + return None; + } + + let value = str::from_utf8(unsafe{ + CStr::from_ptr(vptr).to_bytes() + }).unwrap(); + + return Some(value); +} + +// Return the value of key as a boolean. A value that is not set is +// the same as having it set to false. +pub fn conf_get_bool(key: &str) -> bool { + if let Some(val) = conf_get(key) { + match val { + "1" | "yes" | "true" | "on" => { + return true; + }, + _ => {}, + } + } + + return false; +} + +/// Wrap a Suricata ConfNode and expose some of its methods with a +/// Rust friendly interface. +pub struct ConfNode { + pub conf: *const c_void, +} + +impl ConfNode { + + pub fn wrap(conf: *const c_void) -> Self { + return Self { conf } + } + + pub fn get_child_value(&self, key: &str) -> Option<&str> { + let mut vptr: *const c_char = ptr::null_mut(); + + unsafe { + let s = CString::new(key).unwrap(); + if ConfGetChildValue(self.conf, + s.as_ptr(), + &mut vptr) != 1 { + return None; + } + } + + if vptr.is_null() { + return None; + } + + let value = str::from_utf8(unsafe{ + CStr::from_ptr(vptr).to_bytes() + }).unwrap(); + + return Some(value); + } + + pub fn get_child_bool(&self, key: &str) -> bool { + let mut vptr: c_int = 0; + + unsafe { + let s = CString::new(key).unwrap(); + if ConfGetChildValueBool(self.conf, + s.as_ptr(), + &mut vptr) != 1 { + return false; + } + } + + if vptr == 1 { + return true; + } + return false; + } + +} + +const BYTE: u64 = 1; +const KILOBYTE: u64 = 1024; +const MEGABYTE: u64 = 1_048_576; +const GIGABYTE: u64 = 1_073_741_824; + +/// Helper function to retrieve memory unit from a string slice +/// +/// Return value: u64 +/// +/// # Arguments +/// +/// * `unit` - A string slice possibly containing memory unit +fn get_memunit(unit: &str) -> u64 { + let unit = &unit.to_lowercase()[..]; + match unit { + "b" => { BYTE } + "kb" => { KILOBYTE } + "mb" => { MEGABYTE } + "gb" => { GIGABYTE } + _ => { 0 } + } +} + +/// Parses memory units from human readable form to machine readable +/// +/// Return value: +/// Result => Ok(u64) +/// => Err(error string) +/// +/// # Arguments +/// +/// * `arg` - A string slice that holds the value parsed from the config +pub fn get_memval(arg: &str) -> Result<u64, &'static str> { + let arg = arg.trim(); + let val: f64; + let mut unit: &str; + let mut parser = tuple((preceded(multispace0, double), + preceded(multispace0, verify(not_line_ending, |c: &str| c.len() < 3)))); + let r: IResult<&str, (f64, &str)> = parser(arg); + if let Ok(r) = r { + val = (r.1).0; + unit = (r.1).1; + } else { + return Err("Error parsing the memory value"); + } + if unit.is_empty() { + unit = "B"; + } + let unit = get_memunit(unit); + if unit == 0 { + return Err("Invalid memory unit"); + } + let res = val * unit as f64; + Ok(res as u64) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_memval_nospace() { + let s = "10"; + let res = 10 ; + assert_eq!(Ok(10), get_memval(s)); + + let s = "10kb"; + assert_eq!(Ok(res * KILOBYTE), get_memval(s)); + + let s = "10Kb"; + assert_eq!(Ok(res * KILOBYTE), get_memval(s)); + + let s = "10KB"; + assert_eq!(Ok(res * KILOBYTE), get_memval(s)); + + let s = "10mb"; + assert_eq!(Ok(res * MEGABYTE), get_memval(s)); + + let s = "10gb"; + assert_eq!(Ok(res * GIGABYTE), get_memval(s)); + } + + #[test] + fn test_memval_space_start() { + let s = " 10"; + let res = 10 ; + assert_eq!(Ok(res), get_memval(s)); + + let s = " 10Kb"; + assert_eq!(Ok(res * KILOBYTE), get_memval(s)); + + let s = " 10mb"; + assert_eq!(Ok(res * MEGABYTE), get_memval(s)); + + let s = " 10Gb"; + assert_eq!(Ok(res * GIGABYTE), get_memval(s)); + + let s = " 30b"; + assert_eq!(Ok(30), get_memval(s)); + } + + #[test] + fn test_memval_space_end() { + let s = " 10 "; + let res = 10 ; + assert_eq!(Ok(res), get_memval(s)); + + let s = "10Kb "; + assert_eq!(Ok(res * KILOBYTE), get_memval(s)); + + let s = "10mb "; + assert_eq!(Ok(res * MEGABYTE), get_memval(s)); + + let s = " 10Gb "; + assert_eq!(Ok(res * GIGABYTE), get_memval(s)); + + let s = " 30b "; + assert_eq!(Ok(30), get_memval(s)); + } + + #[test] + fn test_memval_space_in_bw() { + let s = " 10 "; + let res = 10 ; + assert_eq!(Ok(res), get_memval(s)); + + let s = "10 Kb "; + assert_eq!(Ok(res * KILOBYTE), get_memval(s)); + + let s = "10 mb"; + assert_eq!(Ok(res * MEGABYTE), get_memval(s)); + + let s = " 10 Gb "; + assert_eq!(Ok(res * GIGABYTE), get_memval(s)); + + let s = "30 b"; + assert_eq!(Ok(30), get_memval(s)); + } + + #[test] + fn test_memval_float_val() { + let s = " 10.5 "; + assert_eq!(Ok(10), get_memval(s)); + + let s = "10.8Kb "; + assert_eq!(Ok((10.8 * KILOBYTE as f64) as u64), get_memval(s)); + + let s = "10.4 mb "; + assert_eq!(Ok((10.4 * MEGABYTE as f64) as u64), get_memval(s)); + + let s = " 10.5Gb "; + assert_eq!(Ok((10.5 * GIGABYTE as f64) as u64), get_memval(s)); + + let s = " 30.0 b "; + assert_eq!(Ok(30), get_memval(s)); + } + + #[test] + fn test_memval_erroneous_val() { + let s = "5eb"; + assert!(get_memval(s).is_err()); + + let s = "5 1kb"; + assert!(get_memval(s).is_err()); + + let s = "61k b"; + assert!(get_memval(s).is_err()); + + let s = "8 8 k b"; + assert!(get_memval(s).is_err()); + } +} |