1use usiem::{
2 events::tags::BLOCKED_IP,
3 prelude::{
4 holder::DatasetHolder, ip_map::IpMapSynDataset, ip_set::IpSetSynDataset,
5 text_map::TextMapSynDataset, text_map_list::TextMapListSynDataset,
6 text_set::TextSetSynDataset, LogEnrichment, SiemDatasetType, SiemField, SiemIp, SiemLog,
7 },
8 utilities::types::LogString,
9};
10
11#[derive(Clone)]
12pub struct BasicIPEnricher {}
13
14impl LogEnrichment for BasicIPEnricher {
15 fn enrich(&self, mut log: SiemLog, datasets: &DatasetHolder) -> SiemLog {
16 if let Some(fields) = enrich_block_ip(&mut log, datasets) {
17 for (name, value) in fields {
18 log.insert(name, value);
19 }
20 }
21 if let Some(fields) = enrich_block_domain(&mut log, datasets) {
22 for (name, value) in fields {
23 log.insert(name, value);
24 }
25 }
26 if let Some(fields) = enrich_mac_ip(&mut log, datasets) {
27 for (name, value) in fields {
28 log.insert(name, value);
29 }
30 }
31 if let Some(fields) = enrich_asset_with_tags(&mut log, datasets) {
32 for (name, value) in fields {
33 log.insert(name, value);
34 }
35 }
36 if let Some(fields) = enrich_asset_with_vulnerabilities(&mut log, datasets) {
37 for (name, value) in fields {
38 log.insert(name, value);
39 }
40 }
41 log
42 }
43
44 fn name(&self) -> &'static str {
45 "BasicIPEnricher"
46 }
47
48 fn description(&self) -> &'static str {
49 "Enrich all IP fields. Checks if the IP is in the block list, adds mac and hostname information to the IP..."
50 }
51}
52
53fn enrich_block_ip(
54 log: &mut SiemLog,
55 datasets: &DatasetHolder,
56) -> Option<Vec<(LogString, SiemField)>> {
57 let ip_info: &IpSetSynDataset = datasets.get(&SiemDatasetType::BlockIp)?.try_into().ok()?;
58 let mut new_fields = Vec::with_capacity(32);
59 let mut block_list = false;
60 for (field_name, ip_field) in log.ip_fields() {
61 let ip: &SiemIp = match ip_field.try_into() {
62 Ok(v) => v,
63 Err(_) => continue,
64 };
65 if ip_info.contains(ip) {
66 new_fields.push((
67 LogString::Owned(format!("{}.tags", &field_name[..])),
68 SiemField::Array(vec![LogString::Borrowed(BLOCKED_IP)]),
69 ));
70 block_list = true;
71 }
72 }
73 if block_list {
74 log.add_tag(BLOCKED_IP);
75 }
76 Some(new_fields)
77}
78
79fn enrich_mac_ip(
80 log: &mut SiemLog,
81 datasets: &DatasetHolder,
82) -> Option<Vec<(LogString, SiemField)>> {
83 let mac_info: &IpMapSynDataset = datasets.get(&SiemDatasetType::IpMac)?.try_into().ok()?;
84 let host_info: &TextMapSynDataset = datasets.get(&SiemDatasetType::MacHost)?.try_into().ok()?;
85 let mut new_fields = Vec::with_capacity(32);
86
87 for (field_name, ip_field) in log.ip_fields() {
88 let ip: &SiemIp = match ip_field.try_into() {
89 Ok(v) => v,
90 Err(_) => continue,
91 };
92 let mac_addr = match mac_info.get(ip) {
93 Some(v) => v,
94 None => continue,
95 };
96 let host = match host_info.get(&mac_addr[..]) {
97 Some(v) => v,
98 None => continue,
99 };
100 let (field_host, field_mac) = match field_name.find(".ip") {
101 Some(v) => {
102 if v > 0 {
103 (
104 format!("{}.domain", &field_name[..v]),
105 format!("{}.mac", &field_name[..v]),
106 )
107 } else {
108 (
109 format!("{}.domain", &field_name[..]),
110 format!("{}.mac", &field_name[..]),
111 )
112 }
113 }
114 None => (
115 format!("{}.domain", &field_name[..]),
116 format!("{}.mac", &field_name[..]),
117 ),
118 };
119 new_fields.push((LogString::Owned(field_host), SiemField::Text(host.clone())));
120 new_fields.push((LogString::Owned(field_mac), SiemField::Text(host.clone())));
121 }
122 Some(new_fields)
123}
124
125fn enrich_asset_with_tags(
126 log: &mut SiemLog,
127 datasets: &DatasetHolder,
128) -> Option<Vec<(LogString, SiemField)>> {
129 let assets_info: &TextMapListSynDataset =
130 datasets.get(&SiemDatasetType::AssetTag)?.try_into().ok()?;
131
132 let mut new_fields = Vec::with_capacity(32);
133 if let Some(source_host) = log.field("source.domain") {
134 if let SiemField::Text(hostname) = source_host {
135 if let Some(asset_tag) = assets_info.get(&hostname[..]) {
136 new_fields.push((
137 LogString::Owned(format!("source.tags")),
138 SiemField::Array(asset_tag.clone()),
139 ));
140 }
141 }
142 }
143 if let Some(source_host) = log.field("destination.domain") {
144 if let SiemField::Text(hostname) = source_host {
145 if let Some(asset_tag) = assets_info.get(&hostname[..]) {
146 new_fields.push((
147 LogString::Owned(format!("destination.tags")),
148 SiemField::Array(asset_tag.clone()),
149 ));
150 }
151 }
152 }
153 Some(new_fields)
154}
155
156fn enrich_asset_with_vulnerabilities(
157 log: &mut SiemLog,
158 datasets: &DatasetHolder,
159) -> Option<Vec<(LogString, SiemField)>> {
160 let assets_info: &TextMapListSynDataset = datasets
161 .get(&SiemDatasetType::HostVulnerable)?
162 .try_into()
163 .ok()?;
164
165 let mut new_fields = Vec::with_capacity(32);
166
167 if let Some(source_host) = log.field("source.domain") {
168 if let SiemField::Text(hostname) = source_host {
169 if let Some(vulnerabilities) = assets_info.get(&hostname[..]) {
170 new_fields.push((
171 LogString::Owned(format!("source.vulnerability.ids")),
172 SiemField::Array(vulnerabilities.clone()),
173 ));
174 }
175 }
176 }
177 if let Some(source_host) = log.field("destination.domain") {
178 if let SiemField::Text(hostname) = source_host {
179 if let Some(vulnerabilities) = assets_info.get(&hostname[..]) {
180 new_fields.push((
181 LogString::Owned(format!("destination.vulnerability.ids")),
182 SiemField::Array(vulnerabilities.clone()),
183 ));
184 }
185 }
186 }
187 Some(new_fields)
188}
189
190fn enrich_block_domain(
191 log: &mut SiemLog,
192 datasets: &DatasetHolder,
193) -> Option<Vec<(LogString, SiemField)>> {
194 let block_domain: &TextSetSynDataset = datasets
195 .get(&SiemDatasetType::BlockDomain)?
196 .try_into()
197 .ok()?;
198
199 let mut new_fields = Vec::with_capacity(32);
200 let mut block_list = false;
201 if let Some(source_host) = log.field("source.domain") {
202 if let SiemField::Text(hostname) = source_host {
203 if block_domain.contains(hostname) {
204 new_fields.push((
205 LogString::Owned(format!("source.tags")),
206 SiemField::Array(vec![LogString::Borrowed(BLOCKED_IP)]),
207 ));
208 block_list = true;
209 }
210 }
211 }
212 if let Some(source_host) = log.field("destination.domain") {
213 if let SiemField::Text(hostname) = source_host {
214 if block_domain.contains(hostname) {
215 new_fields.push((
216 LogString::Owned(format!("destination.tags")),
217 SiemField::Array(vec![LogString::Borrowed(BLOCKED_IP)]),
218 ));
219 block_list = true;
220 }
221 }
222 }
223 if block_list {
224 log.add_tag(BLOCKED_IP);
225 }
226 Some(new_fields)
227}