Refactored TorNetworkNode

This commit is contained in:
Florian Reimair 2018-11-16 17:49:04 +01:00
parent 136c268dbb
commit 68d813fc0c
7 changed files with 185 additions and 124 deletions

View file

@ -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:externaltor-SNAPSHOT') {
exclude(module: 'slf4j-api')
}
compile('com.github.JesusMcCloud.netlayer:tor.external:externaltor-SNAPSHOT') {
exclude(module: 'slf4j-api')
}
compile('org.apache.httpcomponents:httpclient:4.5.3') {

View file

@ -10,67 +10,3 @@
//
// See https://github.com/signalapp/gradle-witness#using-witness for further details.
dependencyVerification {
verify = [
'org.controlsfx:controlsfx:b98f1c9507c05600f80323674b33d15674926c71b0116f70085b62bdacf1e573',
'org.reactfx:reactfx:81ec8fe545d65661222735711114c2ce427e2187a65f1722e8ac4e4805beeca3',
'net.glxn:qrgen:c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882',
'de.jensd:fontawesomefx:73bacc991a0a6f5cf0f911767c8db161e0949dbca61e8371eb4342e3da96887b',
'de.jensd:fontawesomefx-materialdesignfont:dbad8dfdd1c85e298d5bbae25b2399aec9e85064db57b2427d10f3815aa98752',
'de.jensd:fontawesomefx-commons:5539bb3335ecb822dbf928546f57766eeb9f1516cc1417a064b5709629612149',
'com.googlecode.jcsv:jcsv:73ca7d715e90c8d2c2635cc284543b038245a34f70790660ed590e157b8714a2',
'com.github.sarxos:webcam-capture:d960b7ea8ec3ddf2df0725ef214c3fccc9699ea7772df37f544e1f8e4fd665f6',
'com.github.JesusMcCloud.netlayer:tor.native:0ad92f93c509a200a61cedbe0010d014f35ab57bcf131a4e268e1914e66be2e0',
'org.apache.httpcomponents:httpclient:db3d1b6c2d6a5e5ad47577ad61854e2f0e0936199b8e05eb541ed52349263135',
'net.sf.jopt-simple:jopt-simple:6f45c00908265947c39221035250024f2caec9a15c1c8cf553ebeecee289f342',
'org.fxmisc.easybind:easybind:666af296dda6de68751668a62661571b5238ac6f1c07c8a204fc6f902b222aaf',
'com.fasterxml.jackson.core:jackson-databind:fcf3c2b0c332f5f54604f7e27fa7ee502378a2cc5df6a944bbfae391872c32ff',
'com.fasterxml.jackson.core:jackson-core:39a74610521d7fb9eb3f437bb8739bbf47f6435be12d17bf954c731a0c6352bb',
'com.fasterxml.jackson.core:jackson-annotations:2566b3a6662afa3c6af4f5b25006cb46be2efc68f1b5116291d6998a8cdf7ed3',
'com.google.protobuf:protobuf-java:b5e2d91812d183c9f053ffeebcbcda034d4de6679521940a19064714966c2cd4',
'com.google.code.gson:gson:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32',
'com.googlecode.json-simple:json-simple:4e69696892b88b41c55d49ab2fdcc21eead92bf54acc588c0050596c3b75199c',
'org.springframework:spring-core:c451e8417adb2ffb2445636da5e44a2f59307c4100037a1fe387c3fba4f29b52',
'ch.qos.logback:logback-classic:e66efc674e94837344bc5b748ff510c37a44eeff86cbfdbf9e714ef2eb374013',
'org.slf4j:slf4j-api:3a4cd4969015f3beb4b5b4d81dbafc01765fb60b8a439955ca64d8476fef553e',
'ch.qos.logback:logback-core:4cd46fa17d77057b39160058df2f21ebbc2aded51d0edcc25d2c1cecc042a005',
'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',
'io.github.microutils:kotlin-logging:4992504fd3c6ecdf9ed10874b9508e758bb908af9e9d7af19a61e9afb6b7e27a',
'org.jetbrains.kotlin:kotlin-stdlib:f0595b9ed88ddc6fd66bddf68c56c6f2f6c4b17faa51e43e478acad32b05303e',
'org.jetbrains:annotations:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.bouncycastle:bcpg-jdk15on:de3355b821fc81dd32e1f3f560d5b3eca1c678fd2400011d0bfc69fb91bcde85',
'commons-io:commons-io:cc6a41dc3eaacc9e440a6bd0d2890b20d36b4ee408fe2d67122f328bb6e01581',
'org.apache.commons:commons-lang3:734c8356420cc8e30c795d64fd1fcd5d44ea9d90342a2cc3262c5158fbc6d98b',
'org.bouncycastle:bcprov-jdk15on:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'com.google.zxing:javase:0ec23e2ec12664ddd6347c8920ad647bb3b9da290f897a88516014b56cc77eb9',
'com.nativelibs4java:bridj:101bcd9b6637e6bc16e56deb3daefba62b1f5e8e9e37e1b3e56e3b5860d659cf',
'com.cedricwalter:tor-binary-macos:94f95e127c3409f870ee5c9fc642540c3ba865338cfaf3bb66d1e7e18c7fcee0',
'com.cedricwalter:tor-binary-linux32:af92b0b1ed40e3ff6c0f7b575ce44f19dfd666dfc6709e26cfb0f0bddca752eb',
'com.cedricwalter:tor-binary-linux64:f1fd937ef964e62abb13f62ddd53cd012316ecd09fecf1205e2db9f3333659c1',
'com.cedricwalter:tor-binary-windows:af7d67bc8f74b5c50f68b1aa5aa3e833470964f71882ee06ca40a32cd3dbc940',
'com.github.ravn:jsocks:3c71600af027b2b6d4244e4ad14d98ff2352a379410daebefff5d8cd48d742a4',
'org.apache.httpcomponents:httpcore:d7f853dee87680b07293d30855b39b9eb56c1297bd16ff1cd6f19ddb8fa745fb',
'commons-codec:commons-codec:ad19d2601c3abf0b946b5c3a4113e226a8c1e3305e395b90013b78dd94a723ce',
'commons-logging:commons-logging:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636',
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'aopalliance:aopalliance:0addec670fedcd3f113c5c8091d783280d23f75e3acb841b61a9cdb079376a08',
'com.github.bisq-network.bitcoinj:bitcoinj-core:15e0f4304dd92259c4e9ff0114cbeab7a79abb51a5817b422ce629d3a0a2d551',
'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',
'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',
]
}

View file

@ -21,6 +21,7 @@ import bisq.network.NetworkOptionKeys;
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.TorNetworkNode;
import bisq.common.proto.network.NetworkProtoResolver;
@ -47,7 +48,8 @@ public class NetworkNodeProvider implements Provider<NetworkNode> {
@Named(NetworkOptionKeys.TORRC_OPTIONS) String torrcOptions) {
networkNode = useLocalhostForP2P ?
new LocalhostNetworkNode(address, port, networkProtoResolver) :
new TorNetworkNode(port, torDir, networkProtoResolver, bridgeAddressProvider, torrcFile, torrcOptions);
new TorNetworkNode(port, torDir, networkProtoResolver, bridgeAddressProvider,
new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider.getBridgeAddresses()));
}
@Override

View file

@ -0,0 +1,112 @@
/*
* 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 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(TorNetworkNode.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();
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;
}
}

View file

@ -0,0 +1,46 @@
/*
* 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 org.berndpruenster.netlayer.tor.Tor;
import org.berndpruenster.netlayer.tor.TorCtlException;
/**
* Holds information on how tor should be created and delivers a respective
* {@link Tor} object when asked.
*
* @author Florian Reimair
*
*/
public abstract class TorMode {
/**
* 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
*/
public abstract Tor getTor() throws IOException, TorCtlException;
}

View file

@ -28,11 +28,9 @@ import bisq.common.storage.FileUtil;
import bisq.common.util.Utilities;
import org.berndpruenster.netlayer.tor.HiddenServiceSocket;
import org.berndpruenster.netlayer.tor.NativeTor;
import org.berndpruenster.netlayer.tor.Tor;
import org.berndpruenster.netlayer.tor.TorCtlException;
import org.berndpruenster.netlayer.tor.TorSocket;
import org.berndpruenster.netlayer.tor.Torrc;
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
@ -87,20 +85,18 @@ public class TorNetworkNode extends NetworkNode {
private MonadicBinding<Boolean> allShutDown;
private Tor tor;
private String torrcFile = "";
private String torrcOptions = "";
private TorMode torMode;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public TorNetworkNode(int servicePort, File torDir, NetworkProtoResolver networkProtoResolver, BridgeAddressProvider bridgeAddressProvider, String torrcFile, String torrcOptions) {
public TorNetworkNode(int servicePort, File torDir, NetworkProtoResolver networkProtoResolver,
BridgeAddressProvider bridgeAddressProvider, TorMode torMode) {
super(servicePort, networkProtoResolver);
this.torDir = torDir;
this.bridgeAddressProvider = bridgeAddressProvider;
this.torrcFile = torrcFile;
this.torrcOptions = torrcOptions;
this.torMode = torMode;
}
@ -251,53 +247,11 @@ public class TorNetworkNode extends NetworkNode {
ListenableFuture<Void> future = executorService.submit(() -> {
try {
long ts1 = new Date().getTime();
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(), torrcOptionsMap);
else
override = new Torrc(torrcOptionsMap);
log.info("Starting tor");
Tor.setDefault(new NativeTor(torDir, bridgeEntries, override));
log.info("\n################################################################\n" +
"Tor started after {} ms. Start publishing hidden service.\n" +
"################################################################",
(new Date().getTime() - ts1)); // takes usually a few seconds
// get tor
Tor.setDefault(torMode.getTor());
UserThread.execute(() -> setupListeners.stream().forEach(SetupListener::onTorNodeReady));
// start hidden service
long ts2 = new Date().getTime();
hiddenServiceSocket = new HiddenServiceSocket(localPort, "", servicePort);
hiddenServiceSocket.addReadyListener(socket -> {

View file

@ -26,7 +26,7 @@ import com.google.common.util.concurrent.SettableFuture;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import org.slf4j.Logger;
@ -53,7 +53,9 @@ 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(), null, "", "");
TorNetworkNode node1 = new TorNetworkNode(port, new File("torNode_" + port),
TestUtils.getNetworkProtoResolver(), null,
new NewTor(new File("torNode_" + port), "", "", new ArrayList<String>()));
node1.start(new SetupListener() {
@Override
public void onTorNodeReady() {
@ -79,7 +81,9 @@ public class TorNetworkNodeTest {
latch = new CountDownLatch(1);
int port2 = 9002;
TorNetworkNode node2 = new TorNetworkNode(port2, new File("torNode_" + port2), TestUtils.getNetworkProtoResolver(), null, "", "");
TorNetworkNode node2 = new TorNetworkNode(port2, new File("torNode_" + port2),
TestUtils.getNetworkProtoResolver(), null,
new NewTor(new File("torNode_" + port), "", "", new ArrayList<String>()));
node2.start(new SetupListener() {
@Override
public void onTorNodeReady() {
@ -136,7 +140,9 @@ public class TorNetworkNodeTest {
public void testTorNodeAfterBothReady() throws InterruptedException, IOException {
latch = new CountDownLatch(2);
int port = 9001;
TorNetworkNode node1 = new TorNetworkNode(port, new File("torNode_" + port), TestUtils.getNetworkProtoResolver(), null, "", "");
TorNetworkNode node1 = new TorNetworkNode(port, new File("torNode_" + port),
TestUtils.getNetworkProtoResolver(), null,
new NewTor(new File("torNode_" + port), "", "", new ArrayList<String>()));
node1.start(new SetupListener() {
@Override
public void onTorNodeReady() {
@ -161,7 +167,9 @@ public class TorNetworkNodeTest {
});
int port2 = 9002;
TorNetworkNode node2 = new TorNetworkNode(port2, new File("torNode_" + port), TestUtils.getNetworkProtoResolver(), null, "", "");
TorNetworkNode node2 = new TorNetworkNode(port2, new File("torNode_" + port),
TestUtils.getNetworkProtoResolver(), null,
new NewTor(new File("torNode_" + port), "", "", new ArrayList<String>()));
node2.start(new SetupListener() {
@Override
public void onTorNodeReady() {