diff --git a/bramble-android/build.gradle b/bramble-android/build.gradle index f2f2ba5de5f51e7cd07a3af9251ae5a532bc2c02..fe202931dc6b0d6792dd8cd161139653d9bdc3ce 100644 --- a/bramble-android/build.gradle +++ b/bramble-android/build.gradle @@ -11,6 +11,8 @@ android { versionCode 10011 versionName "1.0.11" consumerProguardFiles 'proguard-rules.txt' + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } compileOptions { @@ -31,6 +33,12 @@ dependencies { annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2' compileOnly 'javax.annotation:jsr250-api:1.0' + + androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput') + androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput') + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.0.2' + androidTestCompileOnly 'javax.annotation:jsr250-api:1.0' } dependencyVerification { diff --git a/bramble-android/src/androidTest/java/org/briarproject/bramble/IntegrationTestComponent.java b/bramble-android/src/androidTest/java/org/briarproject/bramble/IntegrationTestComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..bb5875ac3387e72e974766dc8d2203c198145a7f --- /dev/null +++ b/bramble-android/src/androidTest/java/org/briarproject/bramble/IntegrationTestComponent.java @@ -0,0 +1,23 @@ +package org.briarproject.bramble; + +import org.briarproject.bramble.event.EventModule; +import org.briarproject.bramble.plugin.PluginModule; +import org.briarproject.bramble.plugin.tor.BridgeTest; +import org.briarproject.bramble.system.SystemModule; + +import javax.inject.Singleton; + +import dagger.Component; + +@Singleton +@Component(modules = { + BrambleAndroidModule.class, + PluginModule.class, // needed for BackoffFactory + EventModule.class, + SystemModule.class, +}) +public interface IntegrationTestComponent { + + void inject(BridgeTest init); + +} diff --git a/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/BridgeTest.java b/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/BridgeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cb8c4bd3f76635b239d94ff65e9ff5c12c8a579e --- /dev/null +++ b/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/BridgeTest.java @@ -0,0 +1,102 @@ +package org.briarproject.bramble.plugin.tor; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.briarproject.bramble.DaggerIntegrationTestComponent; +import org.briarproject.bramble.IntegrationTestComponent; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.plugin.BackoffFactory; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.test.BrambleTestCase; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.logging.Logger; + +import javax.inject.Inject; +import javax.net.SocketFactory; + +import static java.util.Collections.singletonList; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.briarproject.bramble.plugin.tor.BridgeProviderImpl.BRIDGES; +import static org.briarproject.bramble.plugin.tor.TorNetworkMetadata.doBridgesWork; +import static org.briarproject.bramble.plugin.tor.TorNetworkMetadata.isTorProbablyBlocked; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + + +@RunWith(AndroidJUnit4.class) +public class BridgeTest extends BrambleTestCase { + + private final static String BRIDGE_COUNTRY = "VE"; + private final static long TIMEOUT = SECONDS.toMillis(23); + + private final static Logger LOG = + Logger.getLogger(BridgeTest.class.getSimpleName()); + + @Inject + EventBus eventBus; + @Inject + BackoffFactory backoffFactory; + @Inject + Clock clock; + + private final TorPluginFactory factory; + private TorPlugin plugin; + private int currentBridge = 0; + + public BridgeTest() { + IntegrationTestComponent component = + DaggerIntegrationTestComponent.builder().build(); + component.inject(this); + + Executor ioExecutor = Executors.newCachedThreadPool(); + ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1); + Context appContext = InstrumentationRegistry.getTargetContext(); + LocationUtils locationUtils = () -> BRIDGE_COUNTRY; + SocketFactory torSocketFactory = SocketFactory.getDefault(); + BridgeProvider bridgeProvider = + () -> singletonList(BRIDGES[currentBridge]); + factory = new TorPluginFactory(ioExecutor, scheduler, appContext, + locationUtils, eventBus, torSocketFactory, + backoffFactory, bridgeProvider, clock); + } + + @Test + public void testBridges() throws Exception { + assertTrue(isTorProbablyBlocked(BRIDGE_COUNTRY)); + assertTrue(doBridgesWork(BRIDGE_COUNTRY)); + assertTrue(BRIDGES.length > 0); + + for (int i = 0; i < BRIDGES.length; i++) { + plugin = (TorPlugin) factory.createPlugin(new TorPluginCallBack()); + testBridge(i); + } + } + + private void testBridge(int bridge) throws Exception { + currentBridge = bridge; + LOG.warning("Testing " + BRIDGES[currentBridge]); + try { + plugin.start(); + long start = clock.currentTimeMillis(); + while (clock.currentTimeMillis() - start < TIMEOUT) { + if (plugin.isRunning()) return; + clock.sleep(500); + } + if (!plugin.isRunning()) { + fail("Could not connect to Tor within timeout."); + } + } finally { + plugin.stop(); + } + } + +} diff --git a/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/TorPluginCallBack.java b/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/TorPluginCallBack.java new file mode 100644 index 0000000000000000000000000000000000000000..320e8f02fa24eb78109683485d70bc3379de688e --- /dev/null +++ b/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/TorPluginCallBack.java @@ -0,0 +1,54 @@ +package org.briarproject.bramble.plugin.tor; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; +import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.settings.Settings; + +@NotNullByDefault +public class TorPluginCallBack implements DuplexPluginCallback { + + @Override + public void incomingConnectionCreated(DuplexTransportConnection d) { + + } + + @Override + public void outgoingConnectionCreated(ContactId c, + DuplexTransportConnection d) { + + } + + @Override + public Settings getSettings() { + return new Settings(); + } + + @Override + public TransportProperties getLocalProperties() { + return new TransportProperties(); + } + + @Override + public void mergeSettings(Settings s) { + + } + + @Override + public void mergeLocalProperties(TransportProperties p) { + + } + + @Override + public void transportEnabled() { + + } + + @Override + public void transportDisabled() { + + } + +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java index 1ec2563482dab905b11ea6f6ea20422ef6390d05..16f2c6c597e622da32bd5a33dda9c2a16079778b 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java @@ -1,11 +1,23 @@ package org.briarproject.bramble; +import org.briarproject.bramble.plugin.tor.BridgeProvider; +import org.briarproject.bramble.plugin.tor.BridgeProviderImpl; import org.briarproject.bramble.system.AndroidSystemModule; +import javax.inject.Singleton; + import dagger.Module; +import dagger.Provides; @Module(includes = { AndroidSystemModule.class }) public class BrambleAndroidModule { + + @Provides + @Singleton + BridgeProvider provideBridgeProvider() { + return new BridgeProviderImpl(); + } + } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/BridgeProvider.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/BridgeProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..a6a74fcb5a92715367aa85bdf52f60b97f5dedfb --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/BridgeProvider.java @@ -0,0 +1,9 @@ +package org.briarproject.bramble.plugin.tor; + +import java.util.List; + +public interface BridgeProvider { + + List<String> getBridges(); + +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/BridgeProviderImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/BridgeProviderImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..c66da9c8a79b5ddf41cda95e0d89533d0538ba0d --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/BridgeProviderImpl.java @@ -0,0 +1,20 @@ +package org.briarproject.bramble.plugin.tor; + +import java.util.Arrays; +import java.util.List; + +public class BridgeProviderImpl implements BridgeProvider { + + final static String[] BRIDGES = { + "Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42", +// "Bridge 128.105.214.161:8081 1E326AAFB3FCB515015250D8FCCC8E37F91A153B", + "Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98", + "Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D", + }; + + @Override + public List<String> getBridges() { + return Arrays.asList(BRIDGES); + } + +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 5851c385acd4659f4f27f67dfdfe59d29d37629c..1079d7ffb3426f39b4950adb2e037cd958440977 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -50,7 +50,9 @@ import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -120,6 +122,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private final Backoff backoff; private final DuplexPluginCallback callback; private final String architecture; + private final BridgeProvider bridgeProvider; private final int maxLatency, maxIdleTime, socketTimeout; private final ConnectionStatus connectionStatus; private final File torDirectory, torFile, geoIpFile, configFile; @@ -139,7 +142,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { Context appContext, LocationUtils locationUtils, SocketFactory torSocketFactory, Clock clock, Backoff backoff, DuplexPluginCallback callback, String architecture, - int maxLatency, int maxIdleTime) { + BridgeProvider bridgeProvider, int maxLatency, int maxIdleTime) { this.ioExecutor = ioExecutor; this.scheduler = scheduler; this.appContext = appContext; @@ -149,6 +152,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { this.backoff = backoff; this.callback = callback; this.architecture = architecture; + this.bridgeProvider = bridgeProvider; this.maxLatency = maxLatency; this.maxIdleTime = maxIdleTime; if (maxIdleTime > Integer.MAX_VALUE / 2) @@ -499,6 +503,17 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } } + private void enableBridges(boolean enable) throws IOException { + if (enable) { + Collection<String> conf = new ArrayList<>(); + conf.add("UseBridges 1"); + conf.addAll(bridgeProvider.getBridges()); + controlConnection.setConf(conf); + } else { + controlConnection.setConf("UseBridges", "0"); + } + } + @Override public void stop() { running = false; @@ -681,7 +696,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } else if (blocked) { if (doBridgesWork(country)) { LOG.info("Enabling network, using bridges"); - controlConnection.setConf("UseBridges", "1"); + enableBridges(true); enableNetwork(true); } else { LOG.info("Disabling network, country is blocked"); @@ -693,6 +708,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { enableNetwork(false); } else { LOG.info("Enabling network"); + enableBridges(false); enableNetwork(true); } } catch (IOException e) { diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPluginFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPluginFactory.java index c380cbb0c96b91ca415d4a300ea511e6ab0363b6..3472a5cd18983b6f018c65c3d6b8107728f15ef3 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPluginFactory.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPluginFactory.java @@ -43,12 +43,14 @@ public class TorPluginFactory implements DuplexPluginFactory { private final EventBus eventBus; private final SocketFactory torSocketFactory; private final BackoffFactory backoffFactory; + private final BridgeProvider bridgeProvider; private final Clock clock; public TorPluginFactory(Executor ioExecutor, ScheduledExecutorService scheduler, Context appContext, LocationUtils locationUtils, EventBus eventBus, SocketFactory torSocketFactory, BackoffFactory backoffFactory, + BridgeProvider bridgeProvider, Clock clock) { this.ioExecutor = ioExecutor; this.scheduler = scheduler; @@ -57,6 +59,7 @@ public class TorPluginFactory implements DuplexPluginFactory { this.eventBus = eventBus; this.torSocketFactory = torSocketFactory; this.backoffFactory = backoffFactory; + this.bridgeProvider = bridgeProvider; this.clock = clock; } @@ -95,7 +98,7 @@ public class TorPluginFactory implements DuplexPluginFactory { MAX_POLLING_INTERVAL, BACKOFF_BASE); TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext, locationUtils, torSocketFactory, clock, backoff, callback, - architecture, MAX_LATENCY, MAX_IDLE_TIME); + architecture, bridgeProvider, MAX_LATENCY, MAX_IDLE_TIME); eventBus.addListener(plugin); return plugin; } diff --git a/bramble-android/src/main/res/raw/torrc b/bramble-android/src/main/res/raw/torrc index d1f881dce723b65ea813650f596301922f996a0c..3d27a7f20593c2902a0620cdc0fe5f3906781ab9 100644 --- a/bramble-android/src/main/res/raw/torrc +++ b/bramble-android/src/main/res/raw/torrc @@ -4,8 +4,3 @@ DisableNetwork 1 RunAsDaemon 1 SafeSocks 1 SocksPort 59050 -UseBridges 0 -Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42 -Bridge 128.105.214.161:8081 1E326AAFB3FCB515015250D8FCCC8E37F91A153B -Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98 -Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java index 03470f4f264ebe8ff221bb33dd4d91579f811091..3cb86634842e0d1ce10e598190766cc3418efc61 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java @@ -25,6 +25,7 @@ import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.Scheduler; import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory; import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory; +import org.briarproject.bramble.plugin.tor.BridgeProvider; import org.briarproject.bramble.plugin.tor.TorPluginFactory; import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.StringUtils; @@ -99,14 +100,14 @@ public class AppModule { AndroidExecutor androidExecutor, SecureRandom random, SocketFactory torSocketFactory, BackoffFactory backoffFactory, Application app, LocationUtils locationUtils, EventBus eventBus, - Clock clock) { + BridgeProvider bridgeProvider, Clock clock) { Context appContext = app.getApplicationContext(); DuplexPluginFactory bluetooth = new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor, appContext, random, eventBus, backoffFactory); DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler, appContext, locationUtils, eventBus, torSocketFactory, - backoffFactory, clock); + backoffFactory, bridgeProvider, clock); DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor, scheduler, backoffFactory, appContext); Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);