diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java index 7ecc2d7d2addb76e603f4a02583926dbd54f2ab4..50936b93197b13e5e3db8ede7498a4ef60179cac 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java @@ -11,6 +11,7 @@ public interface CircumventionProvider { enum BridgeType { DEFAULT_OBFS4, NON_DEFAULT_OBFS4, + VANILLA, MEEK } @@ -23,27 +24,27 @@ public interface CircumventionProvider { String[] BLOCKED = {"BY", "CN", "EG", "IR", "RU", "TM", "VE"}; /** - * Countries where obfs4 or meek bridge connections are likely to work. + * Countries where bridge connections are likely to work. * Should be a subset of {@link #BLOCKED} and the union of - * {@link #DEFAULT_OBFS4_BRIDGES}, {@link #NON_DEFAULT_OBFS4_BRIDGES} and + * {@link #DEFAULT_BRIDGES}, {@link #NON_DEFAULT_BRIDGES} and * {@link #MEEK_BRIDGES}. */ String[] BRIDGES = {"BY", "CN", "EG", "IR", "RU", "TM", "VE"}; /** - * Countries where default obfs4 bridges are likely to work. + * Countries where default obfs4 or vanilla bridges are likely to work. * Should be a subset of {@link #BRIDGES}. */ - String[] DEFAULT_OBFS4_BRIDGES = {"EG", "VE"}; + String[] DEFAULT_BRIDGES = {"EG", "VE"}; /** - * Countries where non-default obfs4 bridges are likely to work. + * Countries where non-default obfs4 or vanilla bridges are likely to work. * Should be a subset of {@link #BRIDGES}. */ - String[] NON_DEFAULT_OBFS4_BRIDGES = {"BY", "RU", "TM"}; + String[] NON_DEFAULT_BRIDGES = {"BY", "RU", "TM"}; /** - * Countries where obfs4 bridges won't work and meek is needed. + * Countries where obfs4 and vanilla bridges won't work and meek is needed. * Should be a subset of {@link #BRIDGES}. */ String[] MEEK_BRIDGES = {"CN", "IR"}; @@ -60,10 +61,11 @@ public interface CircumventionProvider { boolean doBridgesWork(String countryCode); /** - * Returns the best type of bridge connection for the given country, or - * {@link #DEFAULT_OBFS4_BRIDGES} if no bridge type is known to work. + * Returns the types of bridge connection that are suitable for the given + * country, or {@link #DEFAULT_BRIDGES} if no bridge type is known + * to work. */ - BridgeType getBestBridgeType(String countryCode); + List<BridgeType> getSuitableBridgeTypes(String countryCode); @IoExecutor List<String> getBridges(BridgeType type); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java index c05e78bd035d86612df129f941dd8f347e6be62b..fae5044bca1763cd96f50b632d364c96d8f16c81 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java @@ -14,10 +14,12 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4; +import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.VANILLA; @Immutable @NotNullByDefault @@ -30,9 +32,9 @@ class CircumventionProviderImpl implements CircumventionProvider { private static final Set<String> BRIDGE_COUNTRIES = new HashSet<>(asList(BRIDGES)); private static final Set<String> DEFAULT_OBFS4_BRIDGE_COUNTRIES = - new HashSet<>(asList(DEFAULT_OBFS4_BRIDGES)); - private static final Set<String> NON_DEFAULT_OBFS4_BRIDGE_COUNTRIES = - new HashSet<>(asList(NON_DEFAULT_OBFS4_BRIDGES)); + new HashSet<>(asList(DEFAULT_BRIDGES)); + private static final Set<String> NON_DEFAULT_BRIDGE_COUNTRIES = + new HashSet<>(asList(NON_DEFAULT_BRIDGES)); private static final Set<String> MEEK_COUNTRIES = new HashSet<>(asList(MEEK_BRIDGES)); @@ -51,15 +53,15 @@ class CircumventionProviderImpl implements CircumventionProvider { } @Override - public BridgeType getBestBridgeType(String countryCode) { + public List<BridgeType> getSuitableBridgeTypes(String countryCode) { if (DEFAULT_OBFS4_BRIDGE_COUNTRIES.contains(countryCode)) { - return DEFAULT_OBFS4; - } else if (NON_DEFAULT_OBFS4_BRIDGE_COUNTRIES.contains(countryCode)) { - return NON_DEFAULT_OBFS4; + return asList(DEFAULT_OBFS4, VANILLA); + } else if (NON_DEFAULT_BRIDGE_COUNTRIES.contains(countryCode)) { + return asList(NON_DEFAULT_OBFS4, VANILLA); } else if (MEEK_COUNTRIES.contains(countryCode)) { - return MEEK; + return singletonList(MEEK); } else { - return DEFAULT_OBFS4; + return asList(DEFAULT_OBFS4, VANILLA); } } @@ -73,12 +75,10 @@ class CircumventionProviderImpl implements CircumventionProvider { List<String> bridges = new ArrayList<>(); while (scanner.hasNextLine()) { String line = scanner.nextLine(); - boolean isDefaultObfs4 = line.startsWith("d "); - boolean isNonDefaultObfs4 = line.startsWith("n "); - boolean isMeek = line.startsWith("m "); - if ((type == DEFAULT_OBFS4 && isDefaultObfs4) || - (type == NON_DEFAULT_OBFS4 && isNonDefaultObfs4) || - (type == MEEK && isMeek)) { + if ((type == DEFAULT_OBFS4 && line.startsWith("d ")) || + (type == NON_DEFAULT_OBFS4 && line.startsWith("n ")) || + (type == VANILLA && line.startsWith("v ")) || + (type == MEEK && line.startsWith("m "))) { bridges.add(line.substring(2)); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index e71a9107ce9477be25a9c846946bcc43da03d02d..d23d328d076c200e5bee659e24dc776fda4847e1 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -92,7 +92,9 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3; import static org.briarproject.bramble.api.plugin.TorConstants.REASON_BATTERY; import static org.briarproject.bramble.api.plugin.TorConstants.REASON_COUNTRY_BLOCKED; import static org.briarproject.bramble.api.plugin.TorConstants.REASON_MOBILE_DATA; +import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK; +import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4; import static org.briarproject.bramble.plugin.tor.TorRendezvousCrypto.SEED_BYTES; import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.bramble.util.IoUtils.tryToClose; @@ -528,20 +530,24 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { controlConnection.setConf("DisableNetwork", enable ? "0" : "1"); } - private void enableBridges(boolean enable, BridgeType bridgeType) + private void enableBridges(boolean enable, List<BridgeType> bridgeTypes) throws IOException { if (enable) { Collection<String> conf = new ArrayList<>(); conf.add("UseBridges 1"); File obfs4File = getObfs4ExecutableFile(); - if (bridgeType == MEEK) { + if (bridgeTypes.contains(MEEK)) { conf.add("ClientTransportPlugin meek_lite exec " + obfs4File.getAbsolutePath()); - } else { + } + if (bridgeTypes.contains(DEFAULT_OBFS4) || + bridgeTypes.contains(NON_DEFAULT_OBFS4)) { conf.add("ClientTransportPlugin obfs4 exec " + obfs4File.getAbsolutePath()); } - conf.addAll(circumventionProvider.getBridges(bridgeType)); + for (BridgeType bridgeType : bridgeTypes) { + conf.addAll(circumventionProvider.getBridges(bridgeType)); + } controlConnection.setConf(conf); } else { controlConnection.setConf("UseBridges", "0"); @@ -831,8 +837,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { int reasonsDisabled = 0; boolean enableNetwork = false, enableBridges = false; boolean enableConnectionPadding = false; - BridgeType bridgeType = - circumventionProvider.getBestBridgeType(country); + List<BridgeType> bridgeTypes = + circumventionProvider.getSuitableBridgeTypes(country); if (!online) { LOG.info("Disabling network, device is offline"); @@ -861,10 +867,10 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { enableNetwork = true; if (network == PREF_TOR_NETWORK_WITH_BRIDGES || (automatic && bridgesWork)) { - if (ipv6Only) bridgeType = MEEK; + if (ipv6Only) bridgeTypes = singletonList(MEEK); enableBridges = true; if (LOG.isLoggable(INFO)) { - LOG.info("Using bridge type " + bridgeType); + LOG.info("Using bridge types " + bridgeTypes); } } else { LOG.info("Not using bridges"); @@ -882,7 +888,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { try { if (enableNetwork) { - enableBridges(enableBridges, bridgeType); + enableBridges(enableBridges, bridgeTypes); enableConnectionPadding(enableConnectionPadding); useIpv6(ipv6Only); } diff --git a/bramble-core/src/main/resources/bridges b/bramble-core/src/main/resources/bridges index a4f9d1e35ab2448445cb9dbfb63e55b14f8ffe94..101dd1ddea1bee7cb3aabe78e8ebbc83b6f75d63 100644 --- a/bramble-core/src/main/resources/bridges +++ b/bramble-core/src/main/resources/bridges @@ -19,4 +19,8 @@ n Bridge obfs4 70.34.242.31:443 7F026956402CDFF4BCBA8E11EE9C50E3FE0A2B72 cert=hP n Bridge obfs4 192.3.163.88:57145 DEB62DE9643E5956CA4FA78035B48C9BBABE7F29 cert=RMz2z9uVVrioUhx0A8xUmiftRe2RpcXiqIuDfisdIomcHDf82nzfn83X/ixGUiA4rLCAdw iat-mode=0 n Bridge obfs4 93.95.226.151:41185 460B0CFFC0CF1D965F3DE064E08BA1915E7C916A cert=inluPzp5Jp5OzZar1eQb4dcQ/YlAj/v0kHAUCoCr3rmLt03+pVuVTjoH4mRy4+acXpn+Gw iat-mode=0 n Bridge obfs4 120.29.217.52:5223 40FE3DB9800272F9CDC76422F8ED7883280EE96D cert=/71PS4l8c/XJ4DIItlH9xMqNvPFg2RUTrHvPlQWh48u5et8h/yyyjCcYphUadDsfBWpaGQ iat-mode=0 +v Bridge 5.45.96.40:9001 8723B591712AAA03FB92000370BD356AB4997FA7 +v Bridge 135.181.113.164:54444 74AF4CCA614C454B7D3E81FF8BACD78CEBC7D7DE +v Bridge 152.44.197.85:10507 FF07DF6B4720DA4C50F1A025662D50916D6223F6 +v Bridge 209.216.78.21:443 C870D381E7264CDB83BAEEBF074804808CCCDB8D m Bridge meek_lite 192.0.2.2:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com \ No newline at end of file diff --git a/bramble-core/src/test/java/org/briarproject/bramble/plugin/tor/CircumventionProviderTest.java b/bramble-core/src/test/java/org/briarproject/bramble/plugin/tor/CircumventionProviderTest.java index caecdd453f1e061c275b13e61b59db79b89ea28c..593275ed62803575e9339ffd4aaaff911192fa6f 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/plugin/tor/CircumventionProviderTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/tor/CircumventionProviderTest.java @@ -7,14 +7,16 @@ import java.util.HashSet; import java.util.Set; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BLOCKED; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BRIDGES; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4; -import static org.briarproject.bramble.plugin.tor.CircumventionProvider.DEFAULT_OBFS4_BRIDGES; +import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.VANILLA; +import static org.briarproject.bramble.plugin.tor.CircumventionProvider.DEFAULT_BRIDGES; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.MEEK_BRIDGES; -import static org.briarproject.bramble.plugin.tor.CircumventionProvider.NON_DEFAULT_OBFS4_BRIDGES; +import static org.briarproject.bramble.plugin.tor.CircumventionProvider.NON_DEFAULT_BRIDGES; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -27,37 +29,39 @@ public class CircumventionProviderTest extends BrambleTestCase { public void testInvariants() { Set<String> blocked = new HashSet<>(asList(BLOCKED)); Set<String> bridges = new HashSet<>(asList(BRIDGES)); - Set<String> defaultObfs4Bridges = - new HashSet<>(asList(DEFAULT_OBFS4_BRIDGES)); - Set<String> nonDefaultObfs4Bridges = - new HashSet<>(asList(NON_DEFAULT_OBFS4_BRIDGES)); + Set<String> defaultBridges = new HashSet<>(asList(DEFAULT_BRIDGES)); + Set<String> nonDefaultBridges = + new HashSet<>(asList(NON_DEFAULT_BRIDGES)); Set<String> meekBridges = new HashSet<>(asList(MEEK_BRIDGES)); // BRIDGES should be a subset of BLOCKED assertTrue(blocked.containsAll(bridges)); // BRIDGES should be the union of the bridge type sets - Set<String> union = new HashSet<>(defaultObfs4Bridges); - union.addAll(nonDefaultObfs4Bridges); + Set<String> union = new HashSet<>(defaultBridges); + union.addAll(nonDefaultBridges); union.addAll(meekBridges); assertEquals(bridges, union); // The bridge type sets should not overlap - assertEmptyIntersection(defaultObfs4Bridges, nonDefaultObfs4Bridges); - assertEmptyIntersection(defaultObfs4Bridges, meekBridges); - assertEmptyIntersection(nonDefaultObfs4Bridges, meekBridges); + assertEmptyIntersection(defaultBridges, nonDefaultBridges); + assertEmptyIntersection(defaultBridges, meekBridges); + assertEmptyIntersection(nonDefaultBridges, meekBridges); } @Test public void testGetBestBridgeType() { - for (String country : DEFAULT_OBFS4_BRIDGES) { - assertEquals(DEFAULT_OBFS4, provider.getBestBridgeType(country)); + for (String country : DEFAULT_BRIDGES) { + assertEquals(asList(DEFAULT_OBFS4, VANILLA), + provider.getSuitableBridgeTypes(country)); } - for (String country : NON_DEFAULT_OBFS4_BRIDGES) { - assertEquals(NON_DEFAULT_OBFS4, - provider.getBestBridgeType(country)); + for (String country : NON_DEFAULT_BRIDGES) { + assertEquals(asList(NON_DEFAULT_OBFS4, VANILLA), + provider.getSuitableBridgeTypes(country)); } for (String country : MEEK_BRIDGES) { - assertEquals(MEEK, provider.getBestBridgeType(country)); + assertEquals(singletonList(MEEK), + provider.getSuitableBridgeTypes(country)); } - assertEquals(DEFAULT_OBFS4, provider.getBestBridgeType("ZZ")); + assertEquals(asList(DEFAULT_OBFS4, VANILLA), + provider.getSuitableBridgeTypes("ZZ")); } private <T> void assertEmptyIntersection(Set<T> a, Set<T> b) { diff --git a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java index 29adedc3a70e0690356204f8a20a3eeacbd5f2f9..bcbe3ce14fbbea8f78ca078c0de8fe2d617422aa 100644 --- a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java +++ b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java @@ -47,6 +47,7 @@ import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_POR import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK; import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4; +import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.VANILLA; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled; @@ -74,6 +75,9 @@ public class BridgeTest extends BrambleTestCase { for (String bridge : provider.getBridges(NON_DEFAULT_OBFS4)) { states.add(new Params(bridge, NON_DEFAULT_OBFS4, stats, false)); } + for (String bridge : provider.getBridges(VANILLA)) { + states.add(new Params(bridge, VANILLA, stats, false)); + } for (String bridge : provider.getBridges(MEEK)) { states.add(new Params(bridge, MEEK, stats, true)); } @@ -99,8 +103,6 @@ public class BridgeTest extends BrambleTestCase { @Inject ResourceProvider resourceProvider; @Inject - CircumventionProvider circumventionProvider; - @Inject BatteryManager batteryManager; @Inject EventBus eventBus; @@ -150,8 +152,8 @@ public class BridgeTest extends BrambleTestCase { } @Override - public BridgeType getBestBridgeType(String countryCode) { - return params.bridgeType; + public List<BridgeType> getSuitableBridgeTypes(String countryCode) { + return singletonList(params.bridgeType); } @Override