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