summaryrefslogtreecommitdiff
path: root/app/src/main/java/se/leap/bitmaskclient/eip
diff options
context:
space:
mode:
authorcyBerta <cyberta@riseup.net>2019-05-24 18:01:03 +0200
committercyBerta <cyberta@riseup.net>2019-08-02 01:49:37 +0200
commitdb1e1a2045a2e6456d54765be3cf95186ce987f7 (patch)
tree0fc04949eba47e99d7fe7f711fb00bf1c16e3e0a /app/src/main/java/se/leap/bitmaskclient/eip
parent8ffbb96d908fdc5a17255ec3fbdc807f663ade38 (diff)
squashed commit for Pluggable Transports
* implement handling of different provider API version (v1 and v2) * detect provider's obfs support * shapeshifter-dispatcher installation * necessary changes to control shapeshifter-dispatcher from Bitmask * route openvpn traffic over shapeshifter-dispatcher
Diffstat (limited to 'app/src/main/java/se/leap/bitmaskclient/eip')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java73
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java41
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java177
4 files changed, 220 insertions, 73 deletions
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 55ade1ae..b1554af0 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -22,11 +22,17 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
-import java.io.StringReader;
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.ConfigParser;
+import static se.leap.bitmaskclient.Constants.LOCATION;
+import static se.leap.bitmaskclient.Constants.LOCATIONS;
+import static se.leap.bitmaskclient.Constants.NAME;
+import static se.leap.bitmaskclient.Constants.OPENVPN_CONFIGURATION;
+import static se.leap.bitmaskclient.Constants.TIMEZONE;
+import static se.leap.bitmaskclient.Constants.VERSION;
+
/**
* Gateway provides objects defining gateways and their metadata.
* Each instance contains a VpnProfile for OpenVPN specific data and member
@@ -34,6 +40,7 @@ import de.blinkt.openvpn.core.ConfigParser;
*
* @author Sean Leonard <meanderingcode@aetherislands.net>
* @author Parménides GV <parmegv@sdf.org>
+ * @author cyberta
*/
public class Gateway {
@@ -44,50 +51,57 @@ public class Gateway {
private JSONObject secrets;
private JSONObject gateway;
- private String mName;
+ private String name;
private int timezone;
- private VpnProfile mVpnProfile;
+ private int apiVersion;
+ private VpnProfile vpnProfile;
/**
* Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json
* and create a VpnProfile belonging to it.
*/
- public Gateway(JSONObject eip_definition, JSONObject secrets, JSONObject gateway) {
+ public Gateway(JSONObject eipDefinition, JSONObject secrets, JSONObject gateway) {
this.gateway = gateway;
this.secrets = secrets;
- generalConfiguration = getGeneralConfiguration(eip_definition);
- timezone = getTimezone(eip_definition);
- mName = locationAsName(eip_definition);
-
- mVpnProfile = createVPNProfile();
- mVpnProfile.mName = mName;
+ generalConfiguration = getGeneralConfiguration(eipDefinition);
+ timezone = getTimezone(eipDefinition);
+ name = locationAsName(eipDefinition);
+ apiVersion = getApiVersion(eipDefinition);
+ vpnProfile = createVPNProfile();
+ if (vpnProfile != null) {
+ vpnProfile.mName = name;
+ }
}
- private JSONObject getGeneralConfiguration(JSONObject eip_definition) {
+ private JSONObject getGeneralConfiguration(JSONObject eipDefinition) {
try {
- return eip_definition.getJSONObject("openvpn_configuration");
+ return eipDefinition.getJSONObject(OPENVPN_CONFIGURATION);
} catch (JSONException e) {
return new JSONObject();
}
}
- private int getTimezone(JSONObject eip_definition) {
- JSONObject location = getLocationInfo(eip_definition);
- return location.optInt("timezone");
+ private int getTimezone(JSONObject eipDefinition) {
+ JSONObject location = getLocationInfo(eipDefinition);
+ return location.optInt(TIMEZONE);
+ }
+
+ private int getApiVersion(JSONObject eipDefinition) {
+ return eipDefinition.optInt(VERSION);
}
- private String locationAsName(JSONObject eip_definition) {
- JSONObject location = getLocationInfo(eip_definition);
- return location.optString("name");
+ private String locationAsName(JSONObject eipDefinition) {
+ JSONObject location = getLocationInfo(eipDefinition);
+ return location.optString(NAME);
}
private JSONObject getLocationInfo(JSONObject eipDefinition) {
try {
- JSONObject locations = eipDefinition.getJSONObject("locations");
+ JSONObject locations = eipDefinition.getJSONObject(LOCATIONS);
- return locations.getJSONObject(gateway.getString("location"));
+ return locations.getJSONObject(gateway.getString(LOCATION));
} catch (JSONException e) {
return new JSONObject();
}
@@ -98,18 +112,9 @@ public class Gateway {
*/
private VpnProfile createVPNProfile() {
try {
- ConfigParser cp = new ConfigParser();
-
- VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway);
- String configuration = vpnConfigurationGenerator.generate();
-
- cp.parseConfig(new StringReader(configuration));
- return cp.convertProfile();
- } catch (ConfigParser.ConfigParseError e) {
- // FIXME We didn't get a VpnProfile! Error handling! and log level
- e.printStackTrace();
- return null;
- } catch (IOException e) {
+ VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway, apiVersion);
+ return vpnConfigurationGenerator.generateVpnProfile();
+ } catch (ConfigParser.ConfigParseError | IOException | CloneNotSupportedException | JSONException e) {
// FIXME We didn't get a VpnProfile! Error handling! and log level
e.printStackTrace();
return null;
@@ -117,11 +122,11 @@ public class Gateway {
}
public String getName() {
- return mName;
+ return name;
}
public VpnProfile getProfile() {
- return mVpnProfile;
+ return vpnProfile;
}
public int getTimezone() {
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
index 2bd666bf..0ba0f207 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
@@ -36,7 +36,7 @@ public class GatewaySelector {
}
}
- Log.e(TAG, "There are less than " + nClosest + " Gateways available.");
+ Log.e(TAG, "There are less than " + (nClosest + 1) + " Gateways available.");
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 060843fd..c650938c 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -30,11 +30,18 @@ import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
+import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.core.connection.Connection;
import se.leap.bitmaskclient.Provider;
import se.leap.bitmaskclient.utils.PreferenceHelper;
+import static se.leap.bitmaskclient.Constants.CAPABILITIES;
+import static se.leap.bitmaskclient.Constants.GATEWAYS;
import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.Constants.TRANSPORT;
+import static se.leap.bitmaskclient.Constants.TYPE;
+import static se.leap.bitmaskclient.Constants.VERSION;
/**
* @author parmegv
@@ -88,10 +95,11 @@ public class GatewaysManager {
*/
void fromEipServiceJson(JSONObject eipDefinition) {
try {
- JSONArray gatewaysDefined = eipDefinition.getJSONArray("gateways");
+ JSONArray gatewaysDefined = eipDefinition.getJSONArray(GATEWAYS);
+ int apiVersion = eipDefinition.getInt(VERSION);
for (int i = 0; i < gatewaysDefined.length(); i++) {
JSONObject gw = gatewaysDefined.getJSONObject(i);
- if (isOpenVpnGateway(gw)) {
+ if (isOpenVpnGateway(gw, apiVersion)) {
JSONObject secrets = secretsConfiguration();
Gateway aux = new Gateway(eipDefinition, secrets, gw);
if (!gateways.contains(aux)) {
@@ -110,12 +118,29 @@ public class GatewaysManager {
* @param gateway to check
* @return true if gateway is an OpenVpn gateway otherwise false
*/
- private boolean isOpenVpnGateway(JSONObject gateway) {
- try {
- String transport = gateway.getJSONObject("capabilities").getJSONArray("transport").toString();
- return transport.contains("openvpn");
- } catch (JSONException e) {
- return false;
+ private boolean isOpenVpnGateway(JSONObject gateway, int apiVersion) {
+ switch (apiVersion) {
+ default:
+ case 1:
+ try {
+ String transport = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT).toString();
+ return transport.contains("openvpn");
+ } catch (JSONException e) {
+ return false;
+ }
+ case 2:
+ try {
+ JSONArray transports = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT);
+ for (int i = 0; i < transports.length(); i++) {
+ JSONObject transport = transports.getJSONObject(i);
+ if (transport.optString(TYPE).equals("openvpn")) {
+ return true;
+ }
+ }
+ return false;
+ } catch (JSONException e) {
+ return 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 6f0ccf18..7f09d21e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
@@ -20,48 +20,133 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.io.IOException;
+import java.io.StringReader;
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 static se.leap.bitmaskclient.Constants.CAPABILITIES;
+import static se.leap.bitmaskclient.Constants.IP_ADDRESS;
+import static se.leap.bitmaskclient.Constants.OPTIONS;
+import static se.leap.bitmaskclient.Constants.PORTS;
+import static se.leap.bitmaskclient.Constants.PROTOCOLS;
import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
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;
public class VpnConfigGenerator {
- private JSONObject general_configuration;
+ private JSONObject generalConfiguration;
private JSONObject gateway;
private JSONObject secrets;
+ private JSONObject obfs4Transport;
+ private int apiVersion;
+
+ private ConfigParser icsOpenvpnConfigParser = new ConfigParser();
+
public final static String TAG = VpnConfigGenerator.class.getSimpleName();
private final String newLine = System.getProperty("line.separator"); // Platform new line
- public VpnConfigGenerator(JSONObject general_configuration, JSONObject secrets, JSONObject gateway) {
- this.general_configuration = general_configuration;
+ public VpnConfigGenerator(JSONObject generalConfiguration, JSONObject secrets, JSONObject gateway, int apiVersion) {
+ this.generalConfiguration = generalConfiguration;
this.gateway = gateway;
this.secrets = secrets;
+ this.apiVersion = apiVersion;
+ checkCapabilities();
}
- public String generate() {
- return
- generalConfiguration()
+ 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;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public VpnProfile generateVpnProfile() throws IllegalStateException,
+ IOException,
+ ConfigParser.ConfigParseError,
+ CloneNotSupportedException,
+ JSONException,
+ NumberFormatException {
+
+ VpnProfile profile = createOvpnProfile();
+ if (supportsObfs4()) {
+ addPluggableTransportConnections(profile);
+ }
+ return profile;
+ }
+
+ 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() {
+ return generalConfiguration()
+ newLine
- + gatewayConfiguration()
+ + ovpnGatewayConfiguration()
+ newLine
+ secretsConfiguration()
+ newLine
+ androidCustomizations();
}
+ private VpnProfile createOvpnProfile() throws IOException, ConfigParser.ConfigParseError {
+ String configuration = getConfigurationString();
+ icsOpenvpnConfigParser.parseConfig(new StringReader(configuration));
+ return icsOpenvpnConfigParser.convertProfile();
+ }
+
private String generalConfiguration() {
String commonOptions = "";
try {
- Iterator keys = general_configuration.keys();
+ Iterator keys = generalConfiguration.keys();
while (keys.hasNext()) {
String key = keys.next().toString();
commonOptions += key + " ";
- for (String word : String.valueOf(general_configuration.get(key)).split(" "))
+ for (String word : String.valueOf(generalConfiguration.get(key)).split(" "))
commonOptions += word + " ";
commonOptions += newLine;
@@ -76,41 +161,73 @@ public class VpnConfigGenerator {
return commonOptions;
}
- private String gatewayConfiguration() {
+ private String ovpnGatewayConfiguration() {
String remotes = "";
- String ipAddressKeyword = "ip_address";
- String remoteKeyword = "remote";
- String portsKeyword = "ports";
- String protocolKeyword = "protocols";
- String capabilitiesKeyword = "capabilities";
-
+ StringBuilder stringBuilder = new StringBuilder();
try {
- String ip_address = gateway.getString(ipAddressKeyword);
- JSONObject capabilities = gateway.getJSONObject(capabilitiesKeyword);
- JSONArray ports = capabilities.getJSONArray(portsKeyword);
- for (int i = 0; i < ports.length(); i++) {
- String port_specific_remotes = "";
- int port = ports.getInt(i);
- JSONArray protocols = capabilities.getJSONArray(protocolKeyword);
- for (int j = 0; j < protocols.length(); j++) {
- String protocol = protocols.optString(j);
- String new_remote = remoteKeyword + " " + ip_address + " " + port + " " + protocol + newLine;
-
- port_specific_remotes += new_remote;
- }
- remotes += port_specific_remotes;
+ 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);
+ break;
+ case 2:
+ ovpnGatewayConfigApiv2(stringBuilder, ipAddress, transports);
+ break;
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
+
+ remotes = stringBuilder.toString();
if (remotes.endsWith(newLine)) {
remotes = remotes.substring(0, remotes.lastIndexOf(newLine));
}
return remotes;
}
+ private void ovpnGatewayConfigApiv1(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);
+ JSONArray protocols = capabilities.getJSONArray(PROTOCOLS);
+ for (int j = 0; j < protocols.length(); j++) {
+ protocol = protocols.optString(j);
+ String newRemote = REMOTE + " " + ipAddress + " " + port + " " + protocol + newLine;
+ stringBuilder.append(newRemote);
+ }
+ }
+ }
+
+ private void ovpnGatewayConfigApiv2(StringBuilder stringBuilder, String ipAddress, JSONArray transports) throws JSONException {
+ String port;
+ String protocol;
+ 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);
+ }
+ }
+ }
+ }
+
+
private String secretsConfiguration() {
try {
String ca =