mirror of
https://github.com/RetroShare/libretroshare.git
synced 2026-09-14 11:05:45 +05:00
Merge 38dfb43dc5 into 2f093fd7b3
This commit is contained in:
commit
b0d1fd1c5c
@ -235,6 +235,8 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
|
||||
std::string locationName;
|
||||
std::string pgpName;
|
||||
std::string password;
|
||||
bool makeHidden = false;
|
||||
bool makeAutoTor = false;
|
||||
|
||||
// JSON API only
|
||||
std::string apiUser;
|
||||
@ -249,6 +251,8 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
|
||||
RS_SERIAL_PROCESS(locationName);
|
||||
RS_SERIAL_PROCESS(pgpName);
|
||||
RS_SERIAL_PROCESS(password);
|
||||
RS_SERIAL_PROCESS(makeHidden);
|
||||
RS_SERIAL_PROCESS(makeAutoTor);
|
||||
|
||||
// JSON API only
|
||||
RS_SERIAL_PROCESS(apiUser);
|
||||
@ -265,7 +269,8 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
|
||||
|
||||
if(!retval) // call retroshare C++ API
|
||||
retval = rsLoginHelper->createLocationV2(
|
||||
locationId, pgpId, locationName, pgpName, password );
|
||||
locationId, pgpId, locationName, pgpName, password,
|
||||
makeHidden, makeAutoTor );
|
||||
|
||||
if(!retval) retval = authorizeUser(apiUser, apiPass);
|
||||
|
||||
|
||||
@ -498,7 +498,9 @@ public:
|
||||
RsPgpId& pgpId,
|
||||
const std::string& locationName,
|
||||
const std::string& pgpName,
|
||||
const std::string& password
|
||||
const std::string& password,
|
||||
bool makeHidden = false,
|
||||
bool makeAutoTor = false
|
||||
/* JSON API only
|
||||
* const std::string& apiUser
|
||||
* const std::string& apiPass */ );
|
||||
|
||||
@ -128,6 +128,30 @@ 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.
|
||||
*
|
||||
* @param[in] controlAddress Tor control listener address, usually
|
||||
* `127.0.0.1`
|
||||
* @param[in] controlPort Tor control listener TCP port
|
||||
* @param[in] controlPassword Tor control password, or an empty string for
|
||||
* null/cookie authentication
|
||||
* @param[in] socksAddress Tor SOCKS listener address, usually `127.0.0.1`
|
||||
* @param[in] socksPort Tor SOCKS listener TCP port
|
||||
* @return true if the external Tor configuration was accepted
|
||||
*
|
||||
* @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);
|
||||
|
||||
@ -162,12 +186,14 @@ public:
|
||||
/*!
|
||||
* \brief getHiddenServiceInfo
|
||||
* Gets information about the hidden service setup by RS to run.
|
||||
* \param service_id
|
||||
* \param service_onion_address
|
||||
* \param service_port
|
||||
* \param service_target_address
|
||||
* \param target_port
|
||||
* \return
|
||||
* \param[out] service_id Tor service identifier without the `.onion` suffix
|
||||
* \param[out] service_onion_address Complete generated onion hostname
|
||||
* \param[out] service_port Public onion-service port
|
||||
* \param[out] service_target_address Local address receiving Tor traffic
|
||||
* \param[out] target_port Local port receiving Tor traffic
|
||||
* \return true when an AutoTor hidden service is available
|
||||
*
|
||||
* @jsonapi{development}
|
||||
*/
|
||||
static bool getHiddenServiceInfo(std::string& service_id,
|
||||
std::string& service_onion_address,
|
||||
|
||||
@ -2162,6 +2162,15 @@ bool RsInit::startAutoTor()
|
||||
std::string service_id;
|
||||
RsTor::setupHiddenService();
|
||||
|
||||
// If the connection to the Tor control port cannot be established at all
|
||||
// (e.g. an external Tor that is not running, or a wrong control port),
|
||||
// fail after a while instead of waiting forever. Once the control link
|
||||
// has been seen up, wait indefinitely for Tor to bootstrap, as before.
|
||||
|
||||
const time_t control_connect_timeout = 30; // seconds
|
||||
time_t start_time = time(nullptr);
|
||||
bool control_link_seen = false;
|
||||
|
||||
while(RsTor::torStatus() != RsTorStatus::READY && RsTor::getHiddenServiceStatus(service_id) != RsTorHiddenServiceStatus::ONLINE) // runs until some status is reached: either tor works, or it fails.
|
||||
{
|
||||
rstime::rs_usleep(0.5*1000*1000) ;
|
||||
@ -2174,6 +2183,24 @@ bool RsInit::startAutoTor()
|
||||
std::cerr << "(EE) Tor hidden service cannot be started: " << error_msg << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!control_link_seen)
|
||||
switch(RsTor::torConnectivityStatus())
|
||||
{
|
||||
case RsTorConnectivityStatus::SOCKET_CONNECTED:
|
||||
case RsTorConnectivityStatus::AUTHENTICATING:
|
||||
case RsTorConnectivityStatus::AUTHENTICATED:
|
||||
case RsTorConnectivityStatus::HIDDEN_SERVICE_READY:
|
||||
control_link_seen = true;
|
||||
break;
|
||||
default:
|
||||
if(time(nullptr) > start_time + control_connect_timeout)
|
||||
{
|
||||
std::cerr << "(EE) Cannot establish a connection to the Tor control port. Giving up." << std::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// process Qt event loop to deal with messages of online/offline info
|
||||
// QCoreApplication::processEvents();
|
||||
}
|
||||
@ -2236,7 +2263,8 @@ void RsLoginHelper::getLocations(std::vector<RsLoginHelper::Location>& store)
|
||||
std::error_condition RsLoginHelper::createLocationV2(
|
||||
RsPeerId& locationId, RsPgpId& pgpId,
|
||||
const std::string& locationName, const std::string& pgpName,
|
||||
const std::string& password )
|
||||
const std::string& password,
|
||||
bool makeHidden, bool makeAutoTor )
|
||||
{
|
||||
if(isLoggedIn()) return RsInitErrorNum::ALREADY_LOGGED_IN;
|
||||
if(locationName.empty()) return RsInitErrorNum::INVALID_LOCATION_NAME;
|
||||
@ -2256,7 +2284,7 @@ std::error_condition RsLoginHelper::createLocationV2(
|
||||
RsLoginHandler::cachePgpPassphrase(password);
|
||||
|
||||
bool ret = RsAccounts::createNewAccount(
|
||||
pgpId, "", locationName, "", false, false, sslPassword,
|
||||
pgpId, "", locationName, "", makeHidden, makeAutoTor, sslPassword,
|
||||
locationId, errorMessage );
|
||||
if(!ret)
|
||||
{
|
||||
|
||||
@ -211,6 +211,8 @@ void TorControl::connect(const std::string &address, uint16_t port)
|
||||
setStatus(SocketConnected);
|
||||
setTorStatus(TorOffline); // connected and running, but not yet ready
|
||||
}
|
||||
else
|
||||
setStatus(NotConnected); // so that the owner can try connecting again
|
||||
}
|
||||
|
||||
void TorControl::reconnect()
|
||||
@ -221,7 +223,14 @@ void TorControl::reconnect()
|
||||
return;
|
||||
|
||||
setStatus(Connecting);
|
||||
mSocket->connectToHost(mTorAddress, mControlPort);
|
||||
|
||||
if(mSocket->connectToHost(mTorAddress, mControlPort))
|
||||
{
|
||||
setStatus(SocketConnected);
|
||||
setTorStatus(TorOffline); // connected and running, but not yet ready
|
||||
}
|
||||
else
|
||||
setStatus(NotConnected); // so that the owner can try connecting again
|
||||
}
|
||||
|
||||
void TorControl::authenticateReply(TorControlCommand *sender)
|
||||
|
||||
@ -38,12 +38,10 @@
|
||||
#include "util/rsdir.h"
|
||||
#include "retroshare/rsinit.h"
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#if !defined(_WIN32) && !defined(__MINGW32__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#include "TorManager.h"
|
||||
#include "TorProcess.h"
|
||||
@ -74,6 +72,13 @@ public:
|
||||
bool configNeeded;
|
||||
bool mVerbose;
|
||||
std::string userProvidedTorExecutablePath;
|
||||
bool useExternalTor;
|
||||
std::string externalControlAddress;
|
||||
uint16_t externalControlPort;
|
||||
ByteArray externalControlPassword;
|
||||
std::string externalSocksAddress;
|
||||
uint16_t externalSocksPort;
|
||||
time_t lastControlConnectAttempt;
|
||||
|
||||
HiddenService *hiddenService ;
|
||||
|
||||
@ -123,6 +128,10 @@ TorManagerPrivate::TorManagerPrivate(TorManager *parent)
|
||||
, control(new TorControl())
|
||||
, configNeeded(false)
|
||||
, mVerbose(false)
|
||||
, useExternalTor(false)
|
||||
, externalControlPort(0)
|
||||
, externalSocksPort(0)
|
||||
, lastControlConnectAttempt(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<std::string>& 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,28 @@ 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());
|
||||
{
|
||||
// The connection attempt is synchronous and threadTick() runs every
|
||||
// 50ms, so throttle retries when the control port is unreachable
|
||||
// (e.g. an external Tor that is not started yet).
|
||||
|
||||
time_t now = time(nullptr);
|
||||
|
||||
if(now < d->lastControlConnectAttempt + 2)
|
||||
break;
|
||||
d->lastControlConnectAttempt = now;
|
||||
|
||||
if(d->useExternalTor)
|
||||
{
|
||||
RsInfo() << "Connecting to external tor at " << d->externalControlAddress << ":" << d->externalControlPort << "..." ;
|
||||
d->control->connect(d->externalControlAddress,d->externalControlPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
RsInfo() << "Connecting to tor process at " << d->process->controlHost() << ":" << d->process->controlPort() << "..." ;
|
||||
d->control->connect(d->process->controlHost(),d->process->controlPort());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TorControl::SocketConnected:
|
||||
@ -551,7 +581,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 +619,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 +833,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 +887,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)
|
||||
@ -955,17 +1008,14 @@ void RsTor::setHiddenServiceDirectory(const std::string& dir)
|
||||
instance()->setHiddenServiceDirectory(dir);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
TorManager *RsTor::instance()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
assert(pthread_main_np() != 0); // On macOS, ensure we are on the main thread
|
||||
#elif defined(__linux__)
|
||||
assert(getpid() == syscall(SYS_gettid)); // On Linux, ensure we are on the main thread
|
||||
#endif
|
||||
// RsTor methods are exposed through the JSON API, so this can be reached
|
||||
// from any thread. Protect the lazy initialisation, which the former
|
||||
// main-thread asserts used to guard.
|
||||
|
||||
static std::mutex instanceMutex;
|
||||
std::unique_lock<std::mutex> lock(instanceMutex);
|
||||
|
||||
if(rsTorMgr == nullptr)
|
||||
rsTorMgr = new TorManager;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user