1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use std::fmt;
use chrono::{Datelike, Local, NaiveDateTime};
use crate::result::CefResult;
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
pub enum CefSeverity {
String(String),
U8(u8),
}
impl From<&str> for CefSeverity {
fn from(raw: &str) -> CefSeverity {
match raw.parse::<u8>() {
Ok(data) => {
if data > 10 {
panic!("Invalid Cef Level, MUST be between 0 to 10")
}
CefSeverity::U8(data)
}
Err(_) => {
match raw {
"Unknown" | "Low" | "Medium" | "High" | "Very-High" => CefSeverity::String(raw.into()),
_ => panic!("Invalid Cef Level, MUST be between Unknown, Low, Medium, High or Very-High")
}
}
}
}
}
impl fmt::Display for CefSeverity {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CefSeverity::String(data) => write!(f, "{}", data),
CefSeverity::U8(data) => write!(f, "{}", data)
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
pub enum CefSignatureId {
String(String),
U64(u64),
}
impl fmt::Display for CefSignatureId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CefSignatureId::String(data) => write!(f, "{}", data),
CefSignatureId::U64(data) => write!(f, "{}", data)
}
}
}
impl From<&str> for CefSignatureId {
fn from(raw: &str) -> CefSignatureId {
match raw.parse::<u64>() {
Ok(data) => CefSignatureId::U64(data),
Err(_) => CefSignatureId::String(raw.to_string())
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CefRecord<T: ?Sized> {
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<String>,
pub version: u8,
pub device_vendor: String,
pub device_product: String,
pub device_version: String,
pub signature_id: CefSignatureId,
pub signature: String,
pub severity: CefSeverity,
pub extensions: T,
}
impl<T: ?Sized> CefRecord<T> {
pub fn extract_ts_from_headers(headers: &str) -> CefResult<f64> {
let data = format!("{} {}", Local::now().year(), &headers[0..15]);
Ok(NaiveDateTime::parse_from_str(&data, "%Y %b %d %H:%M:%S")?.timestamp() as f64)
}
pub fn extract_hostname_from_headers(headers: &str) -> CefResult<String> {
let re = regex::Regex::new(r".*\s+(?P<host>.*)\sCEF:\d+").unwrap();
Ok(re.captures(headers)?.name("host")?.as_str().to_string())
}
}