Skip to content
This repository has been archived by the owner on Jan 4, 2019. It is now read-only.

Commit

Permalink
Use a timer to expire circuits promptly.
Browse files Browse the repository at this point in the history
The timer is scheduled to run ten minutes after the last circuit that
was created.  This way, the last ten minutes of circuits are not
guaranteed to stick around in memory indefinitely.

Caveat: This doesn't _zero_ the memory, so it may still appear in
`strings /proc/N/mem`.  But it does make the memory available to be
recycled, so it's not _guaranteed_ to still appear in `strings
/proc/N/mem`.

Also, timestamp the map entries.  If we explicitly create a new map
entry for a site by requesting a new identity, the old expiry queue
entry will not delete it, but a new expiry queue entry will delete
it.  This way, circuits created by requesting a new identity are not
shorter-lived than other circuits.

We leave the old entries in the priority queue because there's no
convenient way to delete them with std::priority_queue.  In
principle, this might leak space if you repeatedly request a new
identity, but it can only leak as much space as you use by repeatedly
requesting a new identity for a maximum of ten minutes.

fix #611 real good this time

Auditors: @darkdh

Test Plan:
1. Search DDG for `what is my ip address'.
2. Record the IP address it reports.
3. Reload.
4. Confirm it's the same IP address.
5. Full-reload.
6. Confirm it's a different IP address.  Record the new IP address.
7. Wait >10min.
8. Reload.
9. Confirm it's a different IP address again.
  • Loading branch information
riastradh-brave authored and darkdh committed Jul 6, 2018
1 parent fbf2a29 commit c59eec1
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 28 deletions.
92 changes: 70 additions & 22 deletions brave/browser/net/proxy_resolution/proxy_config_service_tor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,8 @@ ProxyConfigServiceTor::ProxyConfigServiceTor(
tor_proxy.begin() + url.port.begin + url.port.len);
}
std::string proxy_url;
if (tor_proxy_map || username.empty()) {
// Clear expired entries.
const base::Time now = base::Time::Now();
const base::Time deadline = now - kTenMins;
const std::pair<base::Time, std::string>* entry;
while (!tor_proxy_map->queue.empty() &&
(entry = &tor_proxy_map->queue.top(), entry->first < deadline)) {
tor_proxy_map->map.erase(entry->second);
tor_proxy_map->queue.pop();
}
// Look up an entry here.
auto found = tor_proxy_map->map.find(username);
std::string password;
if (found == tor_proxy_map->map.end()) {
password = GenerateNewPassword();
tor_proxy_map->map.emplace(username, password);
tor_proxy_map->queue.emplace(now, username);
} else {
password = found->second;
}
if (tor_proxy_map && !username.empty()) {
std::string password = tor_proxy_map->Get(username);
proxy_url = std::string(scheme_ + "://" + username + ":" + password +
"@" + host_ + ":" + port_);
} else {
Expand All @@ -95,7 +77,7 @@ void ProxyConfigServiceTor::TorSetProxy(
if (!service)
return;
if (new_password && tor_proxy_map)
tor_proxy_map->map.erase(site_url);
tor_proxy_map->Erase(site_url);
std::unique_ptr<net::ProxyConfigServiceTor>
config(new ProxyConfigServiceTor(tor_proxy, site_url, tor_proxy_map));
service->ResetConfigService(std::move(config));
Expand All @@ -110,10 +92,76 @@ ProxyConfigServiceTor::ConfigAvailability
return CONFIG_VALID;
}

std::string ProxyConfigServiceTor::GenerateNewPassword() {
ProxyConfigServiceTor::TorProxyMap::TorProxyMap() = default;
ProxyConfigServiceTor::TorProxyMap::~TorProxyMap() = default;

// static
std::string ProxyConfigServiceTor::TorProxyMap::GenerateNewPassword() {
std::vector<uint8_t> password(kTorPasswordLength);
crypto::RandBytes(password.data(), password.size());
return base::HexEncode(password.data(), password.size());
}

std::string ProxyConfigServiceTor::TorProxyMap::Get(
const std::string& username) {
// Clear any expired entries, in case this one has expired.
ClearExpiredEntries();

// Check for an entry for this username.
auto found = map_.find(username);
if (found != map_.end())
return found->second.first;

// No entry yet. Check our watch and create one.
const base::Time now = base::Time::Now();
const std::string password = GenerateNewPassword();
map_.emplace(username, std::make_pair(password, now));
queue_.emplace(now, username);

// Reschedule the timer for ten minutes from now so that this entry
// won't last more than about ten minutes even if the user stops
// using Tor for a while.
timer_.Stop();
timer_.Start(FROM_HERE, kTenMins, this,
&ProxyConfigServiceTor::TorProxyMap::ClearExpiredEntries);

return password;
}

void ProxyConfigServiceTor::TorProxyMap::Erase(const std::string& username) {
// Just erase it from the map. There will remain an entry in the
// queue, but it is harmless. If anyone creates a new entry in the
// map, the old entry in the queue will cease to affect it because
// the timestamps won't match, and they will simultaneously create a
// new entry in the queue.
map_.erase(username);
}

void ProxyConfigServiceTor::TorProxyMap::ClearExpiredEntries() {
const base::Time cutoff = base::Time::Now() - kTenMins;
for (; !queue_.empty(); queue_.pop()) {
// Check the timestamp. If it's not older than the cutoff, stop.
const std::pair<base::Time, std::string>* entry = &queue_.top();
const base::Time timestamp = entry->first;
if (!(timestamp < cutoff))
break;

// Remove the corresponding entry in the map if there is one and
// if its timestamp is not newer.
const std::string& username = entry->second;
auto found = map_.find(username);
if (found != map_.end()) {
// If the timestamp on the map entry is the same as the
// timestamp on the queue entry, then delete the map entry.
// Otherwise, we assume the map entry was created by an explicit
// request for a new identity, which will have its own entry in
// the queue in order to last the full ten minutes.
const base::Time map_timestamp = found->second.second;
if (map_timestamp == timestamp) {
map_.erase(username);
}
}
}
}

} // namespace net
23 changes: 17 additions & 6 deletions brave/browser/net/proxy_resolution/proxy_config_service_tor.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

#include <string>
#include <map>
#include <queue>
#include <utility>

#include "base/compiler_specific.h"
#include "base/timer/timer.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/proxy_resolution/proxy_config.h"
Expand All @@ -28,9 +30,21 @@ const char kSocksProxy[] = "socks5";
class NET_EXPORT ProxyConfigServiceTor : public ProxyConfigService {
public:
// Used to cache <username, password> of proxies
struct TorProxyMap {
std::map<std::string, std::string> map;
std::priority_queue<std::pair<base::Time, std::string> > queue;
class TorProxyMap {
public:
TorProxyMap();
~TorProxyMap();
std::string Get(const std::string&);
void Erase(const std::string&);
private:
// Generate a new 128 bit random tag
static std::string GenerateNewPassword();
// Clear expired entries in the queue from the map.
void ClearExpiredEntries();
std::map<std::string, std::pair<std::string, base::Time> > map_;
std::priority_queue<std::pair<base::Time, std::string> > queue_;
base::OneShotTimer timer_;
DISALLOW_COPY_AND_ASSIGN(TorProxyMap);
};

explicit ProxyConfigServiceTor(const std::string& tor_proxy,
Expand All @@ -52,9 +66,6 @@ class NET_EXPORT ProxyConfigServiceTor : public ProxyConfigService {
ProxyConfigWithAnnotation* config) override;

private:
// Generate a new 128 bit random tag
std::string GenerateNewPassword();

ProxyConfig config_;

std::string scheme_;
Expand Down

0 comments on commit c59eec1

Please sign in to comment.