mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 01:45:40 -04:00
Refactor fmt_as_address_string
to return a structured value
Instead of formatting to a string right away, we parse the multiaddress into a stricter data structure that only allows the kind of addresses we can dial through Tor. This will allow us to perform further checks on the parsed address.
This commit is contained in:
parent
910ed9a333
commit
ec59184e85
@ -6,8 +6,9 @@ use libp2p::core::transport::TransportError;
|
||||
use libp2p::core::Transport;
|
||||
use libp2p::tcp::tokio::{Tcp, TcpStream};
|
||||
use libp2p::tcp::TcpListenStream;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::borrow::Cow;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::{fmt, io};
|
||||
use tokio_socks::tcp::Socks5Stream;
|
||||
|
||||
/// A [`Transport`] that can dial onion addresses through a running Tor daemon.
|
||||
@ -34,15 +35,17 @@ impl Transport for TorDialOnlyTransport {
|
||||
}
|
||||
|
||||
fn dial(self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
|
||||
let tor_address_string = fmt_as_address_string(addr.clone())?;
|
||||
let tor_compatible_address = TorCompatibleAddress::from_multiaddr(Cow::Borrowed(&addr))?;
|
||||
|
||||
let dial_future = async move {
|
||||
tracing::trace!("Connecting through Tor proxy to address: {}", addr);
|
||||
|
||||
let stream =
|
||||
Socks5Stream::connect((Ipv4Addr::LOCALHOST, self.socks_port), tor_address_string)
|
||||
.await
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::ConnectionRefused, e))?;
|
||||
let stream = Socks5Stream::connect(
|
||||
(Ipv4Addr::LOCALHOST, self.socks_port),
|
||||
tor_compatible_address.to_string(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::ConnectionRefused, e))?;
|
||||
|
||||
tracing::trace!("Connection through Tor established");
|
||||
|
||||
@ -57,36 +60,56 @@ impl Transport for TorDialOnlyTransport {
|
||||
}
|
||||
}
|
||||
|
||||
/// Formats the given [`Multiaddr`] as an "address" string.
|
||||
///
|
||||
/// For our purposes, we define an address as {HOST}(.{TLD}):{PORT}. This format
|
||||
/// is what is compatible with the Tor daemon and allows us to route traffic
|
||||
/// through Tor.
|
||||
fn fmt_as_address_string(multi: Multiaddr) -> Result<String, TransportError<io::Error>> {
|
||||
let mut protocols = multi.iter();
|
||||
/// Represents an address that is _compatible_ with Tor, i.e. can be resolved by
|
||||
/// the Tor daemon.
|
||||
#[derive(Debug)]
|
||||
enum TorCompatibleAddress {
|
||||
Onion3 { host: String, port: u16 },
|
||||
Dns { address: String, port: u16 },
|
||||
Ip4 { address: Ipv4Addr, port: u16 },
|
||||
Ip6 { address: Ipv6Addr, port: u16 },
|
||||
}
|
||||
|
||||
let address_string = match protocols.next() {
|
||||
// if it is an Onion address, we have all we need and can return
|
||||
Some(Protocol::Onion3(addr)) => {
|
||||
return Ok(format!(
|
||||
"{}.onion:{}",
|
||||
BASE32.encode(addr.hash()).to_lowercase(),
|
||||
addr.port()
|
||||
))
|
||||
impl TorCompatibleAddress {
|
||||
/// Constructs a new [`TorCompatibleAddress`] from a [`Multiaddr`].
|
||||
fn from_multiaddr(multi: Cow<'_, Multiaddr>) -> Result<Self, TransportError<io::Error>> {
|
||||
match multi.iter().collect::<Vec<_>>().as_slice() {
|
||||
[Protocol::Onion3(onion), ..] => Ok(TorCompatibleAddress::Onion3 {
|
||||
host: BASE32.encode(onion.hash()).to_lowercase(),
|
||||
port: onion.port(),
|
||||
}),
|
||||
[Protocol::Ip4(address), Protocol::Tcp(port) | Protocol::Udp(port), ..] => {
|
||||
Ok(TorCompatibleAddress::Ip4 {
|
||||
address: *address,
|
||||
port: *port,
|
||||
})
|
||||
}
|
||||
[Protocol::Dns(address) | Protocol::Dns4(address), Protocol::Tcp(port) | Protocol::Udp(port), ..] => {
|
||||
Ok(TorCompatibleAddress::Dns {
|
||||
address: format!("{}", address),
|
||||
port: *port,
|
||||
})
|
||||
}
|
||||
[Protocol::Ip6(address), Protocol::Tcp(port) | Protocol::Udp(port), ..] => {
|
||||
Ok(TorCompatibleAddress::Ip6 {
|
||||
address: *address,
|
||||
port: *port,
|
||||
})
|
||||
}
|
||||
_ => Err(TransportError::MultiaddrNotSupported(multi.into_owned())),
|
||||
}
|
||||
// Deal with non-onion addresses
|
||||
Some(Protocol::Ip4(addr)) => format!("{}", addr),
|
||||
Some(Protocol::Ip6(addr)) => format!("{}", addr),
|
||||
Some(Protocol::Dns(addr) | Protocol::Dns4(addr)) => format!("{}", addr),
|
||||
_ => return Err(TransportError::MultiaddrNotSupported(multi)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let port = match protocols.next() {
|
||||
Some(Protocol::Tcp(port) | Protocol::Udp(port)) => port,
|
||||
_ => return Err(TransportError::MultiaddrNotSupported(multi)),
|
||||
};
|
||||
|
||||
Ok(format!("{}:{}", address_string, port))
|
||||
impl fmt::Display for TorCompatibleAddress {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
TorCompatibleAddress::Onion3 { host, port } => write!(f, "{}.onion:{}", host, port),
|
||||
TorCompatibleAddress::Dns { address, port } => write!(f, "{}:{}", address, port),
|
||||
TorCompatibleAddress::Ip4 { address, port } => write!(f, "{}:{}", address, port),
|
||||
TorCompatibleAddress::Ip6 { address, port } => write!(f, "{}:{}", address, port),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -98,8 +121,10 @@ pub mod test {
|
||||
let address =
|
||||
"/onion3/oarchy4tamydxcitaki6bc2v4leza6v35iezmu2chg2bap63sv6f2did:1024/p2p/12D3KooWPD4uHN74SHotLN7VCH7Fm8zZgaNVymYcpeF1fpD2guc9"
|
||||
;
|
||||
let address_string = fmt_as_address_string(address.parse().unwrap())
|
||||
.expect("To be a multi formatted address.");
|
||||
let address_string =
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(address.parse().unwrap()))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
assert_eq!(
|
||||
address_string,
|
||||
"oarchy4tamydxcitaki6bc2v4leza6v35iezmu2chg2bap63sv6f2did.onion:1024"
|
||||
@ -109,55 +134,67 @@ pub mod test {
|
||||
#[test]
|
||||
fn tcp_to_address_string_should_be_some() {
|
||||
let address = "/ip4/127.0.0.1/tcp/7777";
|
||||
let address_string = fmt_as_address_string(address.parse().unwrap())
|
||||
.expect("To be a formatted multi address. ");
|
||||
let address_string =
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(address.parse().unwrap()))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
assert_eq!(address_string, "127.0.0.1:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ip6_to_address_string_should_be_some() {
|
||||
let address = "/ip6/2001:db8:85a3:8d3:1319:8a2e:370:7348/tcp/7777";
|
||||
let address_string = fmt_as_address_string(address.parse().unwrap())
|
||||
.expect("To be a formatted multi address. ");
|
||||
let address_string =
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(address.parse().unwrap()))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
assert_eq!(address_string, "2001:db8:85a3:8d3:1319:8a2e:370:7348:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn udp_to_address_string_should_be_some() {
|
||||
let address = "/ip4/127.0.0.1/udp/7777";
|
||||
let address_string = fmt_as_address_string(address.parse().unwrap())
|
||||
.expect("To be a formatted multi address. ");
|
||||
let address_string =
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(address.parse().unwrap()))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
assert_eq!(address_string, "127.0.0.1:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ws_to_address_string_should_be_some() {
|
||||
let address = "/ip4/127.0.0.1/tcp/7777/ws";
|
||||
let address_string = fmt_as_address_string(address.parse().unwrap())
|
||||
.expect("To be a formatted multi address. ");
|
||||
let address_string =
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(address.parse().unwrap()))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
assert_eq!(address_string, "127.0.0.1:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dns4_to_address_string_should_be_some() {
|
||||
let address = "/dns4/randomdomain.com/tcp/7777";
|
||||
let address_string = fmt_as_address_string(address.parse().unwrap())
|
||||
.expect("To be a formatted multi address. ");
|
||||
let address_string =
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(address.parse().unwrap()))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
assert_eq!(address_string, "randomdomain.com:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dns_to_address_string_should_be_some() {
|
||||
let address = "/dns/randomdomain.com/tcp/7777";
|
||||
let address_string = fmt_as_address_string(address.parse().unwrap())
|
||||
.expect("To be a formatted multi address. ");
|
||||
let address_string =
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(address.parse().unwrap()))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
assert_eq!(address_string, "randomdomain.com:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dnsaddr_to_address_string_should_be_none() {
|
||||
fn dnsaddr_to_address_string_should_be_error() {
|
||||
let address = "/dnsaddr/randomdomain.com";
|
||||
let address_string = fmt_as_address_string(address.parse().unwrap()).ok();
|
||||
assert_eq!(address_string, None);
|
||||
let _ =
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(address.parse().unwrap())).unwrap_err();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user