Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rolling backup for external Tor feature #1966

Merged
merged 5 commits into from
Nov 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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