diff --git a/src/retroshare/rstor.h b/src/retroshare/rstor.h index fe96348a6..37704d640 100644 --- a/src/retroshare/rstor.h +++ b/src/retroshare/rstor.h @@ -128,6 +128,21 @@ public: */ static RsTorConnectivityStatus torConnectivityStatus() ; + /** + * Configure TorManager to attach to an already running Tor instance. + * This must be called before start(). The external process is never + * stopped or taken over by RetroShare. + * + * This endpoint is available before account login because the Tor + * connection must be configured before hidden-node initialization starts. + * + * @jsonapi{development,unauthenticated} + */ + static bool setExternalTorConnection( + const std::string& controlAddress, uint16_t controlPort, + const std::string& controlPassword, + const std::string& socksAddress, uint16_t socksPort ); + static void setTorDataDirectory(const std::string& dir); static void setHiddenServiceDirectory(const std::string& dir); diff --git a/src/tor/TorManager.cpp b/src/tor/TorManager.cpp index f4bb6d27e..44a31e341 100644 --- a/src/tor/TorManager.cpp +++ b/src/tor/TorManager.cpp @@ -74,6 +74,12 @@ public: bool configNeeded; bool mVerbose; std::string userProvidedTorExecutablePath; + bool useExternalTor; + std::string externalControlAddress; + uint16_t externalControlPort; + ByteArray externalControlPassword; + std::string externalSocksAddress; + uint16_t externalSocksPort; HiddenService *hiddenService ; @@ -123,6 +129,9 @@ TorManagerPrivate::TorManagerPrivate(TorManager *parent) , control(new TorControl()) , configNeeded(false) , mVerbose(false) + , useExternalTor(false) + , externalControlPort(0) + , externalSocksPort(0) , hiddenService(NULL) { control->set_statusChanged_callback([this](int new_status,int /*old_status*/) { controlStatusChanged(new_status); }); @@ -371,6 +380,32 @@ std::string TorManager::torExecutablePath() const return (d==nullptr)?(std::string()):(d->torExecutablePath()); } +bool TorManager::setExternalTorConnection( + const std::string& controlAddress, uint16_t controlPort, + const std::string& controlPassword, + const std::string& socksAddress, uint16_t socksPort ) +{ + if(isRunning()) + { + d->setError("Cannot change Tor connection while TorManager is running."); + return false; + } + if(controlAddress.empty() || controlPort == 0 || + socksAddress.empty() || socksPort == 0) + { + d->setError("External Tor control and SOCKS endpoints must be valid."); + return false; + } + + d->useExternalTor = true; + d->externalControlAddress = controlAddress; + d->externalControlPort = controlPort; + d->externalControlPassword = ByteArray(controlPassword); + d->externalSocksAddress = socksAddress; + d->externalSocksPort = socksPort; + return true; +} + const std::list& TorManager::logMessages() const { return d->logMessages; @@ -394,43 +429,14 @@ bool TorManager::startTorManager() //emit errorChanged(); // not needed because there's no error to handle } -#ifdef TODO - SettingsObject settings("tor"); - - // If a control port is defined by config or environment, skip launching tor - if (!settings.read("controlPort").isUndefined() || - !qEnvironmentVariableIsEmpty("TOR_CONTROL_PORT")) + if(d->useExternalTor) { - QHostAddress address(settings.read("controlAddress").toString()); - quint16 port = (quint16)settings.read("controlPort").toInt(); - QByteArray password = settings.read("controlPassword").toString().toLatin1(); - - if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_HOST")) - address = QHostAddress(qgetenv("TOR_CONTROL_HOST")); - - if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_PORT")) { - bool ok = false; - port = qgetenv("TOR_CONTROL_PORT").toUShort(&ok); - if (!ok) - port = 0; - } - - if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_PASSWD")) - password = qgetenv("TOR_CONTROL_PASSWD"); - - if (!port) { - d->setError("Invalid control port settings from environment or configuration"); - return false; - } - - if (address.isNull()) - address = QHostAddress::LocalHost; - - d->control->setAuthPassword(password); - d->control->connect(address, port); + RsInfo() << "Connecting to external Tor control port at " + << d->externalControlAddress << ":" << d->externalControlPort; + d->control->setAuthPassword(d->externalControlPassword); + d->control->connect(d->externalControlAddress, d->externalControlPort); } else -#endif { // Launch a bundled Tor instance std::string executable = d->torExecutablePath(); @@ -503,7 +509,8 @@ bool TorManager::startTorManager() void TorManager::run() { - d->process->start(); + if(d->process) + d->process->start(); while(!shouldStop()) { @@ -512,7 +519,8 @@ void TorManager::run() } d->control->shutdownSync(); - d->process->stop(); + if(d->process) + d->process->stop(); if(rsEvents) { @@ -526,10 +534,12 @@ void TorManager::threadTick() { static bool authenticated_msg_already_given = false; - d->process->tick(); - - if(d->process->state() != TorProcess::Ready) - return; + if(d->process) + { + d->process->tick(); + if(d->process->state() != TorProcess::Ready) + return; + } switch(d->control->status()) { @@ -538,8 +548,10 @@ void TorManager::threadTick() break; case TorControl::NotConnected: - RsInfo() << "Connecting to tor process at " << d->process->controlHost() << ":" << d->process->controlPort() << "..." ; - d->control->connect(d->process->controlHost(),d->process->controlPort()); + if(d->useExternalTor) + d->control->connect(d->externalControlAddress,d->externalControlPort); + else + d->control->connect(d->process->controlHost(),d->process->controlPort()); break; case TorControl::SocketConnected: @@ -551,7 +563,8 @@ void TorManager::threadTick() setupHiddenService(); } - d->control->setAuthPassword(d->process->controlPassword()); + d->control->setAuthPassword(d->useExternalTor + ? d->externalControlPassword : d->process->controlPassword()); d->control->authenticate(); RsInfo() << "Authenticating..." ; break; @@ -588,6 +601,12 @@ bool TorManager::getProxyServerInfo(std::string& proxy_server_adress,uint16_t& p proxy_server_adress = control()->socksAddress(); proxy_server_port = control()->socksPort(); + if(d->useExternalTor && (proxy_server_adress.empty() || proxy_server_port == 0)) + { + proxy_server_adress = d->externalSocksAddress; + proxy_server_port = d->externalSocksPort; + } + return proxy_server_port > 1023 ; } @@ -796,7 +815,17 @@ void TorManagerPrivate::setError(const std::string &message) bool RsTor::isTorAvailable() { - return !instance()->d->torExecutablePath().empty(); + return instance()->d->useExternalTor || !instance()->d->torExecutablePath().empty(); +} + +bool RsTor::setExternalTorConnection( + const std::string& controlAddress, uint16_t controlPort, + const std::string& controlPassword, + const std::string& socksAddress, uint16_t socksPort ) +{ + return instance()->setExternalTorConnection( + controlAddress, controlPort, controlPassword, + socksAddress, socksPort ); } bool RsTor::getHiddenServiceInfo(std::string& service_id, @@ -840,11 +869,17 @@ void RsTor::setTorExecutablePath(const std::string& e) std::string RsTor::socksAddress() { - return instance()->control()->socksAddress(); + std::string address; + uint16_t port = 0; + instance()->getProxyServerInfo(address, port); + return address; } uint16_t RsTor::socksPort() { - return instance()->control()->socksPort(); + std::string address; + uint16_t port = 0; + instance()->getProxyServerInfo(address, port); + return port; } static RsTorStatus torStatus(Tor::TorControl::TorStatus t) diff --git a/src/tor/TorManager.h b/src/tor/TorManager.h index a37d833c6..6d173fa4c 100644 --- a/src/tor/TorManager.h +++ b/src/tor/TorManager.h @@ -62,6 +62,11 @@ public: std::string torExecutablePath() const; void setTorExecutablePath(const std::string& tor_exe_full_path) ; + bool setExternalTorConnection( + const std::string& controlAddress, uint16_t controlPort, + const std::string& controlPassword, + const std::string& socksAddress, uint16_t socksPort ); + std::string hiddenServiceDirectory() const; void setHiddenServiceDirectory(const std::string &path);