summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/de/blinkt/openvpn/LaunchVPN.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/VpnProfile.java127
-rw-r--r--app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/activities/LogWindow.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java280
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/Connection.java51
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java12
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java53
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java3
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java11
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java153
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java4
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java3
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java8
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/X509Utils.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/views/SeekBarTicks.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Dashboard.java645
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipFragment.java28
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java31
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/SessionDialog.java10
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EIP.java168
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java47
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java94
31 files changed, 1078 insertions, 676 deletions
diff --git a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
index d7f3e110..02abd7a1 100644
--- a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
+++ b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn;
diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
index fb2ba90d..4f747d21 100644
--- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
+++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn;
@@ -42,6 +42,7 @@ import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Locale;
import java.util.UUID;
import java.util.Vector;
@@ -51,13 +52,14 @@ import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
+import de.blinkt.openvpn.core.Connection;
import de.blinkt.openvpn.core.NativeUtils;
import de.blinkt.openvpn.core.OpenVPNService;
import de.blinkt.openvpn.core.VPNLaunchHelper;
import de.blinkt.openvpn.core.VpnStatus;
import de.blinkt.openvpn.core.X509Utils;
-public class VpnProfile implements Serializable {
+public class VpnProfile implements Serializable, Cloneable {
// Note that this class cannot be moved to core where it belongs since
// the profile loading depends on it being here
// The Serializable documentation mentions that class name change are possible
@@ -71,7 +73,7 @@ public class VpnProfile implements Serializable {
private static final long serialVersionUID = 7085688938959334563L;
public static final int MAXLOGLEVEL = 4;
- public static final int CURRENT_PROFILE_VERSION = 2;
+ public static final int CURRENT_PROFILE_VERSION = 5;
public static final int DEFAULT_MSSFIX_SIZE = 1450;
public static String DEFAULT_DNS1 = "8.8.8.8";
public static String DEFAULT_DNS2 = "8.8.4.4";
@@ -106,12 +108,10 @@ public class VpnProfile implements Serializable {
public String mClientKeyFilename;
public String mCaFilename;
public boolean mUseLzo = true;
- public String mServerPort = "1194";
- public boolean mUseUdp = true;
public String mPKCS12Filename;
public String mPKCS12Password;
public boolean mUseTLSAuth = false;
- public String mServerName = "openvpn.blinkt.de";
+
public String mDNS1 = DEFAULT_DNS1;
public String mDNS2 = DEFAULT_DNS2;
public String mIPv4Address;
@@ -152,6 +152,16 @@ public class VpnProfile implements Serializable {
public String mExcludedRoutes;
public String mExcludedRoutesv6;
public int mMssFix =0; // -1 is default,
+ public Connection[] mConnections = new Connection[0];
+ public boolean mRemoteRandom=false;
+ public HashSet<String> mAllowedAppsVpn = new HashSet<String>();
+ public boolean mAllowedAppsVpnAreDisallowed = true;
+
+
+ /* Options no long used in new profiles */
+ public String mServerName = "openvpn.blinkt.de";
+ public String mServerPort = "1194";
+ public boolean mUseUdp = true;
@@ -159,6 +169,9 @@ public class VpnProfile implements Serializable {
mUuid = UUID.randomUUID();
mName = name;
mProfileVersion = CURRENT_PROFILE_VERSION;
+
+ mConnections = new Connection[1];
+ mConnections[0] = new Connection();
}
public static String openVpnEscape(String unescaped) {
@@ -206,7 +219,30 @@ public class VpnProfile implements Serializable {
mAllowLocalLAN = Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT;
}
+ if (mProfileVersion < 4) {
+ moveOptionsToConnection();
+ mAllowedAppsVpnAreDisallowed=true;
+ }
+ if (mAllowedAppsVpn==null)
+ mAllowedAppsVpn = new HashSet<String>();
+ if (mConnections ==null)
+ mConnections = new Connection[0];
+
mProfileVersion= CURRENT_PROFILE_VERSION;
+
+ }
+
+ private void moveOptionsToConnection() {
+ mConnections = new Connection[1];
+ Connection conn = new Connection();
+
+ conn.mServerName = mServerName;
+ conn.mServerPort = mServerPort;
+ conn.mUseUdp = mUseUdp;
+ conn.mCustomConfiguration = "";
+
+ mConnections[0] = conn;
+
}
public String getConfigFile(Context context, boolean configForOvpn3) {
@@ -267,15 +303,27 @@ public class VpnProfile implements Serializable {
// We cannot use anything else than tun
cfg += "dev tun\n";
- // Server Address
- cfg += "remote ";
- cfg += mServerName;
- cfg += " ";
- cfg += mServerPort;
- if (mUseUdp)
- cfg += " udp\n";
- else
- cfg += " tcp-client\n";
+
+ boolean canUsePlainRemotes = true;
+
+ if (mConnections.length==1) {
+ cfg += mConnections[0].getConnectionBlock();
+ } else {
+ for (Connection conn : mConnections) {
+ canUsePlainRemotes = canUsePlainRemotes && conn.isOnlyRemote();
+ }
+
+ if (mRemoteRandom)
+ cfg+="remote-random\n";
+
+ if (canUsePlainRemotes) {
+ for (Connection conn : mConnections) {
+ if (conn.mEnabled) {
+ cfg += conn.getConnectionBlock();
+ }
+ }
+ }
+ }
switch (mAuthenticationType) {
@@ -365,11 +413,6 @@ public class VpnProfile implements Serializable {
}
}
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT && !mAllowLocalLAN)
- cfg+="redirect-private block-local\n";
- else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && mAllowLocalLAN)
- cfg+="redirect-private unblock-local\n";
-
if (mUseDefaultRoutev6)
cfg += "route-ipv6 ::/0\n";
@@ -405,7 +448,7 @@ public class VpnProfile implements Serializable {
if (mAuthenticationType != TYPE_STATICKEYS) {
if (mCheckRemoteCN) {
if (mRemoteCN == null || mRemoteCN.equals(""))
- cfg += "verify-x509-name " + mServerName + " name\n";
+ cfg += "verify-x509-name " + mConnections[0].mServerName + " name\n";
else
switch (mX509AuthType) {
@@ -470,6 +513,19 @@ public class VpnProfile implements Serializable {
}
+ if (!canUsePlainRemotes) {
+ cfg += "# Connection Options are at the end to allow global options (and global custom options) to influence connection blocks\n";
+ for (Connection conn : mConnections) {
+ if (conn.mEnabled) {
+ cfg += "<connection>\n";
+ cfg += conn.getConnectionBlock();
+ cfg += "</connection>\n";
+ }
+ }
+ }
+
+
+
return cfg;
}
@@ -639,6 +695,27 @@ public class VpnProfile implements Serializable {
}
}
+ @Override
+ protected VpnProfile clone() throws CloneNotSupportedException {
+ VpnProfile copy = (VpnProfile) super.clone();
+ copy.mUuid = UUID.randomUUID();
+ copy.mConnections = mConnections.clone();
+ copy.mAllowedAppsVpn = (HashSet<String>) mAllowedAppsVpn.clone();
+ return copy;
+ }
+
+ public VpnProfile copy(String name) {
+ try {
+ VpnProfile copy = (VpnProfile) clone();
+ copy.mName = name;
+ return copy;
+
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
class NoCertReturnedException extends Exception {
public NoCertReturnedException (String msg) {
@@ -769,6 +846,14 @@ public class VpnProfile implements Serializable {
if (!mUseDefaultRoute && (getCustomRoutes(mCustomRoutes) == null || getCustomRoutes(mExcludedRoutes) ==null))
return R.string.custom_route_format_error;
+ boolean noRemoteEnabled = true;
+ for (Connection c : mConnections)
+ if (c.mEnabled)
+ noRemoteEnabled = false;
+
+ if(noRemoteEnabled)
+ return R.string.remote_no_server_selected;
+
// Everything okay
return R.string.no_error_found;
diff --git a/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java b/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java
index 4940d5d6..dfd815e4 100644
--- a/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java
+++ b/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.activities;
diff --git a/app/src/main/java/de/blinkt/openvpn/activities/LogWindow.java b/app/src/main/java/de/blinkt/openvpn/activities/LogWindow.java
index 5e4f9517..45f09c8e 100644
--- a/app/src/main/java/de/blinkt/openvpn/activities/LogWindow.java
+++ b/app/src/main/java/de/blinkt/openvpn/activities/LogWindow.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.activities;
diff --git a/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java b/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java
index ac9a8ccb..e525abd5 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
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 0d8230b7..5dc96bbc 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
@@ -1,13 +1,17 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
+import android.text.TextUtils;
+import android.util.Pair;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
+import java.io.StringReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
@@ -28,48 +32,49 @@ public class ConfigParser {
private HashMap<String, Vector<Vector<String>>> options = new HashMap<String, Vector<Vector<String>>>();
private HashMap<String, Vector<String>> meta = new HashMap<String, Vector<String>>();
-
- private boolean extraRemotesAsCustom=false;
-
public void parseConfig(Reader reader) throws IOException, ConfigParseError {
- BufferedReader br =new BufferedReader(reader);
+ BufferedReader br = new BufferedReader(reader);
- int lineno=0;
- while (true){
- String line = br.readLine();
- lineno++;
- if(line==null)
- break;
+ int lineno = 0;
+ try {
+ while (true) {
+ String line = br.readLine();
+ lineno++;
+ if (line == null)
+ break;
- if (lineno==1 && (line.startsWith("PK\003\004")
- || (line.startsWith("PK\007\008"))))
+ if (lineno == 1 && (line.startsWith("PK\003\004")
+ || (line.startsWith("PK\007\008"))))
throw new ConfigParseError("Input looks like a ZIP Archive. Import is only possible for OpenVPN config files (.ovpn/.conf)");
- // Check for OpenVPN Access Server Meta information
- if (line.startsWith("# OVPN_ACCESS_SERVER_")) {
- Vector<String> metaarg = parsemeta(line);
- meta.put(metaarg.get(0),metaarg);
- continue;
- }
- Vector<String> args = parseline(line);
+ // Check for OpenVPN Access Server Meta information
+ if (line.startsWith("# OVPN_ACCESS_SERVER_")) {
+ Vector<String> metaarg = parsemeta(line);
+ meta.put(metaarg.get(0), metaarg);
+ continue;
+ }
+ Vector<String> args = parseline(line);
- if(args.size() ==0)
- continue;
+ if (args.size() == 0)
+ continue;
- if(args.get(0).startsWith("--"))
- args.set(0, args.get(0).substring(2));
+ if (args.get(0).startsWith("--"))
+ args.set(0, args.get(0).substring(2));
- checkinlinefile(args,br);
+ checkinlinefile(args, br);
- String optionname = args.get(0);
- if(!options.containsKey(optionname)) {
- options.put(optionname, new Vector<Vector<String>>());
- }
- options.get(optionname).add(args);
- }
+ String optionname = args.get(0);
+ if (!options.containsKey(optionname)) {
+ options.put(optionname, new Vector<Vector<String>>());
+ }
+ options.get(optionname).add(args);
+ }
+ } catch (java.lang.OutOfMemoryError memoryError) {
+ throw new ConfigParseError("File too large to parse: " + memoryError.getLocalizedMessage());
+ }
}
private Vector<String> parsemeta(String line) {
@@ -98,7 +103,7 @@ public class ConfigParser {
break;
else {
inlinefile+=line;
- inlinefile+= "\n";
+ inlinefile+= "\n";
}
} while(true);
@@ -132,7 +137,7 @@ public class ConfigParser {
// adapted openvpn's parse function to java
private Vector<String> parseline(String line) throws ConfigParseError {
- Vector<String> parameters = new Vector<String>();
+ Vector<String> parameters = new Vector<String>();
if (line.length()==0)
return parameters;
@@ -145,12 +150,12 @@ public class ConfigParser {
int pos=0;
String currentarg="";
- do {
+ do {
// Emulate the c parsing ...
char in;
if(pos < line.length())
in = line.charAt(pos);
- else
+ else
in = '\0';
if (!backslash && in == '\\' && state != linestate.readin_single_quote)
@@ -228,10 +233,7 @@ public class ConfigParser {
}
- final String[] unsupportedOptions = { "config",
- "connection",
- "proto-force",
- "remote-random",
+ final String[] unsupportedOptions = { "config",
"tls-server"
};
@@ -299,7 +301,7 @@ public class ConfigParser {
"remote",
"float",
"port",
-// "connect-retry",
+ "connect-retry",
"connect-timeout",
"connect-retry-max",
"link-mtu",
@@ -325,7 +327,7 @@ public class ConfigParser {
// This method is far too long
@SuppressWarnings("ConstantConditions")
- public VpnProfile convertProfile() throws ConfigParseError{
+ public VpnProfile convertProfile() throws ConfigParseError, IOException {
boolean noauthtypeset=true;
VpnProfile np = new VpnProfile(CONVERTED_PROFILE);
// Pull, client, tls-client
@@ -338,7 +340,7 @@ public class ConfigParser {
}
Vector<String> secret = getOption("secret", 1, 2);
- if(secret!=null)
+ if(secret!=null)
{
np.mAuthenticationType=VpnProfile.TYPE_STATICKEYS;
noauthtypeset=false;
@@ -362,7 +364,7 @@ public class ConfigParser {
if (route.size() >= 4)
gateway = route.get(3);
- String net = route.get(1);
+ String net = route.get(1);
try {
CIDRIP cidr = new CIDRIP(net, netmask);
if (gateway.equals("net_gateway"))
@@ -398,7 +400,7 @@ public class ConfigParser {
Vector<Vector<String>> tlsauthoptions = getAllOption("tls-auth", 1, 2);
if(tlsauthoptions!=null) {
for(Vector<String> tlsauth:tlsauthoptions) {
- if(tlsauth!=null)
+ if(tlsauth!=null)
{
if(!tlsauth.get(1).equals("[inline]")) {
np.mTLSAuthFilename=tlsauth.get(1);
@@ -458,36 +460,6 @@ public class ConfigParser {
throw new ConfigParseError("Invalid mode for --mode specified, need p2p");
}
- Vector<String> port = getOption("port", 1,1);
- if(port!=null){
- np.mServerPort = port.get(1);
- }
-
- Vector<String> rport = getOption("rport", 1,1);
- if(rport!=null){
- np.mServerPort = rport.get(1);
- }
-
- Vector<String> proto = getOption("proto", 1,1);
- if(proto!=null){
- np.mUseUdp=isUdpProto(proto.get(1));
- }
-
- // Parse remote config
- Vector<Vector<String>> remotes = getAllOption("remote",1,3);
-
- if(remotes!=null && remotes.size()>=1 ) {
- Vector<String> remote = remotes.get(0);
- switch (remote.size()) {
- case 4:
- np.mUseUdp=isUdpProto(remote.get(3));
- case 3:
- np.mServerPort = remote.get(2);
- case 2:
- np.mServerName = remote.get(1);
- }
- }
-
Vector<Vector<String>> dhcpoptions = getAllOption("dhcp-option", 2, 2);
@@ -581,18 +553,18 @@ public class ConfigParser {
if(verifyx509name!=null){
np.mRemoteCN = verifyx509name.get(1);
np.mCheckRemoteCN=true;
- if(verifyx509name.size()>2) {
+ if(verifyx509name.size()>2) {
if (verifyx509name.get(2).equals("name"))
np.mX509AuthType=VpnProfile.X509_VERIFY_TLSREMOTE_RDN;
else if (verifyx509name.get(2).equals("name-prefix"))
np.mX509AuthType=VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX;
- else
+ else
throw new ConfigParseError("Unknown parameter to x509-verify-name: " + verifyx509name.get(2) );
} else {
np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_DN;
}
- }
+ }
Vector<String> verb = getOption("verb",1,1);
@@ -615,7 +587,7 @@ public class ConfigParser {
if(connectretrymax!=null)
np.mConnectRetryMax =connectretrymax.get(1);
- Vector<Vector<String>> remotetls = getAllOption("remote-cert-tls", 1, 1);
+ Vector<Vector<String>> remotetls = getAllOption("remote-cert-tls", 1, 1);
if(remotetls!=null)
if(remotetls.get(0).get(1).equals("server"))
np.mExpectTLSCert=true;
@@ -632,14 +604,55 @@ public class ConfigParser {
np.mAuthenticationType=VpnProfile.TYPE_USERPASS_KEYSTORE;
}
if(authuser.size()>1) {
- // Set option value to password get to get cance to embed later.
+ // Set option value to password get to embed later.
np.mUsername=null;
- np.mPassword=authuser.get(1);
- useEmbbedUserAuth(np,authuser.get(1));
+ useEmbbedUserAuth(np, authuser.get(1));
}
}
- // Parse OpenVPN Access Server extra
+ Pair<Connection, Connection[]> conns = parseConnectionOptions(null);
+ np.mConnections =conns.second;
+
+ Vector<Vector<String>> connectionBlocks = getAllOption("connection", 1, 1);
+
+ if (np.mConnections.length > 0 && connectionBlocks !=null ) {
+ throw new ConfigParseError("Using a <connection> block and --remote is not allowed.");
+ }
+
+ if (connectionBlocks!=null) {
+ np.mConnections = new Connection[connectionBlocks.size()];
+
+ int connIndex = 0;
+ for (Vector<String> conn : connectionBlocks) {
+ Pair<Connection, Connection[]> connectionBlockConnection =
+ parseConnection(conn.get(1), conns.first);
+
+ if (connectionBlockConnection.second.length != 1)
+ throw new ConfigParseError("A <connection> block must have exactly one remote");
+ np.mConnections[connIndex] = connectionBlockConnection.second[0];
+ connIndex++;
+ }
+ }
+ if(getOption("remote-random", 0, 0) != null)
+ np.mRemoteRandom=true;
+
+ Vector<String> protoforce = getOption("proto-force", 1, 1);
+ if(protoforce!=null) {
+ boolean disableUDP;
+ String protoToDisable = protoforce.get(1);
+ if (protoToDisable.equals("udp"))
+ disableUDP=true;
+ else if (protoToDisable.equals("tcp"))
+ disableUDP=false;
+ else
+ throw new ConfigParseError(String.format("Unknown protocol %s in proto-force", protoToDisable));
+
+ for (Connection conn:np.mConnections)
+ if(conn.mUseUdp==disableUDP)
+ conn.mEnabled=false;
+ }
+
+ // Parse OpenVPN Access Server extra
Vector<String> friendlyname = meta.get("FRIENDLY_NAME");
if(friendlyname !=null && friendlyname.size() > 1)
np.mName=friendlyname.get(1);
@@ -649,20 +662,95 @@ public class ConfigParser {
if(ocusername !=null && ocusername.size() > 1)
np.mUsername=ocusername.get(1);
- // Check the other options
- if(remotes !=null && remotes.size()>1 && extraRemotesAsCustom) {
- // first is already added
- remotes.remove(0);
- np.mCustomConfigOptions += getOptionStrings(remotes);
- np.mUseCustomConfig=true;
-
- }
- checkIgnoreAndInvalidOptions(np);
+ checkIgnoreAndInvalidOptions(np);
fixup(np);
return np;
}
+ private Pair<Connection, Connection[]> 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<Connection, Connection[]> conn = connectionParser.parseConnectionOptions(defaultValues);
+
+ return conn;
+ }
+
+ private Pair<Connection, Connection[]> parseConnectionOptions(Connection connDefault) throws ConfigParseError {
+ Connection conn;
+ if (connDefault!=null)
+ try {
+ conn = connDefault.clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ return null;
+ }
+ else
+ conn = new Connection();
+
+ Vector<String> port = getOption("port", 1,1);
+ if(port!=null){
+ conn.mServerPort = port.get(1);
+ }
+
+ Vector<String> rport = getOption("rport", 1,1);
+ if(rport!=null){
+ conn.mServerPort = rport.get(1);
+ }
+
+ Vector<String> proto = getOption("proto", 1,1);
+ if(proto!=null){
+ conn.mUseUdp=isUdpProto(proto.get(1));
+ }
+
+
+ // Parse remote config
+ Vector<Vector<String>> remotes = getAllOption("remote",1,3);
+
+
+ // Assume that we need custom options if connectionDefault are set
+ if(connDefault!=null) {
+ for (Vector<Vector<String>> option : options.values()) {
+
+ conn.mCustomConfiguration += getOptionStrings(option);
+
+ }
+ if (!TextUtils.isEmpty(conn.mCustomConfiguration))
+ conn.mUseCustomConfig = true;
+ }
+ // Make remotes empty to simplify code
+ if (remotes==null)
+ remotes = new Vector<Vector<String>>();
+
+ Connection[] connections = new Connection[remotes.size()];
+
+
+ int i=0;
+ for (Vector<String> remote: remotes) {
+ try {
+ connections[i] = conn.clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ switch (remote.size()) {
+ case 4:
+ connections[i].mUseUdp=isUdpProto(remote.get(3));
+ case 3:
+ connections[i].mServerPort = remote.get(2);
+ case 2:
+ connections[i].mServerName = remote.get(1);
+ }
+ i++;
+ }
+ return Pair.create(conn, connections);
+
+ }
+
private void checkRedirectParameters(VpnProfile np, Vector<Vector<String>> defgw) {
for (Vector<String> redirect: defgw)
for (int i=1;i<redirect.size();i++){
@@ -673,25 +761,21 @@ public class ConfigParser {
}
}
- public void useExtraRemotesAsCustom(boolean b) {
- this.extraRemotesAsCustom = b;
- }
-
private boolean isUdpProto(String proto) throws ConfigParseError {
boolean isudp;
if(proto.equals("udp") || proto.equals("udp6"))
isudp=true;
else if (proto.equals("tcp-client") ||
- proto.equals("tcp") ||
+ proto.equals("tcp") ||
proto.equals("tcp6") ||
proto.endsWith("tcp6-client"))
isudp =false;
- else
+ else
throw new ConfigParseError("Unsupported option to --proto " + proto);
return isudp;
}
- static public void useEmbbedUserAuth(VpnProfile np,String inlinedata)
+ static public void useEmbbedUserAuth(VpnProfile np, String inlinedata)
{
String data = VpnProfile.getEmbeddedContent(inlinedata);
String[] parts = data.split("\n");
diff --git a/app/src/main/java/de/blinkt/openvpn/core/Connection.java b/app/src/main/java/de/blinkt/openvpn/core/Connection.java
new file mode 100644
index 00000000..b10664ce
--- /dev/null
+++ b/app/src/main/java/de/blinkt/openvpn/core/Connection.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
+package de.blinkt.openvpn.core;
+
+import android.text.TextUtils;
+
+import java.io.Serializable;
+
+public class Connection implements Serializable, Cloneable {
+ public String mServerName = "openvpn.blinkt.de";
+ public String mServerPort = "1194";
+ public boolean mUseUdp = true;
+ public String mCustomConfiguration="";
+ public boolean mUseCustomConfig=false;
+ public boolean mEnabled=true;
+
+ private static final long serialVersionUID = 92031902903829089L;
+
+
+ public String getConnectionBlock() {
+ String cfg="";
+
+ // Server Address
+ cfg += "remote ";
+ cfg += mServerName;
+ cfg += " ";
+ cfg += mServerPort;
+ if (mUseUdp)
+ cfg += " udp\n";
+ else
+ cfg += " tcp-client\n";
+
+ if (!TextUtils.isEmpty(mCustomConfiguration) && mUseCustomConfig) {
+ cfg += mCustomConfiguration;
+ cfg += "\n";
+ }
+ return cfg;
+ }
+
+ @Override
+ public Connection clone() throws CloneNotSupportedException {
+ return (Connection) super.clone();
+ }
+
+ public boolean isOnlyRemote() {
+ return TextUtils.isEmpty(mCustomConfiguration) || !mUseCustomConfig;
+ }
+}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java b/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java
index 0d75ae51..4ccf5472 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
@@ -182,18 +182,14 @@ public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountL
screen = connectState.DISCONNECTED;
if (shouldBeConnected()) {
- if (sendusr1) {
- if (lastNetwork == -1) {
- mManagement.resume();
- } else {
- mManagement.reconnect();
- }
+ if (lastNetwork == -1) {
+ mManagement.resume();
} else {
mManagement.networkChange();
+
}
}
-
lastNetwork = newnet;
}
} else if (networkInfo == null) {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java b/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java
index 83e760ca..56a574dc 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
diff --git a/app/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java b/app/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java
new file mode 100644
index 00000000..440458e4
--- /dev/null
+++ b/app/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
+package de.blinkt.openvpn.core;
+
+import android.annotation.TargetApi;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.Build;
+
+/**
+ * Created by arne on 26.11.14.
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class LollipopDeviceStateListener extends ConnectivityManager.NetworkCallback {
+
+ private String mLastConnectedStatus;
+ private String mLastLinkProperties;
+ private String mLastNetworkCapabilities;
+
+ @Override
+ public void onAvailable(Network network) {
+ super.onAvailable(network);
+
+ if (!network.toString().equals(mLastConnectedStatus)) {
+ mLastConnectedStatus = network.toString();
+ VpnStatus.logDebug("Connected to " + mLastConnectedStatus);
+ }
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
+ super.onLinkPropertiesChanged(network, linkProperties);
+
+ if (!linkProperties.toString().equals(mLastLinkProperties)) {
+ mLastLinkProperties = linkProperties.toString();
+ VpnStatus.logDebug(String.format("Linkproperties of %s: %s", network, linkProperties));
+ }
+ }
+
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
+ super.onCapabilitiesChanged(network, networkCapabilities);
+ if (!networkCapabilities.toString().equals(mLastNetworkCapabilities)) {
+ mLastNetworkCapabilities = networkCapabilities.toString();
+ VpnStatus.logDebug(String.format("Network capabilities of %s: %s", network, networkCapabilities));
+ }
+ }
+}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java b/app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java
index 6d7ffdf2..f67b7730 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
@@ -9,6 +9,7 @@ import java.security.InvalidKeyException;
public class NativeUtils {
public static native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException;
+ public static native String[] getIfconfig() throws IllegalArgumentException;
static native void jniclose(int fdint);
static {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java
index 35f46513..26354689 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
@@ -21,6 +21,8 @@ import se.leap.bitmaskclient.BuildConfig;
public class NetworkSpace {
+
+
static class ipAddress implements Comparable<ipAddress> {
private BigInteger netAddress;
public int networkMask;
@@ -198,6 +200,13 @@ public class NetworkSpace {
mIpAddresses.add(new ipAddress(cidrIp, include));
}
+ public void addIPSplit(CIDRIP cidrIp, boolean include) {
+ ipAddress newIP = new ipAddress(cidrIp, include);
+ ipAddress[] splitIps = newIP.split();
+ for (ipAddress split: splitIps)
+ mIpAddresses.add(split);
+ }
+
void addIPv6(Inet6Address address, int mask, boolean included) {
mIpAddresses.add(new ipAddress(address, mask, included));
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java
index e90c16d1..1f28c77d 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
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 d9830955..578d95e7 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
@@ -14,7 +14,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
+import android.net.NetworkRequest;
import android.net.VpnService;
import android.os.Binder;
import android.os.Build;
@@ -23,6 +25,7 @@ import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
@@ -81,6 +84,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
private String mLastTunCfg;
private String mRemoteGW;
private final Object mProcessLock = new Object();
+ private LollipopDeviceStateListener mLollipopDeviceStateListener;
// From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java
public static String humanReadableByteCount(long bytes, boolean mbit) {
@@ -266,6 +270,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
mDeviceStateReceiver = new DeviceStateReceiver(magnagement);
registerReceiver(mDeviceStateReceiver, filter);
VpnStatus.addByteCountListener(mDeviceStateReceiver);
+
+ /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+ addLollipopCMListener(); */
}
synchronized void unregisterDeviceStateReceiver() {
@@ -280,6 +287,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
iae.printStackTrace();
}
mDeviceStateReceiver = null;
+
+ /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+ removeLollipopCMListener();*/
+
}
public void userPause(boolean shouldBePaused) {
@@ -320,7 +331,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
mProfile = ProfileManager.getLastConnectedProfile(this, false);
/* Got no profile, just stop */
- if (mProfile==null) {
+ if (mProfile == null) {
Log.d("OpenVPN", "Got no last connected profile on null intent. Stopping");
stopSelf(startId);
return START_NOT_STICKY;
@@ -431,7 +442,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
private OpenVPNManagement instantiateOpenVPN3Core() {
try {
Class cl = Class.forName("de.blinkt.openvpn.core.OpenVPNThreadv3");
- return (OpenVPNManagement) cl.getConstructor(OpenVPNService.class,VpnProfile.class).newInstance(this,mProfile);
+ return (OpenVPNManagement) cl.getConstructor(OpenVPNService.class, VpnProfile.class).newInstance(this, mProfile);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InstantiationException e) {
@@ -474,6 +485,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
if (mLocalIPv6 != null)
cfg += mLocalIPv6;
+
cfg += "routes: " + TextUtils.join("|", mRoutes.getNetworks(true)) + TextUtils.join("|", mRoutesv6.getNetworks(true));
cfg += "excl. routes:" + TextUtils.join("|", mRoutes.getNetworks(false)) + TextUtils.join("|", mRoutesv6.getNetworks(false));
cfg += "dns: " + TextUtils.join("|", mDnslist);
@@ -490,6 +502,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
VpnStatus.logInfo(R.string.last_openvpn_tun_config);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mProfile.mAllowLocalLAN)
+ {
+ allowAllAFFamilies(builder);
+ }
if (mLocalIP == null && mLocalIPv6 == null) {
VpnStatus.logError(getString(R.string.opentun_no_ipaddr));
@@ -497,6 +513,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
if (mLocalIP != null) {
+ addLocalNetworksToRoutes();
try {
builder.addAddress(mLocalIP.mIp, mLocalIP.len);
} catch (IllegalArgumentException iae) {
@@ -527,7 +544,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
String release = Build.VERSION.RELEASE;
if ((Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && !release.startsWith("4.4.3")
- && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6"))
+ && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6"))
&& mMtu < 1280) {
VpnStatus.logInfo(String.format(Locale.US, "Forcing MTU to 1280 instead of %d to workaround Android Bug #70916", mMtu));
builder.setMtu(1280);
@@ -560,8 +577,12 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
VpnStatus.logInfo(R.string.local_ip_info, mLocalIP.mIp, mLocalIP.len, mLocalIPv6, mMtu);
VpnStatus.logInfo(R.string.dns_server_info, TextUtils.join(", ", mDnslist), mDomain);
VpnStatus.logInfo(R.string.routes_info_incl, TextUtils.join(", ", mRoutes.getNetworks(true)), TextUtils.join(", ", mRoutesv6.getNetworks(true)));
- VpnStatus.logInfo(R.string.routes_info_excl, TextUtils.join(", ", mRoutes.getNetworks(false)),TextUtils.join(", ", mRoutesv6.getNetworks(false)));
+ VpnStatus.logInfo(R.string.routes_info_excl, TextUtils.join(", ", mRoutes.getNetworks(false)), TextUtils.join(", ", mRoutesv6.getNetworks(false)));
VpnStatus.logDebug(R.string.routes_debug, TextUtils.join(", ", positiveIPv4Routes), TextUtils.join(", ", positiveIPv6Routes));
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ setAllowedVpnPackages(builder);
+ }
+
String session = mProfile.mName;
if (mLocalIP != null && mLocalIPv6 != null)
@@ -601,6 +622,82 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void allowAllAFFamilies(Builder builder) {
+ builder.allowFamily(OsConstants.AF_INET);
+ builder.allowFamily(OsConstants.AF_INET6);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ void removeLollipopCMListener() {
+ ConnectivityManager cm = (ConnectivityManager) getBaseContext().getSystemService(CONNECTIVITY_SERVICE);
+ cm.unregisterNetworkCallback(mLollipopDeviceStateListener);
+ mLollipopDeviceStateListener = null;
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ void addLollipopCMListener() {
+ ConnectivityManager cm = (ConnectivityManager) getBaseContext().getSystemService(CONNECTIVITY_SERVICE);
+ NetworkRequest.Builder nrb = new NetworkRequest.Builder();
+
+ mLollipopDeviceStateListener = new LollipopDeviceStateListener();
+ cm.registerNetworkCallback(nrb.build(), mLollipopDeviceStateListener);
+ }
+
+ private void addLocalNetworksToRoutes() {
+
+ // Add local network interfaces
+ String[] localRoutes = NativeUtils.getIfconfig();
+
+ // The format of mLocalRoutes is kind of broken because I don't really like JNI
+ for (int i = 0; i < localRoutes.length; i += 3) {
+ String intf = localRoutes[i];
+ String ipAddr = localRoutes[i + 1];
+ String netMask = localRoutes[i + 2];
+
+ if (intf == null || intf.equals("lo") ||
+ intf.startsWith("tun") || intf.startsWith("rmnet"))
+ continue;
+
+ if (ipAddr==null || netMask == null) {
+ VpnStatus.logError("Local routes are broken?! (Report to author) " + TextUtils.join("|", localRoutes));
+ continue;
+ }
+
+ if (ipAddr.equals(mLocalIP.mIp))
+ continue;
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT && !mProfile.mAllowLocalLAN) {
+ mRoutes.addIPSplit(new CIDRIP(ipAddr, netMask), true);
+
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && mProfile.mAllowLocalLAN)
+ mRoutes.addIP(new CIDRIP(ipAddr, netMask), false);
+ }
+ }
+
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void setAllowedVpnPackages(Builder builder) {
+ for (String pkg : mProfile.mAllowedAppsVpn) {
+ try {
+ if (mProfile.mAllowedAppsVpnAreDisallowed) {
+ builder.addDisallowedApplication(pkg);
+ } else {
+ builder.addAllowedApplication(pkg);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ mProfile.mAllowedAppsVpn.remove(pkg);
+ VpnStatus.logInfo(R.string.app_no_longer_exists, pkg);
+ }
+ }
+
+ if (mProfile.mAllowedAppsVpnAreDisallowed) {
+ VpnStatus.logDebug(R.string.disallowed_vpn_apps_info, TextUtils.join(", ", mProfile.mAllowedAppsVpn));
+ } else {
+ VpnStatus.logDebug(R.string.allowed_vpn_apps_info, TextUtils.join(", ", mProfile.mAllowedAppsVpn));
+ }
+ }
+
public void addDNS(String dns) {
mDnslist.add(dns);
}
@@ -611,28 +708,30 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
}
- /** Route that is always included, used by the v3 core */
- public void addRoute (CIDRIP route) {
+ /**
+ * Route that is always included, used by the v3 core
+ */
+ public void addRoute(CIDRIP route) {
mRoutes.addIP(route, true);
}
- public void addRoute (String dest, String mask, String gateway, String device) {
+ public void addRoute(String dest, String mask, String gateway, String device) {
CIDRIP route = new CIDRIP(dest, mask);
boolean include = isAndroidTunDevice(device);
- NetworkSpace.ipAddress gatewayIP = new NetworkSpace.ipAddress(new CIDRIP(gateway, 32),false);
+ NetworkSpace.ipAddress gatewayIP = new NetworkSpace.ipAddress(new CIDRIP(gateway, 32), false);
- if (mLocalIP==null) {
+ if (mLocalIP == null) {
VpnStatus.logError("Local IP address unset but adding route?! This is broken! Please contact author with log");
return;
}
- NetworkSpace.ipAddress localNet = new NetworkSpace.ipAddress(mLocalIP,true);
+ NetworkSpace.ipAddress localNet = new NetworkSpace.ipAddress(mLocalIP, true);
if (localNet.containsNet(gatewayIP))
- include=true;
+ include = true;
- if (gateway!= null &&
+ if (gateway != null &&
(gateway.equals("255.255.255.255") || gateway.equals(mRemoteGW)))
- include=true;
+ include = true;
if (route.len == 32 && !mask.equals("255.255.255.255")) {
@@ -664,7 +763,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
private boolean isAndroidTunDevice(String device) {
- return device!=null &&
+ return device != null &&
(device.startsWith("tun") || "(null)".equals(device) || "vpnservice-tun".equals(device));
}
@@ -679,7 +778,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
public void setLocalIP(String local, String netmask, int mtu, String mode) {
mLocalIP = new CIDRIP(local, netmask);
mMtu = mtu;
- mRemoteGW=null;
+ mRemoteGW = null;
long netMaskAsInt = CIDRIP.getInt(netmask);
@@ -687,14 +786,17 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
// get the netmask as IP
int masklen;
- if ("net30".equals(mode))
+ long mask;
+ if ("net30".equals(mode)) {
masklen = 30;
- else
+ mask = 0xfffffffc;
+ } else {
masklen = 31;
+ mask = 0xfffffffe;
+ }
- int mask = ~( 1 << (32 - (mLocalIP.len +1)));
// Netmask is Ip address +/-1, assume net30/p2p with small net
- if ((netMaskAsInt & mask) == (mLocalIP.getInt() & mask )) {
+ if ((netMaskAsInt & mask) == (mLocalIP.getInt() & mask)) {
mLocalIP.len = masklen;
} else {
mLocalIP.len = 32;
@@ -702,13 +804,18 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
VpnStatus.logWarning(R.string.ip_not_cidr, local, netmask, mode);
}
}
- if (("p2p".equals(mode) && mLocalIP.len < 32) || ("net30".equals(mode) && mLocalIP.len < 30)) {
+ if (("p2p".equals(mode) && mLocalIP.len < 32) || ("net30".equals(mode) && mLocalIP.len < 30)) {
VpnStatus.logWarning(R.string.ip_looks_like_subnet, local, netmask, mode);
}
+ /* Workaround for Lollipop, it does not route traffic to the VPNs own network mask */
+ if (mLocalIP.len <= 31 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+ addRoute(mLocalIP);
+
+
// Configurations are sometimes really broken...
- mRemoteGW=netmask;
+ mRemoteGW = netmask;
}
public void setLocalIPv6(String ipv6addr) {
@@ -810,7 +917,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
} else {
String release = Build.VERSION.RELEASE;
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && !release.startsWith("4.4.3")
- && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6"))
+ && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6"))
// There will be probably no 4.4.4 or 4.4.5 version, so don't waste effort to do parsing here
return "OPEN_AFTER_CLOSE";
else
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java
index e36a5b8a..298a6c40 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
index 37094a1b..1c3b3362 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
@@ -157,7 +157,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
}
} catch (IOException e) {
- if (!e.getMessage().equals("socket closed"))
+ if (!e.getMessage().equals("socket closed") && !e.getMessage().equals("Connection reset by peer"))
VpnStatus.logException(e);
}
synchronized (active) {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java b/app/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java
index bca0a4ab..a788426a 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;/*
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java b/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
index 2a26152e..1ebc0a57 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java b/app/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java
index cf953863..6e2abb13 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
diff --git a/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java b/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java
index 208aa359..73ed05bc 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
@@ -76,7 +76,6 @@ public class VPNLaunchHelper {
args.add("--config");
args.add(c.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE);
-
return args.toArray(new String[args.size()]);
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
index 25558f13..ffc8097d 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
@@ -480,7 +480,11 @@ public class VpnStatus {
newLogItem(new LogItem(LogLevel.INFO, message));
}
- public static void logInfo(int resourceId, Object... args) {
+ public static void logDebug(String message) {
+ newLogItem(new LogItem(LogLevel.DEBUG, message));
+ }
+
+ public static void logInfo(int resourceId, Object... args) {
newLogItem(new LogItem(LogLevel.INFO, resourceId, args));
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/X509Utils.java b/app/src/main/java/de/blinkt/openvpn/core/X509Utils.java
index ff383e0f..0786967b 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/X509Utils.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/X509Utils.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
diff --git a/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java b/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java
index 77fc21e6..199caa63 100644
--- a/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java
+++ b/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.fragments;
diff --git a/app/src/main/java/de/blinkt/openvpn/views/SeekBarTicks.java b/app/src/main/java/de/blinkt/openvpn/views/SeekBarTicks.java
index e25c2859..82378b00 100644
--- a/app/src/main/java/de/blinkt/openvpn/views/SeekBarTicks.java
+++ b/app/src/main/java/de/blinkt/openvpn/views/SeekBarTicks.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2012-2014 Arne Schwabe
- * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.views;
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
index e32dbdee..4e6120ab 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
@@ -17,37 +17,21 @@
package se.leap.bitmaskclient;
import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.DialogFragment;
-import android.app.FragmentTransaction;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
+import android.app.*;
+import android.content.*;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
+import android.os.*;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.ProgressBar;
-import android.widget.TextView;
+import android.view.*;
+import android.widget.*;
import org.jetbrains.annotations.NotNull;
-import org.json.JSONException;
-import org.json.JSONObject;
+import org.json.*;
+import java.net.*;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import butterknife.ButterKnife;
-import butterknife.InjectView;
-import de.blinkt.openvpn.activities.LogWindow;
-import se.leap.bitmaskclient.eip.Constants;
-import se.leap.bitmaskclient.eip.EIP;
-import se.leap.bitmaskclient.eip.EipStatus;
+import butterknife.*;
+import de.blinkt.openvpn.activities.*;
+import se.leap.bitmaskclient.eip.*;
/**
* The main user facing Activity of Bitmask Android, consisting of status, controls,
@@ -58,16 +42,16 @@ import se.leap.bitmaskclient.eip.EipStatus;
*/
public class Dashboard extends Activity implements SessionDialog.SessionDialogInterface, ProviderAPIResultReceiver.Receiver {
- protected static final int CONFIGURE_LEAP = 0;
- protected static final int SWITCH_PROVIDER = 1;
+ protected static final int CONFIGURE_LEAP = 0;
+ protected static final int SWITCH_PROVIDER = 1;
- final public static String TAG = Dashboard.class.getSimpleName();
- final public static String SHARED_PREFERENCES = "LEAPPreferences";
- final public static String ACTION_QUIT = "quit";
+ public static final String TAG = Dashboard.class.getSimpleName();
+ public static final String SHARED_PREFERENCES = "LEAPPreferences";
+ public static final String ACTION_QUIT = "quit";
public static final String REQUEST_CODE = "request_code";
public static final String PARAMETERS = "dashboard parameters";
public static final String START_ON_BOOT = "dashboard start on boot";
- final public static String ON_BOOT = "dashboard on boot";
+ public static final String ON_BOOT = "dashboard on boot";
public static final String APP_VERSION = "bitmask version";
private static Context app;
@@ -81,6 +65,26 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
private Provider provider;
private static boolean authed_eip;
public ProviderAPIResultReceiver providerAPI_result_receiver;
+ private boolean switching_provider;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ app = this;
+
+ PRNGFixes.apply();
+
+ preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ fragment_manager = new FragmentManagerEnhanced(getFragmentManager());
+ handleVersion();
+
+ provider = getSavedProvider(savedInstanceState);
+ if (provider == null || provider.getName().isEmpty())
+ startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP);
+ else
+ buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false));
+ }
@Override
protected void onSaveInstanceState(@NotNull Bundle outState) {
@@ -89,25 +93,6 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
super.onSaveInstanceState(outState);
}
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- app = this;
-
- PRNGFixes.apply();
-
- preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
- fragment_manager = new FragmentManagerEnhanced(getFragmentManager());
- handleVersion();
-
- provider = getSavedProvider(savedInstanceState);
- if (provider == null || provider.getName().isEmpty())
- startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP);
- else
- buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false));
- }
-
private Provider getSavedProvider(Bundle savedInstanceState) {
Provider provider = null;
if(savedInstanceState != null)
@@ -123,120 +108,109 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
try {
provider = new Provider(new URL(preferences.getString(Provider.MAIN_URL, "")));
provider.define(new JSONObject(preferences.getString(Provider.KEY, "")));
- } catch (MalformedURLException | JSONException e) {
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ } catch (JSONException e) {
e.printStackTrace();
}
return provider;
}
-
private void handleVersion() {
try {
int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
int lastDetectedVersion = preferences.getInt(APP_VERSION, 0);
preferences.edit().putInt(APP_VERSION, versionCode).apply();
- Log.d("Dashboard", "detected version code: " + versionCode);
- Log.d("Dashboard", "last detected version code: " + lastDetectedVersion);
switch(versionCode) {
case 91: // 0.6.0 without Bug #5999
case 101: // 0.8.0
- if(!preferences.getString(Constants.KEY, "").isEmpty()) {
- Intent rebuildVpnProfiles = new Intent(getApplicationContext(), EIP.class);
- rebuildVpnProfiles.setAction(Constants.ACTION_UPDATE_EIP_SERVICE);
- startService(rebuildVpnProfiles);
- }
+ if(!preferences.getString(Constants.KEY, "").isEmpty())
+ updateEipService();
break;
}
} catch (NameNotFoundException e) {
- Log.d(TAG, "Handle version didn't find any " + getPackageName() + " package");
+ Log.d(TAG, "Handle version didn't find any " + getPackageName() + " package");
}
}
@SuppressLint("CommitPrefEdits")
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
- Log.d(TAG, "onActivityResult: requestCode = " + requestCode);
if ( requestCode == CONFIGURE_LEAP || requestCode == SWITCH_PROVIDER) {
if ( resultCode == RESULT_OK ) {
- preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply();
- updateEipService();
-
- if (data.hasExtra(Provider.KEY)) {
- provider = data.getParcelableExtra(Provider.KEY);
- preferences.edit().putBoolean(Constants.PROVIDER_CONFIGURED, true).commit();
- preferences.edit().putString(Provider.MAIN_URL, provider.mainUrl().toString()).apply();
- preferences.edit().putString(Provider.KEY, provider.definition().toString()).apply();
- }
- buildDashboard(false);
- invalidateOptionsMenu();
- if (data.hasExtra(SessionDialog.TAG)) {
- logInDialog(Bundle.EMPTY);
- }
- } else if (resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) {
+ preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply();
+ updateEipService();
+
+ if (data.hasExtra(Provider.KEY)) {
+ provider = data.getParcelableExtra(Provider.KEY);
+ preferences.edit().putBoolean(Constants.PROVIDER_CONFIGURED, true).commit();
+ preferences.edit().putString(Provider.MAIN_URL, provider.mainUrl().toString()).apply();
+ preferences.edit().putString(Provider.KEY, provider.definition().toString()).apply();
+ }
+ buildDashboard(false);
+ invalidateOptionsMenu();
+ if (data.hasExtra(SessionDialog.TAG)) {
+ sessionDialog(Bundle.EMPTY);
+ }
+ } else if (resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) {
finish();
- } else
+ } else
configErrorDialog();
} else if(requestCode == EIP.DISCONNECT) {
EipStatus.getInstance().setConnectedOrDisconnected();
}
}
- /**
- * Dialog shown when encountering a configuration error. Such errors require
- * reconfiguring LEAP or aborting the application.
- */
- private void configErrorDialog() {
- AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext());
- alertBuilder.setTitle(getResources().getString(R.string.setup_error_title));
- alertBuilder
- .setMessage(getResources().getString(R.string.setup_error_text))
- .setCancelable(false)
- .setPositiveButton(getResources().getString(R.string.setup_error_configure_button), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- startActivityForResult(new Intent(getAppContext(),ConfigurationWizard.class),CONFIGURE_LEAP);
- }
- })
- .setNegativeButton(getResources().getString(R.string.setup_error_close_button), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- preferences.edit().remove(Provider.KEY).remove(Constants.PROVIDER_CONFIGURED).apply();
- finish();
- }
- })
- .show();
- }
+ private void configErrorDialog() {
+ AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext());
+ alertBuilder.setTitle(getResources().getString(R.string.setup_error_title));
+ alertBuilder
+ .setMessage(getResources().getString(R.string.setup_error_text))
+ .setCancelable(false)
+ .setPositiveButton(getResources().getString(R.string.setup_error_configure_button), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ startActivityForResult(new Intent(getAppContext(),ConfigurationWizard.class),CONFIGURE_LEAP);
+ }
+ })
+ .setNegativeButton(getResources().getString(R.string.setup_error_close_button), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ preferences.edit().remove(Provider.KEY).remove(Constants.PROVIDER_CONFIGURED).apply();
+ finish();
+ }
+ })
+ .show();
+ }
- /**
- * Inflates permanent UI elements of the View and contains logic for what
- * service dependent UI elements to include.
- */
- private void buildDashboard(boolean hide_and_turn_on_eip) {
- setContentView(R.layout.dashboard);
+ /**
+ * Inflates permanent UI elements of the View and contains logic for what
+ * service dependent UI elements to include.
+ */
+ private void buildDashboard(boolean hide_and_turn_on_eip) {
+ setContentView(R.layout.dashboard);
ButterKnife.inject(this);
- provider_name.setText(provider.getDomain());
- if ( provider.hasEIP()){
-
+ provider_name.setText(provider.getDomain());
+ if ( provider.hasEIP()){
fragment_manager.removePreviousFragment(EipFragment.TAG);
eip_fragment = new EipFragment();
- if (hide_and_turn_on_eip) {
- preferences.edit().remove(Dashboard.START_ON_BOOT).apply();
- Bundle arguments = new Bundle();
- arguments.putBoolean(EipFragment.START_ON_BOOT, true);
+ if (hide_and_turn_on_eip) {
+ preferences.edit().remove(Dashboard.START_ON_BOOT).apply();
+ Bundle arguments = new Bundle();
+ arguments.putBoolean(EipFragment.START_ON_BOOT, true);
if(eip_fragment != null) eip_fragment.setArguments(arguments);
- }
+ }
fragment_manager.replace(R.id.servicesCollection, eip_fragment, EipFragment.TAG);
-
- if (hide_and_turn_on_eip) {
- onBackPressed();
- }
- }
+ if (hide_and_turn_on_eip) {
+ onBackPressed();
+ }
}
+ }
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
@@ -267,277 +241,225 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
}
return true;
}
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.client_dashboard, menu);
+ return true;
+ }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.client_dashboard, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item){
- Intent intent;
- switch (item.getItemId()){
- case R.id.about_leap:
- intent = new Intent(this, AboutActivity.class);
- startActivity(intent);
- return true;
- case R.id.log_window:
- Intent startLW = new Intent(getAppContext(), LogWindow.class);
- startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- startActivity(startLW);
- return true;
- case R.id.switch_provider:
- if (provider.hasEIP()){
- if (preferences.getBoolean(Constants.AUTHED_EIP, false)) {
- logOut();
- }
- eip_fragment.askToStopEIP();
- }
- preferences.edit().clear().apply();
- startActivityForResult(new Intent(this,ConfigurationWizard.class), SWITCH_PROVIDER);
- return true;
- case R.id.login_button:
- logInDialog(Bundle.EMPTY);
- return true;
- case R.id.logout_button:
- logOut();
- return true;
- case R.id.signup_button:
- signUpDialog(Bundle.EMPTY);
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
-
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item){
+ Intent intent;
+ switch (item.getItemId()){
+ case R.id.about_leap:
+ intent = new Intent(this, AboutActivity.class);
+ startActivity(intent);
+ return true;
+ case R.id.log_window:
+ Intent startLW = new Intent(getAppContext(), LogWindow.class);
+ startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ startActivity(startLW);
+ return true;
+ case R.id.switch_provider:
+ switching_provider = true;
+ if (preferences.getBoolean(Constants.AUTHED_EIP, false)) logOut();
+ else switchProvider();
+ return true;
+ case R.id.login_button:
+ sessionDialog(Bundle.EMPTY);
+ return true;
+ case R.id.logout_button:
+ logOut();
+ return true;
+ case R.id.signup_button:
+ sessionDialog(Bundle.EMPTY);
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
}
-
- protected Intent prepareProviderAPICommand() {
- providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
- providerAPI_result_receiver.setReceiver(this);
-
- Intent command = new Intent(this, ProviderAPI.class);
-
- command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver);
- return command;
}
-
- /**
- * Shows the log in dialog.
- */
- public void logInDialog(Bundle resultData) {
- FragmentTransaction transaction = fragment_manager.removePreviousFragment(SessionDialog.TAG);
- DialogFragment newFragment = SessionDialog.newInstance();
- if(resultData != null && !resultData.isEmpty())
- newFragment.setArguments(resultData);
- newFragment.show(transaction, SessionDialog.TAG);
+ @Override
+ public void signUp(String username, String password) {
+ Bundle parameters = bundleParameters(username, password);
+ providerApiCommand(parameters, R.string.signingup_message, ProviderAPI.SRP_REGISTER);
}
@Override
public void logIn(String username, String password) {
- Intent provider_API_command = prepareProviderAPICommand();
- Bundle parameters = provider_API_command.getExtras().getBundle(ProviderAPI.PARAMETERS);
- if(parameters == null)
- parameters = new Bundle();
-
- parameters.putString(SessionDialog.USERNAME, username);
- parameters.putString(SessionDialog.PASSWORD, password);
+ Bundle parameters = bundleParameters(username, password);
+ providerApiCommand(parameters, R.string.authenticating_message, ProviderAPI.SRP_AUTH);
+ }
+
+ public void logOut() {
+ providerApiCommand(Bundle.EMPTY, R.string.logout_message, ProviderAPI.LOG_OUT);
+ }
+ private void downloadAuthedUserCertificate() {
+ Bundle parameters = new Bundle();
+ parameters.putString(ConfigurationWizard.TYPE_OF_CERTIFICATE, ConfigurationWizard.AUTHED_CERTIFICATE);
+
+ providerApiCommand(parameters, R.string.downloading_certificate_message, ProviderAPI.DOWNLOAD_CERTIFICATE);
+ }
+
+ private Bundle bundleParameters(String username, String password) {
+ Bundle parameters = new Bundle();
+ if(!username.isEmpty() && !password.isEmpty()) {
+ parameters.putString(SessionDialog.USERNAME, username);
+ parameters.putString(SessionDialog.PASSWORD, password);
+ }
+ return parameters;
+ }
+
+ private void providerApiCommand(Bundle parameters, int progressbar_message_resId, String providerApi_action) {
if(eip_fragment != null) {
eip_fragment.progress_bar.setVisibility(ProgressBar.VISIBLE);
- eip_fragment.status_message.setText(R.string.authenticating_message);
+ setStatusMessage(progressbar_message_resId);
}
- provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
- provider_API_command.setAction(ProviderAPI.SRP_AUTH);
- startService(provider_API_command);
+
+ Intent command = prepareProviderAPICommand(parameters, providerApi_action);
+ startService(command);
}
- public void cancelLoginOrSignup() {
- EipStatus.getInstance().setConnectedOrDisconnected();
- }
+ protected Intent prepareProviderAPICommand(Bundle parameters, String action) {
+ providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
+ providerAPI_result_receiver.setReceiver(this);
- /**
- * Asks ProviderAPI to log out.
- */
- public void logOut() {
- Intent provider_API_command = prepareProviderAPICommand();
- if(eip_fragment != null) {
+ Intent command = new Intent(this, ProviderAPI.class);
+
+ command.putExtra(ProviderAPI.PARAMETERS, parameters);
+ command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver);
+ command.setAction(action);
+ return command;
+ }
- eip_fragment.progress_bar.setVisibility(ProgressBar.VISIBLE);
- eip_fragment.status_message.setText(R.string.logout_message);
- }
- provider_API_command.setAction(ProviderAPI.LOG_OUT);
- startService(provider_API_command);
+ public void cancelLoginOrSignup() {
+ EipStatus.getInstance().setConnectedOrDisconnected();
}
- /**
- * Shows the sign up dialog.
- */
- public void signUpDialog(Bundle resultData) {
+ public void sessionDialog(Bundle resultData) {
FragmentTransaction transaction = fragment_manager.removePreviousFragment(SessionDialog.TAG);
DialogFragment newFragment = SessionDialog.newInstance();
- if(resultData != null && !resultData.isEmpty()) {
+ if(resultData != null && !resultData.isEmpty() && fragment_manager.findFragmentByTag(SessionDialog.TAG) == null) {
newFragment.setArguments(resultData);
}
newFragment.show(transaction, SessionDialog.TAG);
}
- @Override
- public void signUp(String username, String password) {
- Intent provider_API_command = prepareProviderAPICommand();
- Bundle parameters = provider_API_command.getExtras().getBundle(ProviderAPI.PARAMETERS);
- if(parameters == null)
- parameters = new Bundle();
-
- parameters.putString(SessionDialog.USERNAME, username);
- parameters.putString(SessionDialog.PASSWORD, password);
- if(eip_fragment != null) {
- eip_fragment.progress_bar.setVisibility(ProgressBar.VISIBLE);
- eip_fragment.status_message.setText(R.string.signingup_message);
- }
- provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
- provider_API_command.setAction(ProviderAPI.SRP_REGISTER);
- startService(provider_API_command);
+ private void switchProvider() {
+ if (provider.hasEIP()) eip_fragment.askToStopEIP();
+
+ preferences.edit().clear().apply();
+ switching_provider = false;
+ startActivityForResult(new Intent(this, ConfigurationWizard.class), SWITCH_PROVIDER);
}
- /**
- * Asks ProviderAPI to download an authenticated OpenVPN certificate.
- */
- private void downloadAuthedUserCertificate() {
- providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
- providerAPI_result_receiver.setReceiver(this);
-
- Intent provider_API_command = new Intent(this, ProviderAPI.class);
-
- Bundle parameters = new Bundle();
- parameters.putString(ConfigurationWizard.TYPE_OF_CERTIFICATE, ConfigurationWizard.AUTHED_CERTIFICATE);
-
- provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE);
- provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
- provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver);
-
- startService(provider_API_command);
+ @Override
+ public void onReceiveResult(int resultCode, Bundle resultData) {
+ Log.d(TAG, "onReceiveResult");
+ if(resultCode == ProviderAPI.SUCCESSFUL_SIGNUP) {
+ String username = resultData.getString(SessionDialog.USERNAME);
+ String password = resultData.getString(SessionDialog.PASSWORD);
+ logIn(username, password);
+ } else if(resultCode == ProviderAPI.FAILED_SIGNUP) {
+ updateViewHidingProgressBar(resultCode);
+ sessionDialog(resultData);
+ } else if(resultCode == ProviderAPI.SUCCESSFUL_LOGIN) {
+ authed_eip = true;
+ preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply();
+
+ updateViewHidingProgressBar(resultCode);
+ downloadAuthedUserCertificate();
+ } else if(resultCode == ProviderAPI.FAILED_LOGIN) {
+ updateViewHidingProgressBar(resultCode);
+ sessionDialog(resultData);
+ } else if(resultCode == ProviderAPI.SUCCESSFUL_LOGOUT) {
+ authed_eip = false;
+ preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply();
+
+ updateViewHidingProgressBar(resultCode);
+ if(switching_provider) switchProvider();
+ } else if(resultCode == ProviderAPI.LOGOUT_FAILED) {
+ updateViewHidingProgressBar(resultCode);
+ setResult(RESULT_CANCELED);
+ } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
+ updateViewHidingProgressBar(resultCode);
+ updateEipService();
+ setResult(RESULT_OK);
+ } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
+ updateViewHidingProgressBar(resultCode);
+ setResult(RESULT_CANCELED);
}
+ else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE) {
+ setResult(RESULT_OK);
- @Override
- public void onReceiveResult(int resultCode, Bundle resultData) {
- Log.d(TAG, "onReceiveResult");
- if(resultCode == ProviderAPI.SUCCESSFUL_SIGNUP) {
- String username = resultData.getString(SessionDialog.USERNAME);
- String password = resultData.getString(SessionDialog.PASSWORD);
- logIn(username, password);
- } else if(resultCode == ProviderAPI.FAILED_SIGNUP) {
- changeStatusMessage(resultCode);
- hideProgressBar();
-
- signUpDialog(resultData);
- } else if(resultCode == ProviderAPI.SUCCESSFUL_LOGIN) {
- changeStatusMessage(resultCode);
- hideProgressBar();
-
- invalidateOptionsMenu();
-
- authed_eip = true;
- preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply();
-
- downloadAuthedUserCertificate();
- } else if(resultCode == ProviderAPI.FAILED_LOGIN) {
- changeStatusMessage(resultCode);
- hideProgressBar();
-
- logInDialog(resultData);
- } else if(resultCode == ProviderAPI.SUCCESSFUL_LOGOUT) {
- changeStatusMessage(resultCode);
- hideProgressBar();
-
- invalidateOptionsMenu();
-
- authed_eip = false;
- preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply();
-
- } else if(resultCode == ProviderAPI.LOGOUT_FAILED) {
- changeStatusMessage(resultCode);
- hideProgressBar();
-
- setResult(RESULT_CANCELED);
- } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
- changeStatusMessage(resultCode);
- hideProgressBar();
-
- setResult(RESULT_OK);
-
- updateEipService();
- } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
- changeStatusMessage(resultCode);
- hideProgressBar();
- setResult(RESULT_CANCELED);
- }
- else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE) {
- setResult(RESULT_OK);
+ updateEipService();
+ } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE) {
+ setResult(RESULT_CANCELED);
+ }
+ }
- updateEipService();
- } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE) {
- setResult(RESULT_CANCELED);
+ private void updateViewHidingProgressBar(int resultCode) {
+ changeStatusMessage(resultCode);
+ hideProgressBar();
+ invalidateOptionsMenu();
}
- }
private void updateEipService() {
Intent updateEIP = new Intent(getApplicationContext(), EIP.class);
updateEIP.setAction(Constants.ACTION_UPDATE_EIP_SERVICE);
- ResultReceiver receiver = new ResultReceiver(new Handler()) {
- protected void onReceiveResult(int resultCode, Bundle resultData) {
+ startService(updateEIP);
+ }
+
+ private void changeStatusMessage(final int previous_result_code) {
+ ResultReceiver status_receiver = new ResultReceiver(new Handler()){
+ protected void onReceiveResult(int resultCode, Bundle resultData){
+ super.onReceiveResult(resultCode, resultData);
String request = resultData.getString(Constants.REQUEST_TAG);
- if(request.equalsIgnoreCase(Constants.ACTION_UPDATE_EIP_SERVICE)) {
- if(resultCode == Activity.RESULT_OK) {
- if(authed_eip && eip_fragment != null) eip_fragment.startEipFromScratch();
+ if (request.equalsIgnoreCase(Constants.ACTION_IS_EIP_RUNNING)){
+ if (resultCode == Activity.RESULT_OK){
+ switch(previous_result_code){
+ case ProviderAPI.SUCCESSFUL_LOGIN: setStatusMessage(R.string.succesful_authentication_message); break;
+ case ProviderAPI.FAILED_LOGIN: setStatusMessage(R.string.authentication_failed_message); break;
+ case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: setStatusMessage(R.string.authed_secured_status); break;
+ case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: setStatusMessage(R.string.incorrectly_downloaded_certificate_message); break;
+ case ProviderAPI.SUCCESSFUL_LOGOUT: setStatusMessage(R.string.logged_out_message); break;
+ case ProviderAPI.LOGOUT_FAILED: setStatusMessage(R.string.log_out_failed_message); break;
+
+ }
+ }
+ else if(resultCode == Activity.RESULT_CANCELED){
+ switch(previous_result_code){
+ case ProviderAPI.SUCCESSFUL_LOGIN: setStatusMessage(R.string.succesful_authentication_message); break;
+ case ProviderAPI.FAILED_LOGIN: setStatusMessage(R.string.authentication_failed_message); break;
+ case ProviderAPI.FAILED_SIGNUP: setStatusMessage(R.string.registration_failed_message); break;
+ case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: break;
+ case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: setStatusMessage(R.string.incorrectly_downloaded_certificate_message); break;
+ case ProviderAPI.SUCCESSFUL_LOGOUT: setStatusMessage(R.string.logged_out_message); break;
+ case ProviderAPI.LOGOUT_FAILED: setStatusMessage(R.string.log_out_failed_message); break;
+ }
}
}
+
}
};
- //updateEIP.putExtra(Constants.RECEIVER_TAG, receiver);
- startService(updateEIP);
+ eipIsRunning(status_receiver);
}
- private void changeStatusMessage(final int previous_result_code) {
- // TODO Auto-generated method stub
- ResultReceiver eip_status_receiver = new ResultReceiver(new Handler()){
- protected void onReceiveResult(int resultCode, Bundle resultData){
- super.onReceiveResult(resultCode, resultData);
- String request = resultData.getString(Constants.REQUEST_TAG);
- if (request.equalsIgnoreCase(Constants.ACTION_IS_EIP_RUNNING)){
- if (resultCode == Activity.RESULT_OK){
-
- switch(previous_result_code){
- case ProviderAPI.SUCCESSFUL_LOGIN: eip_fragment.status_message.setText(R.string.succesful_authentication_message); break;
- case ProviderAPI.FAILED_LOGIN: eip_fragment.status_message.setText(R.string.authentication_failed_message); break;
- case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: eip_fragment.status_message.setText(R.string.authed_secured_status); break;
- case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: eip_fragment.status_message.setText(R.string.incorrectly_downloaded_certificate_message); break;
- case ProviderAPI.SUCCESSFUL_LOGOUT: eip_fragment.status_message.setText(R.string.logged_out_message); break;
- case ProviderAPI.LOGOUT_FAILED: eip_fragment.status_message.setText(R.string.log_out_failed_message); break;
-
- }
- }
- else if(resultCode == Activity.RESULT_CANCELED){
-
- switch(previous_result_code){
-
- case ProviderAPI.SUCCESSFUL_LOGIN: eip_fragment.status_message.setText(R.string.succesful_authentication_message); break;
- case ProviderAPI.FAILED_LOGIN: eip_fragment.status_message.setText(R.string.authentication_failed_message); break;
- case ProviderAPI.FAILED_SIGNUP: eip_fragment.status_message.setText(R.string.registration_failed_message); break;
- case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: break;
- case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: eip_fragment.status_message.setText(R.string.incorrectly_downloaded_certificate_message); break;
- case ProviderAPI.SUCCESSFUL_LOGOUT: eip_fragment.status_message.setText(R.string.logged_out_message); break;
- case ProviderAPI.LOGOUT_FAILED: eip_fragment.status_message.setText(R.string.log_out_failed_message); break;
- }
- }
- }
-
- }
- };
- eipIsRunning(eip_status_receiver);
- }
+ private void setStatusMessage(int string_resId) {
+ if(eip_fragment != null && eip_fragment.status_message != null)
+ eip_fragment.status_message.setText(string_resId);
+ }
+
+ private void eipIsRunning(ResultReceiver eip_receiver){
+ // TODO validate "action"...how do we get the list of intent-filters for a class via Android API?
+ Intent intent = new Intent(this, EIP.class);
+ intent.setAction(Constants.ACTION_IS_EIP_RUNNING);
+ intent.putExtra(Constants.RECEIVER_TAG, eip_receiver);
+ startService(intent);
+ }
private void hideProgressBar() {
if(eip_fragment != null) {
@@ -546,28 +468,13 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
}
}
- /**
- * For retrieving the base application Context in classes that don't extend
- * Android's Activity class
- *
- * @return Application Context as defined by <code>this</code> for Dashboard instance
- */
- public static Context getAppContext() {
- return app;
- }
-
-
+ public static Context getAppContext() {
+ return app;
+ }
+
@Override
public void startActivityForResult(Intent intent, int requestCode) {
intent.putExtra(Dashboard.REQUEST_CODE, requestCode);
super.startActivityForResult(intent, requestCode);
}
-
- private void eipIsRunning(ResultReceiver eip_receiver){
- // TODO validate "action"...how do we get the list of intent-filters for a class via Android API?
- Intent eip_intent = new Intent(this, EIP.class);
- eip_intent.setAction(Constants.ACTION_IS_EIP_RUNNING);
- eip_intent.putExtra(Constants.RECEIVER_TAG, eip_receiver);
- startService(eip_intent);
- }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
index 420da7a1..54432033 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
@@ -56,8 +56,7 @@ public class EipFragment extends Fragment implements Observer {
parent_activity = activity;
Dashboard dashboard = (Dashboard) parent_activity;
- Intent provider_API_command = dashboard.prepareProviderAPICommand();
- provider_API_command.setAction(ProviderAPI.DOWNLOAD_EIP_SERVICE);
+ Intent provider_API_command = dashboard.prepareProviderAPICommand(Bundle.EMPTY, ProviderAPI.DOWNLOAD_EIP_SERVICE);
parent_activity.startService(provider_API_command);
}
@@ -110,15 +109,10 @@ public class EipFragment extends Fragment implements Observer {
super.onSaveInstanceState(outState);
}
- protected void saveEipStatus() {
- boolean eip_is_on = false;
- Log.d(TAG, "saveEipStatus");
- if(eip_switch.isChecked()) {
- eip_is_on = true;
- }
-
- if(parent_activity != null)
- Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, eip_is_on).commit();
+ protected void saveStatus() {
+ boolean is_on = eip_switch.isChecked();
+ Log.d(TAG, "saveStatus: is_on = " + is_on);
+ Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, is_on).commit();
}
@OnCheckedChanged(R.id.eipSwitch)
@@ -128,7 +122,7 @@ public class EipFragment extends Fragment implements Observer {
else
handleSwitchOff();
- saveEipStatus();
+ saveStatus();
}
private void handleSwitchOn() {
@@ -139,7 +133,7 @@ public class EipFragment extends Fragment implements Observer {
Dashboard dashboard = (Dashboard) parent_activity;
Bundle bundle = new Bundle();
bundle.putBoolean(IS_PENDING, true);
- dashboard.logInDialog(bundle);
+ dashboard.sessionDialog(bundle);
}
}
@@ -193,8 +187,8 @@ public class EipFragment extends Fragment implements Observer {
if(!eip_switch.isChecked()) {
eip_switch.setChecked(true);
- saveEipStatus();
}
+ saveStatus();
eipCommand(Constants.ACTION_START_EIP);
}
@@ -211,6 +205,7 @@ public class EipFragment extends Fragment implements Observer {
String status = parent_activity.getString(R.string.eip_state_not_connected);
status_message.setText(status);
+
eipCommand(Constants.ACTION_STOP_EIP);
}
@@ -343,10 +338,9 @@ public class EipFragment extends Fragment implements Observer {
progress_bar.setVisibility(View.VISIBLE);
status_message.setText(getString(R.string.updating_certificate_message));
if(LeapSRPSession.getToken().isEmpty() && !Dashboard.preferences.getBoolean(Constants.ALLOWED_ANON, false)) {
- dashboard.logInDialog(Bundle.EMPTY);
+ dashboard.sessionDialog(Bundle.EMPTY);
} else {
- Intent provider_API_command = dashboard.prepareProviderAPICommand();
- provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE);
+ Intent provider_API_command = dashboard.prepareProviderAPICommand(Bundle.EMPTY, ProviderAPI.DOWNLOAD_CERTIFICATE);
parent_activity.startService(provider_API_command);
}
break;
diff --git a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
index 07ed6c8f..96b87085 100644
--- a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
@@ -3,22 +3,29 @@ package se.leap.bitmaskclient;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.util.Log;
import se.leap.bitmaskclient.eip.Constants;
public class OnBootReceiver extends BroadcastReceiver {
- // Debug: am broadcast -a android.intent.action.BOOT_COMPLETED
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
- if (!context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE).getString(Provider.KEY, "").isEmpty() && context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE).getBoolean(Dashboard.START_ON_BOOT, false)) {
- Intent dashboard_intent = new Intent(context, Dashboard.class);
- dashboard_intent.setAction(Constants.ACTION_START_EIP);
- dashboard_intent.putExtra(Dashboard.ON_BOOT, true);
- dashboard_intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(dashboard_intent);
- }
- }
+ SharedPreferences preferences;
+
+ // Debug: am broadcast -a android.intent.action.BOOT_COMPLETED
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ boolean provider_configured = !preferences.getString(Provider.KEY, "").isEmpty();
+ boolean start_on_boot = preferences.getBoolean(Dashboard.START_ON_BOOT, false);
+ Log.d("OnBootReceiver", "Provider configured " + String.valueOf(provider_configured));
+ Log.d("OnBootReceiver", "Start on boot " + String.valueOf(start_on_boot));
+ if(provider_configured && start_on_boot) {
+ Intent dashboard_intent = new Intent(context, Dashboard.class);
+ dashboard_intent.setAction(Constants.ACTION_START_EIP);
+ dashboard_intent.putExtra(Dashboard.ON_BOOT, true);
+ dashboard_intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(dashboard_intent);
}
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java b/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java
index 22e0f128..fd9ca851 100644
--- a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java
@@ -129,15 +129,15 @@ public class SessionDialog extends DialogFragment{
SessionDialogInterface interface_with_Dashboard;
- /**
- * @return a new instance of this DialogFragment.
- */
- public static DialogFragment newInstance() {
+ /**
+ * @return a new instance of this DialogFragment.
+ */
+ public static DialogFragment newInstance() {
if(dialog == null)
dialog = new SessionDialog();
return dialog;
- }
+ }
@Override
public void onAttach(Activity activity) {
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 3d3070c8..533b0281 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -25,19 +25,27 @@ import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.Log;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
+import java.util.NoSuchElementException;
import de.blinkt.openvpn.LaunchVPN;
import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.core.Connection;
import de.blinkt.openvpn.core.ProfileManager;
import se.leap.bitmaskclient.Dashboard;
import se.leap.bitmaskclient.EipFragment;
+import se.leap.bitmaskclient.Provider;
import static se.leap.bitmaskclient.eip.Constants.ACTION_CHECK_CERT_VALIDITY;
import static se.leap.bitmaskclient.eip.Constants.ACTION_IS_EIP_RUNNING;
@@ -71,7 +79,7 @@ public final class EIP extends IntentService {
private static SharedPreferences preferences;
private static JSONObject eip_definition;
- private static List<Gateway> gateways = new ArrayList<Gateway>();
+ private static List<Gateway> gateways = new ArrayList<>();
private static ProfileManager profile_manager;
private static Gateway gateway;
@@ -84,12 +92,14 @@ public final class EIP extends IntentService {
super.onCreate();
context = getApplicationContext();
- profile_manager = ProfileManager.getInstance(context);
+ preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE);
- preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE);
- refreshEipDefinition();
+ profile_manager = ProfileManager.getInstance(context);
+ eip_definition = eipDefinitionFromPreferences();
+ if(gateways.isEmpty())
+ gateways = gatewaysFromPreferences();
}
-
+
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
@@ -101,7 +111,7 @@ public final class EIP extends IntentService {
stopEIP();
else if (action.equals(ACTION_IS_EIP_RUNNING))
isRunning();
- else if (action.equals(ACTION_UPDATE_EIP_SERVICE))
+ else if (action.equals(ACTION_UPDATE_EIP_SERVICE))
updateEIPService();
else if (action.equals(ACTION_CHECK_CERT_VALIDITY))
checkCertValidity();
@@ -122,8 +132,9 @@ public final class EIP extends IntentService {
if(gateway != null && gateway.getProfile() != null) {
mReceiver = EipFragment.getReceiver();
launchActiveGateway();
- }
- tellToReceiver(ACTION_START_EIP, Activity.RESULT_OK);
+ tellToReceiver(ACTION_START_EIP, Activity.RESULT_OK);
+ } else
+ tellToReceiver(ACTION_START_EIP, Activity.RESULT_CANCELED);
}
/**
@@ -147,7 +158,6 @@ public final class EIP extends IntentService {
private void stopEIP() {
EipStatus eip_status = EipStatus.getInstance();
- Log.d(TAG, "stopEip(): eip is connected? " + eip_status.isConnected());
int result_code = Activity.RESULT_CANCELED;
if(eip_status.isConnected() || eip_status.isConnecting())
result_code = Activity.RESULT_OK;
@@ -173,46 +183,55 @@ public final class EIP extends IntentService {
* TODO Implement API call to refresh eip-service.json from the provider
*/
private void updateEIPService() {
- refreshEipDefinition();
- deleteAllVpnProfiles();
- updateGateways();
+ eip_definition = eipDefinitionFromPreferences();
+ if(eip_definition != null)
+ updateGateways();
tellToReceiver(ACTION_UPDATE_EIP_SERVICE, Activity.RESULT_OK);
}
- private void refreshEipDefinition() {
+ private JSONObject eipDefinitionFromPreferences() {
try {
String eip_definition_string = preferences.getString(KEY, "");
if(!eip_definition_string.isEmpty()) {
- eip_definition = new JSONObject(eip_definition_string);
+ return new JSONObject(eip_definition_string);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
+ return null;
}
-
- private void deleteAllVpnProfiles() {
- Collection<VpnProfile> profiles = profile_manager.getProfiles();
- profiles.removeAll(profiles);
- gateways.clear();
+
+ private List<Gateway> gatewaysFromPreferences() {
+ List<Gateway> result;
+
+ String gateways_string = preferences.getString(Gateway.TAG, "");
+ Type type_list_gateways = new TypeToken<ArrayList<Gateway>>() {}.getType();
+ result = gateways_string.isEmpty() ?
+ new ArrayList<Gateway>()
+ : (List<Gateway>) new Gson().fromJson(gateways_string, type_list_gateways);
+ preferences.edit().remove(Gateway.TAG);
+ return result;
}
/**
* Walk the list of gateways defined in eip-service.json and parse them into
* Gateway objects.
- * TODO Store the Gateways (as Serializable) in SharedPreferences
*/
private void updateGateways(){
try {
- if(eip_definition != null) {
JSONArray gatewaysDefined = eip_definition.getJSONArray("gateways");
for (int i = 0; i < gatewaysDefined.length(); i++) {
JSONObject gw = gatewaysDefined.getJSONObject(i);
if (isOpenVpnGateway(gw)) {
- addGateway(new Gateway(eip_definition, context, gw));
+ JSONObject secrets = secretsConfiguration();
+ Gateway aux = new Gateway(eip_definition, secrets, gw);
+ if(!containsProfileWithSecrets(aux.getProfile())) {
+ addGateway(aux);
+ }
}
}
- }
+ gatewaysToPreferences();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -228,11 +247,112 @@ public final class EIP extends IntentService {
}
}
+
+ private JSONObject secretsConfiguration() {
+ JSONObject result = new JSONObject();
+ try {
+ result.put(Provider.CA_CERT, preferences.getString(Provider.CA_CERT, ""));
+ result.put(Constants.PRIVATE_KEY, preferences.getString(Constants.PRIVATE_KEY, ""));
+ result.put(Constants.CERTIFICATE, preferences.getString(Constants.CERTIFICATE, ""));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
private void addGateway(Gateway gateway) {
- profile_manager.addProfile(gateway.getProfile());
+ VpnProfile profile = gateway.getProfile();
+ removeGateway(gateway);
+
+ profile_manager.addProfile(profile);
+ profile_manager.saveProfile(context, profile);
+ profile_manager.saveProfileList(context);
+
gateways.add(gateway);
}
+ private void removeGateway(Gateway gateway) {
+ VpnProfile profile = gateway.getProfile();
+ removeDuplicatedProfile(profile);
+ removeDuplicatedGateway(profile);
+ }
+
+ private void removeDuplicatedProfile(VpnProfile original) {
+ if(containsProfile(original)) {
+ VpnProfile remove = duplicatedProfile(original);
+ profile_manager.removeProfile(context, remove);
+ }if(containsProfile(original)) removeDuplicatedProfile(original);
+ }
+
+ private boolean containsProfile(VpnProfile profile) {
+ Collection<VpnProfile> profiles = profile_manager.getProfiles();
+ for(VpnProfile aux : profiles) {
+ if (sameConnections(profile.mConnections, aux.mConnections)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean containsProfileWithSecrets(VpnProfile profile) {
+ boolean result = false;
+
+ if(containsProfile(profile)) {
+ Collection<VpnProfile> profiles = profile_manager.getProfiles();
+ for(VpnProfile aux : profiles) {
+ result = result == false ?
+ sameConnections(profile.mConnections, aux.mConnections)
+ && profile.mClientCertFilename.equalsIgnoreCase(aux.mClientCertFilename)
+ && profile.mClientKeyFilename.equalsIgnoreCase(aux.mClientKeyFilename)
+ : true;
+ }
+ }
+ return result;
+ }
+
+ private VpnProfile duplicatedProfile(VpnProfile profile) {
+ VpnProfile duplicated = null;
+ Collection<VpnProfile> profiles = profile_manager.getProfiles();
+ for(VpnProfile aux : profiles) {
+ if (sameConnections(profile.mConnections, aux.mConnections)) {
+ duplicated = aux;
+ }
+ }
+ if(duplicated != null) return duplicated;
+ else throw new NoSuchElementException(profile.getName());
+ }
+
+ private boolean sameConnections(Connection[] c1, Connection[] c2) {
+ int same_connections = 0;
+ for(Connection c1_aux : c1) {
+ for(Connection c2_aux : c2)
+ if(c2_aux.mServerName.equals(c1_aux.mServerName)) {
+ same_connections++;
+ break;
+ }
+ }
+ return c1.length == c2.length && c1.length == same_connections;
+
+ }
+
+ private void removeDuplicatedGateway(VpnProfile profile) {
+ Iterator<Gateway> it = gateways.iterator();
+ List<Gateway> gateways_to_remove = new ArrayList<>();
+ while(it.hasNext()) {
+ Gateway aux = it.next();
+ if(sameConnections(aux.getProfile().mConnections, profile.mConnections)) {
+ gateways_to_remove.add(aux);
+ }
+ }
+ gateways.removeAll(gateways_to_remove);
+ }
+
+ private void gatewaysToPreferences() {
+ Type type_list_gateways = new TypeToken<List<Gateway>>() {}.getType();
+ String gateways_string = new Gson().toJson(gateways, type_list_gateways);
+ preferences.edit().putString(Gateway.TAG, gateways_string).apply();
+ }
+
private void checkCertValidity() {
VpnCertificateValidator validator = new VpnCertificateValidator();
int resultCode = validator.isValid(preferences.getString(CERTIFICATE, "")) ?
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 3ee9443c..daf7d4a7 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -17,7 +17,6 @@
package se.leap.bitmaskclient.eip;
import android.app.Activity;
-import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
@@ -26,12 +25,9 @@ import org.json.JSONObject;
import java.io.IOException;
import java.io.StringReader;
-import java.util.Collection;
-import java.util.Iterator;
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.ConfigParser;
-import de.blinkt.openvpn.core.ProfileManager;
import se.leap.bitmaskclient.Dashboard;
/**
@@ -44,48 +40,30 @@ import se.leap.bitmaskclient.Dashboard;
*/
public class Gateway {
- private String TAG = Gateway.class.getSimpleName();
-
+ public static String TAG = Gateway.class.getSimpleName();
+
+ private JSONObject general_configuration;
+ private JSONObject secrets;
+ private JSONObject gateway;
+
private String mName;
private int timezone;
- private JSONObject general_configuration;
- private Context context;
private VpnProfile mVpnProfile;
- private JSONObject mGateway;
-
/**
* Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json
* and create a VpnProfile belonging to it.
- *
- * @param gateway The JSON OpenVPN gateway definition to parse
*/
- protected Gateway(JSONObject eip_definition, Context context, JSONObject gateway){
+ protected Gateway(JSONObject eip_definition, JSONObject secrets, JSONObject gateway){
+
+ this.gateway = gateway;
+ this.secrets = secrets;
- mGateway = gateway;
-
- this.context = context;
general_configuration = getGeneralConfiguration(eip_definition);
timezone = getTimezone(eip_definition);
mName = locationAsName(eip_definition);
- // Currently deletes VpnProfile for host, if there already is one, and builds new
- ProfileManager vpl = ProfileManager.getInstance(context);
- Collection<VpnProfile> profiles = vpl.getProfiles();
- for (Iterator<VpnProfile> it = profiles.iterator(); it.hasNext(); ){
- VpnProfile p = it.next();
-
- if ( p.mName.equalsIgnoreCase( mName ) ) {
- it.remove();
- vpl.removeProfile(context, p);
- }
- }
-
mVpnProfile = createVPNProfile();
mVpnProfile.mName = mName;
-
- vpl.addProfile(mVpnProfile);
- vpl.saveProfile(context, mVpnProfile);
- vpl.saveProfileList(context);
}
private JSONObject getGeneralConfiguration(JSONObject eip_definition) {
@@ -110,7 +88,7 @@ public class Gateway {
try {
JSONObject locations = eip_definition.getJSONObject("locations");
- return locations.getJSONObject(mGateway.getString("location"));
+ return locations.getJSONObject(gateway.getString("location"));
} catch (JSONException e) {
return new JSONObject();
}
@@ -123,8 +101,7 @@ public class Gateway {
try {
ConfigParser cp = new ConfigParser();
- SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE);
- VpnConfigGenerator vpn_configuration_generator = new VpnConfigGenerator(preferences, general_configuration, mGateway);
+ VpnConfigGenerator vpn_configuration_generator = new VpnConfigGenerator(general_configuration, secrets, gateway);
String configuration = vpn_configuration_generator.generate();
cp.parseConfig(new StringReader(configuration));
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 0c8e9a04..6f260f55 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
@@ -31,15 +31,15 @@ public class VpnConfigGenerator {
private JSONObject general_configuration;
private JSONObject gateway;
-
- private static SharedPreferences preferences;
+ private JSONObject secrets;
+
public final static String TAG = VpnConfigGenerator.class.getSimpleName();
private final String new_line = System.getProperty("line.separator"); // Platform new line
- public VpnConfigGenerator(SharedPreferences preferences, JSONObject general_configuration, JSONObject gateway) {
+ public VpnConfigGenerator(JSONObject general_configuration, JSONObject secrets, JSONObject gateway) {
this.general_configuration = general_configuration;
this.gateway = gateway;
- VpnConfigGenerator.preferences = preferences;
+ this.secrets = secrets;
}
public String generate() {
@@ -79,59 +79,67 @@ public class VpnConfigGenerator {
private String gatewayConfiguration() {
String remotes = "";
- String remote = "ip_address";
- String remote_openvpn_keyword = "remote";
- String ports = "ports";
- String protos = "protocols";
- String capabilities = "capabilities";
+ String ip_address_keyword = "ip_address";
+ String remote_keyword = "remote";
+ String ports_keyword = "ports";
+ String protocol_keyword = "protocols";
+ String capabilities_keyword = "capabilities";
String udp = "udp";
try {
- JSONArray protocolsJSON = gateway.getJSONObject(capabilities).getJSONArray(protos);
- for ( int i=0; i<protocolsJSON.length(); i++ ) {
- String remote_line = remote_openvpn_keyword;
- remote_line += " " + gateway.getString(remote);
- remote_line += " " + gateway.getJSONObject(capabilities).getJSONArray(ports).optString(0);
- remote_line += " " + protocolsJSON.optString(i);
- if(remote_line.endsWith(udp))
- remotes = remotes.replaceFirst(remote_openvpn_keyword, remote_line + new_line + remote_openvpn_keyword);
- else
- remotes += remote_line;
- remotes += new_line;
+ String ip_address = gateway.getString(ip_address_keyword);
+ JSONObject capabilities = gateway.getJSONObject(capabilities_keyword);
+ JSONArray ports = capabilities.getJSONArray(ports_keyword);
+ for (int i=0; i<ports.length(); i++) {
+ String port_specific_remotes = "";
+ int port = ports.getInt(i);
+ JSONArray protocols = capabilities.getJSONArray(protocol_keyword);
+ for ( int j=0; j<protocols.length(); j++ ) {
+ String protocol = protocols.optString(j);
+ String new_remote = remote_keyword + " " + ip_address + " " + port + " " + protocol + new_line;
+
+ port_specific_remotes = protocol.equalsIgnoreCase(udp) ?
+ port_specific_remotes.replaceFirst(remote_keyword, new_remote + new_line + remote_keyword) :
+ new_remote;
+ }
+ remotes += port_specific_remotes;
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
- Log.d(TAG, "remotes = " + remotes);
return remotes;
}
private String secretsConfiguration() {
-
- String ca =
- "<ca>"
- + new_line
- + preferences.getString(Provider.CA_CERT, "")
- + new_line
- + "</ca>";
-
- String key =
- "<key>"
- + new_line
- + preferences.getString(Constants.PRIVATE_KEY, "")
- + new_line
- + "</key>";
-
- String openvpn_cert =
- "<cert>"
- + new_line
- + preferences.getString(Constants.CERTIFICATE, "")
- + new_line
- + "</cert>";
+ try {
+ String ca =
+ "<ca>"
+ + new_line
+ + secrets.getString(Provider.CA_CERT)
+ + new_line
+ + "</ca>";
+
+ String key =
+ "<key>"
+ + new_line
+ + secrets.getString(Constants.PRIVATE_KEY)
+ + new_line
+ + "</key>";
+
+ String openvpn_cert =
+ "<cert>"
+ + new_line
+ + secrets.getString(Constants.CERTIFICATE)
+ + new_line
+ + "</cert>";
- return ca + new_line + key + new_line + openvpn_cert;
+ return ca + new_line + key + new_line + openvpn_cert;
+ } catch(JSONException e) {
+ e.printStackTrace();
+ return "";
+ }
}
private String androidCustomizations() {