From c02cfd04253c5f5c839410d418789884b9bfb13a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 16 Mar 2021 22:09:07 +0100 Subject: Adapt gateway selector to check for nearest gateway within a city. Also optionally parse sortedGateways json object from menshen backend reponse --- .../leap/bitmaskclient/base/models/Constants.java | 4 ++ .../bitmaskclient/base/utils/PreferenceHelper.java | 9 +++ .../java/se/leap/bitmaskclient/eip/Gateway.java | 15 ++++- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 64 ++++++++++++++++++---- app/src/test/resources/riseup_geoip_v4.json | 35 ------------ app/src/test/resources/v4/riseup_geoip_v4.json | 35 ++++++++++++ 6 files changed, 115 insertions(+), 47 deletions(-) delete mode 100644 app/src/test/resources/riseup_geoip_v4.json create mode 100644 app/src/test/resources/v4/riseup_geoip_v4.json diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java index a0d295bd..3edfbb3d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java @@ -40,6 +40,7 @@ public interface Constants { String USE_IPv6_FIREWALL = "use_ipv6_firewall"; String RESTART_ON_UPDATE = "restart_on_update"; String LAST_UPDATE_CHECK = "last_update_check"; + String PREFERRED_CITY = "preferred_city"; ////////////////////////////////////////////// @@ -173,4 +174,7 @@ public interface Constants { String OPENVPN_CONFIGURATION = "openvpn_configuration"; String GATEWAYS = "gateways"; String HOST = "host"; + String SORTED_GATEWAYS = "sortedGateways"; + String FULLNESS = "fullness"; + String OVERLOAD = "overload"; } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index d31c7a20..19b30b4d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -24,6 +24,7 @@ import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_SHARED_PREFS_B import static se.leap.bitmaskclient.base.models.Constants.EXCLUDED_APPS; import static se.leap.bitmaskclient.base.models.Constants.LAST_UPDATE_CHECK; import static se.leap.bitmaskclient.base.models.Constants.LAST_USED_PROFILE; +import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_CONFIGURED; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_EIP_DEFINITION; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; @@ -203,6 +204,14 @@ public class PreferenceHelper { return getBoolean(context, ALWAYS_ON_SHOW_DIALOG, true); } + public static String getSelectedCity(Context context) { + return getString(context, PREFERRED_CITY, null); + } + + public static void setPreferredCity(Context context, String city) { + putString(context, PREFERRED_CITY, city); + } + public static JSONObject getEipDefinitionFromPreferences(SharedPreferences preferences) { JSONObject result = new JSONObject(); try { 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..763b5449 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; @@ -59,7 +60,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 +74,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 +91,10 @@ public class Gateway { vpnProfiles = createVPNProfiles(context); } + public void updateLoad(JSONObject load) { + this.load = load; + } + private void addProfileInfos(Context context, HashMap profiles) { Set excludedAppsVpn = PreferenceHelper.getExcludedApps(context); for (VpnProfile profile : profiles.values()) { @@ -156,7 +169,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..9a8ff0bd 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -18,6 +18,8 @@ package se.leap.bitmaskclient.eip; import android.content.Context; +import androidx.annotation.Nullable; + import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -41,8 +43,11 @@ import se.leap.bitmaskclient.base.models.ProviderObservable; 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.getSelectedCity; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePluggableTransports; /** @@ -68,23 +73,24 @@ public class GatewaysManager { */ public Gateway select(int nClosest) { Connection.TransportType transportType = getUsePluggableTransports(context) ? OBFS4 : OPENVPN; - + String selectedCity = getSelectedCity(context); if (presortedList.size() > 0) { - return getGatewayFromPresortedList(nClosest, transportType); + return getGatewayFromPresortedList(nClosest, transportType, selectedCity); } - return getGatewayFromTimezoneCalculation(nClosest, transportType); + return getGatewayFromTimezoneCalculation(nClosest, transportType, selectedCity); } - private Gateway getGatewayFromTimezoneCalculation(int nClosest, Connection.TransportType transportType) { + private Gateway getGatewayFromTimezoneCalculation(int nClosest, Connection.TransportType transportType, @Nullable String city) { List 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 +101,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 +132,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 +149,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 +213,7 @@ public class GatewaysManager { } } - private void parseGatewaysFromGeoIpServiceJson(Provider provider) { + private void parseSimpleGatewayList(Provider provider) { try { JSONObject geoIpJson = provider.getGeoIpJson(); JSONArray gatewaylist = geoIpJson.getJSONArray(GATEWAYS); @@ -226,6 +233,36 @@ public class GatewaysManager { } } + 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 +284,11 @@ public class GatewaysManager { private void configureFromCurrentProvider() { Provider provider = ProviderObservable.getInstance().getCurrentProvider(); parseDefaultGateways(provider); - parseGatewaysFromGeoIpServiceJson(provider); + if (hasSortedGatewaysWithLoad(provider)) { + parseGatewaysWithLoad(provider); + } else { + parseSimpleGatewayList(provider); + } + } } diff --git a/app/src/test/resources/riseup_geoip_v4.json b/app/src/test/resources/riseup_geoip_v4.json deleted file mode 100644 index 439d6ffb..00000000 --- a/app/src/test/resources/riseup_geoip_v4.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "ip":"51.158.144.32", - "cc":"FR", - "city":"Paris", - "lat":48.8628, - "lon":2.3292, - "gateways":[ - "mouette.riseup.net", - "hoatzin.riseup.net", - "zarapito.riseup.net", - "redshank.riseup.net" - ], - "sortedGateways": [ - { - "host": "mouette.riseup.net", - "fullness": 0.3, - "overload": false - }, - { - "host": "hoatzin.riseup.net", - "fullness": 0.36, - "overload": false - }, - { - "host": "zarapito.riseup.net", - "fullness": 0.57, - "overload": false - }, - { - "host": "zarapito.riseup.net", - "fullness": 0.92, - "overload": true - } - ] -} \ No newline at end of file diff --git a/app/src/test/resources/v4/riseup_geoip_v4.json b/app/src/test/resources/v4/riseup_geoip_v4.json new file mode 100644 index 00000000..439d6ffb --- /dev/null +++ b/app/src/test/resources/v4/riseup_geoip_v4.json @@ -0,0 +1,35 @@ +{ + "ip":"51.158.144.32", + "cc":"FR", + "city":"Paris", + "lat":48.8628, + "lon":2.3292, + "gateways":[ + "mouette.riseup.net", + "hoatzin.riseup.net", + "zarapito.riseup.net", + "redshank.riseup.net" + ], + "sortedGateways": [ + { + "host": "mouette.riseup.net", + "fullness": 0.3, + "overload": false + }, + { + "host": "hoatzin.riseup.net", + "fullness": 0.36, + "overload": false + }, + { + "host": "zarapito.riseup.net", + "fullness": 0.57, + "overload": false + }, + { + "host": "zarapito.riseup.net", + "fullness": 0.92, + "overload": true + } + ] +} \ No newline at end of file -- cgit v1.2.3