forensic_rs/field/
utils.rs1use std::net::Ipv6Addr;
2
3pub fn ipv4_from_str(ipv4: &str) -> Result<u32, &'static str> {
4 let mut number: u32 = 0;
5 let mut desplazamiento = 0;
6 for part in ipv4.split('.').rev() {
7 if desplazamiento >= 32 {
8 return Err("More than 4 dots");
9 }
10 let parsed = match part.parse::<u8>() {
11 Ok(v) => v,
12 Err(_) => return Err("Cannot parse as u8"),
13 };
14 number += (parsed as u32) << desplazamiento;
15 desplazamiento += 8;
16 }
17 Ok(number)
18}
19
20fn is_hex_digit(byte: u8) -> bool {
22 matches!(byte, b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F')
23}
24fn hex_to_digit(byte: u8) -> u8 {
26 match byte {
27 b'0'..=b'9' => byte - b'0',
28 b'a'..=b'f' => byte - b'a' + 10,
29 b'A'..=b'F' => byte - b'A' + 10,
30 _ => unreachable!(),
31 }
32}
33pub fn ipv4_to_u32_bytes(ipv4: &[u8]) -> Result<u32, &'static str> {
34 if ipv4.len() != 4 {
35 return Err("Invalid IPV4 length");
36 }
37 Ok(((ipv4[0] as u32) << 24)
38 + ((ipv4[1] as u32) << 16)
39 + ((ipv4[2] as u32) << 8)
40 + (ipv4[3] as u32))
41}
42
43fn read_hextet(bytes: &[u8]) -> (usize, u16) {
47 let mut count = 0;
48 let mut digits: [u8; 4] = [0; 4];
49
50 for b in bytes {
51 if is_hex_digit(*b) {
52 digits[count] = hex_to_digit(*b);
53 count += 1;
54 if count == 4 {
55 break;
56 }
57 } else {
58 break;
59 }
60 }
61
62 if count == 0 {
63 return (0, 0);
64 }
65
66 let mut shift = (count - 1) * 4;
67 let mut res = 0;
68 for digit in &digits[0..count] {
69 res += (*digit as u16) << shift;
70 if shift >= 4 {
71 shift -= 4;
72 } else {
73 break;
74 }
75 }
76
77 (count, res)
78}
79
80pub fn ipv6_from_str(s: &str) -> Result<u128, &'static str> {
81 let bytes = s.as_bytes();
84
85 if bytes.len() > 38 || bytes.len() < 2 {
94 return Err("Invalid ipv6 size");
95 }
96
97 let mut offset = 0;
98 let mut ellipsis: Option<usize> = None;
99
100 if bytes[0] == b':' {
102 if bytes[1] == b':' {
103 if bytes.len() == 2 {
104 return Ok(0);
105 }
106 ellipsis = Some(0);
107 offset += 2;
108 } else {
109 return Err("An IPv6 cannot start with a single column.");
112 }
113 }
114
115 let mut address: [u16; 8] = [0; 8];
118
119 let mut hextet_index = 0;
121
122 loop {
123 if offset == bytes.len() {
124 break;
125 }
126
127 let (bytes_read, hextet) = read_hextet(&bytes[offset..]);
129
130 if bytes_read == 0 {
132 match bytes[offset] {
133 b':' => {
136 if ellipsis.is_some() {
139 return Err("IPv6 can only have one ellipsis");
140 }
141 ellipsis = Some(hextet_index);
144 offset += 1;
145 continue;
147 }
148 _ => return Err("IPv6 can only have one ellipsis"),
152 }
153 }
154
155 address[hextet_index] = hextet;
158 offset += bytes_read;
159 hextet_index += 1;
160
161 if hextet_index == 8 || offset == bytes.len() {
164 break;
165 }
166
167 match bytes[offset] {
170 b':' => offset += 1,
172 b'.' => {
182 let ipv4: u32 = ipv4_to_u32_bytes(&bytes[offset - bytes_read..])?;
185 address[hextet_index - 1] = ((ipv4 & 0xffff_0000) >> 16) as u16;
188 address[hextet_index] = (ipv4 & 0x0000_ffff) as u16;
191 hextet_index += 1;
192 break;
196 }
197 _ => return Err("Unexpected error"),
198 }
199 } if offset < bytes.len() {
204 return Err("There are trailing characters");
205 }
206
207 if hextet_index == 8 && ellipsis.is_some() {
208 return Err("Empty elipsis");
211 }
212
213 if hextet_index < 8 {
215 if let Some(ellipsis_index) = ellipsis {
216 let nb_zeros = 8 - hextet_index;
218 for index in (ellipsis_index..hextet_index).rev() {
220 address[index + nb_zeros] = address[index];
221 address[index] = 0;
222 }
223 } else {
224 return Err("Error");
225 }
226 }
227
228 Ok(((address[0] as u128) << 112)
230 + ((address[1] as u128) << 96)
231 + ((address[2] as u128) << 80)
232 + ((address[3] as u128) << 64)
233 + ((address[4] as u128) << 48)
234 + ((address[5] as u128) << 32)
235 + ((address[6] as u128) << 16)
236 + address[7] as u128)
237}
238
239pub fn ipv4_to_str(ipv4: u32) -> String {
240 let mut chars = [0, 0, 0, 0];
241 let mut ip = ipv4;
242 for i in (0..4).rev() {
243 chars[i] = ip & 0xFF;
244 ip >>= 8;
245 }
246 format!("{}.{}.{}.{}", chars[0], chars[1], chars[2], chars[3])
247}
248
249pub fn ipv6_to_str(ipv6: u128) -> String {
250 Ipv6Addr::from(ipv6).to_string()
251}
252pub fn is_local_ipv6(ip: u128) -> bool {
253 ip >> 120 & 0xfe == 0xfc
254}
255pub fn is_local_ipv4(ip: u32) -> bool {
256 let firstnumber = ip >> 24;
264 if firstnumber == 10 {
265 return true;
266 }
267 let secondnumber = (ip >> 16) & 0xFF;
268 if firstnumber == 172 && (16..=31).contains(&secondnumber) {
269 return true;
270 }
271 if firstnumber == 192 && secondnumber == 168 {
272 return true;
273 }
274 if firstnumber == 100 && (64..=127).contains(&secondnumber) {
275 return true;
276 }
277 false
278}
279
280pub fn port_to_u16(port: &str) -> Result<u16, &'static str> {
281 match port.parse::<u16>() {
282 Ok(port) => Ok(port),
283 Err(_) => Err("Cannot parse port as u16"),
284 }
285}
286
287pub fn parse_ipv4_port(text: &str) -> Option<(u32, u16)> {
288 match text.rfind(':') {
289 Some(pos) => match (ipv4_from_str(&text[..pos]), port_to_u16(&text[(pos + 1)..])) {
290 (Ok(v1), Ok(v2)) => Some((v1, v2)),
291 _ => None,
292 },
293 None => None,
294 }
295}
296
297pub fn is_ipv4_port(text: &str) -> bool {
298 match text.rfind(':') {
299 Some(pos) => matches!((ipv4_from_str(&text[..pos]), port_to_u16(&text[(pos + 1)..])), (Ok(_), Ok(_))),
300 None => false,
301 }
302}
303pub fn is_ipv4(text: &str) -> bool {
304 ipv4_from_str(text).is_ok()
305}
306pub fn is_ipv6(text: &str) -> bool {
307 ipv6_from_str(text).is_ok()
308}
309
310#[cfg(test)]
311mod tests {
312 use super::*;
313
314 #[test]
315 fn should_parse_ips() {
316 assert_eq!(3232235777, ipv4_from_str("192.168.1.1").unwrap());
318 assert_eq!(134744072, ipv4_from_str("8.8.8.8").unwrap());
320 assert_eq!(176152085, ipv4_from_str("10.127.222.21").unwrap());
322 assert_eq!(1681915904, ipv4_from_str("100.64.0.0").unwrap());
324 assert_eq!(184549375, ipv4_from_str("10.255.255.255").unwrap());
326 }
327
328 #[test]
329 fn should_parse_ip_from_u8_array() {
330 assert_eq!(3232235777, ipv4_to_u32_bytes(&[192, 168, 1, 1]).unwrap());
332 assert_eq!(134744072, ipv4_to_u32_bytes(&[8, 8, 8, 8]).unwrap());
334 assert_eq!(176152085, ipv4_to_u32_bytes(&[10, 127, 222, 21]).unwrap());
336 assert_eq!(1681915904, ipv4_to_u32_bytes(&[100, 64, 0, 0]).unwrap());
338 assert_eq!(184549375, ipv4_to_u32_bytes(&[10, 255, 255, 255]).unwrap());
340 }
341
342 #[test]
343 fn check_ip_is_local() {
344 assert_eq!(is_local_ipv4(3232235777), true);
346 assert_eq!(is_local_ipv4(134744072), false);
348 assert_eq!(is_local_ipv4(176152085), true);
350 assert_eq!(is_local_ipv4(1681915904), true);
352 assert_eq!(is_local_ipv4(184549375), true);
354 }
355
356 #[test]
357 fn should_parse_socket() {
358 assert_eq!(is_ipv4_port("192.168.0.1:1000"), true);
359 assert_eq!(is_ipv4_port("192.168.0.1:100000"), false);
360 assert_eq!(is_ipv4("256.168.0.1"), false);
361 assert_eq!(is_ipv4_port("800.168.0.1:10000"), false);
362 assert_eq!(is_ipv4_port("80.0.168.0.1:10000"), false);
363 }
364}