mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 06:49:38 -04:00
net: Add randomized prefix to Tor stream isolation credentials
Add a class TorsStreamIsolationCredentialsGenerator that generates unique credentials based on a randomly generated session prefix and an atomic counter. This makes sure that different launches of the application won't share the same credentials, and thus circuits, even in edge cases. Example with `-debug=proxy`: ``` 2025-03-31T16:30:27Z [proxy] SOCKS5 sending proxy authentication 0afb2da441f5c105-0:0afb2da441f5c105-0 2025-03-31T16:30:31Z [proxy] SOCKS5 sending proxy authentication 0afb2da441f5c105-1:0afb2da441f5c105-1 ``` Thanks to hodlinator for the idea.
This commit is contained in:
parent
c47f81e8ac
commit
ec81a72b36
3 changed files with 43 additions and 7 deletions
|
@ -725,6 +725,43 @@ bool IsProxy(const CNetAddr &addr) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate unique credentials for Tor stream isolation. Tor will create
|
||||
* separate circuits for SOCKS5 proxy connections with different credentials, which
|
||||
* makes it harder to correlate the connections.
|
||||
*/
|
||||
class TorStreamIsolationCredentialsGenerator
|
||||
{
|
||||
public:
|
||||
TorStreamIsolationCredentialsGenerator():
|
||||
m_prefix(GenerateUniquePrefix()) {
|
||||
}
|
||||
|
||||
/** Return the next unique proxy credentials. */
|
||||
ProxyCredentials Generate() {
|
||||
ProxyCredentials auth;
|
||||
auth.username = auth.password = strprintf("%s%i", m_prefix, m_counter);
|
||||
++m_counter;
|
||||
return auth;
|
||||
}
|
||||
|
||||
/** Size of session prefix in bytes. */
|
||||
static constexpr size_t PREFIX_BYTE_LENGTH = 8;
|
||||
private:
|
||||
const std::string m_prefix;
|
||||
std::atomic<uint64_t> m_counter;
|
||||
|
||||
/** Generate a random prefix for each of the credentials returned by this generator.
|
||||
* This makes sure that different launches of the application (either successively or in parallel)
|
||||
* will not share the same circuits, as would be the case with a bare counter.
|
||||
*/
|
||||
static std::string GenerateUniquePrefix() {
|
||||
std::array<uint8_t, PREFIX_BYTE_LENGTH> prefix_bytes;
|
||||
GetRandBytes(prefix_bytes);
|
||||
return HexStr(prefix_bytes) + "-";
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<Sock> ConnectThroughProxy(const Proxy& proxy,
|
||||
const std::string& dest,
|
||||
uint16_t port,
|
||||
|
@ -739,9 +776,8 @@ std::unique_ptr<Sock> ConnectThroughProxy(const Proxy& proxy,
|
|||
|
||||
// do socks negotiation
|
||||
if (proxy.m_tor_stream_isolation) {
|
||||
ProxyCredentials random_auth;
|
||||
static std::atomic_int counter(0);
|
||||
random_auth.username = random_auth.password = strprintf("%i", counter++);
|
||||
static TorStreamIsolationCredentialsGenerator generator;
|
||||
ProxyCredentials random_auth{generator.Generate()};
|
||||
if (!Socks5(dest, port, &random_auth, *sock)) {
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ FUZZ_TARGET(i2p, .init = initialize_i2p)
|
|||
|
||||
const fs::path private_key_path = gArgs.GetDataDirNet() / "fuzzed_i2p_private_key";
|
||||
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), 7656};
|
||||
const Proxy sam_proxy{addr, false};
|
||||
const Proxy sam_proxy{addr, /*tor_stream_isolation=*/false};
|
||||
CThreadInterrupt interrupt;
|
||||
|
||||
i2p::sam::Session session{private_key_path, sam_proxy, &interrupt};
|
||||
|
|
|
@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(unlimited_recv)
|
|||
|
||||
CThreadInterrupt interrupt;
|
||||
const std::optional<CService> addr{Lookup("127.0.0.1", 9000, false)};
|
||||
const Proxy sam_proxy(addr.value(), false);
|
||||
const Proxy sam_proxy(addr.value(), /*tor_stream_isolation=*/false);
|
||||
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key", sam_proxy, &interrupt);
|
||||
|
||||
{
|
||||
|
@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(listen_ok_accept_fail)
|
|||
|
||||
CThreadInterrupt interrupt;
|
||||
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), /*port=*/7656};
|
||||
const Proxy sam_proxy(addr, false);
|
||||
const Proxy sam_proxy(addr, /*tor_stream_isolation=*/false);
|
||||
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key",
|
||||
sam_proxy,
|
||||
&interrupt);
|
||||
|
@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(damaged_private_key)
|
|||
|
||||
CThreadInterrupt interrupt;
|
||||
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), /*port=*/7656};
|
||||
const Proxy sam_proxy{addr, false};
|
||||
const Proxy sam_proxy{addr, /*tor_stream_isolation=*/false};
|
||||
i2p::sam::Session session(i2p_private_key_file, sam_proxy, &interrupt);
|
||||
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue