Skip to content

Commit

Permalink
feat: allow tor proxy to be bypassed for outbound tcp connections (#3424
Browse files Browse the repository at this point in the history
)

Description
---
- Adds `tor_proxy_bypass_for_outbound_tcp` setting that allows direct
  outbound connections to be made for TCP nodes, bypassing tor
- Mobile will have this set for now until it can be configured by the apps

Motivation and Context
---
By default, the most private mode is set and all traffic is routed through tor. With this option set 
outbound tcp traffic bypasses tor for outbound TCP peer addresses in exchange for better 
bandwidth and latency.

How Has This Been Tested?
---
Some unit tests + manually
  • Loading branch information
sdbondi committed Oct 6, 2021
1 parent ce17627 commit 6a5982e
Show file tree
Hide file tree
Showing 18 changed files with 275 additions and 42 deletions.
8 changes: 6 additions & 2 deletions applications/tari_app_utilities/src/utilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

use futures::future::Either;
use log::*;
use std::sync::Arc;
use thiserror::Error;
use tokio::{runtime, runtime::Runtime};

Expand All @@ -42,6 +43,7 @@ use tari_p2p::transport::{TorConfig, TransportType};

use crate::identity_management::load_from_json;
use tari_common_types::emoji::EmojiId;
use tari_comms::transports::predicate::FalsePredicate;

pub const LOG_TARGET: &str = "tari::application";

Expand Down Expand Up @@ -185,7 +187,7 @@ pub fn create_transport_type(config: &GlobalConfig) -> TransportType {
tor_socks_config: tor_socks_address.map(|proxy_address| SocksConfig {
proxy_address,
authentication: tor_socks_auth.map(convert_socks_authentication).unwrap_or_default(),
proxy_bypass_addresses: vec![],
proxy_bypass_predicate: Arc::new(FalsePredicate::new()),
}),
},
CommsTransport::TorHiddenService {
Expand All @@ -195,6 +197,7 @@ pub fn create_transport_type(config: &GlobalConfig) -> TransportType {
auth,
onion_port,
tor_proxy_bypass_addresses,
tor_proxy_bypass_for_outbound_tcp,
} => {
let identity = Some(&config.base_node_tor_identity_file)
.filter(|p| p.exists())
Expand Down Expand Up @@ -227,6 +230,7 @@ pub fn create_transport_type(config: &GlobalConfig) -> TransportType {
socks_address_override,
socks_auth: socks::Authentication::None,
tor_proxy_bypass_addresses,
tor_proxy_bypass_for_outbound_tcp,
})
},
CommsTransport::Socks5 {
Expand All @@ -237,7 +241,7 @@ pub fn create_transport_type(config: &GlobalConfig) -> TransportType {
socks_config: SocksConfig {
proxy_address,
authentication: convert_socks_authentication(auth),
proxy_bypass_addresses: vec![],
proxy_bypass_predicate: Arc::new(FalsePredicate::new()),
},
listener_address,
},
Expand Down
6 changes: 5 additions & 1 deletion base_layer/p2p/src/initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,11 @@ async fn initialize_hidden_service(
.with_socks_authentication(config.socks_auth)
.with_control_server_auth(config.control_server_auth)
.with_control_server_address(config.control_server_addr)
.with_bypass_proxy_addresses(config.tor_proxy_bypass_addresses);
.with_bypass_proxy_addresses(config.tor_proxy_bypass_addresses.into());

if config.tor_proxy_bypass_for_outbound_tcp {
builder = builder.bypass_tor_for_tcp_addresses();
}

if let Some(identity) = config.identity {
builder = builder.with_tor_identity(*identity);
Expand Down
12 changes: 10 additions & 2 deletions base_layer/p2p/src/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,22 @@ pub struct TorConfig {
/// If the underlying SOCKS transport encounters these addresses, bypass the proxy and dial directly using the
/// TcpTransport
pub tor_proxy_bypass_addresses: Vec<Multiaddr>,
/// Use a direct TCP/IP connection if a TCP address is given instead of the tor proxy. This is worse for privacy
/// but can use the full available connection bandwidth
pub tor_proxy_bypass_for_outbound_tcp: bool,
}

impl fmt::Display for TorConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"control_server_addr = {}, control_server_auth = {}, {}, socks_address_override = {:?}",
self.control_server_addr, self.control_server_auth, self.port_mapping, self.socks_address_override
"control_server_addr: {}, control_server_auth: {}, {}, socks_address_override: {:?}, \
tor_proxy_bypass_outbound_tcp_addresses = {:?}",
self.control_server_addr,
self.control_server_auth,
self.port_mapping,
self.socks_address_override,
self.tor_proxy_bypass_for_outbound_tcp
)
}
}
2 changes: 2 additions & 0 deletions base_layer/wallet_ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2424,6 +2424,8 @@ pub unsafe extern "C" fn transport_tor_create(
socks_address_override: None,
socks_auth: authentication,
tor_proxy_bypass_addresses: vec![],
// Prefer performance
tor_proxy_bypass_for_outbound_tcp: true,
};
let transport = TariTransportType::Tor(tor_config);

Expand Down
4 changes: 4 additions & 0 deletions common/config/presets/tari_config_example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ tor_control_auth = "none" # or "password=xxxxxx"
# When these addresses are encountered when dialing another peer, the tor proxy is bypassed and the connection is made
# direcly over TCP. /ip4, /ip6, /dns, /dns4 and /dns6 are supported.
# tor_proxy_bypass_addresses = ["/dns4/my-foo-base-node/tcp/9998"]
# When using the tor transport and set to true, outbound TCP connections bypass the tor proxy. Defaults to false for better privacy
# tor_proxy_bypass_for_outbound_tcp = false;

########################################################################################################################
# #
Expand Down Expand Up @@ -409,6 +411,8 @@ console_wallet_tor_identity_file = "config/console_wallet_tor.json"
# When these addresses are encountered when dialing another peer, the tor proxy is bypassed and the connection is made
# direcly over TCP. /ip4, /ip6, /dns, /dns4 and /dns6 are supported.
# tor_proxy_bypass_addresses = ["/dns4/my-foo-base-node/tcp/9998"]
# When using the tor transport and set to true, outbound TCP connections bypass the tor proxy. Defaults to false for better privacy
# tor_proxy_bypass_for_outbound_tcp = false;

########################################################################################################################
# #
Expand Down
12 changes: 8 additions & 4 deletions common/config/presets/tari_igor_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ tor_control_auth = "none" # or "password=xxxxxx"
# When these addresses are encountered when dialing another peer, the tor proxy is bypassed and the connection is made
# direcly over TCP. /ip4, /ip6, /dns, /dns4 and /dns6 are supported.
# tor_proxy_bypass_addresses = ["/dns4/my-foo-base-node/tcp/9998"]
# When using the tor transport and set to true, outbound TCP connections bypass the tor proxy. Defaults to false for better privacy
# tor_proxy_bypass_for_outbound_tcp = false;

########################################################################################################################
# #
Expand Down Expand Up @@ -281,10 +283,10 @@ data_dir = "igor"
# new nodes can use to introduce themselves to the network.
# peer_seeds = ["public_key1::address1", "public_key2::address2",... ]
peer_seeds = [
"8e7eb81e512f3d6347bf9b1ca9cd67d2c8e29f2836fc5bd608206505cc72af34::/onion3/l4wouomx42nezhzexjdzfh7pcou5l7df24ggmwgekuih7tkv2rsaokqd:18141",
"00b35047a341401bcd336b2a3d564280a72f6dc72ec4c739d30c502acce4e803::/onion3/ojhxd7z6ga7qrvjlr3px66u7eiwasmffnuklscbh5o7g6wrbysj45vid:18141",
"40a9d8573745072534bce7d0ecafe882b1c79570375a69841c08a98dee9ecb5f::/onion3/io37fylc2pupg4cte4siqlsmuszkeythgjsxs2i3prm6jyz2dtophaad:18141",
"126c7ee64f71aca36398b977dd31fbbe9f9dad615df96473fb655bef5709c540::/onion3/6ilmgndocop7ybgmcvivbdsetzr5ggj4hhsivievoa2dx2b43wqlrlid:18141",
"8e7eb81e512f3d6347bf9b1ca9cd67d2c8e29f2836fc5bd608206505cc72af34::/onion3/l4wouomx42nezhzexjdzfh7pcou5l7df24ggmwgekuih7tkv2rsaokqd:18141",
"00b35047a341401bcd336b2a3d564280a72f6dc72ec4c739d30c502acce4e803::/onion3/ojhxd7z6ga7qrvjlr3px66u7eiwasmffnuklscbh5o7g6wrbysj45vid:18141",
"40a9d8573745072534bce7d0ecafe882b1c79570375a69841c08a98dee9ecb5f::/onion3/io37fylc2pupg4cte4siqlsmuszkeythgjsxs2i3prm6jyz2dtophaad:18141",
"126c7ee64f71aca36398b977dd31fbbe9f9dad615df96473fb655bef5709c540::/onion3/6ilmgndocop7ybgmcvivbdsetzr5ggj4hhsivievoa2dx2b43wqlrlid:18141",
]

# This allowlist provides a method to force syncing from any known nodes you may choose, for example if you have a
Expand Down Expand Up @@ -392,6 +394,8 @@ console_wallet_tor_identity_file = "config/console_wallet_tor.json"
# When these addresses are encountered when dialing another peer, the tor proxy is bypassed and the connection is made
# direcly over TCP. /ip4, /ip6, /dns, /dns4 and /dns6 are supported.
# tor_proxy_bypass_addresses = ["/dns4/my-foo-base-node/tcp/9998"]
# When using the tor transport and set to true, outbound TCP connections bypass the tor proxy. Defaults to false for better privacy
# tor_proxy_bypass_for_outbound_tcp = false;

########################################################################################################################
# #
Expand Down
5 changes: 5 additions & 0 deletions common/src/configuration/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -904,13 +904,17 @@ fn network_transport_config(
None => None,
};

let key = config_string(app_str, network, "tor_proxy_bypass_for_outbound_tcp");
let tor_proxy_bypass_for_outbound_tcp = optional(cfg.get_bool(&key))?.unwrap_or(false);

Ok(CommsTransport::TorHiddenService {
control_server_address,
auth,
socks_address_override,
forward_address,
onion_port,
tor_proxy_bypass_addresses,
tor_proxy_bypass_for_outbound_tcp,
})
},
"socks5" => {
Expand Down Expand Up @@ -1051,6 +1055,7 @@ pub enum CommsTransport {
auth: TorControlAuthentication,
onion_port: NonZeroU16,
tor_proxy_bypass_addresses: Vec<Multiaddr>,
tor_proxy_bypass_for_outbound_tcp: bool,
},
/// Use a SOCKS5 proxy transport. This transport recognises any addresses supported by the proxy.
Socks5 {
Expand Down
4 changes: 2 additions & 2 deletions comms/examples/stress/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use tari_comms::{
protocol::{messaging::MessagingProtocolExtension, ProtocolNotification, Protocols},
tor,
tor::{HsFlags, TorIdentity},
transports::{SocksConfig, TcpWithTorTransport},
transports::{predicate::FalsePredicate, SocksConfig, TcpWithTorTransport},
CommsBuilder,
CommsNode,
NodeIdentity,
Expand Down Expand Up @@ -123,7 +123,7 @@ pub async fn create(
.spawn_with_transport(TcpWithTorTransport::with_tor_socks_proxy(SocksConfig {
proxy_address: TOR_SOCKS_ADDR.parse().unwrap(),
authentication: Default::default(),
proxy_bypass_addresses: vec![],
proxy_bypass_predicate: Arc::new(FalsePredicate::new()),
}))
.await
.unwrap()
Expand Down
8 changes: 4 additions & 4 deletions comms/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@
macro_rules! setter {
(
$(#[$outer:meta])*
$func:ident, $name: ident, Option<$type: ty>
$func:ident, $($name: ident).+, Option<$type: ty>
) => {
$(#[$outer])*
pub fn $func(mut self, val: $type) -> Self {
self.$name = Some(val);
self.$($name).+ = Some(val);
self
}
};
(
$(#[$outer:meta])*
$func:ident, $name: ident, $type: ty
$func:ident, $($name: ident).+, $type: ty
) => {
$(#[$outer])*
pub fn $func(mut self, val: $type) -> Self {
self.$name = val;
self.$($name).+ = val;
self
}
};
Expand Down
23 changes: 18 additions & 5 deletions comms/src/tor/hidden_service/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ use super::controller::HiddenServiceControllerError;
use crate::{
multiaddr::Multiaddr,
socks,
tor::{hidden_service::controller::HiddenServiceController, Authentication, PortMapping, TorIdentity},
tor::{
hidden_service::{controller::HiddenServiceController, TorProxyOpts},
Authentication,
PortMapping,
TorIdentity,
},
};
use bitflags::bitflags;
use log::*;
use std::sync::Arc;
use tari_shutdown::{OptionalShutdownSignal, ShutdownSignal};
use thiserror::Error;

Expand Down Expand Up @@ -60,7 +66,7 @@ pub struct HiddenServiceBuilder {
port_mapping: Option<PortMapping>,
socks_addr_override: Option<Multiaddr>,
control_server_addr: Option<Multiaddr>,
proxy_bypass_addresses: Vec<Multiaddr>,
proxy_opts: TorProxyOpts,
control_server_auth: Authentication,
socks_auth: socks::Authentication,
hs_flags: HsFlags,
Expand All @@ -84,8 +90,8 @@ impl HiddenServiceBuilder {
setter!(
/// Configure the underlying SOCKS transport to bypass the proxy and connect directly to these addresses
with_bypass_proxy_addresses,
proxy_bypass_addresses,
Vec<Multiaddr>
proxy_opts.bypass_addresses,
Arc<Vec<Multiaddr>>
);

setter!(
Expand Down Expand Up @@ -117,6 +123,13 @@ impl HiddenServiceBuilder {
HsFlags
);

/// Use a direct TCP/IP connection if a TCP address is given instead of the tor proxy. This is worse for privacy
/// but can use the full available connection bandwidth
pub fn bypass_tor_for_tcp_addresses(mut self) -> Self {
self.proxy_opts.bypass_for_tcpip = true;
self
}

/// The address of the SOCKS5 server. If an address is None, the hidden service builder will use the SOCKS
/// listener address as given by the tor control port.
pub fn with_shutdown_signal(mut self, shutdown_signal: ShutdownSignal) -> Self {
Expand Down Expand Up @@ -164,7 +177,7 @@ impl HiddenServiceBuilder {
self.socks_auth,
self.identity,
self.hs_flags,
self.proxy_bypass_addresses,
self.proxy_opts,
self.shutdown_signal,
);

Expand Down
11 changes: 6 additions & 5 deletions comms/src/tor/hidden_service/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::{
commands::{AddOnionFlag, AddOnionResponse},
TorControlEvent,
},
hidden_service::TorProxyOpts,
Authentication,
HiddenService,
HsFlags,
Expand All @@ -42,7 +43,7 @@ use crate::{
};
use futures::{future, future::Either, pin_mut, StreamExt};
use log::*;
use std::{net::SocketAddr, time::Duration};
use std::{net::SocketAddr, sync::Arc, time::Duration};
use tari_shutdown::OptionalShutdownSignal;
use thiserror::Error;
use tokio::{sync::broadcast, time};
Expand Down Expand Up @@ -75,7 +76,7 @@ pub struct HiddenServiceController {
identity: Option<TorIdentity>,
hs_flags: HsFlags,
is_authenticated: bool,
proxy_bypass_addresses: Vec<Multiaddr>,
proxy_opts: TorProxyOpts,
shutdown_signal: OptionalShutdownSignal,
}

Expand All @@ -89,7 +90,7 @@ impl HiddenServiceController {
socks_auth: socks::Authentication,
identity: Option<TorIdentity>,
hs_flags: HsFlags,
proxy_bypass_addresses: Vec<Multiaddr>,
proxy_opts: TorProxyOpts,
shutdown_signal: OptionalShutdownSignal,
) -> Self {
Self {
Expand All @@ -102,7 +103,7 @@ impl HiddenServiceController {
hs_flags,
identity,
is_authenticated: false,
proxy_bypass_addresses,
proxy_opts,
shutdown_signal,
}
}
Expand All @@ -119,7 +120,7 @@ impl HiddenServiceController {
Ok(SocksTransport::new(SocksConfig {
proxy_address: socks_addr,
authentication: self.socks_auth.clone(),
proxy_bypass_addresses: self.proxy_bypass_addresses.clone(),
proxy_bypass_predicate: Arc::new(self.proxy_opts.to_bypass_predicate()),
}))
}

Expand Down
6 changes: 5 additions & 1 deletion comms/src/tor/hidden_service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ mod builder;
pub use builder::{HiddenServiceBuilder, HiddenServiceBuilderError, HsFlags};

mod controller;
pub use controller::{HiddenServiceController, HiddenServiceControllerError};

mod proxy_opts;
pub use proxy_opts::TorProxyOpts;

use crate::{
multiaddr::Multiaddr,
tor::{PrivateKey, TorClientError},
};
pub use controller::{HiddenServiceController, HiddenServiceControllerError};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use tari_shutdown::OptionalShutdownSignal;
Expand Down
Loading

0 comments on commit 6a5982e

Please sign in to comment.