usiem/events/
ip.rs

1use std::fmt::Display;
2
3use serde::{Deserialize, Serialize, Serializer};
4
5use crate::prelude::{
6    ip_utils::{
7        ipv4_from_str, ipv4_to_str, ipv6_from_str, ipv6_to_str, is_local_ipv4, is_local_ipv6,
8    },
9    SiemField,
10};
11
12#[derive(Deserialize, Debug, Clone, Copy)]
13pub enum SiemIp {
14    V4(u32),
15    V6(u128),
16}
17impl PartialEq for SiemIp {
18    fn eq(&self, other: &Self) -> bool {
19        match (self, other) {
20            (SiemIp::V4(v1), SiemIp::V4(v2)) => v1 == v2,
21            (SiemIp::V6(v1), SiemIp::V6(v2)) => v1 == v2,
22            //TODO: IPv4 in IPV6
23            _ => false,
24        }
25    }
26}
27
28impl SiemIp {
29    pub fn is_local(&self) -> bool {
30        match self {
31            SiemIp::V4(ip) => is_local_ipv4(*ip),
32            SiemIp::V6(ip) => is_local_ipv6(*ip),
33        }
34    }
35    pub fn equals(&self, val: &str) -> bool {
36        match self {
37            SiemIp::V4(ip1) => match ipv4_from_str(val) {
38                Ok(ip2) => *ip1 == ip2,
39                Err(_) => false,
40            },
41            SiemIp::V6(ip1) => match ipv6_from_str(val) {
42                Ok(ip2) => *ip1 == ip2,
43                Err(_) => false,
44            },
45        }
46    }
47    pub fn from_ip_str(val: &str) -> Result<SiemIp, &'static str> {
48        match ipv4_from_str(val) {
49            Ok(val) => Ok(SiemIp::V4(val)),
50            Err(_) => {
51                let ip = ipv6_from_str(val)?;
52                Ok(SiemIp::V6(ip))
53            }
54        }
55    }
56}
57impl Serialize for SiemIp {
58    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
59    where
60        S: Serializer,
61    {
62        serializer.serialize_str(&(&self.to_string())[..])
63    }
64}
65
66impl From<[u32; 4]> for SiemIp {
67    fn from(v: [u32; 4]) -> Self {
68        Self::V4(
69            ((v[0] & 0xff) << 24) + ((v[1] & 0xff) << 16) + ((v[2] & 0xff) << 8) + (v[3] & 0xff),
70        )
71    }
72}
73impl From<[u32; 16]> for SiemIp {
74    fn from(v: [u32; 16]) -> Self {
75        Self::V6(
76            ((v[0] as u128 & 0xffu128) << 120)
77                + ((v[1] as u128 & 0xffu128) << 112)
78                + ((v[2] as u128 & 0xffu128) << 104)
79                + ((v[3] as u128 & 0xffu128) << 96)
80                + ((v[4] as u128 & 0xffu128) << 88)
81                + ((v[5] as u128 & 0xffu128) << 80)
82                + ((v[6] as u128 & 0xffu128) << 72)
83                + ((v[7] as u128 & 0xffu128) << 64)
84                + ((v[8] as u128 & 0xffu128) << 56)
85                + ((v[9] as u128 & 0xffu128) << 48)
86                + ((v[10] as u128 & 0xffu128) << 40)
87                + ((v[11] as u128 & 0xffu128) << 32)
88                + ((v[12] as u128 & 0xffu128) << 24)
89                + ((v[13] as u128 & 0xffu128) << 16)
90                + ((v[14] as u128 & 0xffu128) << 8)
91                + (v[15] as u128 & 0xffu128),
92        )
93    }
94}
95impl From<&u32> for SiemIp {
96    fn from(v: &u32) -> Self {
97        Self::V4(*v)
98    }
99}
100impl From<u32> for SiemIp {
101    fn from(v: u32) -> Self {
102        Self::V4(v)
103    }
104}
105impl From<&u128> for SiemIp {
106    fn from(v: &u128) -> Self {
107        Self::V6(*v)
108    }
109}
110impl From<u128> for SiemIp {
111    fn from(v: u128) -> Self {
112        Self::V6(v)
113    }
114}
115
116impl<'a> TryFrom<&'a SiemField> for &'a SiemIp {
117    type Error = &'static str;
118
119    fn try_from(value: &SiemField) -> Result<&SiemIp, Self::Error> {
120        match value {
121            SiemField::IP(ip) => Ok(ip),
122            _ => Err("Not an IP"),
123        }
124    }
125}
126
127impl TryFrom<SiemField> for SiemIp {
128    type Error = &'static str;
129
130    fn try_from(value: SiemField) -> Result<Self, Self::Error> {
131        match value {
132            SiemField::IP(ip) => Ok(ip),
133            _ => Err("Not an IP"),
134        }
135    }
136}
137
138impl Display for SiemIp {
139    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
140        let ip = match self {
141            SiemIp::V4(ip1) => ipv4_to_str(*ip1),
142            SiemIp::V6(ip1) => ipv6_to_str(*ip1),
143        };
144        write!(f, "{}", ip)
145    }
146}
147impl std::hash::Hash for SiemIp {
148    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
149        match self {
150            SiemIp::V4(v) => v.hash(state),
151            SiemIp::V6(v) => v.hash(state),
152        }
153    }
154}
155
156#[cfg(test)]
157mod tst {
158    use super::*;
159
160    #[test]
161    fn test_equals_between_ips() {
162        assert_eq!(SiemIp::V4(111), SiemIp::V4(111));
163        assert_eq!(SiemIp::V6(111), SiemIp::V6(111));
164        assert_eq!(Some(SiemIp::V6(111)), Some(SiemIp::V6(111)));
165    }
166    #[test]
167    fn test_serialize_ip_field() {
168        assert_eq!(SiemIp::V4(111).to_string(), "0.0.0.111");
169    }
170
171    #[test]
172    fn from_u32_vec() {
173        let ip: SiemIp = [192, 168, 1, 1].into();
174        assert_eq!(ip.to_string(), "192.168.1.1");
175    }
176
177    #[test]
178    fn from_u128_vec() {
179        let ip: SiemIp = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into();
180        assert_eq!(ip.to_string(), "::1");
181    }
182}