Skip to content

Commit e541221

Browse files
committed
Merge rust-bitcoin#4521: feat(p2p): add AddrV2 <> SocketAddr conversions
a1d4bc3 test(p2p): add tests for `AddrV2` <> `SocketAddr` conversions (Luis Schwab) 64387f5 feat(p2p): add `AddrV2` <> `SocketAddr` conversions (Luis Schwab) Pull request description: Closes rust-bitcoin#4436. Note: I made the `AddrV2::Cjdns` to `SocketAddr` conversion throw the `CjdnsNotRecommended` error. Do we want this behavior or just assume the user knows what he is doing? cc Kixunil ### Changelog - Implement `From<SocketAddr> for AddrV2`. - Implement `TryFrom<AddrV2> for SocketAddr`. - Implement `AddrV2ConversionError` enum and it's `fmt::Display`. - Tests for these conversions. ACKs for top commit: apoelstra: ACK a1d4bc3; successfully ran local tests tcharding: ACK a1d4bc3 Tree-SHA512: c11f3053428d2c8ca971bbc6bc4ad4619260fe95cba055586f4889d7397733f7d286dcafa111234a6be4a739fd56cdd7e64dbf71b106a71d2483794ca7018105
2 parents a095580 + a1d4bc3 commit e541221

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

bitcoin/src/p2p/address.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,67 @@ pub enum AddrV2 {
138138
Unknown(u8, Vec<u8>),
139139
}
140140

141+
/// Error types for [`AddrV2`] to [`SocketAddr`] conversion.
142+
#[derive(Debug, PartialEq, Eq)]
143+
pub enum AddrV2ConversionError {
144+
/// A [`AddrV2::TorV3`] address cannot be converted to a [`SocketAddr`].
145+
TorV3NotSupported,
146+
/// A [`AddrV2::I2p`] address cannot be converted to a [`SocketAddr`].
147+
I2pNotSupported,
148+
/// A [`AddrV2::Cjdns`] address can be converted to a [`SocketAddr`],
149+
/// but it won't work with a tradicional socket API.
150+
CjdnsNotRecommended,
151+
/// A [`AddrV2::Unknown`] address cannot be converted to a [`SocketAddr`].
152+
UnknownNotSupported,
153+
}
154+
155+
impl fmt::Display for AddrV2ConversionError {
156+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157+
match self {
158+
Self::TorV3NotSupported => write!(f, "TorV3 addresses cannot be converted to SocketAddr"),
159+
Self::I2pNotSupported => write!(f, "I2P addresses cannot be converted to SocketAddr"),
160+
Self::CjdnsNotRecommended => write!(f, "CJDNS addresses can be converted to SocketAddr, but won't work with a traditional socket API"),
161+
Self::UnknownNotSupported => write!(f, "Unknown address type cannot be converted to SocketAddr"),
162+
}
163+
}
164+
}
165+
166+
impl std::error::Error for AddrV2ConversionError {}
167+
168+
169+
impl From<SocketAddr> for AddrV2 {
170+
fn from(addr: SocketAddr) -> Self {
171+
match addr {
172+
SocketAddr::V4(sock) => AddrV2::Ipv4(*sock.ip()),
173+
SocketAddr::V6(sock) => {
174+
// CJDNS uses the IPv6 network `fc00::/8`
175+
// All CJDNS addresses must have `0xfc00` as the first and second octets
176+
let ip = *sock.ip();
177+
if ip.octets()[0] == 0xfc && ip.octets()[1] == 0x00 {
178+
AddrV2::Cjdns(ip)
179+
} else {
180+
AddrV2::Ipv6(ip)
181+
}
182+
}
183+
}
184+
}
185+
}
186+
187+
impl TryFrom<AddrV2> for SocketAddr {
188+
type Error = AddrV2ConversionError;
189+
190+
fn try_from(addr: AddrV2) -> Result<SocketAddr, Self::Error> {
191+
match addr {
192+
AddrV2::Ipv4(ip) => Ok(SocketAddr::V4(SocketAddrV4::new(ip, 0))),
193+
AddrV2::Ipv6(ip) => Ok(SocketAddr::V6(SocketAddrV6::new(ip, 0, 0, 0))),
194+
AddrV2::Cjdns(_) => Err(AddrV2ConversionError::CjdnsNotRecommended),
195+
AddrV2::TorV3(_) => Err(AddrV2ConversionError::TorV3NotSupported),
196+
AddrV2::I2p(_) => Err(AddrV2ConversionError::I2pNotSupported),
197+
AddrV2::Unknown(_, _) => Err(AddrV2ConversionError::UnknownNotSupported),
198+
}
199+
}
200+
}
201+
141202
impl Encodable for AddrV2 {
142203
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
143204
fn encode_addr<W: Write + ?Sized>(
@@ -533,4 +594,98 @@ mod test {
533594

534595
assert_eq!(serialize(&addresses), raw);
535596
}
597+
598+
#[test]
599+
fn socketaddr_to_addrv2_ipv4() {
600+
let socket = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 8333));
601+
let addr = AddrV2::from(socket);
602+
603+
assert_eq!(addr, AddrV2::Ipv4(Ipv4Addr::new(192, 168, 1, 1)));
604+
}
605+
606+
#[test]
607+
fn socketaddr_to_addrv2_ipv6() {
608+
let socket = SocketAddr::V6(SocketAddrV6::new(
609+
Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1),
610+
8333,
611+
0,
612+
0,
613+
));
614+
let addr = AddrV2::from(socket);
615+
616+
assert_eq!(addr, AddrV2::Ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)));
617+
}
618+
619+
#[test]
620+
fn socketaddr_to_addrv2_cjdns() {
621+
let socket = SocketAddr::V6(SocketAddrV6::new(
622+
Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 1),
623+
8333,
624+
0,
625+
0,
626+
));
627+
let addr = AddrV2::from(socket);
628+
629+
assert_eq!(addr, AddrV2::Cjdns(Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 1)));
630+
}
631+
632+
#[test]
633+
fn addrv2_to_socketaddr_ipv4() {
634+
let addr = AddrV2::Ipv4(Ipv4Addr::new(192, 168, 1, 1));
635+
let socket = SocketAddr::try_from(addr).unwrap();
636+
637+
assert_eq!(socket, SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 0)));
638+
}
639+
640+
#[test]
641+
fn addrv2_to_socketaddr_ipv6() {
642+
let addr = AddrV2::Ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
643+
let socket = SocketAddr::try_from(addr).unwrap();
644+
645+
assert_eq!(
646+
socket,
647+
SocketAddr::V6(SocketAddrV6::new(
648+
Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1),
649+
0,
650+
0,
651+
0
652+
))
653+
);
654+
}
655+
656+
#[test]
657+
fn addrv2_to_socketaddr_cjdns() {
658+
let addr = AddrV2::Cjdns(Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 1));
659+
let result = SocketAddr::try_from(addr);
660+
661+
assert!(result.is_err());
662+
assert_eq!(result.unwrap_err(), AddrV2ConversionError::CjdnsNotRecommended);
663+
}
664+
665+
#[test]
666+
fn addrv2_to_socketaddr_torv3() {
667+
let addr = AddrV2::TorV3([0; 32]);
668+
let result = SocketAddr::try_from(addr);
669+
670+
assert!(result.is_err());
671+
assert_eq!(result.unwrap_err(), AddrV2ConversionError::TorV3NotSupported);
672+
}
673+
674+
#[test]
675+
fn addrv2_to_socketaddr_i2p() {
676+
let addr = AddrV2::I2p([0; 32]);
677+
let result = SocketAddr::try_from(addr);
678+
679+
assert!(result.is_err());
680+
assert_eq!(result.unwrap_err(), AddrV2ConversionError::I2pNotSupported);
681+
}
682+
683+
#[test]
684+
fn addrv2_to_socketaddr_unknown() {
685+
let addr = AddrV2::Unknown(42, vec![1, 2, 3, 4]);
686+
let result = SocketAddr::try_from(addr);
687+
688+
assert!(result.is_err());
689+
assert_eq!(result.unwrap_err(), AddrV2ConversionError::UnknownNotSupported);
690+
}
536691
}

0 commit comments

Comments
 (0)