From f6017ab12d0c472ab4f22e81d9a768ad2510b134 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 31 Mar 2023 15:46:09 +0200 Subject: don't handle obfs4 over kcp as a separate pluggable transport, instead 'tcp' and 'kcp' become valid protocols for obfs4 --- .../leap/bitmaskclient/base/models/Provider.java | 23 +++++++++----- .../main/java/se/leap/bitmaskclient/eip/EIP.java | 17 +++++----- .../java/se/leap/bitmaskclient/eip/Gateway.java | 7 +++-- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 33 ++++++++++++-------- .../leap/bitmaskclient/eip/VpnConfigGenerator.java | 36 ++++++---------------- 5 files changed, 58 insertions(+), 58 deletions(-) (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java index 53f864cf..62fb1fd2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java @@ -16,11 +16,13 @@ */ package se.leap.bitmaskclient.base.models; +import static de.blinkt.openvpn.core.connection.Connection.TransportProtocol.KCP; +import static de.blinkt.openvpn.core.connection.Connection.TransportProtocol.TCP; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_KCP; import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES; import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS; import static se.leap.bitmaskclient.base.models.Constants.LOCATIONS; +import static se.leap.bitmaskclient.base.models.Constants.PROTOCOLS; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOWED_REGISTERED; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOW_ANONYMOUS; import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT; @@ -46,6 +48,7 @@ import java.util.HashSet; import java.util.Locale; import java.util.Set; +import de.blinkt.openvpn.core.connection.Connection.TransportProtocol; import de.blinkt.openvpn.core.connection.Connection.TransportType; import motd.IStringCollection; import motd.Motd; @@ -181,16 +184,16 @@ public final class Provider implements Parcelable { public boolean supportsPluggableTransports() { if (useObfsVpn()) { - return supportsTransports(new TransportType[]{OBFS4, OBFS4_KCP}); + return supportsTransports(new Pair[]{new Pair<>(OBFS4, TCP), new Pair<>(OBFS4, KCP)}); } - return supportsTransports(new TransportType[]{OBFS4}); + return supportsTransports(new Pair[]{new Pair<>(OBFS4, TCP)}); } public boolean supportsExperimentalPluggableTransports() { - return supportsTransports(new TransportType[]{OBFS4_KCP}); + return supportsTransports(new Pair[]{new Pair<>(OBFS4, KCP)}); } - private boolean supportsTransports(TransportType[] transportTypes) { + private boolean supportsTransports(Pair[] transportTypes) { try { JSONArray gatewayJsons = eipServiceJson.getJSONArray(GATEWAYS); for (int i = 0; i < gatewayJsons.length(); i++) { @@ -199,9 +202,13 @@ public final class Provider implements Parcelable { getJSONArray(TRANSPORT); for (int j = 0; j < transports.length(); j++) { String supportedTransportType = transports.getJSONObject(j).getString(TYPE); - for (TransportType transportType : transportTypes) { - if (transportType.toString().equals(supportedTransportType)) { - return true; + JSONArray transportProtocols = transports.getJSONObject(j).getJSONArray(PROTOCOLS); + for (Pair transportPair : transportTypes) { + for (int k = 0; k < transportProtocols.length(); k++) { + if (transportPair.first.toString().equals(supportedTransportType) && + transportPair.second.toString().equals(transportProtocols.getString(k))) { + return true; + } } } } 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 88cdc715..5b082448 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -91,6 +91,7 @@ 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 se.leap.bitmaskclient.eip.GatewaysManager.GatewayOptions; /** * EIP is the abstract base class for interacting with and managing the Encrypted @@ -255,8 +256,8 @@ public final class EIP extends JobIntentService implements Observer { return; } - Pair gatewayTransportTypePair = gatewaysManager.select(nClosestGateway); - launchActiveGateway(gatewayTransportTypePair, nClosestGateway, result); + GatewayOptions gatewayOptions = gatewaysManager.select(nClosestGateway); + launchActiveGateway(gatewayOptions, nClosestGateway, result); if (result.containsKey(BROADCAST_RESULT_KEY) && !result.getBoolean(BROADCAST_RESULT_KEY)) { tellToReceiverOrBroadcast(this, EIP_ACTION_START, RESULT_CANCELED, result); } else { @@ -270,7 +271,7 @@ public final class EIP extends JobIntentService implements Observer { */ private void startEIPAlwaysOnVpn() { GatewaysManager gatewaysManager = new GatewaysManager(getApplicationContext()); - Pair gatewayTransportTypePair = gatewaysManager.select(0); + GatewayOptions gatewayOptions = gatewaysManager.select(0); Bundle result = new Bundle(); if (shouldUpdateVPNCertificate()) { @@ -279,7 +280,7 @@ public final class EIP extends JobIntentService implements Observer { ProviderObservable.getInstance().updateProvider(p); } - launchActiveGateway(gatewayTransportTypePair, 0, result); + launchActiveGateway(gatewayOptions, 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)); } @@ -323,13 +324,13 @@ public final class EIP extends JobIntentService implements Observer { /** * starts the VPN and connects to the given gateway * - * @param gatewayTransportTypePair Pair of Gateway and associated transport used to connect + * @param gatewayOptions GatewayOptions model containing a Gateway and the associated transport used to connect */ - private void launchActiveGateway(@Nullable Pair gatewayTransportTypePair, int nClosestGateway, Bundle result) { + private void launchActiveGateway(@Nullable GatewayOptions gatewayOptions, int nClosestGateway, Bundle result) { VpnProfile profile; - if (gatewayTransportTypePair == null || gatewayTransportTypePair.first == null || - (profile = gatewayTransportTypePair.first.getProfile(gatewayTransportTypePair.second)) == null) { + if (gatewayOptions == null || gatewayOptions.gateway == null || + (profile = gatewayOptions.gateway.getProfile(gatewayOptions.transportType)) == 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 929935eb..719b960e 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,7 @@ */ package se.leap.bitmaskclient.eip; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.PT; 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; @@ -52,7 +53,6 @@ import java.util.HashSet; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.connection.Connection; -import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.utils.ConfigHelper; /** @@ -77,6 +77,9 @@ public class Gateway { private String name; private int timezone; private int apiVersion; + /** FIXME: We expect here that not more than one obfs4 transport is offered by a gateway, however + * it's possible to setup gateways that have obfs4 over kcp and tcp which result in different VpnProfiles each + */ private HashMap vpnProfiles; /** @@ -209,7 +212,7 @@ public class Gateway { } public boolean supportsTransport(Connection.TransportType transportType) { - if (transportType == Connection.TransportType.PT) { + if (transportType == PT) { return supportsPluggableTransports(); } 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 521d095e..28766998 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -17,7 +17,6 @@ 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 de.blinkt.openvpn.core.connection.Connection.TransportType.PT; import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS; @@ -61,7 +60,6 @@ import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.GatewayJson; 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.models.Transport; @@ -103,6 +101,16 @@ public class GatewaysManager { } } + public static class GatewayOptions { + public Gateway gateway; + public TransportType transportType; + + public GatewayOptions(Gateway gateway, TransportType transportType) { + this.gateway = gateway; + this.transportType = transportType; + } + } + private static final String TAG = GatewaysManager.class.getSimpleName(); public static final String PINNED_OBFUSCATION_PROXY = "pinned.obfuscation.proxy"; @@ -122,7 +130,7 @@ public class GatewaysManager { * select closest Gateway * @return the n closest Gateway */ - public Pair select(int nClosest) { + public GatewayOptions select(int nClosest) { if (PreferenceHelper.useObfuscationPinning(context)) { if (nClosest > 2) { // no need to try again the pinned proxy, probably configuration error @@ -132,14 +140,14 @@ public class GatewaysManager { if (gateway == null) { return null; } - return new Pair<>(gateway, getObfuscationPinningKCP(context) ? OBFS4_KCP : OBFS4); + return new GatewayOptions(gateway, OBFS4); } String selectedCity = getPreferredCity(context); return select(nClosest, selectedCity); } - public Pair select(int nClosest, String city) { - TransportType[] transportTypes = getUseBridges(context) ? new TransportType[]{OBFS4, OBFS4_KCP} : new TransportType[]{OPENVPN}; + public GatewayOptions select(int nClosest, String city) { + TransportType[] transportTypes = getUseBridges(context) ? new TransportType[]{OBFS4} : new TransportType[]{OPENVPN}; if (presortedList.size() > 0) { return getGatewayFromPresortedList(nClosest, transportTypes, city); } @@ -266,7 +274,7 @@ public class GatewaysManager { return Load.getLoadByValue(location.getAverageLoad(transportType)); } - private Pair getGatewayFromTimezoneCalculation(int nClosest, TransportType[] transportTypes, @Nullable String city) { + private GatewayOptions getGatewayFromTimezoneCalculation(int nClosest, TransportType[] transportTypes, @Nullable String city) { List list = new ArrayList<>(gateways.values()); GatewaySelector gatewaySelector = new GatewaySelector(list); Gateway gateway; @@ -277,7 +285,7 @@ public class GatewaysManager { if ((city == null && gateway.supportsTransport(transportType)) || (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) { if (found == nClosest) { - return new Pair<>(gateway, transportType); + return new GatewayOptions(gateway, transportType); } found++; } @@ -287,14 +295,14 @@ public class GatewaysManager { return null; } - private Pair getGatewayFromPresortedList(int nClosest, TransportType[] transportTypes, @Nullable String city) { + private GatewayOptions getGatewayFromPresortedList(int nClosest, TransportType[] transportTypes, @Nullable String city) { int found = 0; for (Gateway gateway : presortedList) { 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); + return new GatewayOptions(gateway, transportType); } found++; } @@ -387,10 +395,9 @@ public class GatewaysManager { if (PreferenceHelper.useObfuscationPinning(context)) { try { - TransportType transportType = getObfuscationPinningKCP(context) ? OBFS4_KCP : OBFS4; Transport[] transports = new Transport[]{ - new Transport(transportType.toString(), - new String[]{"tcp"}, + new Transport(OBFS4.toString(), + new String[]{getObfuscationPinningKCP(context) ? "kcp" : "tcp"}, new String[]{getObfuscationPinningPort(context)}, getObfuscationPinningCert(context))}; GatewayJson.Capabilities capabilities = new GatewayJson.Capabilities(false, false, false, transports, false); 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 72a0d80a..141f6274 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java @@ -17,7 +17,6 @@ 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 de.blinkt.openvpn.core.connection.Connection.TransportType.PT; import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES; @@ -63,7 +62,6 @@ public class VpnConfigGenerator { private final JSONObject gateway; private final JSONObject secrets; private JSONObject obfs4Transport; - private JSONObject obfs4TKcpTransport; private final int apiVersion; private final boolean preferUDP; private final boolean experimentalTransports; @@ -122,11 +120,7 @@ public class VpnConfigGenerator { JSONObject transport = supportedTransports.getJSONObject(i); if (transport.getString(TYPE).equals(OBFS4.toString())) { obfs4Transport = transport; - if (!experimentalTransports && !obfuscationPinningKCP) { - break; - } - } else if ((experimentalTransports || obfuscationPinningKCP) && transport.getString(TYPE).equals(OBFS4_KCP.toString())) { - obfs4TKcpTransport = transport; + break; } } } @@ -154,13 +148,6 @@ public class VpnConfigGenerator { e.printStackTrace(); } } - if (supportsObfs4Kcp()) { - try { - profiles.put(OBFS4_KCP, createProfile(OBFS4_KCP)); - } catch (ConfigParser.ConfigParseError | NumberFormatException | JSONException | IOException e) { - e.printStackTrace(); - } - } if (profiles.isEmpty()) { throw new ConfigParser.ConfigParseError("No supported transports detected."); } @@ -171,11 +158,7 @@ public class VpnConfigGenerator { return !useObfuscationPinning && !gatewayConfiguration(OPENVPN).isEmpty(); } private boolean supportsObfs4(){ - return obfs4Transport != null && !(useObfuscationPinning && obfuscationPinningKCP); - } - - private boolean supportsObfs4Kcp() { - return obfs4TKcpTransport != null && !(useObfuscationPinning && !obfuscationPinningKCP); + return obfs4Transport != null || useObfuscationPinning; } private String getConfigurationString(TransportType transportType) { @@ -194,9 +177,10 @@ public class VpnConfigGenerator { ConfigParser icsOpenvpnConfigParser = new ConfigParser(); icsOpenvpnConfigParser.parseConfig(new StringReader(configuration)); if (transportType == OBFS4) { - icsOpenvpnConfigParser.setObfs4Options(getObfs4Options(obfs4Transport, false)); - } else if (transportType == OBFS4_KCP) { - icsOpenvpnConfigParser.setObfs4Options(getObfs4Options(obfs4TKcpTransport, true)); + JSONArray protocols = obfs4Transport.getJSONArray(PROTOCOLS); + // FIXME: currently only one protocol per obfs4 bridge is supported in this client + String protocol = protocols.optString(0); + icsOpenvpnConfigParser.setObfs4Options(getObfs4Options(obfs4Transport, protocol.equalsIgnoreCase("kcp"))); } VpnProfile profile = icsOpenvpnConfigParser.convertProfile(transportType); @@ -208,7 +192,6 @@ public class VpnConfigGenerator { return profile; } - // TODO: whad does private Obfs4Options getObfs4Options(JSONObject transportJson, boolean useUdp) throws JSONException { JSONObject transportOptions = transportJson.getJSONObject(OPTIONS); String iatMode = transportOptions.getString("iatMode"); @@ -367,8 +350,7 @@ public class VpnConfigGenerator { case OPENVPN: return "tcp".equals(protocol) || "udp".equals(protocol); case OBFS4: - case OBFS4_KCP: - return "tcp".equals(protocol); + return "tcp".equals(protocol) || "kcp".equals(protocol); } return false; } @@ -446,10 +428,10 @@ public class VpnConfigGenerator { String remote; if (useObfsVpn()) { if (useObfuscationPinning) { - remote = REMOTE + " " + obfuscationPinningIP + " " + obfuscationPinningPort + newLine; + remote = REMOTE + " " + obfuscationPinningIP + " " + obfuscationPinningPort + " tcp" + newLine; route = "route " + obfuscationPinningIP + " 255.255.255.255 net_gateway" + newLine; } else { - remote = REMOTE + " " + ipAddress + " " + ports.getString(0) + newLine; + remote = REMOTE + " " + ipAddress + " " + ports.getString(0) + " tcp" + newLine; } } else { remote = REMOTE + " " + DISPATCHER_IP + " " + DISPATCHER_PORT + " tcp" + newLine; -- cgit v1.2.3