tetratto_core/model/
addr.rs

1use std::net::SocketAddr;
2
3/// How many bytes should be taken as the prefix (from the begining of the address).
4pub(crate) const IPV6_PREFIX_BYTES: usize = 11;
5
6/// The protocol of a [`RemoteAddr`].
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub enum AddrProto {
9    IPV4,
10    IPV6,
11}
12
13/// A representation of a remote IP address.
14#[derive(Clone, Debug)]
15pub struct RemoteAddr(pub SocketAddr, pub AddrProto);
16
17impl From<&str> for RemoteAddr {
18    fn from(value: &str) -> Self {
19        if value.len() >= 16 {
20            // ipv6 (16 bytes; 128 bits)
21            if !(value.starts_with("[") | value.contains("]:1000")) {
22                Self(format!("[{value}]:1000").parse().unwrap(), AddrProto::IPV6)
23            } else {
24                Self(value.parse().unwrap(), AddrProto::IPV6)
25            }
26        } else {
27            // ipv4 (4 bytes; 32 bits)
28            if !value.contains(":1000") {
29                Self(
30                    format!("{value}:1000")
31                        .parse()
32                        .unwrap_or("0.0.0.0:1000".parse().unwrap()),
33                    AddrProto::IPV4,
34                )
35            } else {
36                Self(
37                    value.parse().unwrap_or("0.0.0.0:1000".parse().unwrap()),
38                    AddrProto::IPV4,
39                )
40            }
41        }
42    }
43}
44
45impl RemoteAddr {
46    /// Get the address' prefix (returns the entire address for IPV4 addresses).
47    ///
48    ///  Operates on the IP address **without** colon characters.
49    pub fn prefix(&self, chop: Option<usize>) -> String {
50        if self.1 == AddrProto::IPV4 {
51            return self.0.to_string();
52        }
53
54        // we're adding 2 bytes to the chop bytes because we also
55        // need to remove 2 colons
56        let as_string = self.ipv6_inner();
57        (&as_string[0..(match chop {
58            Some(c) => c,
59            None => IPV6_PREFIX_BYTES,
60        } + (IPV6_PREFIX_BYTES / 4))])
61            .to_string()
62    }
63
64    /// [`Self::prefix`], but it returns another [`RemoteAddr`].
65    pub fn to_prefix(self, chop: Option<usize>) -> Self {
66        Self::from(self.prefix(chop).as_str())
67    }
68
69    /// Get the innter content from the address (as ipv6).
70    pub fn ipv6_inner(&self) -> String {
71        self.0.to_string().replace("[", "").replace("]:1000", "")
72    }
73}