Skip to content

Commit

Permalink
fix tor hint in base node
Browse files Browse the repository at this point in the history
  • Loading branch information
sdbondi committed Aug 10, 2022
1 parent 5a5a8f4 commit 058dcdc
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 38 deletions.
3 changes: 2 additions & 1 deletion applications/tari_base_node/src/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ where B: BlockchainBackend + 'static
let comms = Self::setup_rpc_services(comms, &handles, self.db.into(), &p2p_config);
let comms = initialization::spawn_comms_using_transport(comms, p2p_config.transport.clone())
.await
.map_err(|e| ExitError::new(ExitCode::NetworkError, e))?;
.map_err(|e| e.to_exit_error())?;

// Save final node identity after comms has initialized. This is required because the public_address can be
// changed by comms during initialization when using tor.
match p2p_config.transport.transport_type {
Expand Down
8 changes: 2 additions & 6 deletions applications/tari_console_wallet/src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ use tari_common::exit_codes::{ExitCode, ExitError};
use tari_comms::{
multiaddr::Multiaddr,
peer_manager::{Peer, PeerFeatures},
tor::HiddenServiceControllerError,
types::CommsPublicKey,
NodeIdentity,
};
use tari_core::transactions::CryptoFactories;
use tari_crypto::keys::PublicKey;
use tari_key_manager::{cipher_seed::CipherSeed, mnemonic::MnemonicLanguage};
use tari_p2p::{initialization::CommsInitializationError, peer_seeds::SeedPeer, TransportType};
use tari_p2p::{peer_seeds::SeedPeer, TransportType};
use tari_shutdown::ShutdownSignal;
use tari_utilities::SafePassword;
use tari_wallet::{
Expand Down Expand Up @@ -319,10 +318,7 @@ pub async fn init_wallet(
)
.await
.map_err(|e| match e {
WalletError::CommsInitializationError(CommsInitializationError::HiddenServiceControllerError(
HiddenServiceControllerError::TorControlPortOffline,
)) => ExitError::new(ExitCode::TorOffline, e),
WalletError::CommsInitializationError(e) => ExitError::new(ExitCode::WalletError, e),
WalletError::CommsInitializationError(cie) => cie.to_exit_error(),
e => ExitError::new(
ExitCode::WalletError,
&format!("Error creating Wallet Container: {}", e),
Expand Down
25 changes: 24 additions & 1 deletion base_layer/p2p/src/initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ use futures::future;
use lmdb_zero::open;
use log::*;
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use tari_common::configuration::Network;
use tari_common::{
configuration::Network,
exit_codes::{ExitCode, ExitError},
};
use tari_comms::{
backoff::ConstantBackoff,
peer_manager::{NodeIdentity, Peer, PeerFeatures, PeerFlags, PeerManagerError},
Expand Down Expand Up @@ -100,6 +103,26 @@ pub enum CommsInitializationError {
IoError(#[from] std::io::Error),
}

impl CommsInitializationError {
pub fn to_exit_error(&self) -> ExitError {
#[allow(clippy::enum_glob_use)]
use HiddenServiceControllerError::*;
match self {
CommsInitializationError::HiddenServiceControllerError(TorControlPortOffline) => {
ExitError::new(ExitCode::TorOffline, self)
},
CommsInitializationError::HiddenServiceControllerError(HashedPasswordAuthAutoNotSupported) => {
ExitError::new(ExitCode::TorAuthConfiguration, self)
},
CommsInitializationError::HiddenServiceControllerError(FailedToLoadCookieFile(_)) => {
ExitError::new(ExitCode::TorAuthUnreadableCookie, self)
},

_ => ExitError::new(ExitCode::NetworkError, self),
}
}
}

/// Initialize Tari Comms configured for tests
pub async fn initialize_local_test_comms<P: AsRef<Path>>(
node_identity: Arc<NodeIdentity>,
Expand Down
50 changes: 30 additions & 20 deletions base_layer/p2p/src/tor_authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ fn parse_key_value(s: &str, split_chr: char) -> (String, Option<&str>) {
(
parts
.next()
.map(|s| s.trim())
.expect("splitn always emits at least one part")
.to_lowercase(),
parts.next(),
parts.next().map(|s| s.trim()),
)
}

Expand Down Expand Up @@ -143,36 +144,45 @@ mod tests {
use super::*;

#[test]
fn tor_parser_test() {
let auth = TorControlAuthentication::from_str("none");
assert_eq!(auth, Ok(TorControlAuthentication::None));
fn tor_parser_valid_case() {
let auth = TorControlAuthentication::from_str("auto").unwrap();
assert_eq!(auth, TorControlAuthentication::Auto);

let auth = TorControlAuthentication::from_str("password=");
assert_eq!(auth, Ok(TorControlAuthentication::Password("".into())));
let auth = TorControlAuthentication::from_str("none").unwrap();
assert_eq!(auth, TorControlAuthentication::None);

let auth = TorControlAuthentication::from_str("password=123");
assert_eq!(auth, Ok(TorControlAuthentication::Password("123".into())));
let auth = TorControlAuthentication::from_str("password=").unwrap();
assert_eq!(auth, TorControlAuthentication::Password("".into()));

let auth = TorControlAuthentication::from_str("cookie=");
assert_eq!(auth, Ok(TorControlAuthentication::hex("".into())));
let auth = TorControlAuthentication::from_str("password = 123 ").unwrap();
assert_eq!(auth, TorControlAuthentication::Password("123".into()));

let auth = TorControlAuthentication::from_str("cookie=8b6f");
assert_eq!(auth, Ok(TorControlAuthentication::hex("8b6f".into())));
let auth = TorControlAuthentication::from_str("password=123").unwrap();
assert_eq!(auth, TorControlAuthentication::Password("123".into()));

let auth = TorControlAuthentication::from_str("cookie=@");
let auth = TorControlAuthentication::from_str("cookie=").unwrap();
assert_eq!(auth, TorControlAuthentication::hex("".into()));

let auth = TorControlAuthentication::from_str("cookie=8b6f").unwrap();
assert_eq!(auth, TorControlAuthentication::hex("8b6f".into()));

let auth = TorControlAuthentication::from_str("cookie=@").unwrap();
assert_eq!(
auth,
Ok(TorControlAuthentication::Cookie(TorCookie::FilePath(
DEFAULT_TOR_COOKIE_PATH.into()
)))
TorControlAuthentication::Cookie(TorCookie::FilePath(DEFAULT_TOR_COOKIE_PATH.into()))
);

let auth = TorControlAuthentication::from_str("cookie=@/path/to/file");
let auth = TorControlAuthentication::from_str("cookie=@/path/to/file").unwrap();
assert_eq!(
auth,
Ok(TorControlAuthentication::Cookie(TorCookie::FilePath(
"/path/to/file".into()
)))
TorControlAuthentication::Cookie(TorCookie::FilePath("/path/to/file".into()))
);
}

#[test]
fn tor_parser_invalid_case() {
TorControlAuthentication::from_str("").unwrap_err();
TorControlAuthentication::from_str("not_valid").unwrap_err();
TorControlAuthentication::from_str("cookie abcd").unwrap_err();
}
}
28 changes: 26 additions & 2 deletions common/src/exit_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,36 @@ impl From<anyhow::Error> for ExitError {

const TOR_HINT: &str = r#"Unable to connect to the Tor control port.
Please check that you have the Tor proxy running and that access to the Tor control port is turned on.
Please check that you have the Tor proxy running and that access to the Tor control port is turned on in your `torrc`.
If you are unsure of what to do, use the following command to start the Tor proxy:
tor --allow-missing-torrc --ignore-missing-torrc --clientonly 1 --socksport 9050 --controlport 127.0.0.1:9051 --log "warn stdout" --clientuseipv6 1"#;

const TOR_CONFIG_AUTH_HINT: &str = r#"Unable to authenticate to the Tor control port.
Please check the Tor control port configuration in your torrc and update your Tari configuration to match the configured authentication method.
If you are unsure of what to do, use the following command to start the Tor proxy:
tor --allow-missing-torrc --ignore-missing-torrc --clientonly 1 --socksport 9050 --controlport 127.0.0.1:9051 --log "warn stdout" --clientuseipv6 1 --cookieauthentication 1"#;

const TOR_AUTH_UNREADABLE_COOKIE_HINT: &str = r#"Unable to read tor control port cookie file.
The current user must have permissions to read the tor control port cookie file.
On a linux system this means adding your current user to the `debian-tor` group with the following command (requires root):
sudo usermod -aG debian-tor $USER
If you are unsure of what to do, use the following command to start the Tor proxy:
tor --allow-missing-torrc --ignore-missing-torrc --clientonly 1 --socksport 9050 --controlport 127.0.0.1:9051 --log "warn stdout" --clientuseipv6 1 --cookieauthentication 1"#;

impl ExitCode {
pub fn hint(&self) -> Option<&str> {
use ExitCode::TorOffline;
#[allow(clippy::enum_glob_use)]
use ExitCode::*;
match self {
TorOffline => Some(TOR_HINT),
TorAuthConfiguration => Some(TOR_CONFIG_AUTH_HINT),
TorAuthUnreadableCookie => Some(TOR_AUTH_UNREADABLE_COOKIE_HINT),
_ => None,
}
}
Expand Down Expand Up @@ -96,6 +116,10 @@ pub enum ExitCode {
DigitalAssetError = 116,
#[error("Unable to create or load an identity file")]
IdentityError = 117,
#[error("Tor control port authentication is not configured correctly")]
TorAuthConfiguration = 118,
#[error("Unable to read Tor cookie file")]
TorAuthUnreadableCookie = 119,
}

impl From<super::ConfigError> for ExitError {
Expand Down
24 changes: 16 additions & 8 deletions comms/core/src/tor/hidden_service/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@ pub enum HiddenServiceControllerError {
FailedToParseSocksAddress,
#[error("TorClientError: {0}")]
TorClientError(#[from] TorClientError),
#[error("Unable to connect to the Tor control port")]
#[error(
"Unable to connect to the Tor control port. Make sure tor is running and 'ControlPort 9051' is in your torrc."
)]
TorControlPortOffline,
#[error("The given tor service id is not a valid detached service id")]
InvalidDetachedServiceId,
#[error("The shutdown signal interrupted the HiddenServiceController")]
ShutdownSignalInterrupt,
#[error("Tor is configured to used a hashed password. Please provide this to the configuration.")]
#[error("Tor is configured to use a hashed password for control port auth. Please add the.")]
HashedPasswordAuthAutoNotSupported,
#[error("Tor is configured with an unsupported authentication method '{0}'.")]
UnrecognizedAuthenticationMethod(String),
Expand Down Expand Up @@ -189,7 +191,6 @@ impl HiddenServiceController {
if !self.is_authenticated {
self.connect().await?;
self.authenticate().await?;
self.is_authenticated = true;
}
Ok(())
}
Expand Down Expand Up @@ -260,6 +261,12 @@ impl HiddenServiceController {
async fn detect_authentication(&mut self) -> Result<Authentication, HiddenServiceControllerError> {
let client = self.client_mut()?;
let info = client.protocol_info().await?;
info!(
target: LOG_TARGET,
"Detected tor v{} configured with control port auth: {}",
info.tor_version,
info.auth_methods.methods.join(", ")
);
if info.auth_methods.methods.iter().any(|s| s == "COOKIE") {
let cookie_path = info.auth_methods.cookie_file.ok_or_else(|| {
TorClientError::ServerInvalidResponse(
Expand Down Expand Up @@ -287,12 +294,13 @@ impl HiddenServiceController {
}

async fn authenticate(&mut self) -> Result<(), HiddenServiceControllerError> {
let auth = if let Authentication::Auto = &self.control_server_auth {
self.detect_authentication().await?
} else {
self.control_server_auth.clone()
};
if let Authentication::Auto = &self.control_server_auth {
self.control_server_auth = self.detect_authentication().await?;
}

let auth = self.control_server_auth.clone();
self.client_mut()?.authenticate(&auth).await?;
self.is_authenticated = true;
Ok(())
}

Expand Down

0 comments on commit 058dcdc

Please sign in to comment.