diff options
Diffstat (limited to 'app/src/main/java/se/leap/bitmaskclient/eip')
4 files changed, 177 insertions, 110 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 46f91781..b3efd21f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -16,6 +16,36 @@ */ package se.leap.bitmaskclient.eip; +import static android.app.Activity.RESULT_CANCELED; +import static android.app.Activity.RESULT_OK; +import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; +import static se.leap.bitmaskclient.R.string.warning_client_parsing_error_gateways; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.base.models.Constants.CLEARLOG; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_CHECK_CERT_VALIDITY; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_IS_RUNNING; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_ALWAYS_ON_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_BLOCKING_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES; +import static se.leap.bitmaskclient.base.models.Constants.EIP_N_CLOSEST_GATEWAY; +import static se.leap.bitmaskclient.base.models.Constants.EIP_RECEIVER; +import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT; +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.eip.EIP.EIPErrors.ERROR_INVALID_PROFILE; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_VPN_PREPARE; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.NO_MORE_GATEWAYS; +import static se.leap.bitmaskclient.eip.EipResultBroadcast.tellToReceiverOrBroadcast; + import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; @@ -31,6 +61,7 @@ import android.os.ResultReceiver; import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.WorkerThread; import androidx.core.app.JobIntentService; @@ -57,42 +88,10 @@ import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.OnBootReceiver; import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.models.Pair; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import static android.app.Activity.RESULT_CANCELED; -import static android.app.Activity.RESULT_OK; -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.R.string.vpn_certificate_is_invalid; -import static se.leap.bitmaskclient.R.string.warning_client_parsing_error_gateways; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; -import static se.leap.bitmaskclient.base.models.Constants.CLEARLOG; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_CHECK_CERT_VALIDITY; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_IS_RUNNING; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_ALWAYS_ON_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_BLOCKING_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES; -import static se.leap.bitmaskclient.base.models.Constants.EIP_N_CLOSEST_GATEWAY; -import static se.leap.bitmaskclient.base.models.Constants.EIP_RECEIVER; -import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT; -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.getUseBridges; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_PROFILE; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_VPN_PREPARE; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.NO_MORE_GATEWAYS; -import static se.leap.bitmaskclient.eip.EipResultBroadcast.tellToReceiverOrBroadcast; - /** * EIP is the abstract base class for interacting with and managing the Encrypted * Internet Proxy connection. Connections are started, stopped, and queried through @@ -256,8 +255,8 @@ public final class EIP extends JobIntentService implements Observer { return; } - Gateway gateway = gatewaysManager.select(nClosestGateway); - launchActiveGateway(gateway, nClosestGateway, result); + Pair<Gateway, Connection.TransportType> gatewayTransportTypePair = gatewaysManager.select(nClosestGateway); + launchActiveGateway(gatewayTransportTypePair, nClosestGateway, result); if (result.containsKey(BROADCAST_RESULT_KEY) && !result.getBoolean(BROADCAST_RESULT_KEY)) { tellToReceiverOrBroadcast(this, EIP_ACTION_START, RESULT_CANCELED, result); } else { @@ -271,7 +270,7 @@ public final class EIP extends JobIntentService implements Observer { */ private void startEIPAlwaysOnVpn() { GatewaysManager gatewaysManager = new GatewaysManager(getApplicationContext()); - Gateway gateway = gatewaysManager.select(0); + Pair<Gateway, Connection.TransportType> gatewayTransportTypePair = gatewaysManager.select(0); Bundle result = new Bundle(); if (shouldUpdateVPNCertificate()) { @@ -280,7 +279,7 @@ public final class EIP extends JobIntentService implements Observer { ProviderObservable.getInstance().updateProvider(p); } - launchActiveGateway(gateway, 0, result); + launchActiveGateway(gatewayTransportTypePair, 0, result); if (result.containsKey(BROADCAST_RESULT_KEY) && !result.getBoolean(BROADCAST_RESULT_KEY)){ VpnStatus.logWarning("ALWAYS-ON VPN: " + getString(R.string.no_vpn_profiles_defined)); } @@ -324,13 +323,13 @@ public final class EIP extends JobIntentService implements Observer { /** * starts the VPN and connects to the given gateway * - * @param gateway to connect to + * @param gatewayTransportTypePair Pair of Gateway and associated transport used to connect */ - private void launchActiveGateway(Gateway gateway, int nClosestGateway, Bundle result) { + private void launchActiveGateway(@Nullable Pair<Gateway, Connection.TransportType> gatewayTransportTypePair, int nClosestGateway, Bundle result) { VpnProfile profile; - Connection.TransportType transportType = getUseBridges(this) ? OBFS4 : OPENVPN; - if (gateway == null || - (profile = gateway.getProfile(transportType)) == null) { + + if (gatewayTransportTypePair == null || gatewayTransportTypePair.first == null || + (profile = gatewayTransportTypePair.first.getProfile(gatewayTransportTypePair.second)) == null) { String preferredLocation = getPreferredCity(getApplicationContext()); if (preferredLocation != null) { setErrorResult(result, NO_MORE_GATEWAYS.toString(), getStringResourceForNoMoreGateways(), getString(R.string.app_name), preferredLocation); 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 60507363..e9281609 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -16,6 +16,17 @@ */ package se.leap.bitmaskclient.eip; +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; + import android.content.Context; import androidx.annotation.NonNull; @@ -36,17 +47,6 @@ import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.base.utils.ConfigHelper; 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; - /** * Gateway provides objects defining gateways and their metadata. * Each instance contains a VpnProfile for OpenVPN specific data and member @@ -175,7 +175,8 @@ public class Gateway { private @NonNull HashMap<Connection.TransportType, VpnProfile> createVPNProfiles(Context context) throws ConfigParser.ConfigParseError, IOException, JSONException { boolean preferUDP = PreferenceHelper.getPreferUDP(context); - VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway, apiVersion, preferUDP); + boolean allowExperimentalTransports = PreferenceHelper.allowExperimentalTransports(context); + VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway, apiVersion, preferUDP, allowExperimentalTransports); HashMap<Connection.TransportType, VpnProfile> profiles = vpnConfigurationGenerator.generateVpnProfiles(); addProfileInfos(context, profiles); return profiles; @@ -194,6 +195,9 @@ public class Gateway { } public boolean supportsTransport(Connection.TransportType transportType) { + if (transportType == Connection.TransportType.PT) { + return supportsPluggableTransports(); + } return vpnProfiles.get(transportType) != null; } @@ -201,6 +205,15 @@ public class Gateway { return new HashSet<>(vpnProfiles.keySet()); } + public boolean supportsPluggableTransports() { + for (Connection.TransportType transportType : vpnProfiles.keySet()) { + if (transportType.isPluggableTransport() && vpnProfiles.get(transportType) != null) { + return true; + } + } + return false; + } + public int getTimezone() { return timezone; } 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 a11c7e34..db7dd38c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -43,12 +43,15 @@ import de.blinkt.openvpn.core.connection.Connection; import de.blinkt.openvpn.core.connection.Connection.TransportType; import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.base.models.Location; +import se.leap.bitmaskclient.base.models.Pair; 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.OBFS4_KCP; 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; import static se.leap.bitmaskclient.base.models.Constants.HOST; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; @@ -111,18 +114,18 @@ public class GatewaysManager { * select closest Gateway * @return the n closest Gateway */ - public Gateway select(int nClosest) { + public Pair<Gateway, TransportType> select(int nClosest) { String selectedCity = getPreferredCity(context); return select(nClosest, selectedCity); } - public Gateway select(int nClosest, String city) { - TransportType transportType = getUseBridges(context) ? OBFS4 : OPENVPN; + public Pair<Gateway, TransportType> select(int nClosest, String city) { + TransportType[] transportTypes = getUseBridges(context) ? new TransportType[]{OBFS4, OBFS4_KCP} : new TransportType[]{OPENVPN}; if (presortedList.size() > 0) { - return getGatewayFromPresortedList(nClosest, transportType, city); + return getGatewayFromPresortedList(nClosest, transportTypes, city); } - return getGatewayFromTimezoneCalculation(nClosest, transportType, city); + return getGatewayFromTimezoneCalculation(nClosest, transportTypes, city); } public void updateTransport(TransportType transportType) { @@ -158,7 +161,7 @@ public class GatewaysManager { } else { int index = locationNames.get(gateway.getName()); Location location = locations.get(index); - updateLocation(location, gateway, OBFS4); + updateLocation(location, gateway, PT); updateLocation(location, gateway, OPENVPN); locations.set(index, location); } @@ -173,9 +176,9 @@ public class GatewaysManager { private Location initLocation(String name, Gateway gateway, String preferredCity) { HashMap<TransportType, Double> averageLoadMap = new HashMap<>(); HashMap<TransportType, Integer> numberOfGatewaysMap = new HashMap<>(); - if (gateway.getSupportedTransports().contains(OBFS4)) { - averageLoadMap.put(OBFS4, gateway.getFullness()); - numberOfGatewaysMap.put(OBFS4, 1); + if (gateway.supportsPluggableTransports()) { + averageLoadMap.put(PT, gateway.getFullness()); + numberOfGatewaysMap.put(PT, 1); } if (gateway.getSupportedTransports().contains(OPENVPN)) { averageLoadMap.put(OPENVPN, gateway.getFullness()); @@ -189,7 +192,7 @@ public class GatewaysManager { } private void updateLocation(Location location, Gateway gateway, Connection.TransportType transportType) { - if (gateway.getSupportedTransports().contains(transportType)) { + if (gateway.supportsTransport(transportType)) { double averageLoad = location.getAverageLoad(transportType); int numberOfGateways = location.getNumberOfGateways(transportType); averageLoad = (numberOfGateways * averageLoad + gateway.getFullness()) / (numberOfGateways + 1); @@ -218,35 +221,40 @@ public class GatewaysManager { return Load.getLoadByValue(location.getAverageLoad(transportType)); } - private Gateway getGatewayFromTimezoneCalculation(int nClosest, TransportType transportType, @Nullable String city) { + private Pair<Gateway, TransportType> getGatewayFromTimezoneCalculation(int nClosest, TransportType[] transportTypes, @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 ((city == null && gateway.supportsTransport(transportType)) || - (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) { - if (found == nClosest) { - return gateway; + for (TransportType transportType : transportTypes) { + if ((city == null && gateway.supportsTransport(transportType)) || + (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) { + if (found == nClosest) { + return new Pair<>(gateway, transportType); + } + found++; } - found++; } i++; } return null; } - private Gateway getGatewayFromPresortedList(int nClosest, TransportType transportType, @Nullable String city) { + private Pair<Gateway, TransportType> getGatewayFromPresortedList(int nClosest, TransportType[] transportTypes, @Nullable String city) { int found = 0; for (Gateway gateway : presortedList) { - if ((city == null && gateway.supportsTransport(transportType)) || - (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) { - if (found == nClosest) { - return gateway; + for (TransportType transportType : transportTypes) { + if ((city == null && gateway.supportsTransport(transportType)) || + (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) { + if (found == nClosest) { + return new Pair<>(gateway, transportType); + } + found++; } - found++; } + } return null; } @@ -265,7 +273,7 @@ public class GatewaysManager { } private int getPositionFromPresortedList(VpnProfile profile) { - TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; + TransportType transportType = profile.getTransportType(); int nClosest = 0; for (Gateway gateway : presortedList) { if (gateway.supportsTransport(transportType)) { @@ -277,9 +285,9 @@ public class GatewaysManager { } return -1; } - + private int getPositionFromTimezoneCalculatedList(VpnProfile profile) { - TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; + TransportType transportType = profile.getTransportType(); GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values())); Gateway gateway; int nClosest = 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 5ddb74ab..58732713 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java @@ -16,6 +16,25 @@ */ 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_KCP; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; +import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES; +import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS; +import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS6; +import static se.leap.bitmaskclient.base.models.Constants.OPTIONS; +import static se.leap.bitmaskclient.base.models.Constants.PORTS; +import static se.leap.bitmaskclient.base.models.Constants.PROTOCOLS; +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.REMOTE; +import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT; +import static se.leap.bitmaskclient.base.models.Constants.TYPE; +import static se.leap.bitmaskclient.base.models.Constants.UDP; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.pluggableTransports.Shapeshifter.DISPATCHER_IP; +import static se.leap.bitmaskclient.pluggableTransports.Shapeshifter.DISPATCHER_PORT; + import androidx.annotation.VisibleForTesting; import org.json.JSONArray; @@ -31,50 +50,36 @@ 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.BuildConfig; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.utils.ConfigHelper; import se.leap.bitmaskclient.pluggableTransports.Obfs4Options; -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.CAPABILITIES; -import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS; -import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS6; -import static se.leap.bitmaskclient.base.models.Constants.OPTIONS; -import static se.leap.bitmaskclient.base.models.Constants.PORTS; -import static se.leap.bitmaskclient.base.models.Constants.PROTOCOLS; -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.REMOTE; -import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT; -import static se.leap.bitmaskclient.base.models.Constants.TYPE; -import static se.leap.bitmaskclient.base.models.Constants.UDP; -import static se.leap.bitmaskclient.pluggableTransports.Shapeshifter.DISPATCHER_IP; -import static se.leap.bitmaskclient.pluggableTransports.Shapeshifter.DISPATCHER_PORT; - public class VpnConfigGenerator { - private JSONObject generalConfiguration; - private JSONObject gateway; - private JSONObject secrets; + private final JSONObject generalConfiguration; + private final JSONObject gateway; + private final JSONObject secrets; private JSONObject obfs4Transport; - private int apiVersion; - private boolean preferUDP; + private JSONObject obfs4TKcpTransport; + private final int apiVersion; + private final boolean preferUDP; + private final boolean experimentalTransports; public final static String TAG = VpnConfigGenerator.class.getSimpleName(); private final String newLine = System.getProperty("line.separator"); // Platform new line - public VpnConfigGenerator(JSONObject generalConfiguration, JSONObject secrets, JSONObject gateway, int apiVersion, boolean preferUDP) throws ConfigParser.ConfigParseError { + public VpnConfigGenerator(JSONObject generalConfiguration, JSONObject secrets, JSONObject gateway, int apiVersion, boolean preferUDP, boolean experimentalTransports) throws ConfigParser.ConfigParseError { this.generalConfiguration = generalConfiguration; this.gateway = gateway; this.secrets = secrets; this.apiVersion = apiVersion; this.preferUDP = preferUDP; + this.experimentalTransports = experimentalTransports; checkCapabilities(); } public void checkCapabilities() throws ConfigParser.ConfigParseError { - try { if (apiVersion >= 3) { JSONArray supportedTransports = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT); @@ -82,7 +87,11 @@ public class VpnConfigGenerator { JSONObject transport = supportedTransports.getJSONObject(i); if (transport.getString(TYPE).equals(OBFS4.toString())) { obfs4Transport = transport; - break; + if (!experimentalTransports) { + break; + } + } else if (experimentalTransports && transport.getString(TYPE).equals(OBFS4_KCP.toString())) { + obfs4TKcpTransport = transport; } } } @@ -106,6 +115,13 @@ public class VpnConfigGenerator { e.printStackTrace(); } } + if (supportsObfs4Kcp()) { + try { + profiles.put(OBFS4_KCP, createProfile(OBFS4_KCP)); + } catch (ConfigParser.ConfigParseError | NumberFormatException | JSONException | IOException e) { + e.printStackTrace(); + } + } return profiles; } @@ -113,6 +129,10 @@ public class VpnConfigGenerator { return obfs4Transport != null; } + private boolean supportsObfs4Kcp() { + return obfs4TKcpTransport != null; + } + private String getConfigurationString(Connection.TransportType transportType) { return generalConfiguration() + newLine @@ -129,18 +149,28 @@ public class VpnConfigGenerator { ConfigParser icsOpenvpnConfigParser = new ConfigParser(); icsOpenvpnConfigParser.parseConfig(new StringReader(configuration)); if (transportType == OBFS4) { - icsOpenvpnConfigParser.setObfs4Options(getObfs4Options()); + icsOpenvpnConfigParser.setObfs4Options(getObfs4Options(obfs4Transport, false)); + } else if (transportType == OBFS4_KCP) { + icsOpenvpnConfigParser.setObfs4Options(getObfs4Options(obfs4TKcpTransport, true)); } return icsOpenvpnConfigParser.convertProfile(transportType); } - private Obfs4Options getObfs4Options() throws JSONException { - JSONObject transportOptions = obfs4Transport.getJSONObject(OPTIONS); + private Obfs4Options getObfs4Options(JSONObject transportJson, boolean useUdp) throws JSONException { + JSONObject transportOptions = transportJson.getJSONObject(OPTIONS); String iatMode = transportOptions.getString("iatMode"); String cert = transportOptions.getString("cert"); String port = obfs4Transport.getJSONArray(PORTS).getString(0); String ip = gateway.getString(IP_ADDRESS); - return new Obfs4Options(ip, port, cert, iatMode); + boolean udp = useUdp; + + if (BuildConfig.obfsvpn_pinning) { + cert = BuildConfig.obfsvpn_cert; + port = BuildConfig.obfsvpn_port; + ip = BuildConfig.obfsvpn_port; + udp = BuildConfig.obfsvpn_use_kcp; + } + return new Obfs4Options(ip, port, cert, iatMode, udp); } private String generalConfiguration() { @@ -321,10 +351,27 @@ public class VpnConfigGenerator { return; } + JSONArray ports = obfs4Transport.getJSONArray(PORTS); + if (ports.isNull(0)){ + VpnStatus.logError("Misconfigured provider: no ports defined in obfs4 transport JSON."); + return; + } + String route = "route " + ipAddress + " 255.255.255.255 net_gateway" + newLine; stringBuilder.append(route); - String remote = REMOTE + " " + DISPATCHER_IP + " " + DISPATCHER_PORT + " tcp" + newLine; - stringBuilder.append(remote); + if (useObfsVpn()) { + String remote; + if (BuildConfig.obfsvpn_pinning) { + remote = REMOTE + " " + BuildConfig.obfsvpn_ip + " " + BuildConfig.obfsvpn_port + newLine; + } else { + remote = REMOTE + " " + ipAddress + " " + ports.getString(0) + newLine; + } + + stringBuilder.append(remote); + } else { + String remote = REMOTE + " " + DISPATCHER_IP + " " + DISPATCHER_PORT + " tcp" + newLine; + stringBuilder.append(remote); + } } private String secretsConfiguration() { |