Skip to content

Commit

Permalink
Merge pull request #1966 from freimair/externalTorRollingBackup
Browse files Browse the repository at this point in the history
Rolling backup for external Tor feature
  • Loading branch information
ManfredKarrer authored Nov 25, 2018
2 parents f8b633d + e4568a3 commit 1859511
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public NetworkNodeProvider(NetworkProtoResolver networkProtoResolver,
@Named(NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE) boolean useSafeCookieAuthentication ) {
networkNode = useLocalhostForP2P ?
new LocalhostNetworkNode(address, port, networkProtoResolver) :
new TorNetworkNode(port, torDir, networkProtoResolver,
new TorNetworkNode(port, networkProtoResolver,
!controlPort.isEmpty() ?
new RunningTor(torDir, Integer.parseInt(controlPort), password, cookieFile, useSafeCookieAuthentication) :
new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider.getBridgeAddresses()));
Expand Down
19 changes: 13 additions & 6 deletions p2p/src/main/java/bisq/network/p2p/network/NewTor.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
import org.berndpruenster.netlayer.tor.Tor;
import org.berndpruenster.netlayer.tor.TorCtlException;
import org.berndpruenster.netlayer.tor.Torrc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import lombok.extern.slf4j.Slf4j;

/**
* This class creates a brand new instance of the Tor onion router.
Expand All @@ -44,20 +44,27 @@
* @author Florian Reimair
*
*/
@Slf4j
public class NewTor extends TorMode {

private static final Logger log = LoggerFactory.getLogger(NewTor.class);
/**
* <code>Netlayer</code> stores its hidden service files in a custom
* subdirectory of <code>$torDir/hiddenservice/</code>. Note that the
* {@link HiddenServiceSocket} does add this part on its own, hence,
* {@link NewTor#getHiddenServiceDirectory()} returns only the custom
* subdirectory (which happens to be <code>""</code>)
*/
private static final String HIDDEN_SERVICE_DIRECTORY = "hiddenservice";

private final String torrcFile;
private final String torrcOptions;
private final Collection<String> bridgeEntries;
private final File torWorkikngDirectory;

public NewTor(File torWorkingDirectory, String torrcFile, String torrcOptions, Collection<String> bridgeEntries) {
super(torWorkingDirectory, HIDDEN_SERVICE_DIRECTORY);
this.torrcFile = torrcFile;
this.torrcOptions = torrcOptions;
this.bridgeEntries = bridgeEntries;
this.torWorkikngDirectory = torWorkingDirectory;
}

@Override
Expand Down Expand Up @@ -103,7 +110,7 @@ public Tor getTor() throws IOException, TorCtlException {
override = new Torrc(torrcOptionsMap);

log.info("Starting tor");
NativeTor result = new NativeTor(torWorkikngDirectory, bridgeEntries, override);
NativeTor result = new NativeTor(torDir, bridgeEntries, override);
log.info(
"\n################################################################\n"
+ "Tor started after {} ms. Start publishing hidden service.\n"
Expand Down
14 changes: 7 additions & 7 deletions p2p/src/main/java/bisq/network/p2p/network/RunningTor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import org.berndpruenster.netlayer.tor.ExternalTor;
import org.berndpruenster.netlayer.tor.Tor;
import org.berndpruenster.netlayer.tor.TorCtlException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import lombok.extern.slf4j.Slf4j;

/**
* This class creates a brand new instance of the Tor onion router.
Expand All @@ -37,19 +37,19 @@
* @author Florian Reimair
*
*/
@Slf4j
public class RunningTor extends TorMode {

private static final Logger log = LoggerFactory.getLogger(RunningTor.class);
private static final String EXTERNAL_TOR_HIDDEN_SERVICE = "externalTorHiddenService";
private final int controlPort;
private final String password;
private final String torDir;
private final File cookieFile;
private final boolean useSafeCookieAuthentication;


public RunningTor(final File torDir, final int controlPort, final String password, final String cookieFile,
final boolean useSafeCookieAuthentication) {
this.torDir = torDir.getAbsolutePath();
super(torDir, EXTERNAL_TOR_HIDDEN_SERVICE);
this.controlPort = controlPort;
this.password = password;
this.cookieFile = new File(cookieFile);
Expand All @@ -72,7 +72,7 @@ else if (cookieFile.exists())

log.info(
"\n################################################################\n"
+ "Tor started after {} ms. Start publishing hidden service.\n"
+ "Connecting to Tor successful after {} ms. Start publishing hidden service.\n"
+ "################################################################",
(new Date().getTime() - ts1)); // takes usually a few seconds

Expand All @@ -81,7 +81,7 @@ else if (cookieFile.exists())

@Override
public String getHiddenServiceDirectory() {
return torDir + File.separator + "externalTorHiddenService";
return new File(torDir, EXTERNAL_TOR_HIDDEN_SERVICE).getAbsolutePath();
}

}
38 changes: 34 additions & 4 deletions p2p/src/main/java/bisq/network/p2p/network/TorMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import org.berndpruenster.netlayer.tor.Tor;
import org.berndpruenster.netlayer.tor.TorCtlException;

import bisq.common.storage.FileUtil;

/**
* Holds information on how tor should be created and delivers a respective
* {@link Tor} object when asked.
Expand All @@ -32,11 +34,31 @@
*/
public abstract class TorMode {

/**
* The directory where the <code>private_key</code> file sits in. Kept private,
* because it is only valid for the {@link TorMode#doRollingBackup()} due to the
* inner workings of the <code>Netlayer</code> dependency.
*/
private final File hiddenServiceDirectory;
protected final File torDir;

/**
* @param torDir points to the place, where we will persist private
* key and address data
* @param hiddenServiceDir The directory where the <code>private_key</code> file
* sits in. Note that, due to the inner workings of the
* <code>Netlayer</code> dependency, it does not
* necessarily equal
* {@link TorMode#getHiddenServiceDirectory()}.
*/
public TorMode(File torDir, String hiddenServiceDir) {
this.torDir = torDir;
this.hiddenServiceDirectory = new File(torDir, hiddenServiceDir);
}

/**
* Returns a fresh {@link Tor} object.
*
* @param torDir points to the place, where we will persist private key and
* address data
* @return a fresh instance of {@link Tor}
* @throws IOException
* @throws TorCtlException
Expand All @@ -49,12 +71,20 @@ public abstract class TorMode {
* <code>""</code>) as a hidden service directory is fine. {@link ExternalTor},
* however, does not have a Tor installation path and thus, takes the hidden
* service path literally. Hence, we set
* <code>"torDir/ephemeralHiddenService"</code> as the hidden service directory.
* <code>"torDir/externalTorHiddenService"</code> as the hidden service
* directory.
*
* @return <code>""</code> in {@link NewTor} Mode,
* <code>"torDir/ephemeralHiddenService"</code> in {@link RunningTor}
* <code>"torDir/externalTorHiddenService"</code> in {@link RunningTor}
* mode
*/
public abstract String getHiddenServiceDirectory();

/**
* Do a rolling backup of the "private_key" file.
*/
protected void doRollingBackup() {
FileUtil.rollingBackup(hiddenServiceDirectory, "private_key", 20);
}

}
17 changes: 4 additions & 13 deletions p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import bisq.common.UserThread;
import bisq.common.app.Log;
import bisq.common.proto.network.NetworkProtoResolver;
import bisq.common.storage.FileUtil;
import bisq.common.util.Utilities;

import org.berndpruenster.netlayer.tor.HiddenServiceSocket;
Expand All @@ -47,14 +46,9 @@

import java.net.Socket;

import java.nio.file.Paths;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -74,7 +68,6 @@ public class TorNetworkNode extends NetworkNode {


private HiddenServiceSocket hiddenServiceSocket;
private final File torDir;
private Timer shutDownTimeoutTimer;
private int restartCounter;
@SuppressWarnings("FieldCanBeLocal")
Expand All @@ -87,9 +80,8 @@ public class TorNetworkNode extends NetworkNode {
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////

public TorNetworkNode(int servicePort, File torDir, NetworkProtoResolver networkProtoResolver, TorMode torMode) {
public TorNetworkNode(int servicePort, NetworkProtoResolver networkProtoResolver, TorMode torMode) {
super(servicePort, networkProtoResolver);
this.torDir = torDir;
this.torMode = torMode;
}

Expand All @@ -100,8 +92,7 @@ public TorNetworkNode(int servicePort, File torDir, NetworkProtoResolver network

@Override
public void start(@Nullable SetupListener setupListener) {
final File hiddenservice = new File(Paths.get(torDir.getAbsolutePath(), "hiddenservice").toString());
FileUtil.rollingBackup(hiddenservice, "private_key", 20);
torMode.doRollingBackup();

if (setupListener != null)
addSetupListener(setupListener);
Expand Down Expand Up @@ -280,8 +271,8 @@ public void run() {
log.error("Could not connect to running Tor: "
+ e.getMessage());

// Seems a bit harsh, but since we cannot connect to Tor, we cannot do nothing
// furthermore, we have no hidden services started yet, so there is no graceful
// Seems a bit harsh, but since we cannot connect to Tor, we cannot do nothing.
// Furthermore, we have no hidden services started yet, so there is no graceful
// shutdown needed either
System.exit(1);
} catch (Throwable ignore) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ public class TorNetworkNodeTest {
public void testTorNodeBeforeSecondReady() throws InterruptedException, IOException {
latch = new CountDownLatch(1);
int port = 9001;
TorNetworkNode node1 = new TorNetworkNode(port, new File("torNode_" + port),
TestUtils.getNetworkProtoResolver(),
TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(),
new NewTor(new File("torNode_" + port), "", "", new ArrayList<String>()));
node1.start(new SetupListener() {
@Override
Expand All @@ -81,8 +80,7 @@ public void onRequestCustomBridges() {

latch = new CountDownLatch(1);
int port2 = 9002;
TorNetworkNode node2 = new TorNetworkNode(port2, new File("torNode_" + port2),
TestUtils.getNetworkProtoResolver(),
TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(),
new NewTor(new File("torNode_" + port), "", "", new ArrayList<String>()));
node2.start(new SetupListener() {
@Override
Expand Down Expand Up @@ -140,8 +138,7 @@ public void onFailure(@NotNull Throwable throwable) {
public void testTorNodeAfterBothReady() throws InterruptedException, IOException {
latch = new CountDownLatch(2);
int port = 9001;
TorNetworkNode node1 = new TorNetworkNode(port, new File("torNode_" + port),
TestUtils.getNetworkProtoResolver(),
TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(),
new NewTor(new File("torNode_" + port), "", "", new ArrayList<String>()));
node1.start(new SetupListener() {
@Override
Expand All @@ -167,8 +164,7 @@ public void onRequestCustomBridges() {
});

int port2 = 9002;
TorNetworkNode node2 = new TorNetworkNode(port2, new File("torNode_" + port),
TestUtils.getNetworkProtoResolver(),
TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(),
new NewTor(new File("torNode_" + port), "", "", new ArrayList<String>()));
node2.start(new SetupListener() {
@Override
Expand Down

0 comments on commit 1859511

Please sign in to comment.