From d6190becb1c48ee912b11a4206116d0fd4c90772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 20 Dec 2014 20:14:23 +0100 Subject: Update ics-openvpn to 1006 --- app/src/main/java/de/blinkt/openvpn/LaunchVPN.java | 2 +- .../main/java/de/blinkt/openvpn/VpnProfile.java | 127 ++++++++-- .../blinkt/openvpn/activities/DisconnectVPN.java | 2 +- .../de/blinkt/openvpn/activities/LogWindow.java | 2 +- .../main/java/de/blinkt/openvpn/core/CIDRIP.java | 2 +- .../java/de/blinkt/openvpn/core/ConfigParser.java | 280 +++++++++++++-------- .../java/de/blinkt/openvpn/core/Connection.java | 51 ++++ .../blinkt/openvpn/core/DeviceStateReceiver.java | 12 +- .../blinkt/openvpn/core/ICSOpenVPNApplication.java | 2 +- .../openvpn/core/LollipopDeviceStateListener.java | 53 ++++ .../java/de/blinkt/openvpn/core/NativeUtils.java | 3 +- .../java/de/blinkt/openvpn/core/NetworkSpace.java | 11 +- .../de/blinkt/openvpn/core/OpenVPNManagement.java | 2 +- .../de/blinkt/openvpn/core/OpenVPNService.java | 153 +++++++++-- .../java/de/blinkt/openvpn/core/OpenVPNThread.java | 2 +- .../openvpn/core/OpenVpnManagementThread.java | 4 +- .../java/de/blinkt/openvpn/core/PRNGFixes.java | 2 +- .../de/blinkt/openvpn/core/ProfileManager.java | 2 +- .../de/blinkt/openvpn/core/ProxyDetection.java | 2 +- .../de/blinkt/openvpn/core/VPNLaunchHelper.java | 3 +- .../java/de/blinkt/openvpn/core/VpnStatus.java | 8 +- .../java/de/blinkt/openvpn/core/X509Utils.java | 2 +- .../de/blinkt/openvpn/fragments/LogFragment.java | 2 +- .../java/de/blinkt/openvpn/views/SeekBarTicks.java | 2 +- 24 files changed, 560 insertions(+), 171 deletions(-) create mode 100644 app/src/main/java/de/blinkt/openvpn/core/Connection.java create mode 100644 app/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java (limited to 'app/src/main/java/de') 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 mAllowedAppsVpn = new HashSet(); + 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(); + 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 += "\n"; + cfg += conn.getConnectionBlock(); + cfg += "\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) 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>> options = new HashMap>>(); private HashMap> meta = new HashMap>(); - - 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 metaarg = parsemeta(line); - meta.put(metaarg.get(0),metaarg); - continue; - } - Vector args = parseline(line); + // Check for OpenVPN Access Server Meta information + if (line.startsWith("# OVPN_ACCESS_SERVER_")) { + Vector metaarg = parsemeta(line); + meta.put(metaarg.get(0), metaarg); + continue; + } + Vector 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>()); - } - options.get(optionname).add(args); - } + String optionname = args.get(0); + if (!options.containsKey(optionname)) { + options.put(optionname, new Vector>()); + } + options.get(optionname).add(args); + } + } catch (java.lang.OutOfMemoryError memoryError) { + throw new ConfigParseError("File too large to parse: " + memoryError.getLocalizedMessage()); + } } private Vector 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 parseline(String line) throws ConfigParseError { - Vector parameters = new Vector(); + Vector parameters = new Vector(); 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 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> tlsauthoptions = getAllOption("tls-auth", 1, 2); if(tlsauthoptions!=null) { for(Vector 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 port = getOption("port", 1,1); - if(port!=null){ - np.mServerPort = port.get(1); - } - - Vector rport = getOption("rport", 1,1); - if(rport!=null){ - np.mServerPort = rport.get(1); - } - - Vector proto = getOption("proto", 1,1); - if(proto!=null){ - np.mUseUdp=isUdpProto(proto.get(1)); - } - - // Parse remote config - Vector> remotes = getAllOption("remote",1,3); - - if(remotes!=null && remotes.size()>=1 ) { - Vector 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> 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 verb = getOption("verb",1,1); @@ -615,7 +587,7 @@ public class ConfigParser { if(connectretrymax!=null) np.mConnectRetryMax =connectretrymax.get(1); - Vector> remotetls = getAllOption("remote-cert-tls", 1, 1); + Vector> 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 conns = parseConnectionOptions(null); + np.mConnections =conns.second; + + Vector> connectionBlocks = getAllOption("connection", 1, 1); + + if (np.mConnections.length > 0 && connectionBlocks !=null ) { + throw new ConfigParseError("Using a block and --remote is not allowed."); + } + + if (connectionBlocks!=null) { + np.mConnections = new Connection[connectionBlocks.size()]; + + int connIndex = 0; + for (Vector conn : connectionBlocks) { + Pair connectionBlockConnection = + parseConnection(conn.get(1), conns.first); + + if (connectionBlockConnection.second.length != 1) + throw new ConfigParseError("A block must have exactly one remote"); + np.mConnections[connIndex] = connectionBlockConnection.second[0]; + connIndex++; + } + } + if(getOption("remote-random", 0, 0) != null) + np.mRemoteRandom=true; + + Vector 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 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 parseConnection(String connection, Connection defaultValues) throws IOException, ConfigParseError { + // Parse a connection Block as a new configuration file + + + ConfigParser connectionParser = new ConfigParser(); + StringReader reader = new StringReader(connection.substring(VpnProfile.INLINE_TAG.length())); + connectionParser.parseConfig(reader); + + Pair conn = connectionParser.parseConnectionOptions(defaultValues); + + return conn; + } + + private Pair 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 port = getOption("port", 1,1); + if(port!=null){ + conn.mServerPort = port.get(1); + } + + Vector rport = getOption("rport", 1,1); + if(rport!=null){ + conn.mServerPort = rport.get(1); + } + + Vector proto = getOption("proto", 1,1); + if(proto!=null){ + conn.mUseUdp=isUdpProto(proto.get(1)); + } + + + // Parse remote config + Vector> remotes = getAllOption("remote",1,3); + + + // Assume that we need custom options if connectionDefault are set + if(connDefault!=null) { + for (Vector> 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>(); + + Connection[] connections = new Connection[remotes.size()]; + + + int i=0; + for (Vector 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> defgw) { for (Vector redirect: defgw) for (int i=1;i { 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; -- cgit v1.2.3