1use std::fmt::{self, Display};
34use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
35use std::str::FromStr;
36
37use anyhow::{Result, anyhow};
38use serde::{Deserialize, Serialize};
39
40pub use saorsa_transport::transport::TransportAddr;
41
42use crate::identity::peer_id::PeerId;
43
44#[must_use]
47pub(crate) fn is_lan_ip(ip: IpAddr) -> bool {
48 match ip {
49 IpAddr::V4(ip) => is_lan_ipv4(ip),
50 IpAddr::V6(ip) => {
51 if let Some(ip) = ip.to_ipv4_mapped() {
52 return is_lan_ipv4(ip);
53 }
54 is_lan_ipv6(ip)
55 }
56 }
57}
58
59fn is_lan_ipv4(ip: Ipv4Addr) -> bool {
60 ip.is_loopback()
61 || ip.is_private()
62 || ip.is_link_local()
63 || (ip.octets()[0] == 100 && (ip.octets()[1] & 0b1100_0000) == 64)
64}
65
66fn is_lan_ipv6(ip: Ipv6Addr) -> bool {
67 let octets = ip.octets();
68 ip.is_loopback()
69 || (octets[0] & 0xfe) == 0xfc
70 || (octets[0] == 0xfe && (octets[1] & 0xc0) == 0x80)
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Hash)]
80pub struct MultiAddr {
81 transport: TransportAddr,
82 peer_id: Option<PeerId>,
83}
84
85impl From<TransportAddr> for MultiAddr {
86 fn from(transport: TransportAddr) -> Self {
87 Self::new(transport)
88 }
89}
90
91impl MultiAddr {
92 #[must_use]
94 pub fn new(transport: TransportAddr) -> Self {
95 Self {
96 transport,
97 peer_id: None,
98 }
99 }
100
101 #[must_use]
103 pub fn quic(addr: SocketAddr) -> Self {
104 Self::new(TransportAddr::Quic(addr))
105 }
106
107 #[must_use]
109 pub fn tcp(addr: SocketAddr) -> Self {
110 Self::new(TransportAddr::Tcp(addr))
111 }
112
113 #[must_use]
115 pub fn with_peer_id(mut self, peer_id: PeerId) -> Self {
116 self.peer_id = Some(peer_id);
117 self
118 }
119
120 #[must_use]
122 pub fn from_ip_port(ip: IpAddr, port: u16) -> Self {
123 Self::quic(SocketAddr::new(ip, port))
124 }
125
126 #[must_use]
128 pub fn from_ipv4(ip: Ipv4Addr, port: u16) -> Self {
129 Self::from_ip_port(IpAddr::V4(ip), port)
130 }
131
132 #[must_use]
134 pub fn from_ipv6(ip: Ipv6Addr, port: u16) -> Self {
135 Self::from_ip_port(IpAddr::V6(ip), port)
136 }
137
138 #[must_use]
144 pub fn transport(&self) -> &TransportAddr {
145 &self.transport
146 }
147
148 #[must_use]
150 pub fn peer_id(&self) -> Option<&PeerId> {
151 self.peer_id.as_ref()
152 }
153
154 #[must_use]
158 pub fn is_quic(&self) -> bool {
159 matches!(self.transport, TransportAddr::Quic(_))
160 }
161
162 #[must_use]
169 pub fn dialable_socket_addr(&self) -> Option<SocketAddr> {
170 match self.transport {
171 TransportAddr::Quic(sa) => Some(sa),
172 _ => None,
173 }
174 }
175
176 #[must_use]
179 pub fn socket_addr(&self) -> Option<SocketAddr> {
180 self.transport.as_socket_addr()
181 }
182
183 #[must_use]
185 pub fn ip(&self) -> Option<IpAddr> {
186 self.socket_addr().map(|a| a.ip())
187 }
188
189 #[must_use]
191 pub fn port(&self) -> Option<u16> {
192 self.socket_addr().map(|a| a.port())
193 }
194
195 pub fn is_ipv4(&self) -> bool {
197 self.socket_addr().is_some_and(|a| a.is_ipv4())
198 }
199
200 pub fn is_ipv6(&self) -> bool {
202 self.socket_addr().is_some_and(|a| a.is_ipv6())
203 }
204
205 pub fn is_loopback(&self) -> bool {
207 self.ip().is_some_and(|ip| ip.is_loopback())
208 }
209
210 pub fn is_private(&self) -> bool {
213 self.ip().is_some_and(is_lan_ip)
214 }
215}
216
217impl Display for MultiAddr {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 write!(f, "{}", self.transport)?;
224 if let Some(pid) = &self.peer_id {
225 write!(f, "/p2p/{}", pid.to_hex())?;
226 }
227 Ok(())
228 }
229}
230
231impl FromStr for MultiAddr {
236 type Err = anyhow::Error;
237
238 fn from_str(s: &str) -> Result<Self> {
239 if s.is_empty() {
240 return Err(anyhow!("Invalid address format: empty string"));
241 }
242
243 if let Some(p2p_idx) = s.rfind("/p2p/") {
245 let transport_part = &s[..p2p_idx];
246 let peer_hex = &s[p2p_idx + 5..]; if transport_part.is_empty() {
250 return Err(anyhow!(
251 "Peer-only addresses (/p2p/<id>) are not yet supported as standalone MultiAddr"
252 ));
253 }
254
255 if peer_hex.contains('/') {
257 return Err(anyhow!(
258 "Unexpected trailing components after peer ID in: {}",
259 s
260 ));
261 }
262
263 let transport = transport_part
264 .parse::<TransportAddr>()
265 .map_err(|e| anyhow!("Invalid transport address: {}", e))?;
266 let peer_id = PeerId::from_hex(peer_hex)
267 .map_err(|e| anyhow!("Invalid peer ID in address: {}", e))?;
268
269 Ok(MultiAddr {
270 transport,
271 peer_id: Some(peer_id),
272 })
273 } else {
274 let transport = s
276 .parse::<TransportAddr>()
277 .map_err(|e| anyhow!("Invalid address: {}", e))?;
278
279 Ok(MultiAddr {
280 transport,
281 peer_id: None,
282 })
283 }
284 }
285}
286
287impl Serialize for MultiAddr {
292 fn serialize<S: serde::Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
293 s.serialize_str(&self.to_string())
294 }
295}
296
297impl<'de> Deserialize<'de> for MultiAddr {
298 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
299 let s = String::deserialize(d)?;
300 s.parse::<MultiAddr>().map_err(serde::de::Error::custom)
301 }
302}
303
304#[cfg(test)]
309mod tests {
310 use super::*;
311 use std::net::Ipv6Addr;
312
313 #[test]
314 fn test_network_address_creation() {
315 let addr = MultiAddr::from_ipv4(Ipv4Addr::new(127, 0, 0, 1), 8080);
316 assert_eq!(addr.ip(), Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))));
317 assert_eq!(addr.port(), Some(8080));
318 assert!(addr.is_ipv4());
319 assert!(addr.is_loopback());
320 }
321
322 #[test]
323 fn test_network_address_from_string() {
324 let addr = "/ip4/127.0.0.1/udp/8080/quic".parse::<MultiAddr>().unwrap();
325 assert_eq!(addr.ip(), Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))));
326 assert_eq!(addr.port(), Some(8080));
327 }
328
329 #[test]
330 fn test_network_address_display() {
331 let addr = MultiAddr::from_ipv4(Ipv4Addr::new(192, 168, 1, 1), 9000);
332 assert_eq!(addr.to_string(), "/ip4/192.168.1.1/udp/9000/quic");
333 }
334
335 #[test]
336 fn test_private_address_detection() {
337 let private_addr = MultiAddr::from_ipv4(Ipv4Addr::new(192, 168, 1, 1), 9000);
338 assert!(private_addr.is_private());
339
340 let public_addr = MultiAddr::from_ipv4(Ipv4Addr::new(8, 8, 8, 8), 53);
341 assert!(!public_addr.is_private());
342 }
343
344 #[test]
345 fn test_ipv4_mapped_lan_address_detection() {
346 let mapped_private: IpAddr = "::ffff:192.168.1.10".parse().unwrap();
347 let mapped_loopback: IpAddr = "::ffff:127.0.0.1".parse().unwrap();
348 let mapped_link_local: IpAddr = "::ffff:169.254.1.10".parse().unwrap();
349 let mapped_cgnat: IpAddr = "::ffff:100.64.0.1".parse().unwrap();
350 let mapped_public: IpAddr = "::ffff:8.8.8.8".parse().unwrap();
351
352 assert!(is_lan_ip(mapped_private));
353 assert!(is_lan_ip(mapped_loopback));
354 assert!(is_lan_ip(mapped_link_local));
355 assert!(is_lan_ip(mapped_cgnat));
356 assert!(!is_lan_ip(mapped_public));
357 }
358
359 #[test]
360 fn test_ipv4_mapped_private_multiaddr_detection() {
361 let addr: MultiAddr = "/ip6/::ffff:192.168.1.10/udp/9000/quic".parse().unwrap();
362
363 assert!(addr.is_private());
364 }
365
366 #[test]
367 fn test_ipv6_address() {
368 let addr = MultiAddr::from_ipv6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080);
369 assert!(addr.is_ipv6());
370 assert!(addr.is_loopback());
371 }
372
373 #[test]
374 fn test_multiaddr_tcp_parsing() {
375 let addr = "/ip4/192.168.1.1/tcp/9000".parse::<MultiAddr>().unwrap();
376 assert_eq!(addr.ip(), Some(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))));
377 assert_eq!(addr.port(), Some(9000));
378 assert!(matches!(addr.transport(), TransportAddr::Tcp(_)));
379 }
380
381 #[test]
382 fn test_multiaddr_quic_parsing() {
383 let addr = "/ip4/10.0.0.1/udp/9000/quic".parse::<MultiAddr>().unwrap();
384 assert_eq!(addr.ip(), Some(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))));
385 assert_eq!(addr.port(), Some(9000));
386 assert!(matches!(addr.transport(), TransportAddr::Quic(_)));
387 }
388
389 #[test]
390 fn test_multiaddr_raw_udp_parsing() {
391 let addr = "/ip4/10.0.0.1/udp/5000".parse::<MultiAddr>().unwrap();
392 assert_eq!(addr.port(), Some(5000));
393 assert!(matches!(addr.transport(), TransportAddr::Udp(_)));
394 }
395
396 #[test]
397 fn test_multiaddr_ipv6_quic_parsing() {
398 let addr = "/ip6/::1/udp/8080/quic".parse::<MultiAddr>().unwrap();
399 assert_eq!(
400 addr.ip(),
401 Some(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)))
402 );
403 assert_eq!(addr.port(), Some(8080));
404 assert!(addr.is_loopback());
405 }
406
407 #[test]
408 fn test_display_roundtrip_quic() {
409 let addr = MultiAddr::from_ipv4(Ipv4Addr::new(1, 2, 3, 4), 9000);
410 let s = addr.to_string();
411 let parsed: MultiAddr = s.parse().unwrap();
412 assert_eq!(addr, parsed);
413 }
414
415 #[test]
416 fn test_display_roundtrip_tcp() {
417 let addr = MultiAddr::tcp(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 80));
418 let s = addr.to_string();
419 let parsed: MultiAddr = s.parse().unwrap();
420 assert_eq!(addr, parsed);
421 }
422
423 #[test]
424 fn test_bluetooth_roundtrip() {
425 let addr = MultiAddr::new(TransportAddr::Bluetooth {
426 mac: [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF],
427 channel: 5,
428 });
429 let s = addr.to_string();
430 assert_eq!(s, "/bt/AA:BB:CC:DD:EE:FF/rfcomm/5");
431 let parsed: MultiAddr = s.parse().unwrap();
432 assert_eq!(addr, parsed);
433 }
434
435 #[test]
436 fn test_ble_roundtrip() {
437 let addr = MultiAddr::new(TransportAddr::Ble {
438 mac: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
439 psm: 128,
440 });
441 let s = addr.to_string();
442 assert_eq!(s, "/ble/01:02:03:04:05:06/l2cap/128");
443 let parsed: MultiAddr = s.parse().unwrap();
444 assert_eq!(addr, parsed);
445 }
446
447 #[test]
448 fn test_lora_roundtrip() {
449 let addr = MultiAddr::new(TransportAddr::LoRa {
450 dev_addr: [0xDE, 0xAD, 0xBE, 0xEF],
451 freq_hz: 868_000_000,
452 });
453 let s = addr.to_string();
454 assert_eq!(s, "/lora/deadbeef/868000000");
455 let parsed: MultiAddr = s.parse().unwrap();
456 assert_eq!(addr, parsed);
457 }
458
459 #[test]
460 fn test_lorawan_roundtrip() {
461 let addr = MultiAddr::new(TransportAddr::LoRaWan {
462 dev_eui: 0x0011_2233_4455_6677,
463 });
464 let s = addr.to_string();
465 assert_eq!(s, "/lorawan/0011223344556677");
466 let parsed: MultiAddr = s.parse().unwrap();
467 assert_eq!(addr, parsed);
468 }
469
470 #[test]
471 fn test_peer_id_suffix() {
472 let peer_id = PeerId::from_bytes([0xAA; 32]);
473 let addr = MultiAddr::from_ipv4(Ipv4Addr::new(1, 2, 3, 4), 9000).with_peer_id(peer_id);
474 let s = addr.to_string();
475 assert!(s.starts_with("/ip4/1.2.3.4/udp/9000/quic/p2p/"));
476 let parsed: MultiAddr = s.parse().unwrap();
477 assert_eq!(addr, parsed);
478 assert_eq!(parsed.peer_id(), Some(&peer_id));
479 }
480
481 #[test]
482 fn test_non_ip_transport_accessors() {
483 let addr = MultiAddr::new(TransportAddr::Bluetooth {
484 mac: [0; 6],
485 channel: 1,
486 });
487 assert_eq!(addr.socket_addr(), None);
488 assert_eq!(addr.ip(), None);
489 assert_eq!(addr.port(), None);
490 assert!(!addr.is_loopback());
491 assert!(!addr.is_private());
492 assert!(!addr.is_ipv4());
493 assert!(!addr.is_ipv6());
494 }
495
496 #[test]
497 fn test_serde_direct_roundtrip() {
498 let addr = MultiAddr::from_ipv4(Ipv4Addr::new(10, 0, 0, 1), 9000);
499 let json = serde_json::to_string(&addr).unwrap();
500 assert_eq!(json, r#""/ip4/10.0.0.1/udp/9000/quic""#);
501 let recovered: MultiAddr = serde_json::from_str(&json).unwrap();
502 assert_eq!(addr, recovered);
503 }
504
505 #[test]
506 fn test_transport_kind() {
507 assert_eq!(
508 TransportAddr::Quic(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0)).kind(),
509 "quic"
510 );
511 assert_eq!(
512 TransportAddr::Tcp(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0)).kind(),
513 "tcp"
514 );
515 assert_eq!(
516 TransportAddr::Bluetooth {
517 mac: [0; 6],
518 channel: 0
519 }
520 .kind(),
521 "bluetooth"
522 );
523 }
524
525 #[test]
526 fn test_invalid_format_rejected() {
527 assert!("127.0.0.1:8080".parse::<MultiAddr>().is_err());
529 assert!("garbage".parse::<MultiAddr>().is_err());
530 assert!("/ip4/not-an-ip/tcp/80".parse::<MultiAddr>().is_err());
531 assert!("".parse::<MultiAddr>().is_err());
532 }
533
534 #[test]
536 fn test_serde_roundtrip_with_peer_id() {
537 let peer_id = PeerId::from_bytes([0xBB; 32]);
538 let addr = MultiAddr::from_ipv4(Ipv4Addr::new(10, 0, 0, 1), 9000).with_peer_id(peer_id);
539
540 let json = serde_json::to_string(&addr).unwrap();
541 assert!(
542 json.contains("/p2p/"),
543 "serialized form must contain /p2p/ suffix"
544 );
545
546 let recovered: MultiAddr = serde_json::from_str(&json).unwrap();
547 assert_eq!(addr, recovered, "serde roundtrip must be lossless");
548 assert_eq!(recovered.peer_id(), Some(&peer_id));
549 }
550
551 #[test]
553 fn test_dialable_socket_addr_none_for_tcp() {
554 let tcp_addr = MultiAddr::tcp(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 80));
555 assert!(
556 tcp_addr.dialable_socket_addr().is_none(),
557 "TCP addresses should not be dialable (QUIC-only policy)"
558 );
559
560 let quic_addr = MultiAddr::quic(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 80));
562 assert!(quic_addr.dialable_socket_addr().is_some());
563 }
564
565 #[test]
567 fn test_standalone_peer_id_rejected() {
568 let peer_hex = "aa".repeat(32); let input = format!("/p2p/{peer_hex}");
570 let result = input.parse::<MultiAddr>();
571 assert!(
572 result.is_err(),
573 "standalone /p2p/<id> without transport must be rejected"
574 );
575 }
576
577 #[test]
579 fn test_from_transport_addr() {
580 let transport = TransportAddr::Quic(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9000));
581 let addr: MultiAddr = transport.clone().into();
582 assert_eq!(addr.transport(), &transport);
583 assert_eq!(addr.peer_id(), None);
584 }
585}