rust_ipfs/p2p/
addr.rs

1use libp2p::{multiaddr::Protocol, Multiaddr, PeerId};
2
3pub trait MultiaddrExt {
4    /// Peer id
5    fn peer_id(&self) -> Option<PeerId>;
6
7    fn extract_peer_id(&mut self) -> Option<PeerId>;
8
9    /// Relay peer id
10    fn relay_peer_id(&self) -> Option<PeerId>;
11
12    /// Address that only doesnt include peer protocols
13    fn address(&self) -> Multiaddr;
14
15    /// Determine if the address is a relay circuit
16    fn is_relay(&self) -> bool;
17
18    /// Determine if the address is being relayed to a peer
19    fn is_relayed(&self) -> bool;
20
21    /// Determine if address is loopback or local address
22    fn is_loopback(&self) -> bool;
23
24    /// Determine if address is private address
25    fn is_private(&self) -> bool;
26}
27
28impl MultiaddrExt for Multiaddr {
29    fn peer_id(&self) -> Option<PeerId> {
30        if let Some(Protocol::P2p(peer)) = self.iter().last() {
31            return Some(peer);
32        }
33
34        None
35    }
36
37    fn extract_peer_id(&mut self) -> Option<PeerId> {
38        self.peer_id()?;
39
40        match self.pop() {
41            Some(Protocol::P2p(peer)) => Some(peer),
42            _ => None,
43        }
44    }
45
46    fn relay_peer_id(&self) -> Option<PeerId> {
47        if !self.is_relay() {
48            return None;
49        }
50
51        while let Some(protocol) = self.iter().next() {
52            //Find the first peer id and return it
53            if let Protocol::P2p(peer) = protocol {
54                return Some(peer);
55            }
56        }
57
58        None
59    }
60
61    fn address(&self) -> Multiaddr {
62        let mut addr = Multiaddr::empty();
63
64        for proto in self.iter() {
65            if matches!(
66                proto,
67                Protocol::Ip4(_)
68                    | Protocol::Ip6(_)
69                    | Protocol::Tcp(_)
70                    | Protocol::Udp(_)
71                    | Protocol::Quic
72                    | Protocol::QuicV1
73                    | Protocol::Dnsaddr(_)
74            ) {
75                addr.push(proto);
76            }
77        }
78
79        addr
80    }
81
82    fn is_relay(&self) -> bool {
83        self.iter()
84            .any(|proto| matches!(proto, Protocol::P2pCircuit))
85    }
86
87    fn is_relayed(&self) -> bool {
88        if !self.is_relay() {
89            return false;
90        }
91
92        if self.peer_id().is_none() {
93            return false;
94        }
95
96        true
97    }
98
99    fn is_loopback(&self) -> bool {
100        self.iter().any(|proto| match proto {
101            Protocol::Ip4(ip) => ip.is_loopback(),
102            Protocol::Ip6(ip) => ip.is_loopback(),
103            _ => false,
104        })
105    }
106
107    fn is_private(&self) -> bool {
108        self.iter().any(|proto| match proto {
109            Protocol::Ip4(ip) => ip.is_private(),
110            Protocol::Ip6(ip) => {
111                (ip.segments()[0] & 0xffc0) != 0xfe80 && (ip.segments()[0] & 0xfe00) != 0xfc00
112            }
113            _ => false,
114        })
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use std::str::FromStr;
121
122    use super::*;
123
124    #[test]
125    fn connection_targets() {
126        let peer_id = PeerId::from_str("QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ")
127            .expect("Valid peer id");
128        let multiaddr_wo_peer =
129            Multiaddr::from_str("/ip4/104.131.131.82/tcp/4001").expect("Valid multiaddr");
130        let multiaddr_with_peer =
131            Multiaddr::from_str(&format!("{multiaddr_wo_peer}/p2p/{peer_id}"))
132                .expect("valid multiaddr");
133        let p2p_peer = Multiaddr::from_str(&format!("/p2p/{peer_id}")).expect("Valid multiaddr");
134
135        assert!(multiaddr_wo_peer.peer_id().is_none());
136        assert!(multiaddr_with_peer.peer_id().is_some());
137        assert!(p2p_peer.peer_id().is_some());
138
139        let peer_id_target = multiaddr_with_peer.peer_id().expect("Valid peer id");
140
141        assert_eq!(peer_id_target, peer_id);
142    }
143}