summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java14
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java93
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/utils/BitmaskCoreProvider.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java139
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java255
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java163
6 files changed, 433 insertions, 233 deletions
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 cdec9e7a..b826d338 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
@@ -545,11 +545,17 @@ public final class Provider implements Parcelable {
}
public boolean hasGatewaysInDifferentLocations() {
- try {
- return getEipServiceJson().getJSONObject(LOCATIONS).length() > 1;
- } catch (NullPointerException | JSONException e) {
- return false;
+ if (apiVersion >= 5) {
+ //FIXME: getService().getLocations()
+ return true;
+ } else {
+ try {
+ return getEipServiceJson().getJSONObject(LOCATIONS).length() > 1;
+ } catch (NullPointerException | JSONException e) {
+ return false;
+ }
}
+
}
@Override
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java
index c2590012..abd42812 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java
@@ -1,5 +1,14 @@
package se.leap.bitmaskclient.base.models;
+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.CERT;
+import static se.leap.bitmaskclient.base.models.Constants.IAT_MODE;
+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.TRANSPORT;
+
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.gson.FieldNamingPolicy;
@@ -7,11 +16,16 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
+import org.json.JSONArray;
import org.json.JSONObject;
import java.io.Serializable;
+import java.util.Map;
+import java.util.Vector;
import de.blinkt.openvpn.core.connection.Connection;
+import io.swagger.client.model.ModelsBridge;
+import io.swagger.client.model.ModelsGateway;
public class Transport implements Serializable {
private final String type;
@@ -32,6 +46,13 @@ public class Transport implements Serializable {
this.options = options;
}
+ public Transport(String type, String[] protocols, @Nullable String[] ports) {
+ this.type = type;
+ this.protocols = protocols;
+ this.ports = ports;
+ this.options = null;
+ }
+
public String getType() {
return type;
}
@@ -67,6 +88,78 @@ public class Transport implements Serializable {
fromJson(json.toString(), Transport.class);
}
+ public static Transport createTransportFrom(ModelsBridge modelsBridge) {
+ if (modelsBridge == null) {
+ return null;
+ }
+ Map<String, Object> options = modelsBridge.getOptions();
+ Transport.Options transportOptions = new Transport.Options((String) options.get(CERT), (String) options.get(IAT_MODE));
+ Transport transport = new Transport(
+ modelsBridge.getType(),
+ new String[]{modelsBridge.getTransport()},
+ new String[]{String.valueOf(modelsBridge.getPort())},
+ transportOptions
+ );
+ return transport;
+ }
+
+ public static Transport createTransportFrom(ModelsGateway modelsGateway) {
+ if (modelsGateway == null) {
+ return null;
+ }
+ Transport transport = new Transport(
+ modelsGateway.getType(),
+ new String[]{modelsGateway.getTransport()},
+ new String[]{String.valueOf(modelsGateway.getPort())}
+ );
+ return transport;
+ }
+
+
+ @NonNull
+ public static Vector<Transport> createTransportsFrom(JSONObject gateway, int apiVersion) throws IllegalArgumentException {
+ Vector<Transport> transports = new Vector<>();
+ try {
+ if (apiVersion >= 3) {
+ JSONArray supportedTransports = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT);
+ for (int i = 0; i < supportedTransports.length(); i++) {
+ Transport transport = Transport.fromJson(supportedTransports.getJSONObject(i));
+ transports.add(transport);
+ }
+ } else {
+ JSONObject capabilities = gateway.getJSONObject(CAPABILITIES);
+ JSONArray ports = capabilities.getJSONArray(PORTS);
+ JSONArray protocols = capabilities.getJSONArray(PROTOCOLS);
+ String[] portArray = new String[ports.length()];
+ String[] protocolArray = new String[protocols.length()];
+ for (int i = 0; i < ports.length(); i++) {
+ portArray[i] = String.valueOf(ports.get(i));
+ }
+ for (int i = 0; i < protocols.length(); i++) {
+ protocolArray[i] = protocols.optString(i);
+ }
+ Transport transport = new Transport(OPENVPN.toString(), protocolArray, portArray);
+ transports.add(transport);
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException();
+ //throw new ConfigParser.ConfigParseError("Api version ("+ apiVersion +") did not match required JSON fields");
+ }
+ return transports;
+ }
+
+ public static Vector<Transport> createTransportsFrom(ModelsBridge modelsBridge) {
+ Vector<Transport> transports = new Vector<>();
+ transports.add(Transport.createTransportFrom(modelsBridge));
+ return transports;
+ }
+
+ public static Vector<Transport> createTransportsFrom(ModelsGateway modelsGateway) {
+ Vector<Transport> transports = new Vector<>();
+ transports.add(Transport.createTransportFrom(modelsGateway));
+ return transports;
+ }
+
public static class Options implements Serializable {
@Nullable
private final String cert;
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/BitmaskCoreProvider.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/BitmaskCoreProvider.java
new file mode 100644
index 00000000..a9797142
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/BitmaskCoreProvider.java
@@ -0,0 +1,2 @@
+package se.leap.bitmaskclient.base.utils;public class BitmaskCoreProvider {
+}
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 16c92855..234eb9b0 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -20,6 +20,7 @@ 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;
+import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS6;
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;
@@ -27,6 +28,7 @@ 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 static se.leap.bitmaskclient.base.models.Transport.createTransportsFrom;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningCert;
@@ -47,12 +49,18 @@ import org.json.JSONObject;
import java.io.IOException;
import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
import java.util.Set;
import java.util.Vector;
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.ConfigParser;
import de.blinkt.openvpn.core.connection.Connection;
+import io.swagger.client.model.ModelsBridge;
+import io.swagger.client.model.ModelsEIPService;
+import io.swagger.client.model.ModelsGateway;
+import se.leap.bitmaskclient.base.models.Transport;
import se.leap.bitmaskclient.base.utils.ConfigHelper;
/**
@@ -71,6 +79,8 @@ public class Gateway {
private JSONObject generalConfiguration;
private JSONObject secrets;
private JSONObject gateway;
+ private Vector<ModelsGateway> modelsGateways;
+ private Vector<ModelsBridge> modelsBridges;
private JSONObject load;
// the location of a gateway is its name
@@ -78,6 +88,10 @@ public class Gateway {
private int timezone;
private int apiVersion;
private Vector<VpnProfile> vpnProfiles;
+ private String remoteIpAddress;
+ private String remoteIpAddressV6;
+ private String host;
+ private String locationName;
/**
* Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json
@@ -94,32 +108,62 @@ public class Gateway {
this.gateway = gateway;
this.secrets = secrets;
this.load = load;
+ this.apiVersion = eipDefinition.optInt(VERSION);
+ this.remoteIpAddress = gateway.optString(IP_ADDRESS);
+ this.remoteIpAddressV6 = gateway.optString(IP_ADDRESS6);
+ this.host = gateway.optString(HOST);
+ JSONObject location = getLocationInfo(gateway, eipDefinition);
+ this.locationName = location.optString(NAME);
+ this.timezone = location.optInt(TIMEZONE);
+ VpnConfigGenerator.Configuration configuration = getProfileConfig(Transport.createTransportsFrom(gateway, apiVersion));
+ this.generalConfiguration = getGeneralConfiguration(eipDefinition);
+ this.name = configuration.profileName;
+ this.vpnProfiles = createVPNProfiles(configuration);
+ }
+
+
+ public Gateway(ModelsEIPService eipService, JSONObject secrets, ModelsGateway modelsGateway, int apiVersion) throws ConfigParser.ConfigParseError, JSONException, IOException {
+ this.apiVersion = apiVersion;
+ generalConfiguration = getGeneralConfiguration(eipService);
+ this.secrets = secrets;
+ this.modelsGateways = new Vector<>();
+ this.modelsBridges = new Vector<>();
+ this.modelsGateways.add(modelsGateway);
+
+ this.remoteIpAddress = modelsGateway.getIpAddr();
+ this.remoteIpAddressV6 = modelsGateway.getIp6Addr();
+ this.host = modelsGateway.getHost();
+ this.locationName = "UNKNOWN due to bug in menshen";
+ // TODO eipService.getLocations().get
+ this.timezone = 2; // modelsGateway.getLocation()...
+ this.apiVersion = apiVersion;
+ VpnConfigGenerator.Configuration configuration = getProfileConfig(createTransportsFrom(modelsGateway));
+ this.name = configuration.profileName;
+ this.vpnProfiles = createVPNProfiles(configuration);
+ }
- apiVersion = getApiVersion(eipDefinition);
- VpnConfigGenerator.Configuration configuration = getProfileConfig(eipDefinition, apiVersion);
- generalConfiguration = getGeneralConfiguration(eipDefinition);
- timezone = getTimezone(eipDefinition);
+ public Gateway(ModelsEIPService eipService, JSONObject secrets, ModelsBridge modelsBridge, int apiVersion) throws ConfigParser.ConfigParseError, JSONException, IOException {
+ this.apiVersion = apiVersion;
+ generalConfiguration = getGeneralConfiguration(eipService);
+ this.secrets = secrets;
+ this.modelsGateways = new Vector<>();
+ this.modelsBridges = new Vector<>();
+ this.modelsBridges.add(modelsBridge);
+ remoteIpAddress = modelsBridge.getIpAddr();
+ host = modelsBridge.getHost();
+ locationName = "UNKNOWN due to bug in menshen";
+ // FIXME eipService.getLocations().get
+ timezone = 2; // modelsGateway.getLocation()...
+ this.apiVersion = apiVersion;
+ VpnConfigGenerator.Configuration configuration = getProfileConfig(Transport.createTransportsFrom(modelsBridge));
name = configuration.profileName;
vpnProfiles = createVPNProfiles(configuration);
}
- private VpnConfigGenerator.Configuration getProfileConfig(JSONObject eipDefinition, int apiVersion) {
- VpnConfigGenerator.Configuration config = new VpnConfigGenerator.Configuration();
- config.apiVersion = apiVersion;
- config.preferUDP = getPreferUDP();
- config.experimentalTransports = allowExperimentalTransports();
- config.excludedApps = getExcludedApps();
-
- config.remoteGatewayIP = config.useObfuscationPinning ? getObfuscationPinningIP() : gateway.optString(IP_ADDRESS);
- config.useObfuscationPinning = useObfuscationPinning();
- config.profileName = config.useObfuscationPinning ? getObfuscationPinningGatewayLocation() : locationAsName(eipDefinition);
- if (config.useObfuscationPinning) {
- config.obfuscationProxyIP = getObfuscationPinningIP();
- config.obfuscationProxyPort = getObfuscationPinningPort();
- config.obfuscationProxyCert = getObfuscationPinningCert();
- config.obfuscationProxyKCP = getObfuscationPinningKCP();
- }
- return config;
+
+
+ private VpnConfigGenerator.Configuration getProfileConfig(Vector<Transport> transports) {
+ return VpnConfigGenerator.Configuration.createProfileConfig(transports, apiVersion, remoteIpAddress, remoteIpAddressV6, locationName);
}
public void updateLoad(JSONObject load) {
@@ -134,29 +178,33 @@ public class Gateway {
}
}
- private int getTimezone(JSONObject eipDefinition) {
- JSONObject location = getLocationInfo(eipDefinition);
- return location.optInt(TIMEZONE);
- }
+ private JSONObject getGeneralConfiguration(ModelsEIPService eipService) {
+ JSONObject config = new JSONObject();
+ Map<String, Object> openvpnOptions = eipService.getOpenvpnConfiguration();
+ Set<String> keys = openvpnOptions.keySet();
+ Iterator<String> i = keys.iterator();
+ while (i.hasNext()) {
+ try {
+ String key = i.next();
+ Object o = openvpnOptions.get(key);
+ config.put(key, o);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
- private int getApiVersion(JSONObject eipDefinition) {
- return eipDefinition.optInt(VERSION);
+ return config;
}
public String getRemoteIP() {
- return gateway.optString(IP_ADDRESS);
+ return remoteIpAddress;
}
public String getHost() {
- return gateway.optString(HOST);
+ return host;
}
- private String locationAsName(JSONObject eipDefinition) {
- JSONObject location = getLocationInfo(eipDefinition);
- return location.optString(NAME);
- }
-
- private JSONObject getLocationInfo(JSONObject eipDefinition) {
+ private JSONObject getLocationInfo(JSONObject gateway, JSONObject eipDefinition) {
try {
JSONObject locations = eipDefinition.getJSONObject(LOCATIONS);
@@ -191,9 +239,8 @@ public class Gateway {
*/
private @NonNull Vector<VpnProfile> createVPNProfiles(VpnConfigGenerator.Configuration profileConfig)
throws ConfigParser.ConfigParseError, IOException, JSONException {
- VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway, profileConfig);
- Vector<VpnProfile> profiles = vpnConfigurationGenerator.generateVpnProfiles();
- return profiles;
+ VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, profileConfig);
+ return vpnConfigurationGenerator.generateVpnProfiles();
}
public String getName() {
@@ -250,8 +297,8 @@ public class Gateway {
return getProfile(transportType, obfuscationTransportLayerProtocols) != null;
}
- public HashSet<Connection.TransportType> getSupportedTransports() {
- HashSet<Connection.TransportType> transportTypes = new HashSet<>();
+ public Set<Connection.TransportType> getSupportedTransports() {
+ Set<Connection.TransportType> transportTypes = new HashSet<>();
for (VpnProfile p : vpnProfiles) {
transportTypes.add(p.getTransportType());
}
@@ -277,4 +324,16 @@ public class Gateway {
return new Gson().toJson(this, Gateway.class);
}
+ public Gateway addTransport(Transport transport) {
+ Vector<Transport> transports = new Vector<>();
+ transports.add(transport);
+ VpnConfigGenerator.Configuration profileConfig = getProfileConfig(transports);
+ try {
+ Vector<VpnProfile> profiles = createVPNProfiles(profileConfig);
+ vpnProfiles.addAll(profiles);
+ } catch (ConfigParser.ConfigParseError | IOException | JSONException e) {
+ e.printStackTrace();
+ }
+ return this;
+ }
}
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 37360f81..d7f3b42e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -20,8 +20,10 @@ import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_HOP;
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.CERT;
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.IAT_MODE;
import static se.leap.bitmaskclient.base.models.Constants.KCP;
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.base.models.Constants.SORTED_GATEWAYS;
@@ -65,6 +67,9 @@ import de.blinkt.openvpn.core.ConfigParser;
import de.blinkt.openvpn.core.VpnStatus;
import de.blinkt.openvpn.core.connection.Connection;
import de.blinkt.openvpn.core.connection.Connection.TransportType;
+import io.swagger.client.model.ModelsBridge;
+import io.swagger.client.model.ModelsEIPService;
+import io.swagger.client.model.ModelsGateway;
import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.base.models.GatewayJson;
@@ -415,84 +420,150 @@ public class GatewaysManager {
return new Gson().toJson(gateways, listType);
}
- /**
- * parse gateways from Provider's eip service
- * @param provider
- */
- private void parseDefaultGateways(Provider provider) {
- try {
- JSONObject eipDefinition = provider.getEipServiceJson();
- JSONObject secrets = secretsConfigurationFromCurrentProvider();
- JSONArray gatewaysDefined = new JSONArray();
- try {
- gatewaysDefined = eipDefinition.getJSONArray(GATEWAYS);
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- if (PreferenceHelper.useObfuscationPinning()) {
- try {
- Transport[] transports = new Transport[]{
- new Transport(OBFS4.toString(),
- new String[]{getObfuscationPinningKCP() ? "kcp" : "tcp"},
- new String[]{getObfuscationPinningPort()},
- getObfuscationPinningCert())};
- GatewayJson.Capabilities capabilities = new GatewayJson.Capabilities(false, false, false, transports, false);
- GatewayJson gatewayJson = new GatewayJson(context.getString(R.string.unknown_location), getObfuscationPinningIP(
-
- ), null, PINNED_OBFUSCATION_PROXY, capabilities);
- Gateway gateway = new Gateway(eipDefinition, secrets, new JSONObject(gatewayJson.toString()));
- addGateway(gateway);
- } catch (JSONException | ConfigParser.ConfigParseError | IOException e) {
- e.printStackTrace();
- }
- } else {
- for (int i = 0; i < gatewaysDefined.length(); i++) {
- try {
- JSONObject gw = gatewaysDefined.getJSONObject(i);
- Gateway aux = new Gateway(eipDefinition, secrets, gw);
- if (gateways.get(aux.getHost()) == null) {
- addGateway(aux);
- }
- } catch (JSONException | IOException e) {
- e.printStackTrace();
- VpnStatus.logError("Unable to parse gateway config!");
- } catch (ConfigParser.ConfigParseError e) {
- VpnStatus.logError("Unable to parse gateway config: " + e.getLocalizedMessage());
- }
- }
- }
- } catch (NullPointerException npe) {
- npe.printStackTrace();
- }
+ public void parseGatewaysV3(Provider provider) {
+ try {
+ JSONObject eipDefinition = provider.getEipServiceJson();
+ JSONObject secrets = secretsConfigurationFromCurrentProvider();
+ JSONArray gatewaysDefined = new JSONArray();
+ try {
+ gatewaysDefined = eipDefinition.getJSONArray(GATEWAYS);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ if (PreferenceHelper.useObfuscationPinning()) {
+ try {
+ Transport[] transports = new Transport[]{
+ new Transport(OBFS4.toString(),
+ new String[]{getObfuscationPinningKCP() ? "kcp" : "tcp"},
+ new String[]{getObfuscationPinningPort()},
+ getObfuscationPinningCert())};
+ GatewayJson.Capabilities capabilities = new GatewayJson.Capabilities(false, false, false, transports, false);
+ GatewayJson gatewayJson = new GatewayJson(context.getString(R.string.unknown_location), getObfuscationPinningIP(
+
+ ), null, PINNED_OBFUSCATION_PROXY, capabilities);
+ Gateway gateway = new Gateway(eipDefinition, secrets, new JSONObject(gatewayJson.toString()));
+ addGateway(gateway);
+ } catch (JSONException | ConfigParser.ConfigParseError | IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ for (int i = 0; i < gatewaysDefined.length(); i++) {
+ try {
+ JSONObject gw = gatewaysDefined.getJSONObject(i);
+ Gateway aux = new Gateway(eipDefinition, secrets, gw);
+ if (gateways.get(aux.getHost()) == null) {
+ addGateway(aux);
+ }
+ } catch (JSONException | IOException e) {
+ e.printStackTrace();
+ VpnStatus.logError("Unable to parse gateway config!");
+ } catch (ConfigParser.ConfigParseError e) {
+ VpnStatus.logError("Unable to parse gateway config: " + e.getLocalizedMessage());
+ }
+ }
+ }
+ } catch (NullPointerException npe) {
+ npe.printStackTrace();
+ }
+
+ if (BuildConfig.BUILD_TYPE.equals("debug") && handleGatewayPinning()) {
+ return;
+ }
+
+ // parse v3 menshen geoIP json variants
+ if (hasSortedGatewaysWithLoad(provider)) {
+ parseGatewaysWithLoad(provider);
+ } else {
+ parseSimpleGatewayList(provider);
+ }
+ }
+
+ public void parseGatewaysV5(Provider provider) {
+ ModelsGateway[] modelsGateways = provider.getGateways();
+ ModelsBridge[] modelsBridges = provider.getBridges();
+ ModelsEIPService modelsEIPService = provider.getService();
+ JSONObject secrets = secretsConfigurationFromCurrentProvider();
+ int apiVersion = provider.getApiVersion();
+
+ if (PreferenceHelper.useObfuscationPinning()) {
+ try {
+ ModelsBridge modelsBridge = new ModelsBridge();
+ modelsBridge.ipAddr(getObfuscationPinningIP());
+ modelsBridge.port(Integer.valueOf(getObfuscationPinningPort()));
+ HashMap<String, Object> options = new HashMap<>();
+ options.put(CERT, getObfuscationPinningCert());
+ options.put(IAT_MODE, "0");
+ modelsBridge.options(options);
+ modelsBridge.transport(getObfuscationPinningKCP() ? "kcp" : "tcp");
+ modelsBridge.type(OBFS4.toString());
+ modelsBridge.host(PINNED_OBFUSCATION_PROXY);
+ Gateway gateway = new Gateway(modelsEIPService, secrets, modelsBridge, provider.getApiVersion());
+ addGateway(gateway);
+ } catch (NumberFormatException | ConfigParser.ConfigParseError | JSONException |
+ IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ for (ModelsGateway modelsGateway : modelsGateways) {
+ String host = modelsGateway.getHost();
+ Gateway gateway = gateways.get(host);
+ if (gateway == null) {
+ try {
+ addGateway(new Gateway(modelsEIPService, secrets, modelsGateway, apiVersion));
+ } catch (ConfigParser.ConfigParseError | JSONException | IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ addGateway(gateway.addTransport(Transport.createTransportFrom(modelsGateway)));
+ }
+ }
+ for (ModelsBridge modelsBridge : modelsBridges) {
+ String host = modelsBridge.getHost();
+ Gateway gateway = gateways.get(host);
+ if (gateway == null) {
+ try {
+ addGateway(new Gateway(modelsEIPService, secrets, modelsBridge, apiVersion));
+ } catch (ConfigParser.ConfigParseError | JSONException | IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ addGateway(gateway.addTransport(Transport.createTransportFrom(modelsBridge)));
+ }
+ }
+ }
+
+ if (BuildConfig.BUILD_TYPE.equals("debug")) {
+ handleGatewayPinning();
+ }
}
private void parseSimpleGatewayList(Provider provider) {
- try {
- JSONObject geoIpJson = provider.getGeoIpJson();
- JSONArray gatewaylist = geoIpJson.getJSONArray(GATEWAYS);
-
- for (int i = 0; i < gatewaylist.length(); i++) {
- try {
- String key = gatewaylist.getString(i);
- if (gateways.containsKey(key)) {
- presortedList.add(gateways.get(key));
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- } catch (NullPointerException | JSONException npe) {
- Log.d(TAG, "No valid geoip json found: " + npe.getLocalizedMessage());
- }
+ try {
+ JSONObject geoIpJson = provider.getGeoIpJson();
+ JSONArray gatewaylist = geoIpJson.getJSONArray(GATEWAYS);
+
+ for (int i = 0; i < gatewaylist.length(); i++) {
+ try {
+ String key = gatewaylist.getString(i);
+ if (gateways.containsKey(key)) {
+ presortedList.add(gateways.get(key));
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ } catch (NullPointerException | JSONException npe) {
+ Log.d(TAG, "No valid geoip json found: " + npe.getLocalizedMessage());
+ }
}
private boolean hasSortedGatewaysWithLoad(@Nullable Provider provider) {
- if (provider == null) {
- return false;
- }
- JSONObject geoIpJson = provider.getGeoIpJson();
- return geoIpJson.has(SORTED_GATEWAYS);
+ if (provider == null) {
+ return false;
+ }
+ JSONObject geoIpJson = provider.getGeoIpJson();
+ return geoIpJson.has(SORTED_GATEWAYS);
}
private void parseGatewaysWithLoad(Provider provider) {
@@ -534,30 +605,28 @@ public class GatewaysManager {
}
private void configureFromCurrentProvider() {
- Provider provider = ProviderObservable.getInstance().getCurrentProvider();
- parseDefaultGateways(provider);
- if (BuildConfig.BUILD_TYPE.equals("debug") && handleGatewayPinning()) {
- return;
- }
- if (hasSortedGatewaysWithLoad(provider)) {
- parseGatewaysWithLoad(provider);
- } else {
- parseSimpleGatewayList(provider);
- }
-
+ Provider provider = ProviderObservable.getInstance().getCurrentProvider();
+ if (provider == null) {
+ return;
+ }
+ if (provider.getApiVersion() < 5) {
+ parseGatewaysV3(provider);
+ } else {
+ parseGatewaysV5(provider);
+ }
}
private boolean handleGatewayPinning() {
- String host = PreferenceHelper.getPinnedGateway();
- if (host == null) {
- return false;
- }
- Gateway gateway = gateways.get(host);
- gateways.clear();
- if (gateway != null) {
- gateways.put(host, gateway);
- }
- return true;
+ String host = PreferenceHelper.getPinnedGateway();
+ if (host == null) {
+ return false;
+ }
+ Gateway gateway = gateways.get(host);
+ gateways.clear();
+ if (gateway != null) {
+ gateways.put(host, gateway);
+ }
+ return true;
}
}
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 5defa7e6..f988dfa0 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
@@ -19,22 +19,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_HOP;
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.KCP;
-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_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.base.models.Constants.REMOTE;
import static se.leap.bitmaskclient.base.models.Constants.TCP;
-import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT;
import static se.leap.bitmaskclient.base.models.Constants.UDP;
-
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningCert;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningGatewayLocation;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningIP;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningKCP;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningPort;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useObfuscationPinning;
+
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -57,7 +60,6 @@ import se.leap.bitmaskclient.pluggableTransports.models.Obfs4Options;
public class VpnConfigGenerator {
private final JSONObject generalConfiguration;
- private final JSONObject gateway;
private final JSONObject secrets;
Vector<Transport> transports = new Vector<>();
private final int apiVersion;
@@ -69,6 +71,7 @@ public class VpnConfigGenerator {
private final String obfuscationPinningCert;
private final boolean obfuscationPinningKCP;
private final String remoteGatewayIP;
+ private final String remoteGatewayIPv6;
private final String profileName;
private final Set<String> excludedApps;
@@ -81,6 +84,7 @@ public class VpnConfigGenerator {
boolean preferUDP;
boolean experimentalTransports;
String remoteGatewayIP = "";
+ String remoteGatewayIPv6 = "";
String profileName = "";
Set<String> excludedApps = null;
@@ -89,11 +93,33 @@ public class VpnConfigGenerator {
String obfuscationProxyIP = "";
String obfuscationProxyPort = "";
String obfuscationProxyCert = "";
+ Vector<Transport> transports = new Vector<>();
+
+ public static VpnConfigGenerator.Configuration createProfileConfig(Vector<Transport> transports, int apiVersion, String remoteIpAddress, String remoteIpAddressV6, String locationName) {
+ VpnConfigGenerator.Configuration config = new VpnConfigGenerator.Configuration();
+ config.apiVersion = apiVersion;
+ config.preferUDP = getPreferUDP();
+ config.experimentalTransports = allowExperimentalTransports();
+ config.excludedApps = getExcludedApps();
+
+ config.remoteGatewayIP = config.useObfuscationPinning ? getObfuscationPinningIP() : remoteIpAddress;
+ config.remoteGatewayIPv6 = config.useObfuscationPinning ? null : remoteIpAddressV6;
+ config.useObfuscationPinning = useObfuscationPinning();
+ config.profileName = config.useObfuscationPinning ? getObfuscationPinningGatewayLocation() : locationName;
+ if (config.useObfuscationPinning) {
+ config.obfuscationProxyIP = getObfuscationPinningIP();
+ config.obfuscationProxyPort = getObfuscationPinningPort();
+ config.obfuscationProxyCert = getObfuscationPinningCert();
+ config.obfuscationProxyKCP = getObfuscationPinningKCP();
+ }
+ config.transports = transports;
+ return config;
+ }
}
- public VpnConfigGenerator(JSONObject generalConfiguration, JSONObject secrets, JSONObject gateway, Configuration config) throws ConfigParser.ConfigParseError {
+
+ public VpnConfigGenerator(JSONObject generalConfiguration, JSONObject secrets, Configuration config) {
this.generalConfiguration = generalConfiguration;
- this.gateway = gateway;
this.secrets = secrets;
this.apiVersion = config.apiVersion;
this.preferUDP = config.preferUDP;
@@ -104,23 +130,10 @@ public class VpnConfigGenerator {
this.obfuscationPinningCert = config.obfuscationProxyCert;
this.obfuscationPinningKCP = config.obfuscationProxyKCP;
this.remoteGatewayIP = config.remoteGatewayIP;
+ this.remoteGatewayIPv6 = config.remoteGatewayIPv6;
+ this.transports = config.transports;
this.profileName = config.profileName;
this.excludedApps = config.excludedApps;
- checkCapabilities();
- }
-
- public void checkCapabilities() throws ConfigParser.ConfigParseError {
- try {
- if (apiVersion >= 3) {
- JSONArray supportedTransports = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT);
- for (int i = 0; i < supportedTransports.length(); i++) {
- Transport transport = Transport.fromJson(supportedTransports.getJSONObject(i));
- transports.add(transport);
- }
- }
- } catch (Exception e) {
- throw new ConfigParser.ConfigParseError("Api version ("+ apiVersion +") did not match required JSON fields");
- }
}
public Vector<VpnProfile> generateVpnProfiles() throws
@@ -128,42 +141,28 @@ public class VpnConfigGenerator {
NumberFormatException {
Vector<VpnProfile> profiles = new Vector<>();
- if (apiVersion >= 3) {
- for (Transport transport : transports){
- if (transport.getTransportType().isPluggableTransport()) {
- Transport.Options transportOptions = transport.getOptions();
- if (!experimentalTransports && transportOptions != null && transportOptions.isExperimental()) {
- continue;
- }
- } else if (transport.getTransportType() == OPENVPN && useObfuscationPinning) {
+ for (Transport transport : transports){
+ if (transport.getTransportType().isPluggableTransport()) {
+ Transport.Options transportOptions = transport.getOptions();
+ if (!experimentalTransports && transportOptions != null && transportOptions.isExperimental()) {
continue;
}
- try {
- profiles.add(createProfile(transport));
- } catch (ConfigParser.ConfigParseError | NumberFormatException | JSONException | IOException e) {
- e.printStackTrace();
- }
+ } else if (transport.getTransportType() == OPENVPN && useObfuscationPinning) {
+ continue;
}
- } else if (supportsOpenvpn()) {
- // API v1 - TODO: let's remove support for API v1 soon
try {
- profiles.add(createApiv1OpenvpnProfile());
+ profiles.add(createProfile(transport));
} catch (ConfigParser.ConfigParseError | NumberFormatException | JSONException | IOException e) {
e.printStackTrace();
}
}
+
if (profiles.isEmpty()) {
throw new ConfigParser.ConfigParseError("No supported transports detected.");
}
return profiles;
}
- private boolean supportsOpenvpn() {
- return !useObfuscationPinning &&
- ((apiVersion >= 3 && getTransport(OPENVPN) != null) ||
- (apiVersion < 3 && !gatewayConfiguration(null).isEmpty()));
- }
-
private String getConfigurationString(Transport transport) {
return generalConfiguration()
+ newLine
@@ -193,23 +192,8 @@ public class VpnConfigGenerator {
return profile;
}
- @VisibleForTesting
- protected VpnProfile createApiv1OpenvpnProfile() throws IOException, ConfigParser.ConfigParseError, JSONException {
- String configuration = getConfigurationString(null);
- ConfigParser icsOpenvpnConfigParser = new ConfigParser();
- icsOpenvpnConfigParser.parseConfig(new StringReader(configuration));
-
- VpnProfile profile = icsOpenvpnConfigParser.convertProfile(OPENVPN);
- profile.mName = profileName;
- profile.mGatewayIp = remoteGatewayIP;
- if (excludedApps != null) {
- profile.mAllowedAppsVpn = new HashSet<>(excludedApps);
- }
- return profile;
- }
-
- private Obfs4Options getObfs4Options(Transport transport) throws JSONException {
- String ip = gateway.getString(IP_ADDRESS);
+ private Obfs4Options getObfs4Options(Transport transport) throws JSONException, NullPointerException {
+ String ip = remoteGatewayIP;
if (useObfuscationPinning) {
transport = new Transport(OBFS4.toString(),
new String[]{obfuscationPinningKCP ? KCP : TCP},
@@ -223,9 +207,9 @@ public class VpnConfigGenerator {
private String generalConfiguration() {
String commonOptions = "";
try {
- Iterator keys = generalConfiguration.keys();
+ Iterator<String> keys = generalConfiguration.keys();
while (keys.hasNext()) {
- String key = keys.next().toString();
+ String key = keys.next();
commonOptions += key + " ";
for (String word : String.valueOf(generalConfiguration.get(key)).split(" "))
@@ -243,32 +227,19 @@ public class VpnConfigGenerator {
return commonOptions;
}
- private String gatewayConfiguration(@Nullable Transport transport) {
+ private String gatewayConfiguration(@NonNull Transport transport) {
String configs = "";
StringBuilder stringBuilder = new StringBuilder();
try {
- String ipAddress = null;
- JSONObject capabilities = gateway.getJSONObject(CAPABILITIES);
switch (apiVersion) {
- default:
- case 1:
- case 2:
- ipAddress = gateway.getString(IP_ADDRESS);
- gatewayConfigApiv1(stringBuilder, ipAddress, capabilities);
- break;
- case 3:
- case 4:
- ipAddress = gateway.optString(IP_ADDRESS);
- String ipAddress6 = gateway.optString(IP_ADDRESS6);
- String[] ipAddresses = ipAddress6.isEmpty() ?
- new String[]{ipAddress} :
- new String[]{ipAddress6, ipAddress};
- if (transport == null) {
- throw new NullPointerException("Transport is not allowed to be null in APIv3+");
- }
+ case 1, 2 -> gatewayConfigApiv1(transport, stringBuilder, remoteGatewayIP);
+ case 3, 4, 5 -> {
+ String[] ipAddresses = (remoteGatewayIPv6 == null || remoteGatewayIPv6.isEmpty()) ?
+ new String[]{remoteGatewayIP} :
+ new String[]{remoteGatewayIPv6, remoteGatewayIP};
gatewayConfigMinApiv3(transport, stringBuilder, ipAddresses);
- break;
+ }
}
} catch (JSONException | NullPointerException e) {
// TODO Auto-generated catch block
@@ -300,15 +271,15 @@ public class VpnConfigGenerator {
return null;
}
- private void gatewayConfigApiv1(StringBuilder stringBuilder, String ipAddress, JSONObject capabilities) throws JSONException {
- int port;
- String protocol;
- JSONArray ports = capabilities.getJSONArray(PORTS);
- JSONArray protocols = capabilities.getJSONArray(PROTOCOLS);
- for (int i = 0; i < ports.length(); i++) {
- port = ports.getInt(i);
- for (int j = 0; j < protocols.length(); j++) {
- protocol = protocols.optString(j);
+ private void gatewayConfigApiv1(Transport transport, StringBuilder stringBuilder, String ipAddress) throws JSONException {
+ if (transport == null || transport.getProtocols() == null || transport.getPorts() == null) {
+ VpnStatus.logError("Misconfigured provider: missing details for transport openvpn on gateway " + ipAddress);
+ return;
+ }
+ String[] ports = transport.getPorts();
+ String[] protocols = transport.getProtocols();
+ for (String port : ports) {
+ for (String protocol : protocols) {
String newRemote = REMOTE + " " + ipAddress + " " + port + " " + protocol + newLine;
stringBuilder.append(newRemote);
}