Explicitly get circuit established status when Tor control is ready in case a circuit has already been established

This commit is contained in:
Anthony Tseng
2021-03-03 22:57:15 -08:00
parent 52eb66234f
commit e4179f3ede
5 changed files with 203 additions and 0 deletions
+55
View File
@@ -40,6 +40,9 @@ constexpr char kGetVersionCmd[] = "GETINFO version";
constexpr char kGetVersionReply[] = "version=";
constexpr char kGetSOCKSListenersCmd[] = "GETINFO net/listeners/socks";
constexpr char kGetSOCKSListenersReply[] = "net/listeners/socks=";
constexpr char kGetCircuitEstablishedCmd[] =
"GETINFO status/circuit-established";
constexpr char kGetCircuitEstablishedReply[] = "status/circuit-established=";
static std::string escapify(const char* buf, int len) {
std::ostringstream s;
@@ -461,6 +464,58 @@ void TorControl::GetSOCKSListenersDone(
std::move(callback).Run(false, *listeners);
}
void TorControl::GetCircuitEstablished(
base::OnceCallback<void(bool error, bool established)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(owner_sequence_checker_);
std::unique_ptr<std::string> established = std::make_unique<std::string>();
std::string* established_p = established.get();
io_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&TorControl::DoCmd, weak_ptr_factory_.GetWeakPtr(),
kGetCircuitEstablishedCmd,
base::BindRepeating(&TorControl::GetCircuitEstablishedLine,
weak_ptr_factory_.GetWeakPtr(), established_p),
base::BindOnce(&TorControl::GetCircuitEstablishedDone,
weak_ptr_factory_.GetWeakPtr(), std::move(established),
std::move(callback))));
}
void TorControl::GetCircuitEstablishedLine(std::string* established,
const std::string& status,
const std::string& reply) {
DCHECK_CALLED_ON_VALID_SEQUENCE(io_sequence_checker_);
if (status != "250" ||
!base::StartsWith(reply, kGetCircuitEstablishedReply,
base::CompareCase::SENSITIVE) ||
!established->empty()) {
VLOG(0) << "tor: unexpected " << kGetCircuitEstablishedCmd << " reply";
return;
}
*established = reply.substr(strlen(kGetCircuitEstablishedReply));
}
void TorControl::GetCircuitEstablishedDone(
std::unique_ptr<std::string> established,
base::OnceCallback<void(bool error, bool established)> callback,
bool error,
const std::string& status,
const std::string& reply) {
DCHECK_CALLED_ON_VALID_SEQUENCE(io_sequence_checker_);
bool result;
if (*established == "1")
result = true;
else if (*established == "0")
result = false;
else
error = true;
if (error || status != "250" || reply != "OK" || established->empty()) {
std::move(callback).Run(true, false);
return;
}
std::move(callback).Run(false, result);
}
///////////////////////////////////////////////////////////////////////////////
// Writing state machine
+12
View File
@@ -90,12 +90,15 @@ class TorControl {
base::OnceCallback<void(bool error,
const std::vector<std::string>& listeners)>
callback);
void GetCircuitEstablished(
base::OnceCallback<void(bool error, bool established)> callback);
protected:
friend class TorControlTest;
FRIEND_TEST_ALL_PREFIXES(TorControlTest, ParseQuoted);
FRIEND_TEST_ALL_PREFIXES(TorControlTest, ParseKV);
FRIEND_TEST_ALL_PREFIXES(TorControlTest, ReadLine);
FRIEND_TEST_ALL_PREFIXES(TorControlTest, GetCircuitEstablishedDone);
static bool ParseKV(const std::string& string,
std::string* key,
@@ -137,6 +140,15 @@ class TorControl {
bool error,
const std::string& status,
const std::string& reply);
void GetCircuitEstablishedLine(std::string* established,
const std::string& status,
const std::string& reply);
void GetCircuitEstablishedDone(
std::unique_ptr<std::string> established,
base::OnceCallback<void(bool error, bool established)> callback,
bool error,
const std::string& status,
const std::string& reply);
void DoSubscribe(TorControlEvent event,
base::OnceCallback<void(bool error)> callback);
+116
View File
@@ -184,4 +184,120 @@ TEST(TorControlTest, ReadLine) {
base::RunLoop().RunUntilIdle();
}
TEST(TorControlTest, GetCircuitEstablishedDone) {
content::BrowserTaskEnvironment task_environment;
scoped_refptr<base::SequencedTaskRunner> io_task_runner =
content::GetIOThreadTaskRunner({});
MockTorControlDelegate delegate;
std::unique_ptr<TorControl> control =
std::make_unique<TorControl>(&delegate, io_task_runner);
io_task_runner->PostTask(
FROM_HERE, base::BindOnce(
[](std::unique_ptr<TorControl> control) {
std::unique_ptr<std::string> established =
std::make_unique<std::string>("0");
bool is_called = false;
control->GetCircuitEstablishedDone(
std::move(established),
base::BindOnce(
[](bool* is_called, bool error, bool result) {
*is_called = true;
EXPECT_FALSE(error);
EXPECT_FALSE(result);
},
&is_called),
false, "250", "OK");
EXPECT_TRUE(is_called);
is_called = false;
established.reset(new std::string("1"));
control->GetCircuitEstablishedDone(
std::move(established),
base::BindOnce(
[](bool* is_called, bool error, bool result) {
*is_called = true;
EXPECT_FALSE(error);
EXPECT_TRUE(result);
},
&is_called),
false, "250", "OK");
EXPECT_TRUE(is_called);
// --- Error cases ---
is_called = false;
established.reset(new std::string("iambrave"));
control->GetCircuitEstablishedDone(
std::move(established),
base::BindOnce(
[](bool* is_called, bool error, bool result) {
*is_called = true;
EXPECT_TRUE(error);
EXPECT_FALSE(result);
},
&is_called),
false, "250", "OK");
EXPECT_TRUE(is_called);
is_called = false;
established.reset(new std::string(""));
control->GetCircuitEstablishedDone(
std::move(established),
base::BindOnce(
[](bool* is_called, bool error, bool result) {
*is_called = true;
EXPECT_TRUE(error);
EXPECT_FALSE(result);
},
&is_called),
false, "250", "OK");
EXPECT_TRUE(is_called);
is_called = false;
established.reset(new std::string("1"));
control->GetCircuitEstablishedDone(
std::move(established),
base::BindOnce(
[](bool* is_called, bool error, bool result) {
*is_called = true;
EXPECT_TRUE(error);
EXPECT_FALSE(result);
},
&is_called),
true, "250", "OK");
EXPECT_TRUE(is_called);
is_called = false;
established.reset(new std::string("1"));
control->GetCircuitEstablishedDone(
std::move(established),
base::BindOnce(
[](bool* is_called, bool error, bool result) {
*is_called = true;
EXPECT_TRUE(error);
EXPECT_FALSE(result);
},
&is_called),
false, "500", "OK");
EXPECT_TRUE(is_called);
is_called = false;
established.reset(new std::string("1"));
control->GetCircuitEstablishedDone(
std::move(established),
base::BindOnce(
[](bool* is_called, bool error, bool result) {
*is_called = true;
EXPECT_TRUE(error);
EXPECT_FALSE(result);
},
&is_called),
false, "500", "NOT_OK");
EXPECT_TRUE(is_called);
},
std::move(control)));
base::RunLoop().RunUntilIdle();
}
} // namespace tor
+19
View File
@@ -233,6 +233,14 @@ void TorLauncherFactory::OnTorControlReady() {
base::BindPostTask(base::SequencedTaskRunnerHandle::Get(),
base::BindOnce(&TorLauncherFactory::GotSOCKSListeners,
weak_ptr_factory_.GetWeakPtr())));
// A Circuit might have been established when Tor control is ready, in that
// case we will not receive circuit established events. So we query the status
// directly as fail safe, otherwise Tor window might stuck in disconnected
// state while Tor circuit is ready.
control_->GetCircuitEstablished(base::BindPostTask(
base::SequencedTaskRunnerHandle::Get(),
base::BindOnce(&TorLauncherFactory::GotCircuitEstablished,
weak_ptr_factory_.GetWeakPtr())));
control_->Subscribe(tor::TorControlEvent::NETWORK_LIVENESS,
base::DoNothing::Once<bool>());
control_->Subscribe(tor::TorControlEvent::STATUS_CLIENT,
@@ -277,6 +285,17 @@ void TorLauncherFactory::GotSOCKSListeners(
observer.OnTorNewProxyURI(tor_proxy_uri);
}
void TorLauncherFactory::GotCircuitEstablished(bool error, bool established) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (error) {
VLOG(1) << "Failed to get circuit established!";
return;
}
is_connected_ = established;
for (auto& observer : observers_)
observer.OnTorCircuitEstablished(established);
}
void TorLauncherFactory::OnTorControlClosed(bool was_running) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(2) << "TOR CONTROL: Closed!";
+1
View File
@@ -78,6 +78,7 @@ class TorLauncherFactory : public tor::TorControl::Delegate {
void GotVersion(bool error, const std::string& version);
void GotSOCKSListeners(bool error, const std::vector<std::string>& listeners);
void GotCircuitEstablished(bool error, bool established);
void LaunchTorInternal();
void RelaunchTor();