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 _ => 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}