1use std::{
6 borrow::Cow,
7 net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
8};
9
10pub use ::multiaddr::{Error, Protocol};
11use eyre::{Result, eyre};
12use tracing::error;
13
14#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
15pub struct Multiaddr(::multiaddr::Multiaddr);
16
17impl Multiaddr {
18 pub fn empty() -> Self {
19 Self(::multiaddr::Multiaddr::empty())
20 }
21
22 #[cfg(test)]
23 pub(crate) fn new_internal(inner: ::multiaddr::Multiaddr) -> Self {
24 Self(inner)
25 }
26
27 pub fn iter(&self) -> ::multiaddr::Iter<'_> {
28 self.0.iter()
29 }
30
31 pub fn pop<'a>(&mut self) -> Option<Protocol<'a>> {
32 self.0.pop()
33 }
34
35 pub fn push(&mut self, p: Protocol<'_>) {
36 self.0.push(p)
37 }
38
39 pub fn replace<'a, F>(&self, at: usize, by: F) -> Option<Multiaddr>
40 where
41 F: FnOnce(&Protocol<'_>) -> Option<Protocol<'a>>,
42 {
43 self.0.replace(at, by).map(Self)
44 }
45
46 pub fn len(&self) -> usize {
47 self.0.len()
48 }
49
50 pub fn is_empty(&self) -> bool {
51 self.0.is_empty()
52 }
53
54 pub fn to_anemo_address(&self) -> Result<anemo::types::Address, &'static str> {
57 let mut iter = self.iter();
58
59 match (iter.next(), iter.next()) {
60 (Some(Protocol::Ip4(ipaddr)), Some(Protocol::Udp(port))) => Ok((ipaddr, port).into()),
61 (Some(Protocol::Ip6(ipaddr)), Some(Protocol::Udp(port))) => Ok((ipaddr, port).into()),
62 (Some(Protocol::Dns(hostname)), Some(Protocol::Udp(port))) => {
63 Ok((hostname.as_ref(), port).into())
64 }
65
66 _ => {
67 tracing::warn!("unsupported p2p multiaddr: '{self}'");
68 Err("invalid address")
69 }
70 }
71 }
72
73 pub fn udp_multiaddr_to_listen_address(&self) -> Option<std::net::SocketAddr> {
74 let mut iter = self.iter();
75
76 match (iter.next(), iter.next()) {
77 (Some(Protocol::Ip4(ipaddr)), Some(Protocol::Udp(port))) => Some((ipaddr, port).into()),
78 (Some(Protocol::Ip6(ipaddr)), Some(Protocol::Udp(port))) => Some((ipaddr, port).into()),
79
80 (Some(Protocol::Dns(_)), Some(Protocol::Udp(port))) => {
81 Some((std::net::Ipv4Addr::UNSPECIFIED, port).into())
82 }
83
84 _ => None,
85 }
86 }
87
88 pub fn to_socket_addr(&self) -> Result<SocketAddr> {
93 let mut iter = self.iter();
94 let ip = match iter.next().ok_or_else(|| {
95 eyre!("failed to convert to SocketAddr: Multiaddr does not contain IP")
96 })? {
97 Protocol::Ip4(ip4_addr) => IpAddr::V4(ip4_addr),
98 Protocol::Ip6(ip6_addr) => IpAddr::V6(ip6_addr),
99 unsupported => return Err(eyre!("unsupported protocol {unsupported}")),
100 };
101 let tcp_port = parse_tcp(&mut iter)?;
102 Ok(SocketAddr::new(ip, tcp_port))
103 }
104
105 pub fn is_loosely_valid_tcp_addr(&self) -> bool {
107 let mut iter = self.iter();
108 iter.next(); match iter.next() {
110 Some(Protocol::Tcp(_)) => true,
111 _ => false, }
113 }
114
115 pub fn with_zero_ip(&self) -> Self {
120 let mut new_address = self.0.clone();
121 let Some(protocol) = new_address.iter().next() else {
122 error!("Multiaddr is empty");
123 return Self(new_address);
124 };
125 match protocol {
126 multiaddr::Protocol::Ip4(_)
127 | multiaddr::Protocol::Dns(_)
128 | multiaddr::Protocol::Dns4(_) => {
129 new_address = new_address
130 .replace(0, |_| Some(multiaddr::Protocol::Ip4(Ipv4Addr::UNSPECIFIED)))
131 .unwrap();
132 }
133 multiaddr::Protocol::Ip6(_) | multiaddr::Protocol::Dns6(_) => {
134 new_address = new_address
135 .replace(0, |_| Some(multiaddr::Protocol::Ip6(Ipv6Addr::UNSPECIFIED)))
136 .unwrap();
137 }
138 p => {
139 error!("Unsupported protocol {} in Multiaddr {}!", p, new_address);
140 }
141 }
142 Self(new_address)
143 }
144
145 pub fn with_localhost_ip(&self) -> Self {
149 let mut new_address = self.0.clone();
150 let Some(protocol) = new_address.iter().next() else {
151 error!("Multiaddr is empty");
152 return Self(new_address);
153 };
154 match protocol {
155 multiaddr::Protocol::Ip4(_)
156 | multiaddr::Protocol::Dns(_)
157 | multiaddr::Protocol::Dns4(_) => {
158 new_address = new_address
159 .replace(0, |_| Some(multiaddr::Protocol::Ip4(Ipv4Addr::LOCALHOST)))
160 .unwrap();
161 }
162 multiaddr::Protocol::Ip6(_) | multiaddr::Protocol::Dns6(_) => {
163 new_address = new_address
164 .replace(0, |_| Some(multiaddr::Protocol::Ip6(Ipv6Addr::LOCALHOST)))
165 .unwrap();
166 }
167 p => {
168 error!("Unsupported protocol {} in Multiaddr {}!", p, new_address);
169 }
170 }
171 Self(new_address)
172 }
173
174 pub fn is_localhost_ip(&self) -> bool {
175 let Some(protocol) = self.0.iter().next() else {
176 error!("Multiaddr is empty");
177 return false;
178 };
179 match protocol {
180 multiaddr::Protocol::Ip4(addr) => addr == Ipv4Addr::LOCALHOST,
181 multiaddr::Protocol::Ip6(addr) => addr == Ipv6Addr::LOCALHOST,
182 _ => false,
183 }
184 }
185
186 pub fn hostname(&self) -> Option<String> {
187 for component in self.iter() {
188 match component {
189 Protocol::Ip4(ip) => return Some(ip.to_string()),
190 Protocol::Ip6(ip) => return Some(ip.to_string()),
191 Protocol::Dns(dns) => return Some(dns.to_string()),
192 _ => (),
193 }
194 }
195 None
196 }
197
198 pub fn port(&self) -> Option<u16> {
199 for component in self.iter() {
200 match component {
201 Protocol::Udp(port) | Protocol::Tcp(port) => return Some(port),
202 _ => (),
203 }
204 }
205 None
206 }
207
208 pub fn rewrite_udp_to_tcp(&self) -> Self {
209 let mut new = Self::empty();
210
211 for component in self.iter() {
212 if let Protocol::Udp(port) = component {
213 new.push(Protocol::Tcp(port));
214 } else {
215 new.push(component);
216 }
217 }
218
219 new
220 }
221}
222
223impl std::fmt::Display for Multiaddr {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 std::fmt::Display::fmt(&self.0, f)
226 }
227}
228
229impl std::str::FromStr for Multiaddr {
230 type Err = Error;
231
232 fn from_str(s: &str) -> Result<Self, Self::Err> {
233 ::multiaddr::Multiaddr::from_str(s).map(Self)
234 }
235}
236
237impl<'a> TryFrom<&'a str> for Multiaddr {
238 type Error = Error;
239
240 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
241 value.parse()
242 }
243}
244
245impl TryFrom<String> for Multiaddr {
246 type Error = Error;
247
248 fn try_from(value: String) -> Result<Self, Self::Error> {
249 value.parse()
250 }
251}
252
253impl serde::Serialize for Multiaddr {
254 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
255 where
256 S: serde::Serializer,
257 {
258 serializer.serialize_str(&self.0.to_string())
259 }
260}
261
262impl<'de> serde::Deserialize<'de> for Multiaddr {
263 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
264 where
265 D: serde::Deserializer<'de>,
266 {
267 let s = String::deserialize(deserializer)?;
268 s.parse()
269 .map(Self)
270 .map_err(|e| serde::de::Error::custom(e.to_string()))
271 }
272}
273
274impl std::net::ToSocketAddrs for Multiaddr {
275 type Iter = Box<dyn Iterator<Item = SocketAddr>>;
276
277 fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
278 let mut iter = self.iter();
279
280 match (iter.next(), iter.next()) {
281 (Some(Protocol::Ip4(ip4)), Some(Protocol::Tcp(port) | Protocol::Udp(port))) => {
282 (ip4, port)
283 .to_socket_addrs()
284 .map(|iter| Box::new(iter) as _)
285 }
286 (Some(Protocol::Ip6(ip6)), Some(Protocol::Tcp(port) | Protocol::Udp(port))) => {
287 (ip6, port)
288 .to_socket_addrs()
289 .map(|iter| Box::new(iter) as _)
290 }
291 (Some(Protocol::Dns(hostname)), Some(Protocol::Tcp(port) | Protocol::Udp(port))) => {
292 (hostname.as_ref(), port)
293 .to_socket_addrs()
294 .map(|iter| Box::new(iter) as _)
295 }
296 _ => Err(std::io::Error::new(
297 std::io::ErrorKind::InvalidInput,
298 "unable to convert Multiaddr to SocketAddr",
299 )),
300 }
301 }
302}
303
304pub(crate) fn parse_tcp<'a, T: Iterator<Item = Protocol<'a>>>(protocols: &mut T) -> Result<u16> {
305 if let Protocol::Tcp(port) = protocols
306 .next()
307 .ok_or_else(|| eyre!("unexpected end of multiaddr"))?
308 {
309 Ok(port)
310 } else {
311 Err(eyre!("expected tcp protocol"))
312 }
313}
314
315pub(crate) fn parse_http_https<'a, T: Iterator<Item = Protocol<'a>>>(
316 protocols: &mut T,
317) -> Result<&'static str> {
318 match protocols.next() {
319 Some(Protocol::Http) => Ok("http"),
320 Some(Protocol::Https) => Ok("https"),
321 _ => Ok("http"),
322 }
323}
324
325pub(crate) fn parse_end<'a, T: Iterator<Item = Protocol<'a>>>(protocols: &mut T) -> Result<()> {
326 if protocols.next().is_none() {
327 Ok(())
328 } else {
329 Err(eyre!("expected end of multiaddr"))
330 }
331}
332
333pub(crate) fn parse_dns(address: &Multiaddr) -> Result<(Cow<'_, str>, u16, &'static str)> {
335 let mut iter = address.iter();
336
337 let dns_name = match iter
338 .next()
339 .ok_or_else(|| eyre!("unexpected end of multiaddr"))?
340 {
341 Protocol::Dns(dns_name) => dns_name,
342 other => return Err(eyre!("expected dns found {other}")),
343 };
344 let tcp_port = parse_tcp(&mut iter)?;
345 let http_or_https = parse_http_https(&mut iter)?;
346 parse_end(&mut iter)?;
347 Ok((dns_name, tcp_port, http_or_https))
348}
349
350pub(crate) fn parse_ip4(address: &Multiaddr) -> Result<(SocketAddr, &'static str)> {
352 let mut iter = address.iter();
353
354 let ip_addr = match iter
355 .next()
356 .ok_or_else(|| eyre!("unexpected end of multiaddr"))?
357 {
358 Protocol::Ip4(ip4_addr) => IpAddr::V4(ip4_addr),
359 other => return Err(eyre!("expected ip4 found {other}")),
360 };
361 let tcp_port = parse_tcp(&mut iter)?;
362 let http_or_https = parse_http_https(&mut iter)?;
363 parse_end(&mut iter)?;
364 let socket_addr = SocketAddr::new(ip_addr, tcp_port);
365
366 Ok((socket_addr, http_or_https))
367}
368
369pub(crate) fn parse_ip6(address: &Multiaddr) -> Result<(SocketAddr, &'static str)> {
371 let mut iter = address.iter();
372
373 let ip_addr = match iter
374 .next()
375 .ok_or_else(|| eyre!("unexpected end of multiaddr"))?
376 {
377 Protocol::Ip6(ip6_addr) => IpAddr::V6(ip6_addr),
378 other => return Err(eyre!("expected ip6 found {other}")),
379 };
380 let tcp_port = parse_tcp(&mut iter)?;
381 let http_or_https = parse_http_https(&mut iter)?;
382 parse_end(&mut iter)?;
383 let socket_addr = SocketAddr::new(ip_addr, tcp_port);
384
385 Ok((socket_addr, http_or_https))
386}
387
388#[cfg(test)]
389mod test {
390 use multiaddr::multiaddr;
391
392 use super::Multiaddr;
393
394 #[test]
395 fn test_to_socket_addr_basic() {
396 let multi_addr_ipv4 = Multiaddr(multiaddr!(Ip4([127, 0, 0, 1]), Tcp(10500u16)));
397 let socket_addr_ipv4 = multi_addr_ipv4
398 .to_socket_addr()
399 .expect("Couldn't convert to socket addr");
400 assert_eq!(socket_addr_ipv4.to_string(), "127.0.0.1:10500");
401
402 let multi_addr_ipv6 = Multiaddr(multiaddr!(Ip6([172, 0, 0, 1, 1, 1, 1, 1]), Tcp(10500u16)));
403 let socket_addr_ipv6 = multi_addr_ipv6
404 .to_socket_addr()
405 .expect("Couldn't convert to socket addr");
406 assert_eq!(socket_addr_ipv6.to_string(), "[ac::1:1:1:1:1]:10500");
407 }
408
409 #[test]
410 fn test_to_socket_addr_unsupported_protocol() {
411 let multi_addr_dns = Multiaddr(multiaddr!(Dnsaddr("iota.iota"), Tcp(10500u16)));
412 let _ = multi_addr_dns
413 .to_socket_addr()
414 .expect_err("DNS is unsupported");
415 }
416
417 #[test]
418 fn test_is_loosely_valid_tcp_addr() {
419 let multi_addr_ipv4 = Multiaddr(multiaddr!(Ip4([127, 0, 0, 1]), Tcp(10500u16)));
420 assert!(multi_addr_ipv4.is_loosely_valid_tcp_addr());
421 let multi_addr_ipv6 = Multiaddr(multiaddr!(Ip6([172, 0, 0, 1, 1, 1, 1, 1]), Tcp(10500u16)));
422 assert!(multi_addr_ipv6.is_loosely_valid_tcp_addr());
423 let multi_addr_dns = Multiaddr(multiaddr!(Dnsaddr("iota.iota"), Tcp(10500u16)));
424 assert!(multi_addr_dns.is_loosely_valid_tcp_addr());
425
426 let multi_addr_ipv4 = Multiaddr(multiaddr!(Ip4([127, 0, 0, 1]), Udp(10500u16)));
427 assert!(!multi_addr_ipv4.is_loosely_valid_tcp_addr());
428 let multi_addr_ipv6 = Multiaddr(multiaddr!(Ip6([172, 0, 0, 1, 1, 1, 1, 1]), Udp(10500u16)));
429 assert!(!multi_addr_ipv6.is_loosely_valid_tcp_addr());
430 let multi_addr_dns = Multiaddr(multiaddr!(Dnsaddr("iota.iota"), Udp(10500u16)));
431 assert!(!multi_addr_dns.is_loosely_valid_tcp_addr());
432
433 let invalid_multi_addr_ipv4 = Multiaddr(multiaddr!(Ip4([127, 0, 0, 1])));
434 assert!(!invalid_multi_addr_ipv4.is_loosely_valid_tcp_addr());
435 }
436
437 #[test]
438 fn test_get_hostname_port() {
439 let multi_addr_ip4 = Multiaddr(multiaddr!(Ip4([127, 0, 0, 1]), Tcp(10500u16)));
440 assert_eq!(Some("127.0.0.1".to_string()), multi_addr_ip4.hostname());
441 assert_eq!(Some(10500u16), multi_addr_ip4.port());
442
443 let multi_addr_dns = Multiaddr(multiaddr!(Dns("iota.iota"), Tcp(10501u16)));
444 assert_eq!(Some("iota.iota".to_string()), multi_addr_dns.hostname());
445 assert_eq!(Some(10501u16), multi_addr_dns.port());
446 }
447
448 #[test]
449 fn test_to_anemo_address() {
450 let addr_ip4 = Multiaddr(multiaddr!(Ip4([15, 15, 15, 1]), Udp(10500u16)))
451 .to_anemo_address()
452 .unwrap();
453 assert_eq!("15.15.15.1:10500".to_string(), addr_ip4.to_string());
454
455 let addr_ip6 = Multiaddr(multiaddr!(
456 Ip6([15, 15, 15, 15, 15, 15, 15, 1]),
457 Udp(10500u16)
458 ))
459 .to_anemo_address()
460 .unwrap();
461 assert_eq!("[f:f:f:f:f:f:f:1]:10500".to_string(), addr_ip6.to_string());
462
463 let addr_dns = Multiaddr(multiaddr!(Dns("iota.iota"), Udp(10501u16)))
464 .to_anemo_address()
465 .unwrap();
466 assert_eq!("iota.iota:10501".to_string(), addr_dns.to_string());
467
468 let addr_invalid =
469 Multiaddr(multiaddr!(Dns("iota.iota"), Tcp(10501u16))).to_anemo_address();
470 assert!(addr_invalid.is_err());
471 }
472
473 #[test]
474 fn test_with_zero_ip() {
475 let multi_addr_ip4 =
476 Multiaddr(multiaddr!(Ip4([15, 15, 15, 1]), Tcp(10500u16))).with_zero_ip();
477 assert_eq!(Some("0.0.0.0".to_string()), multi_addr_ip4.hostname());
478 assert_eq!(Some(10500u16), multi_addr_ip4.port());
479
480 let multi_addr_ip6 = Multiaddr(multiaddr!(
481 Ip6([15, 15, 15, 15, 15, 15, 15, 1]),
482 Tcp(10500u16)
483 ))
484 .with_zero_ip();
485 assert_eq!(Some("::".to_string()), multi_addr_ip6.hostname());
486 assert_eq!(Some(10500u16), multi_addr_ip4.port());
487
488 let multi_addr_dns = Multiaddr(multiaddr!(Dns("iota.iota"), Tcp(10501u16))).with_zero_ip();
489 assert_eq!(Some("0.0.0.0".to_string()), multi_addr_dns.hostname());
490 assert_eq!(Some(10501u16), multi_addr_dns.port());
491 }
492
493 #[test]
494 fn test_with_localhost_ip() {
495 let multi_addr_ip4 =
496 Multiaddr(multiaddr!(Ip4([15, 15, 15, 1]), Tcp(10500u16))).with_localhost_ip();
497 assert_eq!(Some("127.0.0.1".to_string()), multi_addr_ip4.hostname());
498 assert_eq!(Some(10500u16), multi_addr_ip4.port());
499
500 let multi_addr_ip6 = Multiaddr(multiaddr!(
501 Ip6([15, 15, 15, 15, 15, 15, 15, 1]),
502 Tcp(10500u16)
503 ))
504 .with_localhost_ip();
505 assert_eq!(Some("::1".to_string()), multi_addr_ip6.hostname());
506 assert_eq!(Some(10500u16), multi_addr_ip4.port());
507
508 let multi_addr_dns =
509 Multiaddr(multiaddr!(Dns("iota.iota"), Tcp(10501u16))).with_localhost_ip();
510 assert_eq!(Some("127.0.0.1".to_string()), multi_addr_dns.hostname());
511 assert_eq!(Some(10501u16), multi_addr_dns.port());
512 }
513}