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

Bisq can now use an external Tor service #1935

Merged
merged 8 commits into from
Nov 17, 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
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ configure(project(':common')) {
configure(project(':p2p')) {
dependencies {
compile project(':common')
compile('com.github.JesusMcCloud.netlayer:tor.native:0.4.7.1.1') {
compile('com.github.JesusMcCloud.netlayer:tor.native:0.6') {
exclude(module: 'slf4j-api')
}
compile('com.github.JesusMcCloud.netlayer:tor.external:0.6') {
exclude(module: 'slf4j-api')
}
compile('org.apache.httpcomponents:httpclient:4.5.3') {
Expand Down
20 changes: 19 additions & 1 deletion core/src/main/java/bisq/core/app/BisqEnvironment.java
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,10 @@ private static String appDataDir(String userDataDir, String appName) {
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, externalTorPassword, externalTorCookieFile,
socks5ProxyHttpAddress, useAllProvidedNodes, numConnectionForBtc, genesisTxId, genesisBlockHeight, referralId, daoActivated;

protected final boolean externalTorUseSafeCookieAuthentication;

public BisqEnvironment(OptionSet options) {
this(new JOptCommandLinePropertySource(BISQ_COMMANDLINE_PROPERTY_SOURCE_NAME, checkNotNull(
Expand Down Expand Up @@ -274,6 +275,18 @@ public BisqEnvironment(PropertySource commandLineProperties) {
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) :
"";
externalTorPassword = commandLineProperties.containsProperty(NetworkOptionKeys.EXTERNAL_TOR_PASSWORD) ?
(String) commandLineProperties.getProperty(NetworkOptionKeys.EXTERNAL_TOR_PASSWORD) :
"";
externalTorCookieFile = commandLineProperties.containsProperty(NetworkOptionKeys.EXTERNAL_TOR_COOKIE_FILE) ?
(String) commandLineProperties.getProperty(NetworkOptionKeys.EXTERNAL_TOR_COOKIE_FILE) :
"";
externalTorUseSafeCookieAuthentication = commandLineProperties.containsProperty(NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE) ?
true :
false;

//RpcOptionKeys
rpcUser = commandLineProperties.containsProperty(DaoOptionKeys.RPC_USER) ?
Expand Down Expand Up @@ -444,6 +457,11 @@ private PropertySource<?> defaultProperties() {
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(NetworkOptionKeys.EXTERNAL_TOR_PASSWORD, externalTorPassword);
setProperty(NetworkOptionKeys.EXTERNAL_TOR_COOKIE_FILE, externalTorCookieFile);
if (externalTorUseSafeCookieAuthentication)
setProperty(NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE, "true");

setProperty(AppOptionKeys.APP_DATA_DIR_KEY, appDataDir);
setProperty(AppOptionKeys.DESKTOP_WITH_HTTP_API, desktopWithHttpApi);
Expand Down
18 changes: 18 additions & 0 deletions core/src/main/java/bisq/core/app/BisqExecutable.java
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,24 @@ protected void customizeOptionParsing(OptionParser parser) {
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);
parser.accepts(NetworkOptionKeys.EXTERNAL_TOR_PASSWORD,
description("The password for controlling the already running Tor service.", ""))
.availableIf(NetworkOptionKeys.EXTERNAL_TOR_CONTROL_PORT)
.withRequiredArg();
parser.accepts(NetworkOptionKeys.EXTERNAL_TOR_COOKIE_FILE,
description("The cookie file for authenticating against the already running Tor service. Use in conjunction with --" + NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE, ""))
.availableIf(NetworkOptionKeys.EXTERNAL_TOR_CONTROL_PORT)
.availableUnless(NetworkOptionKeys.EXTERNAL_TOR_PASSWORD)
.withRequiredArg()
.withValuesConvertedBy(new PathConverter(PathProperties.FILE_EXISTING, PathProperties.READABLE));
parser.accepts(NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE,
description("Use the SafeCookie method when authenticating to the already running Tor service.", ""))
.availableIf(NetworkOptionKeys.EXTERNAL_TOR_COOKIE_FILE);

//AppOptionKeys
parser.accepts(AppOptionKeys.USER_DATA_DIR_KEY,
Expand Down
16 changes: 8 additions & 8 deletions gradle/witness/gradle-witness.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ dependencyVerification {
'de.jensd:fontawesomefx-commons:5539bb3335ecb822dbf928546f57766eeb9f1516cc1417a064b5709629612149',
'com.googlecode.jcsv:jcsv:73ca7d715e90c8d2c2635cc284543b038245a34f70790660ed590e157b8714a2',
'com.github.sarxos:webcam-capture:d960b7ea8ec3ddf2df0725ef214c3fccc9699ea7772df37f544e1f8e4fd665f6',
'com.github.JesusMcCloud.netlayer:tor.native:0ad92f93c509a200a61cedbe0010d014f35ab57bcf131a4e268e1914e66be2e0',
'com.github.JesusMcCloud.netlayer:tor.native:f1bf0096f9eb6020645a65d91aa530d15aef97e69cc5a79d7b2405421f74700a',
'com.github.JesusMcCloud.netlayer:tor.external:cfba681398c191a1906d6d023a3be28a8fa9b1f4eee52e966daf7b1ae630414f',
'org.apache.httpcomponents:httpclient:db3d1b6c2d6a5e5ad47577ad61854e2f0e0936199b8e05eb541ed52349263135',
'net.sf.jopt-simple:jopt-simple:6f45c00908265947c39221035250024f2caec9a15c1c8cf553ebeecee289f342',
'org.fxmisc.easybind:easybind:666af296dda6de68751668a62661571b5238ac6f1c07c8a204fc6f902b222aaf',
Expand All @@ -37,11 +38,11 @@ dependencyVerification {
'com.google.code.findbugs:jsr305:c885ce34249682bc0236b4a7d56efcc12048e6135a5baf7a9cde8ad8cda13fcd',
'com.google.guava:guava:36a666e3b71ae7f0f0dca23654b67e086e6c93d192f60ba5dfd5519db6c288c8',
'com.google.inject:guice:9b9df27a5b8c7864112b4137fd92b36c3f1395bfe57be42fedf2f520ead1a93e',
'com.github.JesusMcCloud.netlayer:tor:4a6a6102331c35e7ad2a574cf81ddab89fc1256305805e82c5af1f542f336629',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:b306e0e6735841e31e320bf3260c71d60fc35057cfa87895f23251ee260a64a8',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:169ee5879cba8444499243ceea5e6a2cb6ecea5424211cc819f0704501154b35',
'com.github.JesusMcCloud.netlayer:tor:ac8465b7dda30ea920ec31a6bde42df7e88bee0282e805ce2797628938e3cf0b',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:193ab7813e4d249f2ea4fc1b968fea8c2126bcbeeb5d6127050ce1b93dbaa7c2',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:877b59bbe466b24a88275a71fd06cd97359d2085420f6f1ac1d766afa8116001',
'io.github.microutils:kotlin-logging:4992504fd3c6ecdf9ed10874b9508e758bb908af9e9d7af19a61e9afb6b7e27a',
'org.jetbrains.kotlin:kotlin-stdlib:f0595b9ed88ddc6fd66bddf68c56c6f2f6c4b17faa51e43e478acad32b05303e',
'org.jetbrains.kotlin:kotlin-stdlib:4ff0fcb97f4983b4aaba12668c24ad21b08460915db1b021d8f1d8bee687f21c',
'org.jetbrains:annotations:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.bouncycastle:bcpg-jdk15on:de3355b821fc81dd32e1f3f560d5b3eca1c678fd2400011d0bfc69fb91bcde85',
'commons-io:commons-io:cc6a41dc3eaacc9e440a6bd0d2890b20d36b4ee408fe2d67122f328bb6e01581',
Expand All @@ -63,14 +64,13 @@ dependencyVerification {
'com.lambdaworks:scrypt:9a82d218099fb14c10c0e86e7eefeebd8c104de920acdc47b8b4b7a686fb73b4',
'com.google.zxing:core:11aae8fd974ab25faa8208be50468eb12349cd239e93e7c797377fa13e381729',
'com.cedricwalter:tor-binary-geoip:fbd7656a262607e5a73016e048d5270cbabcd4639a1795b4b4e762df8877429d',
'com.github.JesusMcCloud:jtorctl:c6ef92e46074d8d26db718ce0fe4b64b8cf7b934b7377d164c5d613b4cd7b847',
'org.apache.commons:commons-compress:a778bbd659722889245fc52a0ec2873fbbb89ec661bc1ad3dc043c0757c784c4',
'com.github.JesusMcCloud:jtorctl:ba71601cbe50474ccc39a17bc6f7880c1412d8d19b94d37aee69ea2917f72046',
'org.apache.commons:commons-compress:5f2df1e467825e4cac5996d44890c4201c000b43c0b23cffc0782d28a0beb9b0',
'org.tukaani:xz:a594643d73cc01928cf6ca5ce100e094ea9d73af760a5d4fb6b75fa673ecec96',
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
'net.jcip:jcip-annotations:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
'org.bitcoinj:orchid:f836325cfa0466a011cb755c9b0fee6368487a2352eb45f4306ad9e4c18de080',
'com.squareup.okhttp:okhttp:b4c943138fcef2bcc9d2006b2250c4aabbedeafc5947ed7c0af7fd103ceb2707',
'org.objenesis:objenesis:5e168368fbc250af3c79aa5fef0c3467a2d64e5a7bd74005f25d8399aeb0708d',
'com.squareup.okio:okio:114bdc1f47338a68bcbc95abf2f5cdc72beeec91812f2fcd7b521c1937876266',
]
}
4 changes: 4 additions & 0 deletions p2p/src/main/java/bisq/network/NetworkOptionKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ 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";
public static final String EXTERNAL_TOR_PASSWORD = "torControlPassword";
public static final String EXTERNAL_TOR_COOKIE_FILE = "torControlCookieFile";
public static final String EXTERNAL_TOR_USE_SAFECOOKIE = "torControlUseSafeCookieAuth";
}
13 changes: 11 additions & 2 deletions p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
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;
Expand All @@ -44,10 +46,17 @@ public NetworkNodeProvider(NetworkProtoResolver networkProtoResolver,
@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,
@Named(NetworkOptionKeys.EXTERNAL_TOR_PASSWORD) String password,
@Named(NetworkOptionKeys.EXTERNAL_TOR_COOKIE_FILE) String cookieFile,
@Named(NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE) boolean useSafeCookieAuthentication ) {
networkNode = useLocalhostForP2P ?
new LocalhostNetworkNode(address, port, networkProtoResolver) :
new TorNetworkNode(port, torDir, networkProtoResolver, bridgeAddressProvider, torrcFile, torrcOptions);
new TorNetworkNode(port, torDir, networkProtoResolver,
!controlPort.isEmpty() ?
new RunningTor(torDir, Integer.parseInt(controlPort), password, cookieFile, useSafeCookieAuthentication) :
new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider.getBridgeAddresses()));
}

@Override
Expand Down
4 changes: 4 additions & 0 deletions p2p/src/main/java/bisq/network/p2p/P2PModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,9 @@ protected void configure() {
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));
bindConstant().annotatedWith(named(NetworkOptionKeys.EXTERNAL_TOR_PASSWORD)).to(environment.getRequiredProperty(NetworkOptionKeys.EXTERNAL_TOR_PASSWORD));
bindConstant().annotatedWith(named(NetworkOptionKeys.EXTERNAL_TOR_COOKIE_FILE)).to(environment.getRequiredProperty(NetworkOptionKeys.EXTERNAL_TOR_COOKIE_FILE));
bindConstant().annotatedWith(named(NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE)).to(environment.containsProperty(NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE) ? true : false);
}
}
121 changes: 121 additions & 0 deletions p2p/src/main/java/bisq/network/p2p/network/NewTor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* 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.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.stream.Collectors;

import org.berndpruenster.netlayer.tor.NativeTor;
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;

/**
* This class creates a brand new instance of the Tor onion router.
*
* When asked, the class checks, whether command line parameters such as
* --torrcFile and --torrcOptions are set and if so, takes these settings into
* account. Then, a fresh set of Tor binaries is installed and Tor is launched.
* Finally, a {@link Tor} instance is returned for further use.
*
* @author Florian Reimair
*
*/
public class NewTor extends TorMode {

private static final Logger log = LoggerFactory.getLogger(NewTor.class);

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) {
this.torrcFile = torrcFile;
this.torrcOptions = torrcOptions;
this.bridgeEntries = bridgeEntries;
this.torWorkikngDirectory = torWorkingDirectory;
}

@Override
public Tor getTor() throws IOException, TorCtlException {
long ts1 = new Date().getTime();

if (bridgeEntries != null)
log.info("Using bridges: {}", bridgeEntries.stream().collect(Collectors.joining(",")));

Torrc override = null;

// check if the user wants to provide his own torrc file
if (!"".equals(torrcFile)) {
try {
override = new Torrc(new FileInputStream(new File(torrcFile)));
} catch (IOException e) {
log.error("custom torrc file not found ('{}'). Proceeding with defaults.", torrcFile);
}
}

// check if the user wants to temporarily add to the default torrc file
LinkedHashMap<String, String> torrcOptionsMap = new LinkedHashMap<>();
if (!"".equals(torrcOptions)) {
Arrays.asList(torrcOptions.split(",")).forEach(line -> {
line = line.trim();
if (line.matches("^[^\\s]+\\s.+")) {
String[] tmp = line.split("\\s", 2);
torrcOptionsMap.put(tmp[0].trim(), tmp[1].trim());
} else {
log.error("custom torrc override parse error ('{}'). Proceeding without custom overrides.", line);
torrcOptionsMap.clear();
}
});
}

// assemble final override options
if (!torrcOptionsMap.isEmpty())
// check for custom torrcFile
if (override != null)
// and merge the contents
override = new Torrc(override.getInputStream$tor_native(), torrcOptionsMap);
else
override = new Torrc(torrcOptionsMap);

log.info("Starting tor");
NativeTor result = new NativeTor(torWorkikngDirectory, bridgeEntries, override);
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 "";
}

}
Loading