summaryrefslogtreecommitdiff
path: root/app/src/main/java/se/leap/bitmaskclient/eip
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/se/leap/bitmaskclient/eip')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EIP.java13
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java37
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java102
3 files changed, 137 insertions, 15 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
index 74226250..d632c09e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -84,6 +84,7 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE;
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports;
import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_PROFILE;
import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE;
@@ -317,7 +318,12 @@ public final class EIP extends JobIntentService implements Observer {
Connection.TransportType transportType = getUsePluggableTransports(this) ? OBFS4 : OPENVPN;
if (gateway == null ||
(profile = gateway.getProfile(transportType)) == null) {
- setErrorResult(result, NO_MORE_GATEWAYS.toString(), getStringResourceForNoMoreGateways(), getString(R.string.app_name));
+ String preferredLocation = getPreferredCity(getApplicationContext());
+ if (preferredLocation != null) {
+ setErrorResult(result, NO_MORE_GATEWAYS.toString(), getStringResourceForNoMoreGateways(), getString(R.string.app_name), preferredLocation);
+ } else {
+ setErrorResult(result, NO_MORE_GATEWAYS.toString(), getStringResourceForNoMoreGateways(), getString(R.string.app_name));
+ }
return;
}
@@ -527,7 +533,10 @@ public final class EIP extends JobIntentService implements Observer {
private @StringRes int getStringResourceForNoMoreGateways() {
- if (ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports()) {
+ boolean isManualGatewaySelection = PreferenceHelper.getLastConnectedVpnProfile(getApplicationContext()) != null;
+ if (isManualGatewaySelection) {
+ return R.string.warning_no_more_gateways_manual_gw_selection;
+ } else if (ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports()) {
if (PreferenceHelper.getUsePluggableTransports(getApplicationContext())) {
return R.string.warning_no_more_gateways_use_ovpn;
} else {
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
index 6b44856e..78b33355 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -17,6 +17,7 @@
package se.leap.bitmaskclient.eip;
import android.content.Context;
+
import androidx.annotation.NonNull;
import com.google.gson.Gson;
@@ -34,12 +35,14 @@ import de.blinkt.openvpn.core.ConfigParser;
import de.blinkt.openvpn.core.connection.Connection;
import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+import static se.leap.bitmaskclient.base.models.Constants.FULLNESS;
import static se.leap.bitmaskclient.base.models.Constants.HOST;
import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS;
import static se.leap.bitmaskclient.base.models.Constants.LOCATION;
import static se.leap.bitmaskclient.base.models.Constants.LOCATIONS;
import static se.leap.bitmaskclient.base.models.Constants.NAME;
import static se.leap.bitmaskclient.base.models.Constants.OPENVPN_CONFIGURATION;
+import static se.leap.bitmaskclient.base.models.Constants.OVERLOAD;
import static se.leap.bitmaskclient.base.models.Constants.TIMEZONE;
import static se.leap.bitmaskclient.base.models.Constants.VERSION;
@@ -59,7 +62,9 @@ public class Gateway {
private JSONObject generalConfiguration;
private JSONObject secrets;
private JSONObject gateway;
+ private JSONObject load;
+ // the location of a gateway is its name
private String name;
private int timezone;
private int apiVersion;
@@ -71,9 +76,15 @@ public class Gateway {
*/
public Gateway(JSONObject eipDefinition, JSONObject secrets, JSONObject gateway, Context context)
throws ConfigParser.ConfigParseError, JSONException, IOException {
+ this(eipDefinition, secrets, gateway, null, context);
+ }
+
+ public Gateway(JSONObject eipDefinition, JSONObject secrets, JSONObject gateway, JSONObject load, Context context)
+ throws ConfigParser.ConfigParseError, JSONException, IOException {
this.gateway = gateway;
this.secrets = secrets;
+ this.load = load;
generalConfiguration = getGeneralConfiguration(eipDefinition);
timezone = getTimezone(eipDefinition);
@@ -82,6 +93,10 @@ public class Gateway {
vpnProfiles = createVPNProfiles(context);
}
+ public void updateLoad(JSONObject load) {
+ this.load = load;
+ }
+
private void addProfileInfos(Context context, HashMap<Connection.TransportType, VpnProfile> profiles) {
Set<String> excludedAppsVpn = PreferenceHelper.getExcludedApps(context);
for (VpnProfile profile : profiles.values()) {
@@ -133,6 +148,26 @@ public class Gateway {
}
}
+ public boolean hasLoadInfo() {
+ return load != null;
+ }
+
+ public double getFullness() {
+ try {
+ return load.getDouble(FULLNESS);
+ } catch (JSONException | NullPointerException e) {
+ return 0;
+ }
+ }
+
+ public boolean isOverloaded() {
+ try {
+ return load.getBoolean(OVERLOAD);
+ } catch (JSONException | NullPointerException e) {
+ return false;
+ }
+ }
+
/**
* Create and attach the VpnProfile to our gateway object
*/
@@ -156,7 +191,7 @@ public class Gateway {
return vpnProfiles.get(transportType);
}
- public boolean suppoortsTransport(Connection.TransportType transportType) {
+ public boolean supportsTransport(Connection.TransportType transportType) {
return vpnProfiles.get(transportType) != null;
}
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 a5d4c416..77ecfc5f 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,9 @@
package se.leap.bitmaskclient.eip;
import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
@@ -28,6 +31,8 @@ import org.json.JSONObject;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@@ -35,14 +40,19 @@ import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.ConfigParser;
import de.blinkt.openvpn.core.VpnStatus;
import de.blinkt.openvpn.core.connection.Connection;
+import se.leap.bitmaskclient.base.models.Location;
import se.leap.bitmaskclient.base.models.Provider;
import se.leap.bitmaskclient.base.models.ProviderObservable;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS;
+import static se.leap.bitmaskclient.base.models.Constants.HOST;
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY;
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Constants.SORTED_GATEWAYS;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports;
/**
@@ -67,24 +77,56 @@ public class GatewaysManager {
* @return the n closest Gateway
*/
public Gateway select(int nClosest) {
- Connection.TransportType transportType = getUsePluggableTransports(context) ? OBFS4 : OPENVPN;
+ String selectedCity = getPreferredCity(context);
+ return select(nClosest, selectedCity);
+ }
+ public Gateway select(int nClosest, String city) {
+ Connection.TransportType transportType = getUsePluggableTransports(context) ? OBFS4 : OPENVPN;
if (presortedList.size() > 0) {
- return getGatewayFromPresortedList(nClosest, transportType);
+ return getGatewayFromPresortedList(nClosest, transportType, city);
}
- return getGatewayFromTimezoneCalculation(nClosest, transportType);
+ return getGatewayFromTimezoneCalculation(nClosest, transportType, city);
}
+ public List<Location> getGatewayLocations() {
+ String selectedCity = PreferenceHelper.getPreferredCity(context);
+ HashMap<String, Integer> locationNames = new HashMap<>();
+ ArrayList<Location> locations = new ArrayList<>();
+ int n = 0;
+ Gateway gateway;
+ while ((gateway = select(n, null)) != null) {
+ if (!locationNames.containsKey(gateway.getName())) {
+ locationNames.put(gateway.getName(), locations.size());
+ Location location = new Location(
+ gateway.getName(),
+ gateway.getFullness(),
+ 1,
+ gateway.getName().equals(selectedCity));
+ locations.add(location);
+ } else {
+ int index = locationNames.get(gateway.getName());
+ Location location = locations.get(index);
+ location.averageLoad = (location.numberOfGateways * location.averageLoad + gateway.getFullness()) / (location.numberOfGateways + 1);
+ location.numberOfGateways += 1;
+ locations.set(index, location);
+ }
+ n++;
+ }
+
+ return locations;
+ }
- private Gateway getGatewayFromTimezoneCalculation(int nClosest, Connection.TransportType transportType) {
+ private Gateway getGatewayFromTimezoneCalculation(int nClosest, Connection.TransportType transportType, @Nullable String city) {
List<Gateway> list = new ArrayList<>(gateways.values());
GatewaySelector gatewaySelector = new GatewaySelector(list);
Gateway gateway;
int found = 0;
int i = 0;
while ((gateway = gatewaySelector.select(i)) != null) {
- if (gateway.suppoortsTransport(transportType)) {
+ if ((city == null && gateway.supportsTransport(transportType)) ||
+ (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) {
if (found == nClosest) {
return gateway;
}
@@ -95,10 +137,11 @@ public class GatewaysManager {
return null;
}
- private Gateway getGatewayFromPresortedList(int nClosest, Connection.TransportType transportType) {
+ private Gateway getGatewayFromPresortedList(int nClosest, Connection.TransportType transportType, @Nullable String city) {
int found = 0;
for (Gateway gateway : presortedList) {
- if (gateway.suppoortsTransport(transportType)) {
+ if ((city == null && gateway.supportsTransport(transportType)) ||
+ (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) {
if (found == nClosest) {
return gateway;
}
@@ -125,7 +168,7 @@ public class GatewaysManager {
Connection.TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN;
int nClosest = 0;
for (Gateway gateway : presortedList) {
- if (gateway.suppoortsTransport(transportType)) {
+ if (gateway.supportsTransport(transportType)) {
if (profile.equals(gateway.getProfile(transportType))) {
return nClosest;
}
@@ -142,7 +185,7 @@ public class GatewaysManager {
int nClosest = 0;
int i = 0;
while ((gateway = gatewaySelector.select(i)) != null) {
- if (gateway.suppoortsTransport(transportType)) {
+ if (gateway.supportsTransport(transportType)) {
if (profile.equals(gateway.getProfile(transportType))) {
return nClosest;
}
@@ -206,7 +249,7 @@ public class GatewaysManager {
}
}
- private void parseGatewaysFromGeoIpServiceJson(Provider provider) {
+ private void parseSimpleGatewayList(Provider provider) {
try {
JSONObject geoIpJson = provider.getGeoIpJson();
JSONArray gatewaylist = geoIpJson.getJSONArray(GATEWAYS);
@@ -222,10 +265,40 @@ public class GatewaysManager {
}
}
} catch (NullPointerException | JSONException npe) {
- npe.printStackTrace();
+ Log.d(TAG, "No valid geoip json found: " + npe.getLocalizedMessage());
}
}
+ private boolean hasSortedGatewaysWithLoad(@Nullable Provider provider) {
+ if (provider == null) {
+ return false;
+ }
+ JSONObject geoIpJson = provider.getGeoIpJson();
+ return geoIpJson.has(SORTED_GATEWAYS);
+ }
+
+ private void parseGatewaysWithLoad(Provider provider) {
+ try {
+ JSONObject geoIpJson = provider.getGeoIpJson();
+ JSONArray gatewaylist = geoIpJson.getJSONArray(SORTED_GATEWAYS);
+ for (int i = 0; i < gatewaylist.length(); i++) {
+ try {
+ JSONObject load = gatewaylist.getJSONObject(i);
+ String hostName = load.getString(HOST);
+ if (gateways.containsKey(hostName)) {
+ Gateway gateway = gateways.get(hostName);
+ gateway.updateLoad(load);
+ presortedList.add(gateway);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ } catch (NullPointerException | JSONException npe) {
+ npe.printStackTrace();
+ }
+ }
+
private JSONObject secretsConfigurationFromCurrentProvider() {
JSONObject result = new JSONObject();
Provider provider = ProviderObservable.getInstance().getCurrentProvider();
@@ -247,6 +320,11 @@ public class GatewaysManager {
private void configureFromCurrentProvider() {
Provider provider = ProviderObservable.getInstance().getCurrentProvider();
parseDefaultGateways(provider);
- parseGatewaysFromGeoIpServiceJson(provider);
+ if (hasSortedGatewaysWithLoad(provider)) {
+ parseGatewaysWithLoad(provider);
+ } else {
+ parseSimpleGatewayList(provider);
+ }
+
}
}