1use url::Url;
2
3use crate::{
4 multiaddr::{Multiaddr, Protocol},
5 secio::PeerId,
6};
7use std::{
8 borrow::Cow,
9 iter::{self},
10 net::{IpAddr, SocketAddr},
11};
12
13#[cfg(not(target_family = "wasm"))]
15pub mod dns;
16
17pub fn is_reachable(ip: IpAddr) -> bool {
20 match ip {
21 IpAddr::V4(ipv4) => {
22 !ipv4.is_private()
23 && !ipv4.is_loopback()
24 && !ipv4.is_link_local()
25 && !ipv4.is_broadcast()
26 && !ipv4.is_documentation()
27 && !ipv4.is_unspecified()
28 }
29 IpAddr::V6(ipv6) => {
30 let scope = if ipv6.is_multicast() {
31 match ipv6.segments()[0] & 0x000f {
32 1 => Some(false),
33 2 => Some(false),
34 3 => Some(false),
35 4 => Some(false),
36 5 => Some(false),
37 8 => Some(false),
38 14 => Some(true),
39 _ => None,
40 }
41 } else {
42 None
43 };
44 match scope {
45 Some(true) => true,
46 None => {
47 !(ipv6.is_multicast()
48 || ipv6.is_loopback()
49 || ((ipv6.segments()[0] & 0xffc0) == 0xfe80)
51 || ((ipv6.segments()[0] & 0xffc0) == 0xfec0)
53 || ((ipv6.segments()[0] & 0xfe00) == 0xfc00)
55 || ipv6.is_unspecified()
56 || ((ipv6.segments()[0] == 0x2001) && (ipv6.segments()[1] == 0xdb8)))
58 }
59 _ => false,
60 }
61 }
62 }
63}
64
65pub fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Option<SocketAddr> {
67 let mut iter = addr.iter().peekable();
68
69 while iter.peek().is_some() {
70 match iter.peek() {
71 Some(Protocol::Ip4(_)) | Some(Protocol::Ip6(_)) => (),
72 _ => {
73 let _ignore = iter.next();
75 continue;
76 }
77 }
78
79 let proto1 = iter.next()?;
80 let proto2 = iter.next()?;
81
82 match (proto1, proto2) {
83 (Protocol::Ip4(ip), Protocol::Tcp(port)) => {
84 return Some(SocketAddr::new(ip.into(), port));
85 }
86 (Protocol::Ip6(ip), Protocol::Tcp(port)) => {
87 return Some(SocketAddr::new(ip.into(), port));
88 }
89 _ => (),
90 }
91 }
92
93 None
94}
95
96pub fn socketaddr_to_multiaddr(address: SocketAddr) -> Multiaddr {
98 let proto = match address.ip() {
99 IpAddr::V4(ip) => Protocol::Ip4(ip),
100 IpAddr::V6(ip) => Protocol::Ip6(ip),
101 };
102 iter::once(proto)
103 .chain(iter::once(Protocol::Tcp(address.port())))
104 .collect()
105}
106
107pub fn extract_peer_id(addr: &Multiaddr) -> Option<PeerId> {
109 let mut iter = addr.iter();
110
111 iter.find_map(|proto| {
112 if let Protocol::P2P(raw_bytes) = proto {
113 PeerId::from_bytes(raw_bytes.to_vec()).ok()
114 } else {
115 None
116 }
117 })
118}
119
120#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
122pub enum TransportType {
123 Ws,
125 Wss,
127 Tcp,
129 Tls,
131 Memory,
133 Onion,
135}
136
137pub fn find_type(addr: &Multiaddr) -> TransportType {
139 let mut iter = addr.iter();
140
141 iter.find_map(|proto| {
142 if let Protocol::Ws = proto {
143 Some(TransportType::Ws)
144 } else if let Protocol::Wss = proto {
145 Some(TransportType::Wss)
146 } else if let Protocol::Tls(_) = proto {
147 Some(TransportType::Tls)
148 } else if let Protocol::Memory(_) = proto {
149 Some(TransportType::Memory)
150 } else if let Protocol::Onion3(_) = proto {
151 Some(TransportType::Onion)
152 } else {
153 None
154 }
155 })
156 .unwrap_or(TransportType::Tcp)
157}
158
159pub fn redact_auth_from_url(url: &Url) -> Cow<'_, Url> {
172 let mut owned_url = url.clone();
173 let mut modified = false;
174
175 if url.username() != "" && owned_url.set_username("****").is_ok() {
176 modified = true;
177 }
178
179 if url.password().is_some() && owned_url.set_password(Some("****")).is_ok() {
180 modified = true;
181 }
182
183 if modified {
184 Cow::Owned(owned_url)
185 } else {
186 Cow::Borrowed(url)
187 }
188}
189
190#[cfg(test)]
191mod test {
192 use crate::{
193 multiaddr::Multiaddr,
194 secio::SecioKeyPair,
195 utils::{extract_peer_id, multiaddr_to_socketaddr},
196 };
197
198 #[test]
199 fn parser_peer_id_from_multiaddr() {
200 let peer_id = SecioKeyPair::secp256k1_generated().peer_id();
201 let addr_1: Multiaddr = format!("/ip4/127.0.0.1/tcp/1337/p2p/{}", peer_id.to_base58())
202 .parse()
203 .unwrap();
204 let addr_2: Multiaddr = format!("/p2p/{}", peer_id.to_base58()).parse().unwrap();
205
206 let second = extract_peer_id(&addr_1).unwrap();
207 let third = extract_peer_id(&addr_2).unwrap();
208 assert_eq!(peer_id, second);
209 assert_eq!(peer_id, third);
210 }
211
212 #[test]
213 fn parser_socket_addr_from_multiaddr() {
214 let peer_id = SecioKeyPair::secp256k1_generated().peer_id();
215 let addr_1: Multiaddr = format!("/ip4/127.0.0.1/tcp/1337/p2p/{}", peer_id.to_base58())
216 .parse()
217 .unwrap();
218 let addr_2: Multiaddr = format!("/p2p/{}/ip4/127.0.0.1/tcp/1337", peer_id.to_base58())
219 .parse()
220 .unwrap();
221 let addr_3: Multiaddr = "/ip4/127.0.0.1/tcp/1337".parse().unwrap();
222
223 let second = multiaddr_to_socketaddr(&addr_1).unwrap();
224 let third = multiaddr_to_socketaddr(&addr_2).unwrap();
225 let fourth = multiaddr_to_socketaddr(&addr_3).unwrap();
226 assert_eq!(second, "127.0.0.1:1337".parse().unwrap());
227 assert_eq!(third, "127.0.0.1:1337".parse().unwrap());
228 assert_eq!(fourth, "127.0.0.1:1337".parse().unwrap());
229 }
230
231 #[test]
232 #[should_panic]
233 fn parser_socket_addr_fail() {
234 let peer_id = SecioKeyPair::secp256k1_generated().peer_id();
235 let addr: Multiaddr = format!("/ip4/127.0.0.1/p2p/{}/tcp/1337", peer_id.to_base58())
236 .parse()
237 .unwrap();
238 multiaddr_to_socketaddr(&addr).unwrap();
239 }
240}