Connect to external Tor with NullAuthentication

This commit is contained in:
Florian Reimair 2018-11-16 18:58:43 +01:00
parent aa584acb92
commit 63f8bbf8c5
9 changed files with 119 additions and 5 deletions

View file

@ -193,7 +193,7 @@ public class BisqEnvironment extends StandardEnvironment {
protected final String btcNodes, seedNodes, ignoreDevMsg, useDevPrivilegeKeys, useDevMode, useTorForBtc, rpcUser, rpcPassword,
rpcPort, rpcBlockNotificationPort, dumpBlockchainData, fullDaoNode,
myAddress, banList, dumpStatistics, maxMemory, socks5ProxyBtcAddress,
torRcFile, torRcOptions,
torRcFile, torRcOptions, externalTorControlPort,
socks5ProxyHttpAddress, useAllProvidedNodes, numConnectionForBtc, genesisTxId, genesisBlockHeight, referralId, daoActivated;
@ -274,6 +274,9 @@ public class BisqEnvironment extends StandardEnvironment {
torRcOptions = commandLineProperties.containsProperty(NetworkOptionKeys.TORRC_OPTIONS) ?
(String) commandLineProperties.getProperty(NetworkOptionKeys.TORRC_OPTIONS) :
"";
externalTorControlPort = commandLineProperties.containsProperty(NetworkOptionKeys.EXTERNAL_TOR_CONTROL_PORT) ?
(String) commandLineProperties.getProperty(NetworkOptionKeys.EXTERNAL_TOR_CONTROL_PORT) :
"";
//RpcOptionKeys
rpcUser = commandLineProperties.containsProperty(DaoOptionKeys.RPC_USER) ?
@ -444,6 +447,7 @@ public class BisqEnvironment extends StandardEnvironment {
setProperty(NetworkOptionKeys.SOCKS_5_PROXY_HTTP_ADDRESS, socks5ProxyHttpAddress);
setProperty(NetworkOptionKeys.TORRC_FILE, torRcFile);
setProperty(NetworkOptionKeys.TORRC_OPTIONS, torRcOptions);
setProperty(NetworkOptionKeys.EXTERNAL_TOR_CONTROL_PORT, externalTorControlPort);
setProperty(AppOptionKeys.APP_DATA_DIR_KEY, appDataDir);
setProperty(AppOptionKeys.DESKTOP_WITH_HTTP_API, desktopWithHttpApi);

View file

@ -363,6 +363,11 @@ public abstract class BisqExecutable implements GracefulShutDownHandler {
description("A list of torrc-entries to amend to Bisqs torrc. Note that torrc-entries, which are critical to Bisqs flawless operation, cannot be overwritten. [torrc options line, torrc option, ...]", ""))
.withRequiredArg()
.withValuesConvertedBy(RegexMatcher.regex("^([^\\s,]+\\s[^,]+,?\\s*)+$"));
parser.accepts(NetworkOptionKeys.EXTERNAL_TOR_CONTROL_PORT,
description("The control port of an already running Tor service to be used by Bisq [port].", ""))
.availableUnless(NetworkOptionKeys.TORRC_FILE, NetworkOptionKeys.TORRC_OPTIONS)
.withRequiredArg()
.ofType(int.class);
//AppOptionKeys
parser.accepts(AppOptionKeys.USER_DATA_DIR_KEY,

View file

@ -31,4 +31,5 @@ public class NetworkOptionKeys {
public static final String SOCKS_5_PROXY_HTTP_ADDRESS = "socks5ProxyHttpAddress";
public static final String TORRC_OPTIONS = "torrcOptions";
public static final String TORRC_FILE = "torrcFile";
public static final String EXTERNAL_TOR_CONTROL_PORT = "torControlPort";
}

View file

@ -22,6 +22,7 @@ import bisq.network.p2p.network.BridgeAddressProvider;
import bisq.network.p2p.network.LocalhostNetworkNode;
import bisq.network.p2p.network.NetworkNode;
import bisq.network.p2p.network.NewTor;
import bisq.network.p2p.network.RunningTor;
import bisq.network.p2p.network.TorNetworkNode;
import bisq.common.proto.network.NetworkProtoResolver;
@ -45,11 +46,14 @@ public class NetworkNodeProvider implements Provider<NetworkNode> {
@Named(NetworkOptionKeys.PORT_KEY) int port,
@Named(NetworkOptionKeys.TOR_DIR) File torDir,
@Named(NetworkOptionKeys.TORRC_FILE) String torrcFile,
@Named(NetworkOptionKeys.TORRC_OPTIONS) String torrcOptions) {
@Named(NetworkOptionKeys.TORRC_OPTIONS) String torrcOptions,
@Named(NetworkOptionKeys.EXTERNAL_TOR_CONTROL_PORT) String controlPort) {
networkNode = useLocalhostForP2P ?
new LocalhostNetworkNode(address, port, networkProtoResolver) :
new TorNetworkNode(port, torDir, networkProtoResolver, bridgeAddressProvider,
new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider.getBridgeAddresses()));
!controlPort.isEmpty() ?
new RunningTor(torDir, Integer.parseInt(controlPort)) :
new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider.getBridgeAddresses()));
}
@Override

View file

@ -90,5 +90,6 @@ public class P2PModule extends AppModule {
bindConstant().annotatedWith(named(NetworkOptionKeys.SOCKS_5_PROXY_HTTP_ADDRESS)).to(environment.getRequiredProperty(NetworkOptionKeys.SOCKS_5_PROXY_HTTP_ADDRESS));
bindConstant().annotatedWith(named(NetworkOptionKeys.TORRC_FILE)).to(environment.getRequiredProperty(NetworkOptionKeys.TORRC_FILE));
bindConstant().annotatedWith(named(NetworkOptionKeys.TORRC_OPTIONS)).to(environment.getRequiredProperty(NetworkOptionKeys.TORRC_OPTIONS));
bindConstant().annotatedWith(named(NetworkOptionKeys.EXTERNAL_TOR_CONTROL_PORT)).to(environment.getRequiredProperty(NetworkOptionKeys.EXTERNAL_TOR_CONTROL_PORT));
}
}

View file

@ -45,7 +45,7 @@ import org.slf4j.LoggerFactory;
*/
public class NewTor extends TorMode {
private static final Logger log = LoggerFactory.getLogger(TorNetworkNode.class);
private static final Logger log = LoggerFactory.getLogger(NewTor.class);
private final String torrcFile;
private final String torrcOptions;
@ -109,4 +109,9 @@ public class NewTor extends TorMode {
return result;
}
@Override
public String getHiddenServiceDirectory() {
return "";
}
}

View file

@ -0,0 +1,72 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.network.p2p.network;
import java.io.File;
import java.io.IOException;
import java.util.Date;
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;
/**
* This class creates a brand new instance of the Tor onion router.
*
* When asked, the class checks for the authentication method selected and
* connects to the given control port. Finally, a {@link Tor} instance is
* returned for further use.
*
* @author Florian Reimair
*
*/
public class RunningTor extends TorMode {
private static final Logger log = LoggerFactory.getLogger(RunningTor.class);
private final int controlPort;
private final String torDir;
public RunningTor(final File torDir, final int controlPort) {
this.torDir = torDir.getAbsolutePath();
this.controlPort = controlPort;
}
@Override
public Tor getTor() throws IOException, TorCtlException {
long ts1 = new Date().getTime();
log.info("Connecting to running tor");
Tor result = new ExternalTor(controlPort);
log.info(
"\n################################################################\n"
+ "Tor started after {} ms. Start publishing hidden service.\n"
+ "################################################################",
(new Date().getTime() - ts1)); // takes usually a few seconds
return result;
}
@Override
public String getHiddenServiceDirectory() {
return torDir + File.separator + "externalTorHiddenService";
}
}

View file

@ -43,4 +43,18 @@ public abstract class TorMode {
*/
public abstract Tor getTor() throws IOException, TorCtlException;
/**
* {@link NativeTor}'s inner workings prepend its Tor installation path and some
* other stuff to the hiddenServiceDir, thus, selecting nothing (i.e.
* <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.
*
* @return <code>""</code> in {@link NewTor} Mode,
* <code>"torDir/ephemeralHiddenService"</code> in {@link RunningTor}
* mode
*/
public abstract String getHiddenServiceDirectory();
}

View file

@ -250,7 +250,7 @@ public class TorNetworkNode extends NetworkNode {
// start hidden service
long ts2 = new Date().getTime();
hiddenServiceSocket = new HiddenServiceSocket(localPort, "", servicePort);
hiddenServiceSocket = new HiddenServiceSocket(localPort, torMode.getHiddenServiceDirectory(), servicePort);
hiddenServiceSocket.addReadyListener(socket -> {
try {
log.info("\n################################################################\n" +
@ -281,6 +281,14 @@ public class TorNetworkNode extends NetworkNode {
} catch (TorCtlException e) {
log.error("Tor node creation failed: " + (e.getCause() != null ? e.getCause().toString() : e.toString()));
restartTor(e.getMessage());
} catch (IOException e) {
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
// shutdown needed either
System.exit(1);
} catch (Throwable ignore) {
}