summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java13
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java5
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java93
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java27
-rw-r--r--app/src/test/resources/ptdemo_obfs4hop_tcp_gateways.json3
6 files changed, 138 insertions, 4 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
index 52030ce3..ad95c823 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
@@ -55,6 +55,7 @@ public class GatewaySelector {
return offsets.isEmpty() ? null : offsets.firstEntry().getValue().iterator().next();
}
+ // calculateOffsets randomizes the order of Gateways with the same distance, e.g. from the same location
private TreeMap<Integer, Set<Gateway>> calculateOffsets() {
TreeMap<Integer, Set<Gateway>> offsets = new TreeMap<Integer, Set<Gateway>>();
int localOffset = getCurrentTimezone();
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
index 28766998..d114665b 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -17,6 +17,7 @@
package se.leap.bitmaskclient.eip;
import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
+import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_HOP;
import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
import static de.blinkt.openvpn.core.connection.Connection.TransportType.PT;
import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS;
@@ -121,6 +122,8 @@ public class GatewaysManager {
private ArrayList<Location> locations = new ArrayList<>();
private TransportType selectedTransport;
+ GatewaySelector gatewaySelector;
+
public GatewaysManager(Context context) {
this.context = context;
configureFromCurrentProvider();
@@ -147,7 +150,7 @@ public class GatewaysManager {
}
public GatewayOptions select(int nClosest, String city) {
- TransportType[] transportTypes = getUseBridges(context) ? new TransportType[]{OBFS4} : new TransportType[]{OPENVPN};
+ TransportType[] transportTypes = getUseBridges(context) ? new TransportType[]{OBFS4, OBFS4_HOP} : new TransportType[]{OPENVPN};
if (presortedList.size() > 0) {
return getGatewayFromPresortedList(nClosest, transportTypes, city);
}
@@ -276,7 +279,9 @@ public class GatewaysManager {
private GatewayOptions getGatewayFromTimezoneCalculation(int nClosest, TransportType[] transportTypes, @Nullable String city) {
List<Gateway> list = new ArrayList<>(gateways.values());
- GatewaySelector gatewaySelector = new GatewaySelector(list);
+ if (gatewaySelector == null) {
+ gatewaySelector = new GatewaySelector(list);
+ }
Gateway gateway;
int found = 0;
int i = 0;
@@ -341,7 +346,9 @@ public class GatewaysManager {
private int getPositionFromTimezoneCalculatedList(VpnProfile profile) {
TransportType transportType = profile.getTransportType();
- GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values()));
+ if (gatewaySelector == null) {
+ gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values()));
+ }
Gateway gateway;
int nClosest = 0;
int i = 0;
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
index 90ffb6b0..2c22d4f7 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
@@ -140,7 +140,12 @@ public class VpnConfigGenerator {
}
if (apiVersion >= 3) {
for (TransportType transportType : transports.keySet()) {
+ Transport transport = transports.get(transportType);
if (transportType.isPluggableTransport()) {
+ Transport.Options transportOptions = transport.getOptions();
+ if (!experimentalTransports && transportOptions != null && transportOptions.isExperimental()) {
+ continue;
+ }
try {
profiles.put(transportType, createProfile(transportType));
} catch (ConfigParser.ConfigParseError | NumberFormatException | JSONException | IOException e) {
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java
index 998ed2fd..ee6ccce5 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java
@@ -16,6 +16,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
import de.blinkt.openvpn.VpnProfile;
@@ -215,6 +216,88 @@ public class GatewaysManagerTest {
}
@Test
+ public void TestSelectN_select_includeExperimentalTransport_DecoupledPortHoppingGW() {
+ Provider provider = getProvider(null, null, null, null, null, null, "decoupled_pt_portHopping.eip-service.json", null);
+
+ MockHelper.mockProviderObservable(provider);
+ mockStatic(PreferenceHelper.class);
+ when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(true);
+ when(PreferenceHelper.allowExperimentalTransports(any(Context.class))).thenReturn(true);
+ GatewaysManager gatewaysManager = new GatewaysManager(mockContext);
+ ArrayList<String> hosts = new ArrayList<>();
+ hosts.add(gatewaysManager.select(0).gateway.getHost());
+ hosts.add(gatewaysManager.select(1).gateway.getHost());
+
+ assertTrue(hosts.contains("bridge-nyc1-02.bitmask-dev.leapvpn.net"));
+ assertTrue(hosts.contains("bridge-nyc1-01.bitmask-dev.leapvpn.net"));
+
+ }
+
+ @Test
+ public void TestSelectN_select_includeExperimentalTransport_DecoupledPortAndIPHoppingGW() {
+ Provider provider = getProvider(null, null, null, null, null, null, "decoupled_pt.eip-service.json", null);
+
+ MockHelper.mockProviderObservable(provider);
+ mockStatic(PreferenceHelper.class);
+ when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(true);
+ when(PreferenceHelper.allowExperimentalTransports(any(Context.class))).thenReturn(true);
+ GatewaysManager gatewaysManager = new GatewaysManager(mockContext);
+
+ ArrayList<String> hosts = new ArrayList<>();
+ hosts.add(gatewaysManager.select(0).gateway.getHost());
+ hosts.add(gatewaysManager.select(1).gateway.getHost());
+ assertTrue(hosts.contains("bridge-nyc1-02.bitmask-dev.leapvpn.net"));
+ assertTrue(hosts.contains("bridge-nyc1-01.bitmask-dev.leapvpn.net"));
+ }
+
+ @Test
+ public void TestSelectN_select_excludeExperimentalTransport_DecoupledPortHoppingGW() {
+ Provider provider = getProvider(null, null, null, null, null, null, "decoupled_pt_portHopping.eip-service.json", null);
+
+ MockHelper.mockProviderObservable(provider);
+ mockStatic(PreferenceHelper.class);
+ when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(true);
+ when(PreferenceHelper.allowExperimentalTransports(any(Context.class))).thenReturn(false);
+
+ for (int i = 0; i < 1000; i++) {
+ GatewaysManager gatewaysManager = new GatewaysManager(mockContext);
+ assertEquals("bridge-nyc1-01.bitmask-dev.leapvpn.net", gatewaysManager.select(0).gateway.getHost());
+ }
+ }
+
+ @Test
+ public void TestSelectN_select_excludeExperimentalTransport_DecoupledPortAndIPHoppingGW() {
+ Provider provider = getProvider(null, null, null, null, null, null, "decoupled_pt.eip-service.json", null);
+
+ MockHelper.mockProviderObservable(provider);
+ mockStatic(PreferenceHelper.class);
+ when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(true);
+ when(PreferenceHelper.allowExperimentalTransports(any(Context.class))).thenReturn(false);
+ GatewaysManager gatewaysManager = new GatewaysManager(mockContext);
+
+ assertEquals("bridge-nyc1-01.bitmask-dev.leapvpn.net", gatewaysManager.select(0).gateway.getHost());
+ assertNull(gatewaysManager.select(1));
+ }
+
+ @Test
+ public void TestSelectN_select_excludeExperimentalTransport_InGatewayHoppingPTBridge() {
+ Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_obfs4hop_tcp_gateways.json", null);
+
+ MockHelper.mockProviderObservable(provider);
+ mockStatic(PreferenceHelper.class);
+ when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(true);
+ when(PreferenceHelper.allowExperimentalTransports(any(Context.class))).thenReturn(false);
+ GatewaysManager gatewaysManager = new GatewaysManager(mockContext);
+
+ ArrayList<String> hosts = new ArrayList<>();
+ hosts.add(gatewaysManager.select(0).gateway.getHost());
+ hosts.add(gatewaysManager.select(1).gateway.getHost());
+
+ assertTrue(hosts.contains("pt.demo.bitmask.net"));
+ assertTrue(hosts.contains("manila.bitmask.net"));
+ }
+
+ @Test
public void testSelectN_selectFromPresortedGateways_returnsGatewaysInPresortedOrder() {
Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_three_mixed_gateways.json", "ptdemo_three_mixed_gateways.geoip.json");
@@ -555,6 +638,16 @@ public class GatewaysManagerTest {
Provider provider = getProvider(null, null, null, null, null, null, "decoupled_pt.eip-service.json", null);
MockHelper.mockProviderObservable(provider);
GatewaysManager gatewaysManager = new GatewaysManager(mockContext);
+ assertEquals(2, gatewaysManager.size());
+ }
+
+ @Test
+ public void testGatewayManagerFromCurrentProvider_decoupledBridgesIncludingExperimental_threeGateways() throws IOException, NullPointerException {
+ Provider provider = getProvider(null, null, null, null, null, null, "decoupled_pt.eip-service.json", null);
+ MockHelper.mockProviderObservable(provider);
+ mockStatic(PreferenceHelper.class);
+ when(PreferenceHelper.allowExperimentalTransports(any(Context.class))).thenReturn(true);
+ GatewaysManager gatewaysManager = new GatewaysManager(mockContext);
assertEquals(3, gatewaysManager.size());
}
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java
index 565e6396..93231055 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java
@@ -2,6 +2,7 @@ package se.leap.bitmaskclient.eip;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -33,6 +34,7 @@ import java.io.File;
import java.util.HashMap;
import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.core.ConfigParser;
import de.blinkt.openvpn.core.connection.Connection;
import de.blinkt.openvpn.core.connection.Obfs4Connection;
import de.blinkt.openvpn.core.connection.Obfs4HopConnection;
@@ -2041,6 +2043,7 @@ public class VpnConfigGeneratorTest {
generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_obfs4hop_tcp_gateways.json"))).getJSONObject(OPENVPN_CONFIGURATION);
VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration();
configuration.apiVersion = 3;
+ configuration.experimentalTransports = true;
vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration);
HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles();
assertTrue(vpnProfiles.containsKey(OBFS4_HOP) && ((Obfs4HopConnection)vpnProfiles.get(OBFS4_HOP).mConnections[0]).getObfs4Options().transport.getProtocols()[0].equals("tcp"));
@@ -2053,6 +2056,7 @@ public class VpnConfigGeneratorTest {
generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_obfs4hop_kcp_gateways.json"))).getJSONObject(OPENVPN_CONFIGURATION);
VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration();
configuration.apiVersion = 3;
+ configuration.experimentalTransports = true;
vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration);
HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles();
assertTrue(vpnProfiles.containsKey(OBFS4_HOP) && ((Obfs4HopConnection)vpnProfiles.get(OBFS4_HOP).mConnections[0]).getObfs4Options().transport.getProtocols()[0].equals("kcp"));
@@ -2066,6 +2070,7 @@ public class VpnConfigGeneratorTest {
generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("decoupled_pt_portHopping.eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION);
VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration();
configuration.apiVersion = 3;
+ configuration.experimentalTransports = true;
vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration);
HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles();
System.out.println(vpnProfiles.get(OBFS4_HOP).getConfigFile(context, false));
@@ -2079,6 +2084,7 @@ public class VpnConfigGeneratorTest {
generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("decoupled_pt_portHopping.eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION);
VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration();
configuration.apiVersion = 3;
+ configuration.experimentalTransports = true;
vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration);
HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles();
System.out.println(vpnProfiles.get(OBFS4_HOP).getConfigFile(context, false));
@@ -2091,6 +2097,7 @@ public class VpnConfigGeneratorTest {
generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("decoupled_pt.eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION);
VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration();
configuration.apiVersion = 3;
+ configuration.experimentalTransports = true;
vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration);
HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles();
assertTrue(vpnProfiles.containsKey(OBFS4));
@@ -2105,6 +2112,7 @@ public class VpnConfigGeneratorTest {
generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("decoupled_pt.eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION);
VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration();
configuration.apiVersion = 3;
+ configuration.experimentalTransports = true;
vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration);
HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles();
assertTrue(vpnProfiles.containsKey(OBFS4_HOP));
@@ -2114,12 +2122,31 @@ public class VpnConfigGeneratorTest {
}
@Test
+ public void testGenerateVpnProfile_noExperimental_skipObfs4Hop() throws Exception {
+ when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(true);
+ gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("decoupled_pt.eip-service.json"))).getJSONArray("gateways").getJSONObject(2);
+ generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("decoupled_pt.eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION);
+ VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration();
+ configuration.apiVersion = 3;
+ configuration.experimentalTransports = false;
+ vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration);
+ Exception exception = null;
+ try {
+ vpnConfigGenerator.generateVpnProfiles();
+ } catch (ConfigParser.ConfigParseError e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ }
+
+ @Test
public void testGenerateVpnProfile_obfs4hop_onlyPortHopping_decoupled() throws Exception {
when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(true);
gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("decoupled_pt_portHopping.eip-service.json"))).getJSONArray("gateways").getJSONObject(2);
generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("decoupled_pt_portHopping.eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION);
VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration();
configuration.apiVersion = 3;
+ configuration.experimentalTransports = true;
vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration);
HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles();
assertTrue(vpnProfiles.containsKey(OBFS4_HOP));
diff --git a/app/src/test/resources/ptdemo_obfs4hop_tcp_gateways.json b/app/src/test/resources/ptdemo_obfs4hop_tcp_gateways.json
index 6a748a4f..34bcecb3 100644
--- a/app/src/test/resources/ptdemo_obfs4hop_tcp_gateways.json
+++ b/app/src/test/resources/ptdemo_obfs4hop_tcp_gateways.json
@@ -66,7 +66,8 @@
{
"type":"openvpn",
"protocols":[
- "tcp"
+ "tcp",
+ "udp"
],
"ports":[
"1195"