usiem_utils/enrichment/
basic_ip.rs

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}