Commit daac8a80 authored by zeroleak's avatar zeroleak
Browse files

optimize Tor: single instance, multiple SOCKSPort

parent a2d7724b
......@@ -31,6 +31,22 @@ public abstract class JavaHttpClient extends JacksonHttpClient {
this.requestTimeout = requestTimeout;
}
public void changeIdentity() {
// restart httpClientRegOut
try {
httpClientRegOut.stop();
httpClientRegOut.start();
} catch (Exception e) {
log.error("", e);
try {
httpClientRegOut.stop();
} catch (Exception ee) {
}
httpClientRegOut = null;
}
// httpClientShared will renew on next websocket connexion, don't break opened connexions
}
protected abstract HttpClient computeHttpClient(boolean isRegisterOutput) throws Exception;
@Override
......
......@@ -19,12 +19,9 @@ import org.slf4j.LoggerFactory;
public class JavaTorClient {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static final String TOR_DIR_SHARED = "whirlpoolTorShared";
private static final String TOR_DIR_REG_OUT = "whirlpoolTorRegOut";
private CliConfig cliConfig;
private TorOnionProxyInstance torInstanceShared;
private TorOnionProxyInstance torInstanceRegOut;
private TorOnionProxyInstance torInstance;
private boolean started = false;
public JavaTorClient(CliConfig cliConfig) {
......@@ -35,15 +32,9 @@ public class JavaTorClient {
TorSettings torSettings = computeTorSettings();
Optional<File> torExecutable = computeTorExecutableAndVerify();
// setup Tor instances
this.torInstanceShared =
this.torInstance =
new TorOnionProxyInstance(
new WhirlpoolTorInstaller(TOR_DIR_SHARED, torExecutable), torSettings, "shared");
// run second instance on different ports
this.torInstanceRegOut =
new TorOnionProxyInstance(
new WhirlpoolTorInstaller(TOR_DIR_REG_OUT, torExecutable), torSettings, "regOut");
new WhirlpoolTorInstaller("whirlpoolTor", torExecutable), torSettings);
}
private Optional<File> computeTorExecutableAndVerify() throws Exception {
......@@ -183,7 +174,7 @@ public class JavaTorClient {
+ (torExecutable.isPresent() ? torExecutable.get().getAbsolutePath() : "embedded")
+ ")");
}
new WhirlpoolTorInstaller("temp", torExecutable).setup(); // throws
new WhirlpoolTorInstaller("whirlpoolTorInstaller", torExecutable).setup(); // throws
}
public void connect() {
......@@ -195,8 +186,7 @@ public class JavaTorClient {
log.debug("Connecting Tor...");
}
torInstanceShared.start();
torInstanceRegOut.start();
torInstance.start();
started = true;
}
......@@ -204,8 +194,7 @@ public class JavaTorClient {
if (!started) {
connect();
}
torInstanceShared.waitReady();
torInstanceRegOut.waitReady();
torInstance.waitReady();
log.info("Tor is ready");
}
......@@ -220,8 +209,7 @@ public class JavaTorClient {
log.debug("Changing Tor identity");
}
torInstanceShared.changeIdentity();
torInstanceRegOut.changeIdentity();
torInstance.changeIdentity();
}
}
......@@ -231,20 +219,23 @@ public class JavaTorClient {
}
started = false;
torInstanceShared.stop();
torInstanceRegOut.stop();
torInstance.stop();
}
public void shutdown() {
started = false;
torInstanceShared.clear();
torInstanceRegOut.clear();
torInstanceShared = null;
torInstanceRegOut = null;
torInstance.clear();
torInstance = null;
}
public int getProgress() {
if (torInstance == null) {
return 0;
}
return torInstance.getProgress();
}
public JavaTorConnexion getConnexion(boolean isRegisterOutput) {
TorOnionProxyInstance torInstance = isRegisterOutput ? torInstanceRegOut : torInstanceShared;
public JavaTorConnexion getConnexion() {
return torInstance;
}
......
......@@ -5,7 +5,5 @@ import com.samourai.whirlpool.client.exception.NotifiableException;
public interface JavaTorConnexion {
CliProxy getTorProxy() throws NotifiableException;
int getProgress();
CliProxy getTorProxy(boolean isRegisterOutput) throws NotifiableException;
}
......@@ -7,24 +7,24 @@ import com.samourai.whirlpool.cli.Application;
import com.samourai.whirlpool.cli.beans.CliProxy;
import com.samourai.whirlpool.cli.beans.CliProxyProtocol;
import com.samourai.whirlpool.client.exception.NotifiableException;
import com.samourai.whirlpool.client.utils.ClientUtils;
import java.lang.invoke.MethodHandles;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.SocketUtils;
public class TorOnionProxyInstance implements JavaTorConnexion {
private Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static final int PROGRESS_CONNECTING = 50;
private OnionProxyManager onionProxyManager;
private Thread startThread;
private CliProxy torSocks = null;
private boolean torSocksReady = false;
private CliProxy torSocksShared = null;
private CliProxy torSocksRegOut = null;
private int progress;
public TorOnionProxyInstance(
WhirlpoolTorInstaller torInstaller, TorSettings torSettings, String logPrefix)
public TorOnionProxyInstance(WhirlpoolTorInstaller torInstaller, TorSettings torSettings)
throws Exception {
this.log = ClientUtils.prefixLogger(log, logPrefix);
TorConfig torConfig = torInstaller.getConfig();
if (log.isDebugEnabled()) {
log.debug("new TorOnionProxyInstance: " + torConfig + " ; " + torSettings);
......@@ -34,6 +34,15 @@ public class TorOnionProxyInstance implements JavaTorConnexion {
onionProxyManager = new OnionProxyManager(context);
TorConfigBuilder builder = onionProxyManager.getContext().newConfigBuilder().updateTorConfig();
int socksPortShared = SocketUtils.findAvailableTcpPort();
builder.socksPort(Integer.toString(socksPortShared), null);
torSocksShared = new CliProxy(CliProxyProtocol.SOCKS, "127.0.0.1", socksPortShared);
int socksPortRegOut = SocketUtils.findAvailableTcpPort();
builder.socksPort(Integer.toString(socksPortRegOut), null);
torSocksRegOut = new CliProxy(CliProxyProtocol.SOCKS, "127.0.0.1", socksPortRegOut);
onionProxyManager.getContext().getInstaller().updateTorConfigCustom(builder.asString());
onionProxyManager.setup();
......@@ -96,13 +105,7 @@ public class TorOnionProxyInstance implements JavaTorConnexion {
boolean ready = onionProxyManager.isRunning();
if (ready && progress != 100) {
if (log.isDebugEnabled()) {
String torProxy = "error";
try {
torProxy = getTorProxy().toString();
} catch (Exception e) {
log.error("", e);
}
log.debug("Tor connected! " + torProxy);
log.debug("Tor connected! " + torSocksShared + " | " + torSocksRegOut);
}
progress = 100;
}
......@@ -130,7 +133,7 @@ public class TorOnionProxyInstance implements JavaTorConnexion {
}
}
torSocks = null;
torSocksReady = false;
}
public synchronized void clear() {
......@@ -177,35 +180,30 @@ public class TorOnionProxyInstance implements JavaTorConnexion {
}
}
@Override
public int getProgress() {
protected int getProgress() {
return progress;
}
@Override
public CliProxy getTorProxy() throws NotifiableException {
CliProxy proxy;
while ((proxy = getTorSocksOrNull()) == null) {
waitReady();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
return proxy;
public CliProxy getTorProxy(boolean isRegisterOutput) throws NotifiableException {
waitTorSocks();
return isRegisterOutput ? torSocksRegOut : torSocksShared;
}
private CliProxy getTorSocksOrNull() {
if (torSocks == null && onionProxyManager.isRunning()) {
private void waitTorSocks() {
while (!torSocksReady && onionProxyManager.isRunning()) {
try {
// we should have a connexion now
int socksPort = onionProxyManager.getIPv4LocalHostSocksPort();
torSocks = new CliProxy(CliProxyProtocol.SOCKS, "127.0.0.1", socksPort);
log.info("TorSocks started: " + torSocks);
onionProxyManager.getIPv4LocalHostSocksPort();
torSocksReady = true;
log.info("TorSocks started.");
} catch (Exception e) {
log.error("Unable to get TorSocks", e);
log.error("TorSocks error", e);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
return torSocks;
}
}
......@@ -74,11 +74,11 @@ public class CliTorClientService {
}
}
public Optional<JavaTorConnexion> getTorConnexion(boolean isRegisterOutput) {
public Optional<JavaTorConnexion> getTorConnexion() {
if (cliConfig.getTor()) {
if (torClient.isPresent()) {
// Tor enabled
JavaTorConnexion torConnexion = torClient.get().getConnexion(isRegisterOutput);
JavaTorConnexion torConnexion = torClient.get().getConnexion();
return Optional.of(torConnexion);
}
}
......@@ -94,10 +94,7 @@ public class CliTorClientService {
return Optional.empty(); // Tor is disabled
}
// average progress of the two connexions
int progressShared = torClient.get().getConnexion(false).getProgress();
int progressRegOut = torClient.get().getConnexion(true).getProgress();
int progress = (progressShared + progressRegOut) / 2;
int progress = torClient.get().getProgress();
return Optional.of(progress);
}
}
......@@ -140,7 +140,8 @@ public class CliWalletService extends WhirlpoolWalletService {
cliConfig,
cliConfigService,
walletAggregateService,
cliTorClientService);
cliTorClientService,
httpClient);
return (CliWallet) openWallet(cliWallet);
}
......
......@@ -159,9 +159,11 @@ public class CliUtils {
Optional<CliProxy> cliProxyDefault)
throws Exception {
// use torConnexion when available, otherwise cliProxyDefault
Optional<JavaTorConnexion> torConnexion = torClientService.getTorConnexion(isRegisterOutput);
Optional<JavaTorConnexion> torConnexion = torClientService.getTorConnexion();
Optional<CliProxy> cliProxyOptional =
torConnexion.isPresent() ? Optional.of(torConnexion.get().getTorProxy()) : cliProxyDefault;
torConnexion.isPresent()
? Optional.of(torConnexion.get().getTorProxy(isRegisterOutput))
: cliProxyDefault;
return computeHttpClient(cliProxyOptional, ClientUtils.USER_AGENT);
}
......
package com.samourai.whirlpool.cli.wallet;
import com.samourai.http.client.CliHttpClient;
import com.samourai.wallet.client.Bip84ApiWallet;
import com.samourai.whirlpool.cli.config.CliConfig;
import com.samourai.whirlpool.cli.services.CliConfigService;
......@@ -25,18 +26,21 @@ public class CliWallet extends WhirlpoolWallet {
private CliConfigService cliConfigService;
private WalletAggregateService walletAggregateService;
private CliTorClientService cliTorClientService;
private CliHttpClient httpClient;
public CliWallet(
WhirlpoolWallet whirlpoolWallet,
CliConfig cliConfig,
CliConfigService cliConfigService,
WalletAggregateService walletAggregateService,
CliTorClientService cliTorClientService) {
CliTorClientService cliTorClientService,
CliHttpClient httpClient) {
super(whirlpoolWallet);
this.cliConfig = cliConfig;
this.cliConfigService = cliConfigService;
this.walletAggregateService = walletAggregateService;
this.cliTorClientService = cliTorClientService;
this.httpClient = httpClient;
}
@Override
......@@ -67,6 +71,7 @@ public class CliWallet extends WhirlpoolWallet {
// change Tor identity
cliTorClientService.changeIdentity();
httpClient.changeIdentity();
}
@Override
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment