From 8f7146a89fba31bcb9a204415a38e796cfa7d403 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 14 Jun 2019 18:18:18 +0200 Subject: * refactor vpn profile generation * fix lzo-comp flag parsing in ConfigParser --- .../main/java/de/blinkt/openvpn/VpnProfile.java | 25 ++-- .../java/de/blinkt/openvpn/core/ConfigParser.java | 43 +++--- .../de/blinkt/openvpn/core/OpenVPNService.java | 9 +- .../blinkt/openvpn/core/connection/Connection.java | 16 ++- .../openvpn/core/connection/Obfs4Connection.java | 74 ++++------- .../java/se/leap/bitmaskclient/eip/Gateway.java | 2 +- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 10 +- .../leap/bitmaskclient/eip/VpnConfigGenerator.java | 145 +++++++++++---------- .../pluggableTransports/Dispatcher.java | 35 +++-- .../pluggableTransports/DispatcherOptions.java | 18 +++ 10 files changed, 200 insertions(+), 177 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/pluggableTransports/DispatcherOptions.java diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java index 9f18b8ed..dc12c6a8 100644 --- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -5,11 +5,6 @@ package de.blinkt.openvpn; -import de.blinkt.openvpn.core.connection.Connection; -import de.blinkt.openvpn.core.connection.OpenvpnConnection; -import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.BuildConfig; - import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; @@ -58,7 +53,6 @@ import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; -import de.blinkt.openvpn.core.Connection; import de.blinkt.openvpn.core.ExtAuthHelper; import de.blinkt.openvpn.core.NativeUtils; import de.blinkt.openvpn.core.OpenVPNService; @@ -68,9 +62,13 @@ import de.blinkt.openvpn.core.Preferences; import de.blinkt.openvpn.core.VPNLaunchHelper; import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.X509Utils; +import de.blinkt.openvpn.core.connection.Connection; +import de.blinkt.openvpn.core.connection.Obfs4Connection; +import de.blinkt.openvpn.core.connection.OpenvpnConnection; import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE; public class VpnProfile implements Serializable, Cloneable { @@ -121,7 +119,7 @@ public class VpnProfile implements Serializable, Cloneable { public String mTLSAuthFilename; public String mClientKeyFilename; public String mCaFilename; - public boolean mUseLzo = true; + public boolean mUseLzo = false; public String mPKCS12Filename; public String mPKCS12Password; public boolean mUseTLSAuth = false; @@ -186,16 +184,16 @@ public class VpnProfile implements Serializable, Cloneable { // set members to default values private UUID mUuid; private int mProfileVersion; + public boolean mUsePluggableTransports; - - public VpnProfile(String name) { + public VpnProfile(String name, Connection.TransportType transportType) { mUuid = UUID.randomUUID(); mName = name; mProfileVersion = CURRENT_PROFILE_VERSION; mConnections = new Connection[1]; - mConnections[0] = new OpenvpnConnection(); mLastUsed = System.currentTimeMillis(); + mUsePluggableTransports = transportType == OBFS4; } public static String openVpnEscape(String unescaped) { @@ -297,6 +295,7 @@ public class VpnProfile implements Serializable, Cloneable { return mName; } + @Deprecated public void upgradeProfile() { if (mProfileVersion < 2) { /* default to the behaviour the OS used */ @@ -327,9 +326,10 @@ public class VpnProfile implements Serializable, Cloneable { } + @Deprecated private void moveOptionsToConnection() { mConnections = new Connection[1]; - Connection conn = new OpenvpnConnection(); + Connection conn = mUsePluggableTransports ? new Obfs4Connection() : new OpenvpnConnection(); conn.setServerName(mServerName); conn.setServerPort(mServerPort); @@ -499,7 +499,8 @@ public class VpnProfile implements Serializable, Cloneable { if (!TextUtils.isEmpty(mCrlFilename)) cfg.append(insertFileData("crl-verify", mCrlFilename)); - if (mUseLzo) { + // compression does not work in conjunction with shapeshifter-dispatcher so far + if (mUseLzo && !mUsePluggableTransports) { cfg.append("comp-lzo\n"); } diff --git a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java index 0e9b1bc4..4c53087f 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java +++ b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java @@ -6,8 +6,8 @@ package de.blinkt.openvpn.core; import android.os.Build; -import android.text.TextUtils; import android.support.v4.util.Pair; +import android.text.TextUtils; import java.io.BufferedReader; import java.io.IOException; @@ -23,7 +23,11 @@ import java.util.Vector; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.connection.Connection; +import de.blinkt.openvpn.core.connection.Obfs4Connection; import de.blinkt.openvpn.core.connection.OpenvpnConnection; +import se.leap.bitmaskclient.pluggableTransports.DispatcherOptions; + +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; //! Openvpn Config FIle Parser, probably not 100% accurate but close enough @@ -136,6 +140,7 @@ public class ConfigParser { private HashMap>> options = new HashMap<>(); private HashMap> meta = new HashMap>(); private String auth_user_pass_file; + private DispatcherOptions dispatcherOptions; static public void useEmbbedUserAuth(VpnProfile np, String inlinedata) { String data = VpnProfile.getEmbeddedContent(inlinedata); @@ -346,9 +351,9 @@ public class ConfigParser { // This method is far too long @SuppressWarnings("ConstantConditions") - public VpnProfile convertProfile() throws ConfigParseError, IOException { + public VpnProfile convertProfile(Connection.TransportType transportType) throws ConfigParseError, IOException { boolean noauthtypeset = true; - VpnProfile np = new VpnProfile(CONVERTED_PROFILE); + VpnProfile np = new VpnProfile(CONVERTED_PROFILE, transportType); // Pull, client, tls-client np.clearDefaults(); @@ -451,6 +456,7 @@ public class ConfigParser { if (redirectPrivate != null) { checkRedirectParameters(np, redirectPrivate, false); } + Vector dev = getOption("dev", 1, 1); Vector devtype = getOption("dev-type", 1, 1); @@ -476,7 +482,6 @@ public class ConfigParser { } } - Vector tunmtu = getOption("tun-mtu", 1, 1); if (tunmtu != null) { @@ -487,14 +492,12 @@ public class ConfigParser { } } - Vector mode = getOption("mode", 1, 1); if (mode != null) { if (!mode.get(1).equals("p2p")) throw new ConfigParseError("Invalid mode for --mode specified, need p2p"); } - Vector> dhcpoptions = getAllOption("dhcp-option", 2, 2); if (dhcpoptions != null) { for (Vector dhcpoption : dhcpoptions) { @@ -529,8 +532,10 @@ public class ConfigParser { if (getOption("float", 0, 0) != null) np.mUseFloat = true; - if (getOption("comp-lzo", 0, 1) != null) - np.mUseLzo = true; + Vector useLzo = getOption("comp-lzo", 0, 1); + if (useLzo != null) { + np.mUseLzo = Boolean.valueOf(useLzo.get(1)); + } Vector cipher = getOption("cipher", 1, 1); if (cipher != null) @@ -540,7 +545,6 @@ public class ConfigParser { if (auth != null) np.mAuth = auth.get(1); - Vector ca = getOption("ca", 1, 1); if (ca != null) { np.mCaFilename = ca.get(1); @@ -552,6 +556,7 @@ public class ConfigParser { np.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES; noauthtypeset = false; } + Vector key = getOption("key", 1, 1); if (key != null) np.mClientKeyFilename = key.get(1); @@ -612,7 +617,6 @@ public class ConfigParser { np.mVerb = verb.get(1); } - if (getOption("nobind", 0, 1) != null) np.mNobind = true; @@ -682,8 +686,7 @@ public class ConfigParser { } - - Pair conns = parseConnectionOptions(null); + Pair conns = parseConnectionOptions(null, transportType); np.mConnections = conns.second; Vector> connectionBlocks = getAllOption("connection", 1, 1); @@ -706,6 +709,7 @@ public class ConfigParser { connIndex++; } } + if (getOption("remote-random", 0, 0) != null) np.mRemoteRandom = true; @@ -748,20 +752,21 @@ public class ConfigParser { return TextUtils.join(s, str); } + public void setDispatcherOptions(DispatcherOptions dispatcherOptions) { + this.dispatcherOptions = dispatcherOptions; + } + private Pair parseConnection(String connection, Connection defaultValues) throws IOException, ConfigParseError { // Parse a connection Block as a new configuration file - ConfigParser connectionParser = new ConfigParser(); StringReader reader = new StringReader(connection.substring(VpnProfile.INLINE_TAG.length())); connectionParser.parseConfig(reader); - Pair conn = connectionParser.parseConnectionOptions(defaultValues); - - return conn; + return connectionParser.parseConnectionOptions(defaultValues, defaultValues.getTransportType()); } - private Pair parseConnectionOptions(Connection connDefault) throws ConfigParseError { + private Pair parseConnectionOptions(Connection connDefault, Connection.TransportType transportType) throws ConfigParseError { Connection conn; if (connDefault != null) try { @@ -771,7 +776,7 @@ public class ConfigParser { return null; } else - conn = new OpenvpnConnection(); + conn = transportType == OBFS4 ? new Obfs4Connection(dispatcherOptions) : new OpenvpnConnection(); Vector port = getOption("port", 1, 1); if (port != null) { @@ -825,8 +830,6 @@ public class ConfigParser { // Parse remote config Vector> remotes = getAllOption("remote", 1, 3); - - Vector optionsToRemove = new Vector<>(); // Assume that we need custom options if connectionDefault are set or in the connection specific set for (Map.Entry>> option : options.entrySet()) { diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index b775921c..4a33fd49 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -48,7 +48,6 @@ import se.leap.bitmaskclient.VpnNotificationManager; import se.leap.bitmaskclient.pluggableTransports.Dispatcher; import de.blinkt.openvpn.core.connection.Obfs4Connection; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; @@ -386,13 +385,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac VpnStatus.logInfo("Setting up dispatcher."); Connection connection = mProfile.mConnections[0]; - if (connection.getTransportType() == OBFS4) { + if (mProfile.mUsePluggableTransports) { Obfs4Connection obfs4Connection = (Obfs4Connection) connection; - dispatcher = new Dispatcher(this, - obfs4Connection.getmObfs4RemoteProxyName(), - obfs4Connection.getmObfs4RemoteProxyPort(), - obfs4Connection.getmObfs4Certificate(), - obfs4Connection.getmObfs4IatMode()); + dispatcher = new Dispatcher(this, obfs4Connection.getDispatcherOptions()); dispatcher.initSync(); if (dispatcher.isRunning()) { diff --git a/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java b/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java index f333a13e..a318e55d 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java +++ b/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java @@ -35,10 +35,22 @@ public abstract class Connection implements Serializable, Cloneable { } public enum TransportType { - OBFS4, - OPENVPN + OBFS4("obfs4"), + OPENVPN("openvpn"); + + String transport; + + TransportType(String transportType) { + this.transport = transportType; + } + + @Override + public String toString() { + return transport; + } } + private static final long serialVersionUID = 92031902903829089L; diff --git a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java index 790b8b1a..4f6be276 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java +++ b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java @@ -1,6 +1,9 @@ package de.blinkt.openvpn.core.connection; -import org.json.JSONObject; +import se.leap.bitmaskclient.pluggableTransports.DispatcherOptions; + +import static se.leap.bitmaskclient.pluggableTransports.Dispatcher.DISPATCHER_IP; +import static se.leap.bitmaskclient.pluggableTransports.Dispatcher.DISPATCHER_PORT; /** * Created by cyberta on 08.03.19. @@ -9,46 +12,38 @@ import org.json.JSONObject; public class Obfs4Connection extends Connection { private static final String TAG = Obfs4Connection.class.getName(); + private DispatcherOptions options; - - private String mObfs4RemoteProxyName = ""; - private String mObfs4RemoteProxyPort = ""; - private String mObfs4Certificate = ""; - private String mObfs4IatMode = ""; - - public Obfs4Connection() { - setDefaults(); - } - - public Obfs4Connection(Connection connection) { - mObfs4RemoteProxyName = connection.getServerName(); - setConnectTimeout(connection.getConnectTimeout()); - setCustomConfiguration(connection.getCustomConfiguration()); - setUseCustomConfig(connection.isUseCustomConfig()); - - setDefaults(); - } - - private void setDefaults() { + public Obfs4Connection(DispatcherOptions options) { setUseUdp(false); - setServerName("127.0.0.1"); - setServerPort(""); + setServerName(DISPATCHER_IP); + setServerPort(DISPATCHER_PORT); setProxyName(""); setProxyPort(""); setProxyAuthUser(null); setProxyAuthPassword(null); setProxyType(ProxyType.NONE); setUseProxyAuth(false); + this.options = options; } - public void setTransportOptions(JSONObject jsonObject) { - mObfs4Certificate = jsonObject.optString("cert"); - mObfs4IatMode = jsonObject.optString("iat-mode"); - } + @Deprecated + public Obfs4Connection() { + setUseUdp(false); + setServerName(DISPATCHER_IP); + setServerPort(DISPATCHER_PORT); + setProxyName(""); + setProxyPort(""); + setProxyAuthUser(null); + setProxyAuthPassword(null); + setProxyType(ProxyType.NONE); + setUseProxyAuth(false); } @Override public Connection clone() throws CloneNotSupportedException { - return super.clone(); + Obfs4Connection connection = (Obfs4Connection) super.clone(); + connection.options = this.options; + return connection; } @Override @@ -56,28 +51,9 @@ public class Obfs4Connection extends Connection { return TransportType.OBFS4; } - public String getmObfs4RemoteProxyName() { - return mObfs4RemoteProxyName; - } - - public void setObfs4RemoteProxyName(String mObfs4RemoteProxyName) { - this.mObfs4RemoteProxyName = mObfs4RemoteProxyName; - } - - public String getmObfs4RemoteProxyPort() { - return mObfs4RemoteProxyPort; - } - - public void setObfs4RemoteProxyPort(String mObfs4RemoteProxyPort) { - this.mObfs4RemoteProxyPort = mObfs4RemoteProxyPort; - } - - public String getmObfs4Certificate() { - return mObfs4Certificate; - } - public String getmObfs4IatMode() { - return mObfs4IatMode; + public DispatcherOptions getDispatcherOptions() { + return options; } } 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 b1554af0..50fe74b7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -114,7 +114,7 @@ public class Gateway { try { VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway, apiVersion); return vpnConfigurationGenerator.generateVpnProfile(); - } catch (ConfigParser.ConfigParseError | IOException | CloneNotSupportedException | JSONException e) { + } catch (ConfigParser.ConfigParseError | IOException | JSONException e) { // FIXME We didn't get a VpnProfile! Error handling! and log level e.printStackTrace(); return 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 c650938c..cd3ec1c6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -99,12 +99,10 @@ public class GatewaysManager { int apiVersion = eipDefinition.getInt(VERSION); for (int i = 0; i < gatewaysDefined.length(); i++) { JSONObject gw = gatewaysDefined.getJSONObject(i); - if (isOpenVpnGateway(gw, apiVersion)) { - JSONObject secrets = secretsConfiguration(); - Gateway aux = new Gateway(eipDefinition, secrets, gw); - if (!gateways.contains(aux)) { - addGateway(aux); - } + JSONObject secrets = secretsConfiguration(); + Gateway aux = new Gateway(eipDefinition, secrets, gw); + if (!gateways.contains(aux)) { + addGateway(aux); } } } catch (JSONException e) { 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 7f09d21e..a131bdd8 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java @@ -27,9 +27,11 @@ import java.util.Iterator; 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 se.leap.bitmaskclient.Provider; +import se.leap.bitmaskclient.pluggableTransports.DispatcherOptions; +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.Constants.CAPABILITIES; import static se.leap.bitmaskclient.Constants.IP_ADDRESS; import static se.leap.bitmaskclient.Constants.OPTIONS; @@ -40,9 +42,10 @@ import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.Constants.REMOTE; import static se.leap.bitmaskclient.Constants.TRANSPORT; import static se.leap.bitmaskclient.Constants.TYPE; +import static se.leap.bitmaskclient.pluggableTransports.Dispatcher.DISPATCHER_IP; +import static se.leap.bitmaskclient.pluggableTransports.Dispatcher.DISPATCHER_PORT; public class VpnConfigGenerator { - private JSONObject generalConfiguration; private JSONObject gateway; private JSONObject secrets; @@ -66,18 +69,14 @@ public class VpnConfigGenerator { public void checkCapabilities() { try { - switch (apiVersion) { - case 2: - JSONArray supportedTransports = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT); - for (int i = 0; i < supportedTransports.length(); i++) { - JSONObject transport = supportedTransports.getJSONObject(i); - if (transport.getString(TYPE).equals("obfs4")) { - obfs4Transport = transport; - } + if (apiVersion == 2) { + JSONArray supportedTransports = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT); + for (int i = 0; i < supportedTransports.length(); i++) { + JSONObject transport = supportedTransports.getJSONObject(i); + if (transport.getString(TYPE).equals(OBFS4.toString())) { + obfs4Transport = transport; } - break; - default: - break; + } } } catch (JSONException e) { @@ -88,54 +87,45 @@ public class VpnConfigGenerator { public VpnProfile generateVpnProfile() throws IllegalStateException, IOException, ConfigParser.ConfigParseError, - CloneNotSupportedException, - JSONException, - NumberFormatException { + NumberFormatException, JSONException { - VpnProfile profile = createOvpnProfile(); if (supportsObfs4()) { - addPluggableTransportConnections(profile); + return createProfile(OBFS4); } - return profile; + + return createProfile(OPENVPN); } private boolean supportsObfs4(){ return obfs4Transport != null; } - private void addPluggableTransportConnections(VpnProfile profile) throws JSONException, CloneNotSupportedException { - JSONArray ports = obfs4Transport.getJSONArray(PORTS); - Connection[] updatedConnections = new Connection[profile.mConnections.length + ports.length()]; - - for (int i = 0; i < ports.length(); i++) { - String port = ports.getString(i); - Obfs4Connection obfs4Connection = new Obfs4Connection(); - obfs4Connection.setObfs4RemoteProxyName(gateway.getString(IP_ADDRESS)); - obfs4Connection.setObfs4RemoteProxyPort(port); - obfs4Connection.setTransportOptions(obfs4Transport.optJSONObject(OPTIONS)); - updatedConnections[i] = obfs4Connection; - } - int k = 0; - for (int i = ports.length(); i < updatedConnections.length; i++, k++) { - updatedConnections[i] = profile.mConnections[k].clone(); - } - profile.mConnections = updatedConnections; - } - - private String getConfigurationString() { + private String getConfigurationString(Connection.TransportType transportType) { return generalConfiguration() - + newLine - + ovpnGatewayConfiguration() - + newLine - + secretsConfiguration() - + newLine - + androidCustomizations(); + + newLine + + gatewayConfiguration(transportType) + + newLine + + androidCustomizations() + + newLine + + secretsConfiguration(); } - private VpnProfile createOvpnProfile() throws IOException, ConfigParser.ConfigParseError { - String configuration = getConfigurationString(); + private VpnProfile createProfile(Connection.TransportType transportType) throws IOException, ConfigParser.ConfigParseError, JSONException { + String configuration = getConfigurationString(transportType); icsOpenvpnConfigParser.parseConfig(new StringReader(configuration)); - return icsOpenvpnConfigParser.convertProfile(); + if (transportType == OBFS4) { + icsOpenvpnConfigParser.setDispatcherOptions(getDispatcherOptions()); + } + return icsOpenvpnConfigParser.convertProfile(transportType); + } + + private DispatcherOptions getDispatcherOptions() throws JSONException { + JSONObject transportOptions = obfs4Transport.getJSONObject(OPTIONS); + String iatMode = transportOptions.getString("iat-mode"); + String cert = transportOptions.getString("cert"); + String port = obfs4Transport.getJSONArray(PORTS).getString(0); + String ip = gateway.getString(IP_ADDRESS); + return new DispatcherOptions(ip, port, cert, iatMode); } private String generalConfiguration() { @@ -161,21 +151,21 @@ public class VpnConfigGenerator { return commonOptions; } - private String ovpnGatewayConfiguration() { + private String gatewayConfiguration(Connection.TransportType transportType) { String remotes = ""; StringBuilder stringBuilder = new StringBuilder(); try { String ipAddress = gateway.getString(IP_ADDRESS); JSONObject capabilities = gateway.getJSONObject(CAPABILITIES); - JSONArray transports = capabilities.getJSONArray(TRANSPORT); switch (apiVersion) { default: case 1: - ovpnGatewayConfigApiv1(stringBuilder, ipAddress, capabilities); + gatewayConfigApiv1(stringBuilder, ipAddress, capabilities); break; case 2: - ovpnGatewayConfigApiv2(stringBuilder, ipAddress, transports); + JSONArray transports = capabilities.getJSONArray(TRANSPORT); + gatewayConfigApiv2(transportType, stringBuilder, ipAddress, transports); break; } } catch (JSONException e) { @@ -190,10 +180,17 @@ public class VpnConfigGenerator { return remotes; } - private void ovpnGatewayConfigApiv1(StringBuilder stringBuilder, String ipAddress, JSONObject capabilities) throws JSONException { + private void gatewayConfigApiv2(Connection.TransportType transportType, StringBuilder stringBuilder, String ipAddress, JSONArray transports) throws JSONException { + if (transportType == OBFS4) { + obfs4GatewayConfigApiv2(stringBuilder, ipAddress, transports); + } else { + ovpnGatewayConfigApi2(stringBuilder, ipAddress, transports); + } + } + + private void gatewayConfigApiv1(StringBuilder stringBuilder, String ipAddress, JSONObject capabilities) throws JSONException { int port; String protocol; - JSONArray ports = capabilities.getJSONArray(PORTS); for (int i = 0; i < ports.length(); i++) { port = ports.getInt(i); @@ -206,27 +203,41 @@ public class VpnConfigGenerator { } } - private void ovpnGatewayConfigApiv2(StringBuilder stringBuilder, String ipAddress, JSONArray transports) throws JSONException { + private void ovpnGatewayConfigApi2(StringBuilder stringBuilder, String ipAddress, JSONArray transports) throws JSONException { String port; String protocol; + JSONObject openvpnTransport = getTransport(transports, OPENVPN); + JSONArray ports = openvpnTransport.getJSONArray(PORTS); + for (int j = 0; j < ports.length(); j++) { + port = ports.getString(j); + JSONArray protocols = openvpnTransport.getJSONArray(PROTOCOLS); + for (int k = 0; k < protocols.length(); k++) { + protocol = protocols.optString(k); + String newRemote = REMOTE + " " + ipAddress + " " + port + " " + protocol + newLine; + stringBuilder.append(newRemote); + } + } + } + + private JSONObject getTransport(JSONArray transports, Connection.TransportType transportType) throws JSONException { + JSONObject selectedTransport = new JSONObject(); for (int i = 0; i < transports.length(); i++) { JSONObject transport = transports.getJSONObject(i); - if (!transport.getString(TYPE).equals("openvpn")) { - continue; - } - JSONArray ports = transport.getJSONArray(PORTS); - for (int j = 0; j < ports.length(); j++) { - port = ports.getString(j); - JSONArray protocols = transport.getJSONArray(PROTOCOLS); - for (int k = 0; k < protocols.length(); k++) { - protocol = protocols.optString(k); - String newRemote = REMOTE + " " + ipAddress + " " + port + " " + protocol + newLine; - stringBuilder.append(newRemote); - } + if (transport.getString(TYPE).equals(transportType.toString())) { + selectedTransport = transport; + break; } } + return selectedTransport; } + private void obfs4GatewayConfigApiv2(StringBuilder stringBuilder, String ipAddress, JSONArray transports) throws JSONException { + JSONObject obfs4Transport = getTransport(transports, OBFS4); + String route = "route " + ipAddress + " 255.255.255.255 net_gateway" + newLine; + stringBuilder.append(route); + String remote = REMOTE + " " + DISPATCHER_IP + " " + DISPATCHER_PORT + " " + obfs4Transport.getJSONArray(PROTOCOLS).getString(0) + newLine; + stringBuilder.append(remote); + } private String secretsConfiguration() { try { diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Dispatcher.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Dispatcher.java index 05ce2256..240dae75 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Dispatcher.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Dispatcher.java @@ -18,13 +18,13 @@ package se.leap.bitmaskclient.pluggableTransports; import android.content.Context; import android.support.annotation.WorkerThread; +import android.text.TextUtils; import android.util.Log; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; -import java.util.NoSuchElementException; import java.util.StringTokenizer; @@ -34,7 +34,8 @@ import java.util.StringTokenizer; public class Dispatcher { private static final String ASSET_KEY = "piedispatcher"; - private static final String DISPATCHER_PORT = "4430"; + public static final String DISPATCHER_PORT = "4430"; + public static final String DISPATCHER_IP = "127.0.0.1"; private static final String TAG = Dispatcher.class.getName(); private final String remoteIP; private final String remotePort; @@ -43,14 +44,14 @@ public class Dispatcher { private File fileDispatcher; private Context context; private Thread dispatcherThread = null; - private int dipatcherPid = -1; + private int dispatcherPid = -1; - public Dispatcher(Context context, String remoteIP, String remotePort, String certificate, String iatMode) { + public Dispatcher(Context context, DispatcherOptions dispatcherOptions) { this.context = context.getApplicationContext(); - this.remoteIP = remoteIP; - this.remotePort = remotePort; - this.certificate = certificate; - this.iatMode = iatMode; + this.remoteIP = dispatcherOptions.remoteIP; + this.remotePort = dispatcherOptions.remotePort; + this.certificate = dispatcherOptions.cert; + this.iatMode = dispatcherOptions.iatMode; } @WorkerThread @@ -70,7 +71,7 @@ public class Dispatcher { " -transports obfs4" + " -options \"" + String.format("{\\\"cert\\\": \\\"%s\\\", \\\"iatMode\\\": \\\"%s\\\"}\"", certificate, iatMode) + " -logLevel DEBUG -enableLogging" + - " -proxylistenaddr 127.0.0.1:" + DISPATCHER_PORT; + " -proxylistenaddr "+ DISPATCHER_IP + ":" + DISPATCHER_PORT; Log.d(TAG, "dispatcher command: " + dispatcherCommand); runBlockingCmd(new String[]{dispatcherCommand}, dispatcherLog); @@ -82,14 +83,22 @@ public class Dispatcher { }); dispatcherThread.start(); - // get pid of dispatcher + // get pid of dispatcher, try several times in case the dispatcher + // process is not spawned yet StringBuilder log = new StringBuilder(); String pidCommand = "ps | grep piedispatcher"; - runBlockingCmd(new String[]{pidCommand}, log); + for (int i = 0; i < 5; i++) { + runBlockingCmd(new String[]{pidCommand}, log); + if (!TextUtils.isEmpty(log)) { + break; + } + Thread.sleep(100); + } + String output = log.toString(); StringTokenizer st = new StringTokenizer(output, " "); st.nextToken(); // proc owner - dipatcherPid = Integer.parseInt(st.nextToken().trim()); + dispatcherPid = Integer.parseInt(st.nextToken().trim()); } catch(Exception e){ if (dispatcherThread.isAlive()) { Log.e(TAG, e.getMessage() + ". Shutting down Dispatcher thread."); @@ -106,7 +115,7 @@ public class Dispatcher { Log.d(TAG, "Shutting down Dispatcher thread."); if (dispatcherThread != null && dispatcherThread.isAlive()) { try { - killProcess(dipatcherPid); + killProcess(dispatcherPid); } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/DispatcherOptions.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/DispatcherOptions.java new file mode 100644 index 00000000..76ccbd79 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/DispatcherOptions.java @@ -0,0 +1,18 @@ +package se.leap.bitmaskclient.pluggableTransports; + +import java.io.Serializable; + +public class DispatcherOptions implements Serializable { + public String cert; + public String iatMode; + public String remoteIP; + public String remotePort; + + public DispatcherOptions(String remoteIP, String remotePort, String cert, String iatMode) { + this.cert = cert; + this.iatMode = iatMode; + this.remoteIP = remoteIP; + this.remotePort = remotePort; + } + +} -- cgit v1.2.3