Skip to main content

zebra_network/meta_addr/
peer_addr.rs

1//! Wrappers for peer addresses which hide sensitive user and node operator details in logs and
2//! metrics.
3
4use std::{
5    fmt,
6    net::{Ipv4Addr, Ipv6Addr, SocketAddr},
7    ops::{Deref, DerefMut},
8    str::FromStr,
9};
10
11#[cfg(any(test, feature = "proptest-impl"))]
12use proptest_derive::Arbitrary;
13
14/// A thin wrapper for [`SocketAddr`] which hides peer IP addresses in logs and metrics.
15#[derive(
16    Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
17)]
18#[serde(transparent)]
19#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
20#[derive(schemars::JsonSchema)]
21pub struct PeerSocketAddr(SocketAddr);
22
23impl fmt::Debug for PeerSocketAddr {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        fmt::Display::fmt(self, f)
26    }
27}
28
29impl fmt::Display for PeerSocketAddr {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        let ip_version = if self.is_ipv4() { "v4" } else { "v6" };
32
33        // The port is usually not sensitive, and it's useful for debugging.
34        f.pad(&format!("{}redacted:{}", ip_version, self.port()))
35    }
36}
37
38impl FromStr for PeerSocketAddr {
39    type Err = <SocketAddr as FromStr>::Err;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        Ok(Self(s.parse()?))
43    }
44}
45
46impl<S> From<S> for PeerSocketAddr
47where
48    S: Into<SocketAddr>,
49{
50    fn from(value: S) -> Self {
51        Self(value.into())
52    }
53}
54
55impl Deref for PeerSocketAddr {
56    type Target = SocketAddr;
57
58    fn deref(&self) -> &Self::Target {
59        &self.0
60    }
61}
62
63impl DerefMut for PeerSocketAddr {
64    fn deref_mut(&mut self) -> &mut Self::Target {
65        &mut self.0
66    }
67}
68
69impl PeerSocketAddr {
70    /// Returns an unspecified `PeerSocketAddr`, which can't be used for outbound connections.
71    pub fn unspecified() -> Self {
72        Self(SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0))
73    }
74
75    /// Return the underlying [`SocketAddr`], which allows sensitive peer address information to
76    /// be printed and logged.
77    pub fn remove_socket_addr_privacy(&self) -> SocketAddr {
78        **self
79    }
80
81    /// Returns true if the inner [`SocketAddr`]'s IP is the localhost IP.
82    pub fn is_localhost(&self) -> bool {
83        let ip = self.0.ip();
84        ip == Ipv4Addr::LOCALHOST || ip == Ipv6Addr::LOCALHOST
85    }
86}