net: change transport_mixing into a list of transports to be mixed allowing control of the specific transports we want to be mixed

This commit is contained in:
oars
2025-03-14 14:20:35 +03:00
parent cf436360bd
commit 9743cc1d41
5 changed files with 157 additions and 68 deletions

View File

@@ -241,10 +241,6 @@ impl PluginSettings {
"net.outbound_peer_discovery_cooloff_time",
PropertyValue::Uint32(p2p_settings.outbound_peer_discovery_cooloff_time as u32),
);
self.add_setting(
"net.transport_mixing",
PropertyValue::Bool(p2p_settings.transport_mixing),
);
self.add_setting("net.localnet", PropertyValue::Bool(p2p_settings.localnet));
self.add_setting(
"net.greylist_refinery_interval",
@@ -298,8 +294,6 @@ impl PluginSettings {
.unwrap()
.get_property_u32("value")
.unwrap() as u64;
p2p_settings.transport_mixing =
self.get_setting("net.transport_mixing").unwrap().get_property_bool("value").unwrap();
p2p_settings.localnet =
self.get_setting("net.localnet").unwrap().get_property_bool("value").unwrap();
p2p_settings.greylist_refinery_interval = self

View File

@@ -64,7 +64,7 @@ impl Connector {
let settings = self.settings.read().await;
let transports = settings.allowed_transports.clone();
let transport_mixing = settings.transport_mixing;
let mixed_transports = settings.mixed_transports.clone();
let datastore = settings.p2p_datastore.clone();
let outbound_connect_timeout = settings.outbound_connect_timeout;
let i2p_socks5_proxy = settings.i2p_socks5_proxy.clone();
@@ -74,8 +74,26 @@ impl Connector {
let mut endpoint = url.clone();
let scheme = endpoint.scheme();
if !transports.contains(&scheme.to_string()) && transport_mixing {
if transports.contains(&"tor".to_string()) && scheme == "tcp" {
if mixed_transports.contains(&scheme.to_string()) {
if transports.contains(&"socks5".to_string()) && (scheme == "tcp" || scheme == "tor") {
endpoint = tor_socks5_proxy;
endpoint.set_path(&format!(
"{}:{}",
endpoint.host().unwrap(),
endpoint.port().unwrap()
));
endpoint.set_scheme("socks5")?;
} else if transports.contains(&"socks5+tls".to_string()) &&
(scheme == "tcp+tls" || scheme == "tor+tls")
{
endpoint = tor_socks5_proxy;
endpoint.set_path(&format!(
"{}:{}",
endpoint.host().unwrap(),
endpoint.port().unwrap()
));
endpoint.set_scheme("socks5+tls")?;
} else if transports.contains(&"tor".to_string()) && scheme == "tcp" {
endpoint.set_scheme("tor")?;
} else if transports.contains(&"tor+tls".to_string()) && scheme == "tcp+tls" {
endpoint.set_scheme("tor+tls")?;
@@ -83,32 +101,6 @@ impl Connector {
endpoint.set_scheme("nym")?;
} else if transports.contains(&"nym+tls".to_string()) && scheme == "tcp+tls" {
endpoint.set_scheme("nym+tls")?;
} else if transports.contains(&"socks5".to_string()) &&
(scheme == "tcp" || scheme == "tor")
{
endpoint.set_path(&format!(
"{}:{}",
endpoint.host().unwrap(),
endpoint.port().unwrap()
));
endpoint.set_host(tor_socks5_proxy.host_str())?;
endpoint.set_port(tor_socks5_proxy.port())?;
endpoint.set_username(tor_socks5_proxy.username())?;
endpoint.set_password(tor_socks5_proxy.password())?;
endpoint.set_scheme("socks5")?;
} else if transports.contains(&"socks5+tls".to_string()) &&
(scheme == "tcp+tls" || scheme == "tor+tls")
{
endpoint.set_path(&format!(
"{}:{}",
endpoint.host().unwrap(),
endpoint.port().unwrap()
));
endpoint.set_host(tor_socks5_proxy.host_str())?;
endpoint.set_port(tor_socks5_proxy.port())?;
endpoint.set_username(tor_socks5_proxy.username())?;
endpoint.set_password(tor_socks5_proxy.password())?;
endpoint.set_scheme("socks5+tls")?;
}
}

View File

@@ -419,8 +419,8 @@ impl HostContainer {
&self,
color: HostColor,
transports: &[String],
transport_mixing: bool,
tor_socks5_proxy: Url,
mixed_transports: &[String],
tor_socks5_proxy: Url
) -> Vec<(Url, u64)> {
trace!(target: "net::hosts::fetch_addrs()", "[START] {color:?}");
let mut hosts = vec![];
@@ -431,7 +431,9 @@ impl HostContainer {
// However, **do not** mix tor:// and tcp+tls://, nor tor+tls:// and tcp://.
macro_rules! mix_transport {
($a:expr, $b:expr) => {
if transports.contains(&$a.to_string()) && transport_mixing {
if transports.contains(&$a.to_string()) &&
mixed_transports.contains(&$b.to_string())
{
let mut a_to_b = self.fetch_with_schemes(index, &[$b.to_string()], None);
for (addr, last_seen) in a_to_b.iter_mut() {
addr.set_scheme($a).unwrap();
@@ -443,20 +445,19 @@ impl HostContainer {
macro_rules! mix_socks5_transport {
($a:expr, $b:expr) => {
if transports.contains(&$a.to_string()) && transport_mixing {
if transports.contains(&$a.to_string()) &&
mixed_transports.contains(&$b.to_string())
{
let mut a_to_b = self.fetch_with_schemes(index, &[$b.to_string()], None);
for (addr, last_seen) in a_to_b.iter_mut() {
addr.set_path(&format!(
let mut endpoint = tor_socks5_proxy.clone();
endpoint.set_path(&format!(
"{}:{}",
addr.host().unwrap(),
addr.port().unwrap()
));
addr.set_host(tor_socks5_proxy.host_str()).unwrap();
addr.set_port(tor_socks5_proxy.port()).unwrap();
addr.set_username(tor_socks5_proxy.username()).unwrap();
addr.set_password(tor_socks5_proxy.password()).unwrap();
addr.set_scheme($a).unwrap();
hosts.push((addr.clone(), last_seen.clone()));
endpoint.set_scheme($a).unwrap();
hosts.push((endpoint, last_seen.clone()));
}
}
};
@@ -471,8 +472,13 @@ impl HostContainer {
mix_socks5_transport!("socks5", "tor");
mix_socks5_transport!("socks5+tls", "tor+tls");
// Filter out a transport from requested transport if we set it to be mixed as
// we don't want to connect directly to that host
let transports: Vec<String> =
transports.iter().filter(|tp| !mixed_transports.contains(tp)).cloned().collect();
// And now the actual requested transports
for (addr, last_seen) in self.fetch_with_schemes(index, transports, None) {
for (addr, last_seen) in self.fetch_with_schemes(index, &transports, None) {
hosts.push((addr, last_seen));
}
@@ -1238,7 +1244,13 @@ impl Hosts {
/// stored in the blacklist without a port, and if so, it will return
/// true.
pub(in crate::net) fn block_all_ports(&self, url: &Url) -> bool {
let host = url.host().unwrap();
let host = url.host();
if host.is_none() {
// the url is a unix socket or an invalid address so it won't be in hostlist
return false
}
let host = host.unwrap();
self.container.hostlists[HostColor::Black as usize]
.read()
.unwrap()
@@ -1385,13 +1397,8 @@ impl Hosts {
let day = 86400;
self.container.refresh(HostColor::Dark, day);
// If transport mixing is disabled or Socks5 transport is not allowed we will not connect to this host
if !settings.transport_mixing ||
!settings
.allowed_transports
.iter()
.any(|t| t == "socks5" || t == "socks5+tls")
{
// If the scheme is not found in mixed_transports we can not connect to this host
if !settings.mixed_transports.contains(&addr_.scheme().to_string()) {
continue;
}
}
@@ -1904,4 +1911,79 @@ mod tests {
assert!(Hosts::is_i2p_host("node.dark.fi.i2p"));
assert!(!Hosts::is_i2p_host("node.dark.fi"));
}
fn test_transport_tor_mixed_with_tcp_fetch() {
let host_container = HostContainer::new();
host_container.store_or_update(
HostColor::Grey,
Url::parse("tcp://dark.fi:28880").unwrap(),
0,
);
let fetched_hosts = host_container.fetch(
HostColor::Grey,
&["tor+tls".to_string(), "tcp".to_string(), "tor".to_string()],
&["tcp".to_string()],
Url::parse("socks5://127.0.0.1:9050").unwrap(),
);
// test tcp endpoint is changed to tor and tcp will not be used to
// connect to any host directly
assert_eq!(fetched_hosts.len(), 1);
assert_eq!(fetched_hosts[0].0.to_string(), "tor://dark.fi:28880/");
}
#[test]
fn test_transport_socks5_mixed_with_tor_fetch() {
let host_container = HostContainer::new();
let addr = "eweiibe6tdjsdprb4px6rqrzzcsi22m4koia44kc5pcjr7nec2rlxyad.onion:23330";
host_container.store_or_update(
HostColor::Grey,
Url::parse(&format!("tor://{}", addr)).unwrap(),
0,
);
let socks5_proxy_url = Url::parse("socks5://127.0.0.1:9050").unwrap();
let fetched_hosts = host_container.fetch(
HostColor::Grey,
&["socks5".to_string(), "socks5+tls".to_string(), "tor".to_string()],
&["tor".to_string()],
socks5_proxy_url.clone(),
);
// test tor endpoint is changed to socks5 and tor will not be used to
// connect to any host directly
assert_eq!(fetched_hosts.len(), 1);
let mixed_url = fetched_hosts[0].0.clone();
assert_eq!(mixed_url.scheme(), socks5_proxy_url.scheme());
assert_eq!(mixed_url.host(), socks5_proxy_url.host());
assert_eq!(mixed_url.port(), socks5_proxy_url.port());
assert_eq!(mixed_url.path_segments().unwrap().next(), Some(addr));
}
#[test]
fn test_transport_tor_and_socks5_mixed_with_tcp_fetch() {
let host_container = HostContainer::new();
host_container.store_or_update(
HostColor::Grey,
Url::parse("tcp://dark.fi:28880").unwrap(),
0,
);
let fetched_hosts = host_container.fetch(
HostColor::Grey,
&[
"tor".to_string(),
"tor+tls".to_string(),
"socks5".to_string(),
"socks5+tls".to_string(),
],
&["tcp".to_string()],
Url::parse("socks5://127.0.0.1:9050").unwrap(),
);
// test the tcp endpoint is changed to two endpoints socks5 and tor.
assert_eq!(fetched_hosts.len(), 2);
let endpoints: Vec<_> = fetched_hosts.iter().map(|item| item.0.scheme()).collect();
assert!(endpoints.iter().all(|&scheme| scheme == "tor" || scheme == "socks5"));
}
}

View File

@@ -216,7 +216,7 @@ impl Slot {
let gold_count = settings.gold_connect_count;
let transports = settings.allowed_transports.clone();
let transport_mixing = settings.transport_mixing;
let mixed_transports = settings.mixed_transports.clone();
let preference_strict = settings.slot_preference_strict;
let tor_socks5_proxy = settings.tor_socks5_proxy.clone();
@@ -230,13 +230,13 @@ impl Slot {
// If we only have grey entries, select from the greylist. Otherwise,
// use the preference defined in settings.
let addrs = if grey_only && !preference_strict {
container.fetch(HostColor::Grey, &transports, transport_mixing, tor_socks5_proxy)
container.fetch(HostColor::Grey, &transports, &mixed_transports, tor_socks5_proxy)
} else if slot < gold_count {
container.fetch(HostColor::Gold, &transports, transport_mixing, tor_socks5_proxy)
container.fetch(HostColor::Gold, &transports, &mixed_transports, tor_socks5_proxy)
} else if slot < white_count {
container.fetch(HostColor::White, &transports, transport_mixing, tor_socks5_proxy)
container.fetch(HostColor::White, &transports, &mixed_transports, tor_socks5_proxy)
} else {
container.fetch(HostColor::Grey, &transports, transport_mixing, tor_socks5_proxy)
container.fetch(HostColor::Grey, &transports, &mixed_transports, tor_socks5_proxy)
};
hosts.check_addrs(addrs).await

View File

@@ -52,7 +52,7 @@ pub struct Settings {
pub external_addrs: Vec<Url>,
/// Peer nodes to manually connect to
pub peers: Vec<Url>,
/// Seed nodes to connect to for peer discovery and/or adversising our
/// Seed nodes to connect to for peer discovery and/or advertising our
/// own external addresses
pub seeds: Vec<Url>,
/// Magic bytes should be unique per P2P network.
@@ -62,8 +62,18 @@ pub struct Settings {
pub app_version: semver::Version,
/// Whitelisted network transports for outbound connections
pub allowed_transports: Vec<String>,
/// Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
pub transport_mixing: bool,
/// Transports allowed to be mixed (tcp, tcp+tls, tor, tor+tls)
/// When transport is added to this list the corresponding transport
/// in allowed_transports is used to connect to the node.
/// Supported mixing scenarios include
/// allowed_transport | mixed_transport
/// tor | tcp
/// tor+tls | tcp+tls
/// socks5 | tor
/// socks5 | tcp
/// socks5+tls | tor+tls
/// socks5+tls | tcp+tls
pub mixed_transports: Vec<String>,
/// Tor socks5 proxy to connect to when socks5 or socks5+tls are added to allowed transports
/// and transport mixing is enabled
pub tor_socks5_proxy: Url,
@@ -128,7 +138,7 @@ impl Default for Settings {
seeds: vec![],
app_version,
allowed_transports: vec!["tcp+tls".to_string()],
transport_mixing: false,
mixed_transports: vec![],
tor_socks5_proxy: Url::parse("socks5://127.0.0.1:9050").unwrap(),
i2p_socks5_proxy: Url::parse("socks5://127.0.0.1:4447").unwrap(),
outbound_connections: 8,
@@ -228,9 +238,20 @@ pub struct SettingsOpt {
#[structopt(long = "transports")]
pub allowed_transports: Option<Vec<String>>,
/// Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
#[structopt(long)]
pub transport_mixing: Option<bool>,
/// Transports allowed to be mixed (tcp, tcp+tls, tor, tor+tls)
/// When transport is added to this list the corresponding transport
/// in allowed_transports is used to connect to the node.
/// Supported mixing scenarios include
/// allowed_transport | mixed_transport
/// tor | tcp
/// tor+tls | tcp+tls
/// socks5 | tor
/// socks5 | tcp
/// socks5+tls | tor+tls
/// socks5+tls | tcp+tls
#[serde(default)]
#[structopt(long = "mixed-transports")]
pub mixed_transports: Option<Vec<String>>,
/// Tor socks5 proxy to connect to when socks5 or socks5+tls are added to allowed transports
/// and transport mixing is enabled
@@ -316,7 +337,7 @@ impl From<SettingsOpt> for Settings {
seeds: opt.seeds,
app_version: def.app_version,
allowed_transports: opt.allowed_transports.unwrap_or(def.allowed_transports),
transport_mixing: opt.transport_mixing.unwrap_or(def.transport_mixing),
mixed_transports: opt.mixed_transports.unwrap_or(def.mixed_transports),
tor_socks5_proxy: opt.tor_socks5_proxy.unwrap_or(def.tor_socks5_proxy),
i2p_socks5_proxy: opt.i2p_socks5_proxy.unwrap_or(def.i2p_socks5_proxy),
outbound_connections: opt.outbound_connections.unwrap_or(def.outbound_connections),