From b79fd315dd89e7a9f648c6a500b41ce7d9970081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 14 May 2014 20:05:30 +0200 Subject: Copy all java files from ics-openvpn. imports from se.leap.bitmaskclient java files have also been updated. WARNING: compiling errors for de.blinkt.openvpn.R, aidl.de.blinkt.openvpn. --- app/src/main/java/se/leap/bitmaskclient/EIP.java | 16 +- .../se/leap/bitmaskclient/EipServiceFragment.java | 13 +- app/src/main/java/se/leap/openvpn/CIDRIP.java | 58 -- .../main/java/se/leap/openvpn/ConfigParser.java | 569 ---------------- app/src/main/java/se/leap/openvpn/LICENSE.txt | 24 - app/src/main/java/se/leap/openvpn/LaunchVPN.java | 385 ----------- app/src/main/java/se/leap/openvpn/LogWindow.java | 340 --------- .../java/se/leap/openvpn/NetworkSateReceiver.java | 86 --- app/src/main/java/se/leap/openvpn/OpenVPN.java | 250 ------- .../main/java/se/leap/openvpn/OpenVPNThread.java | 130 ---- .../se/leap/openvpn/OpenVpnManagementThread.java | 592 ---------------- .../main/java/se/leap/openvpn/OpenVpnService.java | 513 -------------- .../main/java/se/leap/openvpn/ProfileManager.java | 221 ------ .../main/java/se/leap/openvpn/ProxyDetection.java | 54 -- .../main/java/se/leap/openvpn/VPNLaunchHelper.java | 76 --- app/src/main/java/se/leap/openvpn/VpnProfile.java | 758 --------------------- 16 files changed, 15 insertions(+), 4070 deletions(-) delete mode 100644 app/src/main/java/se/leap/openvpn/CIDRIP.java delete mode 100644 app/src/main/java/se/leap/openvpn/ConfigParser.java delete mode 100644 app/src/main/java/se/leap/openvpn/LICENSE.txt delete mode 100644 app/src/main/java/se/leap/openvpn/LaunchVPN.java delete mode 100644 app/src/main/java/se/leap/openvpn/LogWindow.java delete mode 100644 app/src/main/java/se/leap/openvpn/NetworkSateReceiver.java delete mode 100644 app/src/main/java/se/leap/openvpn/OpenVPN.java delete mode 100644 app/src/main/java/se/leap/openvpn/OpenVPNThread.java delete mode 100644 app/src/main/java/se/leap/openvpn/OpenVpnManagementThread.java delete mode 100644 app/src/main/java/se/leap/openvpn/OpenVpnService.java delete mode 100644 app/src/main/java/se/leap/openvpn/ProfileManager.java delete mode 100644 app/src/main/java/se/leap/openvpn/ProxyDetection.java delete mode 100644 app/src/main/java/se/leap/openvpn/VPNLaunchHelper.java delete mode 100644 app/src/main/java/se/leap/openvpn/VpnProfile.java (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index 68688b90..8b95a586 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -31,14 +31,14 @@ import org.json.JSONException; import org.json.JSONObject; import se.leap.bitmaskclient.R; -import se.leap.openvpn.ConfigParser; -import se.leap.openvpn.ConfigParser.ConfigParseError; -import se.leap.openvpn.LaunchVPN; -import se.leap.openvpn.OpenVpnManagementThread; -import se.leap.openvpn.OpenVpnService; -import se.leap.openvpn.OpenVpnService.LocalBinder; -import se.leap.openvpn.ProfileManager; -import se.leap.openvpn.VpnProfile; +import de.blinkt.openvpn.core.ConfigParser; +import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; +import de.blinkt.openvpn.LaunchVPN; +import de.blinkt.openvpn.core.OpenVpnManagementThread; +import de.blinkt.openvpn.core.OpenVpnService; +import de.blinkt.openvpn.core.OpenVpnService.LocalBinder; +import de.blinkt.openvpn.core.ProfileManager; +import de.blinkt.openvpn.VpnProfile; import android.app.Activity; import android.app.IntentService; import android.content.ComponentName; diff --git a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java index 4341c9dc..89319ea1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java @@ -1,9 +1,10 @@ package se.leap.bitmaskclient; import se.leap.bitmaskclient.R; -import se.leap.openvpn.LogWindow; -import se.leap.openvpn.OpenVPN; -import se.leap.openvpn.OpenVPN.StateListener; +import de.blinkt.openvpn.activities.LogWindow; +import de.blinkt.openvpn.core.VpnStatus; +import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; +import de.blinkt.openvpn.core.VpnStatus.StateListener; import android.app.Activity; import android.app.AlertDialog; import android.app.Fragment; @@ -94,7 +95,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe public void onResume() { super.onResume(); - OpenVPN.addStateListener(this); + VpnStatus.addStateListener(this); if(set_switch_off) { eipSwitch.setChecked(false); set_switch_off = false; @@ -109,7 +110,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe public void onPause() { super.onPause(); - OpenVPN.removeStateListener(this); + VpnStatus.removeStateListener(this); } @Override @@ -203,7 +204,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe } @Override - public void updateState(final String state, final String logmessage, final int localizedResId) { + public void updateState(final String state, final String logmessage, final int localizedResId, ConnectionStatus level) { // Note: "states" are not organized anywhere...collected state strings: // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) getActivity().runOnUiThread(new Runnable() { diff --git a/app/src/main/java/se/leap/openvpn/CIDRIP.java b/app/src/main/java/se/leap/openvpn/CIDRIP.java deleted file mode 100644 index 8c4b6709..00000000 --- a/app/src/main/java/se/leap/openvpn/CIDRIP.java +++ /dev/null @@ -1,58 +0,0 @@ -package se.leap.openvpn; - -class CIDRIP{ - String mIp; - int len; - public CIDRIP(String ip, String mask){ - mIp=ip; - long netmask=getInt(mask); - - // Add 33. bit to ensure the loop terminates - netmask += 1l << 32; - - int lenZeros = 0; - while((netmask & 0x1) == 0) { - lenZeros++; - netmask = netmask >> 1; - } - // Check if rest of netmask is only 1s - if(netmask != (0x1ffffffffl >> lenZeros)) { - // Asume no CIDR, set /32 - len=32; - } else { - len =32 -lenZeros; - } - - } - @Override - public String toString() { - return String.format("%s/%d",mIp,len); - } - - public boolean normalise(){ - long ip=getInt(mIp); - - long newip = ip & (0xffffffffl << (32 -len)); - if (newip != ip){ - mIp = String.format("%d.%d.%d.%d", (newip & 0xff000000) >> 24,(newip & 0xff0000) >> 16, (newip & 0xff00) >> 8 ,newip & 0xff); - return true; - } else { - return false; - } - } - static long getInt(String ipaddr) { - String[] ipt = ipaddr.split("\\."); - long ip=0; - - ip += Long.parseLong(ipt[0])<< 24; - ip += Integer.parseInt(ipt[1])<< 16; - ip += Integer.parseInt(ipt[2])<< 8; - ip += Integer.parseInt(ipt[3]); - - return ip; - } - public long getInt() { - return getInt(mIp); - } - -} \ No newline at end of file diff --git a/app/src/main/java/se/leap/openvpn/ConfigParser.java b/app/src/main/java/se/leap/openvpn/ConfigParser.java deleted file mode 100644 index df4eae1b..00000000 --- a/app/src/main/java/se/leap/openvpn/ConfigParser.java +++ /dev/null @@ -1,569 +0,0 @@ -package se.leap.openvpn; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.util.HashMap; -import java.util.Locale; -import java.util.Vector; - -//! Openvpn Config FIle Parser, probably not 100% accurate but close enough - -// And rember, this is valid :) -// -- -// bar -// -public class ConfigParser { - - - private HashMap>> options = new HashMap>>(); - public void parseConfig(Reader reader) throws IOException, ConfigParseError { - - - BufferedReader br =new BufferedReader(reader); - - @SuppressWarnings("unused") - int lineno=0; - - while (true){ - String line = br.readLine(); - if(line==null) - break; - lineno++; - Vector args = parseline(line); - if(args.size() ==0) - continue; - - - if(args.get(0).startsWith("--")) - args.set(0, args.get(0).substring(2)); - - checkinlinefile(args,br); - - String optionname = args.get(0); - if(!options.containsKey(optionname)) { - options.put(optionname, new Vector>()); - } - options.get(optionname).add(args); - } - } - public void setDefinition(HashMap>> args) { - options = args; - } - - private void checkinlinefile(Vector args, BufferedReader br) throws IOException, ConfigParseError { - String arg0 = args.get(0); - // CHeck for - if(arg0.startsWith("<") && arg0.endsWith(">")) { - String argname = arg0.substring(1, arg0.length()-1); - String inlinefile = VpnProfile.INLINE_TAG; - - String endtag = String.format("",argname); - do { - String line = br.readLine(); - if(line==null){ - throw new ConfigParseError(String.format("No endtag for starttag <%s> found",argname,argname)); - } - if(line.equals(endtag)) - break; - else { - inlinefile+=line; - inlinefile+= "\n"; - } - } while(true); - - args.clear(); - args.add(argname); - args.add(inlinefile); - } - - } - - enum linestate { - initial, - readin_single_quote - , reading_quoted, reading_unquoted, done} - - private boolean space(char c) { - // I really hope nobody is using zero bytes inside his/her config file - // to sperate parameter but here we go: - return Character.isWhitespace(c) || c == '\0'; - - } - - public class ConfigParseError extends Exception { - private static final long serialVersionUID = -60L; - - public ConfigParseError(String msg) { - super(msg); - } - } - - - // adapted openvpn's parse function to java - private Vector parseline(String line) throws ConfigParseError { - Vector parameters = new Vector(); - - if (line.length()==0) - return parameters; - - - linestate state = linestate.initial; - boolean backslash = false; - char out=0; - - int pos=0; - String currentarg=""; - - do { - // Emulate the c parsing ... - char in; - if(pos < line.length()) - in = line.charAt(pos); - else - in = '\0'; - - if (!backslash && in == '\\' && state != linestate.readin_single_quote) - { - backslash = true; - } - else - { - if (state == linestate.initial) - { - if (!space (in)) - { - if (in == ';' || in == '#') /* comment */ - break; - if (!backslash && in == '\"') - state = linestate.reading_quoted; - else if (!backslash && in == '\'') - state = linestate.readin_single_quote; - else - { - out = in; - state = linestate.reading_unquoted; - } - } - } - else if (state == linestate.reading_unquoted) - { - if (!backslash && space (in)) - state = linestate.done; - else - out = in; - } - else if (state == linestate.reading_quoted) - { - if (!backslash && in == '\"') - state = linestate.done; - else - out = in; - } - else if (state == linestate.readin_single_quote) - { - if (in == '\'') - state = linestate.done; - else - out = in; - } - - if (state == linestate.done) - { - /* ASSERT (parm_len > 0); */ - state = linestate.initial; - parameters.add(currentarg); - currentarg = ""; - out =0; - } - - if (backslash && out!=0) - { - if (!(out == '\\' || out == '\"' || space (out))) - { - throw new ConfigParseError("Options warning: Bad backslash ('\\') usage"); - } - } - backslash = false; - } - - /* store parameter character */ - if (out!=0) - { - currentarg+=out; - } - } while (pos++ < line.length()); - - return parameters; - } - - - final String[] unsupportedOptions = { "config", - "connection", - "proto-force", - "remote-random", - "tls-server" - - }; - - // Ignore all scripts - // in most cases these won't work and user who wish to execute scripts will - // figure out themselves - final String[] ignoreOptions = { "tls-client", - "askpass", - "auth-nocache", - "up", - "down", - "route-up", - "ipchange", - "route-up", - "route-pre-down", - "auth-user-pass-verify", - "dhcp-release", - "dhcp-renew", - "dh", - "management-hold", - "management", - "management-query-passwords", - "pause-exit", - "persist-key", - "register-dns", - "route-delay", - "route-gateway", - "route-metric", - "route-method", - "status", - "script-security", - "show-net-up", - "suppress-timestamps", - "tmp-dir", - "tun-ipv6", - "topology", - "win-sys", - }; - - - // This method is far too long - public VpnProfile convertProfile() throws ConfigParseError{ - boolean noauthtypeset=true; - VpnProfile np = new VpnProfile("converted Profile"); - // Pull, client, tls-client - np.clearDefaults(); - - // XXX we are always client - if(/*options.containsKey("client") || options.containsKey("pull")*/ true) { - np.mUsePull=true; - options.remove("pull"); - options.remove("client"); - } - - Vector secret = getOption("secret", 1, 2); - if(secret!=null) - { - np.mAuthenticationType=VpnProfile.TYPE_STATICKEYS; - noauthtypeset=false; - np.mUseTLSAuth=true; - np.mTLSAuthFilename=secret.get(1); - if(secret.size()==3) - np.mTLSAuthDirection=secret.get(2); - - } - - Vector> routes = getAllOption("route", 1, 4); - if(routes!=null) { - String routeopt = ""; - for(Vector route:routes){ - String netmask = "255.255.255.255"; - if(route.size() >= 3) - netmask = route.get(2); - String net = route.get(1); - try { - CIDRIP cidr = new CIDRIP(net, netmask); - routeopt+=cidr.toString() + " "; - } catch (ArrayIndexOutOfBoundsException aioob) { - throw new ConfigParseError("Could not parse netmask of route " + netmask); - } catch (NumberFormatException ne) { - throw new ConfigParseError("Could not parse netmask of route " + netmask); - } - - } - np.mCustomRoutes=routeopt; - } - - // Also recognize tls-auth [inline] direction ... - Vector> tlsauthoptions = getAllOption("tls-auth", 1, 2); - if(tlsauthoptions!=null) { - for(Vector tlsauth:tlsauthoptions) { - if(tlsauth!=null) - { - if(!tlsauth.get(1).equals("[inline]")) { - np.mTLSAuthFilename=tlsauth.get(1); - np.mUseTLSAuth=true; - } - if(tlsauth.size()==3) - np.mTLSAuthDirection=tlsauth.get(2); - } - } - } - - Vector direction = getOption("key-direction", 1, 1); - if(direction!=null) - np.mTLSAuthDirection=direction.get(1); - - - if(getAllOption("redirect-gateway", 0, 5) != null) - np.mUseDefaultRoute=true; - - Vector dev =getOption("dev",1,1); - Vector devtype =getOption("dev-type",1,1); - - if( (devtype !=null && devtype.get(1).equals("tun")) || - (dev!=null && dev.get(1).startsWith("tun")) || - (devtype ==null && dev == null) ) { - //everything okay - } else { - throw new ConfigParseError("Sorry. Only tun mode is supported. See the FAQ for more detail"); - } - - - - Vector mode =getOption("mode",1,1); - if (mode != null){ - if(!mode.get(1).equals("p2p")) - throw new ConfigParseError("Invalid mode for --mode specified, need p2p"); - } - - Vector port = getOption("port", 1,1); - if(port!=null){ - np.mServerPort = port.get(1); - } - - Vector proto = getOption("proto", 1,1); - if(proto!=null){ - np.mUseUdp=isUdpProto(proto.get(1));; - } - - // Parse remote config - Vector remote = getOption("remote",1,3); - if(remote != null){ - 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); - } - } - - // Parse remote config - Vector location = getOption("location",0,2); - if(location != null && location.size() == 2){ - np.mLocation = location.get(1).replace("__", ", "); - } - - Vector> dhcpoptions = getAllOption("dhcp-option", 2, 2); - if(dhcpoptions!=null) { - for(Vector dhcpoption:dhcpoptions) { - String type=dhcpoption.get(1); - String arg = dhcpoption.get(2); - if(type.equals("DOMAIN")) { - np.mSearchDomain=dhcpoption.get(2); - } else if(type.equals("DNS")) { - np.mOverrideDNS=true; - if(np.mDNS1.equals(VpnProfile.DEFAULT_DNS1)) - np.mDNS1=arg; - else - np.mDNS2=arg; - } - } - } - - Vector ifconfig = getOption("ifconfig", 2, 2); - if(ifconfig!=null) { - CIDRIP cidr = new CIDRIP(ifconfig.get(1), ifconfig.get(2)); - np.mIPv4Address=cidr.toString(); - } - - if(getOption("remote-random-hostname", 0, 0)!=null) - np.mUseRandomHostname=true; - - if(getOption("float", 0, 0)!=null) - np.mUseFloat=true; - - if(getOption("comp-lzo", 0, 1)!=null) - np.mUseLzo=true; - - Vector cipher = getOption("cipher", 1, 1); - if(cipher!=null) - np.mCipher= cipher.get(1); - - Vector ca = getOption("ca",1,1); - if(ca!=null){ - np.mCaFilename = ca.get(1); - } - - Vector cert = getOption("cert",1,1); - if(cert!=null){ - np.mClientCertFilename = cert.get(1); - np.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES; - noauthtypeset=false; - } - Vector key= getOption("key",1,1); - if(key!=null) - np.mClientKeyFilename=key.get(1); - - Vector pkcs12 = getOption("pkcs12",1,1); - if(pkcs12!=null) { - np.mPKCS12Filename = pkcs12.get(1); - np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; - noauthtypeset=false; - } - - Vector tlsremote = getOption("tls-remote",1,1); - if(tlsremote!=null){ - np.mRemoteCN = tlsremote.get(1); - np.mCheckRemoteCN=true; - } - - Vector verb = getOption("verb",1,1); - if(verb!=null){ - np.mVerb=verb.get(1); - } - - - if(getOption("nobind", 0, 0) != null) - np.mNobind=true; - - if(getOption("persist-tun", 0,0) != null) - np.mPersistTun=true; - - Vector connectretry = getOption("connect-retry", 1, 1); - if(connectretry!=null) - np.mConnectRetry =connectretry.get(1); - - Vector connectretrymax = getOption("connect-retry-max", 1, 1); - if(connectretrymax!=null) - np.mConnectRetryMax =connectretrymax.get(1); - - Vector> remotetls = getAllOption("remote-cert-tls", 1, 1); - if(remotetls!=null) - if(remotetls.get(0).get(1).equals("server")) - np.mExpectTLSCert=true; - else - options.put("remotetls",remotetls); - - Vector authuser = getOption("auth-user-pass",0,1); - if(authuser !=null){ - if(noauthtypeset) { - np.mAuthenticationType=VpnProfile.TYPE_USERPASS; - } else if(np.mAuthenticationType==VpnProfile.TYPE_CERTIFICATES) { - np.mAuthenticationType=VpnProfile.TYPE_USERPASS_CERTIFICATES; - } else if(np.mAuthenticationType==VpnProfile.TYPE_KEYSTORE) { - np.mAuthenticationType=VpnProfile.TYPE_USERPASS_KEYSTORE; - } - if(authuser.size()>1) { - // Set option value to password get to get canche to embed later. - np.mUsername=null; - np.mPassword=authuser.get(1); - useEmbbedUserAuth(np,authuser.get(1)); - } - - } - - - // Check the other options - - checkIgnoreAndInvalidOptions(np); - fixup(np); - - return np; - } - - 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("tcp6") || - proto.endsWith("tcp6-client")) - isudp =false; - else - throw new ConfigParseError("Unsupported option to --proto " + proto); - return isudp; - } - - static public void useEmbbedUserAuth(VpnProfile np,String inlinedata) - { - String data = inlinedata.replace(VpnProfile.INLINE_TAG, ""); - String[] parts = data.split("\n"); - if(parts.length >= 2) { - np.mUsername=parts[0]; - np.mPassword=parts[1]; - } - } - - private void checkIgnoreAndInvalidOptions(VpnProfile np) throws ConfigParseError { - for(String option:unsupportedOptions) - if(options.containsKey(option)) - throw new ConfigParseError(String.format("Unsupported Option %s encountered in config file. Aborting",option)); - - for(String option:ignoreOptions) - // removing an item which is not in the map is no error - options.remove(option); - - if(options.size()> 0) { - String custom = "# These Options were found in the config file do not map to config settings:\n"; - - for(Vector> option:options.values()) { - for(Vector optionsline: option) { - for (String arg : optionsline) - custom+= VpnProfile.openVpnEscape(arg) + " "; - } - custom+="\n"; - - } - np.mCustomConfigOptions = custom; - np.mUseCustomConfig=true; - - } - } - - - private void fixup(VpnProfile np) { - if(np.mRemoteCN.equals(np.mServerName)) { - np.mRemoteCN=""; - } - } - - private Vector getOption(String option, int minarg, int maxarg) throws ConfigParseError { - Vector> alloptions = getAllOption(option, minarg, maxarg); - if(alloptions==null) - return null; - else - return alloptions.lastElement(); - } - - - private Vector> getAllOption(String option, int minarg, int maxarg) throws ConfigParseError { - Vector> args = options.get(option); - if(args==null) - return null; - - for(Vector optionline:args) - - if(optionline.size()< (minarg+1) || optionline.size() > maxarg+1) { - String err = String.format(Locale.getDefault(),"Option %s has %d parameters, expected between %d and %d", - option,optionline.size()-1,minarg,maxarg ); - throw new ConfigParseError(err); - } - options.remove(option); - return args; - } - -} - - - - diff --git a/app/src/main/java/se/leap/openvpn/LICENSE.txt b/app/src/main/java/se/leap/openvpn/LICENSE.txt deleted file mode 100644 index d897edea..00000000 --- a/app/src/main/java/se/leap/openvpn/LICENSE.txt +++ /dev/null @@ -1,24 +0,0 @@ -License for OpenVPN for Android. Please note that the thirdparty libraries/executables may have other license (OpenVPN, lzo, OpenSSL, Google Breakpad) - -Copyright (c) 2012-2013, Arne Schwabe - All rights reserved. - -If you need a non GPLv2 license of the source please contact me. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -In addition, as a special exception, the copyright holders give -permission to link the code of portions of this program with the -OpenSSL library. diff --git a/app/src/main/java/se/leap/openvpn/LaunchVPN.java b/app/src/main/java/se/leap/openvpn/LaunchVPN.java deleted file mode 100644 index 89f2d372..00000000 --- a/app/src/main/java/se/leap/openvpn/LaunchVPN.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package se.leap.openvpn; - -import java.io.IOException; -import java.util.Collection; -import java.util.Vector; - -import se.leap.bitmaskclient.ConfigHelper; -import se.leap.bitmaskclient.EIP; -import se.leap.bitmaskclient.R; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ListActivity; -import android.content.ActivityNotFoundException; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.VpnService; -import android.os.Bundle; -import android.os.Parcelable; -import android.os.ResultReceiver; -import android.preference.PreferenceManager; -import android.text.InputType; -import android.text.method.PasswordTransformationMethod; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ListView; -import android.widget.TextView; - -/** - * This Activity actually handles two stages of a launcher shortcut's life cycle. - * - * 1. Your application offers to provide shortcuts to the launcher. When - * the user installs a shortcut, an activity within your application - * generates the actual shortcut and returns it to the launcher, where it - * is shown to the user as an icon. - * - * 2. Any time the user clicks on an installed shortcut, an intent is sent. - * Typically this would then be handled as necessary by an activity within - * your application. - * - * We handle stage 1 (creating a shortcut) by simply sending back the information (in the form - * of an {@link android.content.Intent} that the launcher will use to create the shortcut. - * - * You can also implement this in an interactive way, by having your activity actually present - * UI for the user to select the specific nature of the shortcut, such as a contact, picture, URL, - * media item, or action. - * - * We handle stage 2 (responding to a shortcut) in this sample by simply displaying the contents - * of the incoming {@link android.content.Intent}. - * - * In a real application, you would probably use the shortcut intent to display specific content - * or start a particular operation. - */ -public class LaunchVPN extends ListActivity implements OnItemClickListener { - - public static final String EXTRA_KEY = "se.leap.openvpn.shortcutProfileUUID"; - public static final String EXTRA_NAME = "se.leap.openvpn.shortcutProfileName"; - public static final String EXTRA_HIDELOG = "se.leap.openvpn.showNoLogWindow";; - - public static final int START_VPN_PROFILE= 70; - - // Dashboard, maybe more, want to know! - private ResultReceiver mReceiver; - - private ProfileManager mPM; - private VpnProfile mSelectedProfile; - private boolean mhideLog=false; - - private boolean mCmfixed=false; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - mPM =ProfileManager.getInstance(this); - - } - - @Override - protected void onStart() { - super.onStart(); - // Resolve the intent - - final Intent intent = getIntent(); - final String action = intent.getAction(); - - // If something wants feedback, they sent us a Receiver - mReceiver = intent.getParcelableExtra(EIP.RECEIVER_TAG); - - // If the intent is a request to create a shortcut, we'll do that and exit - - - if(Intent.ACTION_MAIN.equals(action)) { - // we got called to be the starting point, most likely a shortcut - String shortcutUUID = intent.getStringExtra( EXTRA_KEY); - String shortcutName = intent.getStringExtra( EXTRA_NAME); - mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false); - - VpnProfile profileToConnect = ProfileManager.get(shortcutUUID); - if(shortcutName != null && profileToConnect ==null) - profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName); - - if(profileToConnect ==null) { - OpenVPN.logError(R.string.shortcut_profile_notfound); - // show Log window to display error - showLogWindow(); - finish(); - return; - } - - mSelectedProfile = profileToConnect; - launchVPN(); - - } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) { - createListView(); - } - } - - private void createListView() { - ListView lv = getListView(); - //lv.setTextFilterEnabled(true); - - Collection vpnlist = mPM.getProfiles(); - - Vector vpnnames=new Vector(); - for (VpnProfile vpnProfile : vpnlist) { - vpnnames.add(vpnProfile.mName); - } - - - - ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,vpnnames); - lv.setAdapter(adapter); - - lv.setOnItemClickListener(this); - } - - /** - * This function creates a shortcut and returns it to the caller. There are actually two - * intents that you will send back. - * - * The first intent serves as a container for the shortcut and is returned to the launcher by - * setResult(). This intent must contain three fields: - * - *
    - *
  • {@link android.content.Intent#EXTRA_SHORTCUT_INTENT} The shortcut intent.
  • - *
  • {@link android.content.Intent#EXTRA_SHORTCUT_NAME} The text that will be displayed with - * the shortcut.
  • - *
  • {@link android.content.Intent#EXTRA_SHORTCUT_ICON} The shortcut's icon, if provided as a - * bitmap, or {@link android.content.Intent#EXTRA_SHORTCUT_ICON_RESOURCE} if provided as - * a drawable resource.
  • - *
- * - * If you use a simple drawable resource, note that you must wrapper it using - * {@link android.content.Intent.ShortcutIconResource}, as shown below. This is required so - * that the launcher can access resources that are stored in your application's .apk file. If - * you return a bitmap, such as a thumbnail, you can simply put the bitmap into the extras - * bundle using {@link android.content.Intent#EXTRA_SHORTCUT_ICON}. - * - * The shortcut intent can be any intent that you wish the launcher to send, when the user - * clicks on the shortcut. Typically this will be {@link android.content.Intent#ACTION_VIEW} - * with an appropriate Uri for your content, but any Intent will work here as long as it - * triggers the desired action within your Activity. - * @param profile - */ - private void setupShortcut(VpnProfile profile) { - // First, set up the shortcut intent. For this example, we simply create an intent that - // will bring us directly back to this activity. A more typical implementation would use a - // data Uri in order to display a more specific result, or a custom action in order to - // launch a specific operation. - - Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); - shortcutIntent.setClass(this, LaunchVPN.class); - shortcutIntent.putExtra(EXTRA_KEY,profile.getUUID().toString()); - - // Then, set up the container intent (the response to the caller) - - Intent intent = new Intent(); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, profile.getName()); - Parcelable iconResource = Intent.ShortcutIconResource.fromContext( - this, R.drawable.icon); - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); - - // Now, return the result to the launcher - - setResult(RESULT_OK, intent); - } - - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - String profilename = ((TextView) view).getText().toString(); - - VpnProfile profile = mPM.getProfileByName(profilename); - - // if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) { - setupShortcut(profile); - finish(); - return; - // } - - } - - - - private void askForPW(final int type) { - - final EditText entry = new EditText(this); - entry.setSingleLine(); - entry.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); - entry.setTransformationMethod(new PasswordTransformationMethod()); - - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle("Need " + getString(type)); - dialog.setMessage("Enter the password for profile " + mSelectedProfile.mName); - dialog.setView(entry); - - dialog.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String pw = entry.getText().toString(); - if(type == R.string.password) { - mSelectedProfile.mTransientPW = pw; - } else { - mSelectedProfile.mTransientPCKS12PW = pw; - } - onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null); - - } - - }); - dialog.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }); - - dialog.create().show(); - - } - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if(requestCode==START_VPN_PROFILE) { - if(resultCode == Activity.RESULT_OK) { - int needpw = mSelectedProfile.needUserPWInput(); - if(needpw !=0) { - askForPW(needpw); - } else { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean showlogwindow = prefs.getBoolean("showlogwindow", false); - - if(!mhideLog && showlogwindow) - showLogWindow(); - new startOpenVpnThread().start(); - } - } else if (resultCode == Activity.RESULT_CANCELED) { - // User does not want us to start, so we just vanish (well, now we tell our receiver, then vanish) - Bundle resultData = new Bundle(); - // For now, nothing else is calling, so this "request" string is good enough - resultData.putString(EIP.REQUEST_TAG, EIP.ACTION_START_EIP); - mReceiver.send(RESULT_CANCELED, resultData); - finish(); - } - } - } - void showLogWindow() { - - Intent startLW = new Intent(getBaseContext(),LogWindow.class); - startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivity(startLW); - - } - - void showConfigErrorDialog(int vpnok) { - AlertDialog.Builder d = new AlertDialog.Builder(this); - d.setTitle(R.string.config_error_found); - d.setMessage(vpnok); - d.setPositiveButton(android.R.string.ok, new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - - } - }); - d.show(); - } - - void launchVPN () { - int vpnok = mSelectedProfile.checkProfile(this); - if(vpnok!= R.string.no_error_found) { - showConfigErrorDialog(vpnok); - return; - } - - Intent intent = VpnService.prepare(this); - // Check if we want to fix /dev/tun - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean usecm9fix = prefs.getBoolean("useCM9Fix", false); - boolean loadTunModule = prefs.getBoolean("loadTunModule", false); - - if(loadTunModule) - execeuteSUcmd("insmod /system/lib/modules/tun.ko"); - - if(usecm9fix && !mCmfixed ) { - execeuteSUcmd("chown system /dev/tun"); - } - - - if (intent != null) { - // Start the query - try { - startActivityForResult(intent, START_VPN_PROFILE); - } catch (ActivityNotFoundException ane) { - // Shame on you Sony! At least one user reported that - // an official Sony Xperia Arc S image triggers this exception - OpenVPN.logError(R.string.no_vpn_support_image); - showLogWindow(); - } - } else { - onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null); - } - - } - - private void execeuteSUcmd(String command) { - ProcessBuilder pb = new ProcessBuilder(new String[] {"su","-c",command}); - try { - Process p = pb.start(); - int ret = p.waitFor(); - if(ret ==0) - mCmfixed=true; - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private class startOpenVpnThread extends Thread { - - @Override - public void run() { - VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext()); - // Tell whom-it-may-concern that we started VPN - Bundle resultData = new Bundle(); - // For now, nothing else is calling, so this "request" string is good enough - resultData.putString(EIP.REQUEST_TAG, EIP.ACTION_START_EIP); - mReceiver.send(RESULT_OK, resultData); - finish(); - - } - - } - - -} diff --git a/app/src/main/java/se/leap/openvpn/LogWindow.java b/app/src/main/java/se/leap/openvpn/LogWindow.java deleted file mode 100644 index b87c4999..00000000 --- a/app/src/main/java/se/leap/openvpn/LogWindow.java +++ /dev/null @@ -1,340 +0,0 @@ -package se.leap.openvpn; - -import java.util.Vector; - -import se.leap.bitmaskclient.R; - -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.ListActivity; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.database.DataSetObserver; -import android.os.Bundle; -import android.os.Handler; -import android.os.Handler.Callback; -import android.os.Message; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; -import se.leap.openvpn.OpenVPN.LogItem; -import se.leap.openvpn.OpenVPN.LogListener; -import se.leap.openvpn.OpenVPN.StateListener; - -public class LogWindow extends ListActivity implements StateListener { - private static final int START_VPN_CONFIG = 0; - private String[] mBconfig=null; - - - class LogWindowListAdapter implements ListAdapter, LogListener, Callback { - - private static final int MESSAGE_NEWLOG = 0; - - private static final int MESSAGE_CLEARLOG = 1; - - private Vector myEntries=new Vector(); - - private Handler mHandler; - - private Vector observers=new Vector(); - - - public LogWindowListAdapter() { - initLogBuffer(); - - if (mHandler == null) { - mHandler = new Handler(this); - } - - OpenVPN.addLogListener(this); - } - - - - private void initLogBuffer() { - myEntries.clear(); - for (LogItem litem : OpenVPN.getlogbuffer()) { - myEntries.add(litem.getString(getContext())); - } - } - - String getLogStr() { - String str = ""; - for(String entry:myEntries) { - str+=entry + '\n'; - } - return str; - } - - - private void shareLog() { - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.putExtra(Intent.EXTRA_TEXT, getLogStr()); - shareIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.bitmask_openvpn_log_file)); - shareIntent.setType("text/plain"); - startActivity(Intent.createChooser(shareIntent, "Send Logfile")); - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - observers.add(observer); - - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - observers.remove(observer); - } - - @Override - public int getCount() { - return myEntries.size(); - } - - @Override - public Object getItem(int position) { - return myEntries.get(position); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - TextView v; - if(convertView==null) - v = new TextView(getBaseContext()); - else - v = (TextView) convertView; - v.setText(myEntries.get(position)); - return v; - } - - @Override - public int getItemViewType(int position) { - return 0; - } - - @Override - public int getViewTypeCount() { - return 1; - } - - @Override - public boolean isEmpty() { - return myEntries.isEmpty(); - - } - - @Override - public boolean areAllItemsEnabled() { - return true; - } - - @Override - public boolean isEnabled(int position) { - return true; - } - - @Override - public void newLog(LogItem logmessage) { - Message msg = Message.obtain(); - msg.what=MESSAGE_NEWLOG; - Bundle mbundle=new Bundle(); - mbundle.putString("logmessage", logmessage.getString(getBaseContext())); - msg.setData(mbundle); - mHandler.sendMessage(msg); - } - - @Override - public boolean handleMessage(Message msg) { - // We have been called - if(msg.what==MESSAGE_NEWLOG) { - - String logmessage = msg.getData().getString("logmessage"); - myEntries.add(logmessage); - - for (DataSetObserver observer : observers) { - observer.onChanged(); - } - } else if (msg.what == MESSAGE_CLEARLOG) { - initLogBuffer(); - for (DataSetObserver observer : observers) { - observer.onInvalidated(); - } - } - - return true; - } - - void clearLog() { - // Actually is probably called from GUI Thread as result of the user - // pressing a button. But better safe than sorry - OpenVPN.clearLog(); - OpenVPN.logMessage(0,"","Log cleared."); - mHandler.sendEmptyMessage(MESSAGE_CLEARLOG); - } - } - - - - private LogWindowListAdapter ladapter; - private TextView mSpeedView; - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId()==R.id.clearlog) { - ladapter.clearLog(); - return true; - } else if(item.getItemId()==R.id.cancel){ - Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.title_cancel); - builder.setMessage(R.string.cancel_connection_query); - builder.setNegativeButton(android.R.string.no, null); - builder.setPositiveButton(android.R.string.yes, new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - ProfileManager.setConntectedVpnProfileDisconnected(getApplicationContext()); - OpenVpnManagementThread.stopOpenVPN(); - } - }); - - builder.show(); - return true; - } else if(item.getItemId()==R.id.info) { - if(mBconfig==null) - OpenVPN.triggerLogBuilderConfig(); - - } else if(item.getItemId()==R.id.send) { - ladapter.shareLog(); - } - - return super.onOptionsItemSelected(item); - - } - - protected Context getContext() { - return this; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.logmenu, menu); - return true; - } - - - @Override - protected void onResume() { - super.onResume(); - OpenVPN.addStateListener(this); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == START_VPN_CONFIG && resultCode==RESULT_OK) { - String configuredVPN = data.getStringExtra(VpnProfile.EXTRA_PROFILEUUID); - - final VpnProfile profile = ProfileManager.get(configuredVPN); - ProfileManager.getInstance(this).saveProfile(this, profile); - // Name could be modified, reset List adapter - - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle(R.string.configuration_changed); - dialog.setMessage(R.string.restart_vpn_after_change); - - - dialog.setPositiveButton(R.string.restart, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Intent intent = new Intent(getBaseContext(), LaunchVPN.class); - intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUIDString()); - intent.setAction(Intent.ACTION_MAIN); - startActivity(intent); - } - - - }); - dialog.setNegativeButton(R.string.ignore, null); - dialog.create().show(); - } - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onStop() { - super.onStop(); - OpenVPN.removeStateListener(this); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.logwindow); - ListView lv = getListView(); - - lv.setOnItemLongClickListener(new OnItemLongClickListener() { - - @Override - public boolean onItemLongClick(AdapterView parent, View view, - int position, long id) { - ClipboardManager clipboard = (ClipboardManager) - getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("Log Entry",((TextView) view).getText()); - clipboard.setPrimaryClip(clip); - Toast.makeText(getBaseContext(), R.string.copied_entry, Toast.LENGTH_SHORT).show(); - return true; - } - }); - - ladapter = new LogWindowListAdapter(); - lv.setAdapter(ladapter); - - mSpeedView = (TextView) findViewById(R.id.speed); - } - - @Override - public void updateState(final String status,final String logmessage, final int resid) { - runOnUiThread(new Runnable() { - - @Override - public void run() { - String prefix=getString(resid) + ":"; - if (status.equals("BYTECOUNT") || status.equals("NOPROCESS") ) - prefix=""; - mSpeedView.setText(prefix + logmessage); - } - }); - - } - - @Override - protected void onDestroy() { - super.onDestroy(); - OpenVPN.removeLogListener(ladapter); - } - -} diff --git a/app/src/main/java/se/leap/openvpn/NetworkSateReceiver.java b/app/src/main/java/se/leap/openvpn/NetworkSateReceiver.java deleted file mode 100644 index 777402b4..00000000 --- a/app/src/main/java/se/leap/openvpn/NetworkSateReceiver.java +++ /dev/null @@ -1,86 +0,0 @@ -package se.leap.openvpn; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.NetworkInfo.State; -import android.preference.PreferenceManager; -import se.leap.bitmaskclient.R; - -public class NetworkSateReceiver extends BroadcastReceiver { - private int lastNetwork=-1; - private OpenVpnManagementThread mManangement; - - private String lastStateMsg=null; - - public NetworkSateReceiver(OpenVpnManagementThread managementThread) { - super(); - mManangement = managementThread; - } - - @Override - public void onReceive(Context context, Intent intent) { - NetworkInfo networkInfo = getCurrentNetworkInfo(context); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean sendusr1 = prefs.getBoolean("netchangereconnect", true); - - String netstatestring; - if(networkInfo==null) - netstatestring = "not connected"; - else { - String subtype = networkInfo.getSubtypeName(); - if(subtype==null) - subtype = ""; - String extrainfo = networkInfo.getExtraInfo(); - if(extrainfo==null) - extrainfo=""; - - /* - if(networkInfo.getType()==android.net.ConnectivityManager.TYPE_WIFI) { - WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - WifiInfo wifiinfo = wifiMgr.getConnectionInfo(); - extrainfo+=wifiinfo.getBSSID(); - - subtype += wifiinfo.getNetworkId(); - }*/ - - - - netstatestring = String.format("%2$s %4$s to %1$s %3$s",networkInfo.getTypeName(), - networkInfo.getDetailedState(),extrainfo,subtype ); - } - - - - if(networkInfo!=null && networkInfo.getState() == State.CONNECTED) { - int newnet = networkInfo.getType(); - - if(sendusr1 && lastNetwork!=newnet) - mManangement.reconnect(); - - lastNetwork = newnet; - } else if (networkInfo==null) { - // Not connected, stop openvpn, set last connected network to no network - lastNetwork=-1; - if(sendusr1) - mManangement.signalusr1(); - } - - if(!netstatestring.equals(lastStateMsg)) - OpenVPN.logInfo(R.string.netstatus, netstatestring); - lastStateMsg=netstatestring; - - } - - private NetworkInfo getCurrentNetworkInfo(Context context) { - ConnectivityManager conn = (ConnectivityManager) - context.getSystemService(Context.CONNECTIVITY_SERVICE); - - NetworkInfo networkInfo = conn.getActiveNetworkInfo(); - return networkInfo; - } - -} diff --git a/app/src/main/java/se/leap/openvpn/OpenVPN.java b/app/src/main/java/se/leap/openvpn/OpenVPN.java deleted file mode 100644 index 8acdc423..00000000 --- a/app/src/main/java/se/leap/openvpn/OpenVPN.java +++ /dev/null @@ -1,250 +0,0 @@ -package se.leap.openvpn; - -import java.util.LinkedList; -import java.util.Locale; -import java.util.Vector; - -import se.leap.bitmaskclient.R; - - -import android.content.Context; -import android.os.Build; -import android.util.Log; - -public class OpenVPN { - - - public static LinkedList logbuffer; - - private static Vector logListener; - private static Vector stateListener; - private static String[] mBconfig; - - private static String mLaststatemsg; - - private static String mLaststate; - - private static int mLastStateresid=R.string.state_noprocess; - public static String TAG="se.leap.openvpn.OpenVPN"; - - static { - logbuffer = new LinkedList(); - logListener = new Vector(); - stateListener = new Vector(); - logInformation(); - } - - public static class LogItem { - public static final int ERROR = 1; - public static final int INFO = 2; - public static final int VERBOSE = 3; - - private Object [] mArgs = null; - private String mMessage = null; - private int mRessourceId; - // Default log priority - int mLevel = INFO; - - public LogItem(int ressourceId, Object[] args) { - mRessourceId = ressourceId; - mArgs = args; - } - - - public LogItem(int loglevel,int ressourceId, Object[] args) { - mRessourceId = ressourceId; - mArgs = args; - mLevel = loglevel; - } - - - public LogItem(String message) { - - mMessage = message; - } - - public LogItem(int loglevel, String msg) { - mLevel = loglevel; - mMessage = msg; - } - - - public LogItem(int loglevel, int ressourceId) { - mRessourceId =ressourceId; - mLevel = loglevel; - } - - - public String getString(Context c) { - if(mMessage !=null) { - return mMessage; - } else { - if(c!=null) { - if(mArgs == null) - return c.getString(mRessourceId); - else - return c.getString(mRessourceId,mArgs); - } else { - String str = String.format(Locale.ENGLISH,"Log (no context) resid %d", mRessourceId); - if(mArgs !=null) - for(Object o:mArgs) - str += "|" + o.toString(); - return str; - } - } - } - } - - private static final int MAXLOGENTRIES = 500; - - - public static final String MANAGMENT_PREFIX = "M:"; - - - - - - - public interface LogListener { - void newLog(LogItem logItem); - } - - public interface StateListener { - void updateState(String state, String logmessage, int localizedResId); - } - - synchronized static void logMessage(int level,String prefix, String message) - { - newlogItem(new LogItem(prefix + message)); - Log.d("OpenVPN log item", message); - } - - synchronized static void clearLog() { - logbuffer.clear(); - logInformation(); - } - - private static void logInformation() { - - logInfo(R.string.mobile_info,Build.MODEL, Build.BOARD,Build.BRAND,Build.VERSION.SDK_INT); - } - - public synchronized static void addLogListener(LogListener ll){ - logListener.add(ll); - } - - public synchronized static void removeLogListener(LogListener ll) { - logListener.remove(ll); - } - - - public synchronized static void addStateListener(StateListener sl){ - stateListener.add(sl); - if(mLaststate!=null) - sl.updateState(mLaststate, mLaststatemsg, mLastStateresid); - } - - private static int getLocalizedState(String state){ - if (state.equals("CONNECTING")) - return R.string.state_connecting; - else if (state.equals("WAIT")) - return R.string.state_wait; - else if (state.equals("AUTH")) - return R.string.state_auth; - else if (state.equals("GET_CONFIG")) - return R.string.state_get_config; - else if (state.equals("ASSIGN_IP")) - return R.string.state_assign_ip; - else if (state.equals("ADD_ROUTES")) - return R.string.state_add_routes; - else if (state.equals("CONNECTED")) - return R.string.state_connected; - else if (state.equals("RECONNECTING")) - return R.string.state_reconnecting; - else if (state.equals("EXITING")) - return R.string.state_exiting; - else if (state.equals("RESOLVE")) - return R.string.state_resolve; - else if (state.equals("TCP_CONNECT")) - return R.string.state_tcp_connect; - else if (state.equals("FATAL")) - return R.string.eip_state_not_connected; - else - return R.string.unknown_state; - - } - - public synchronized static void removeStateListener(StateListener sl) { - stateListener.remove(sl); - } - - - synchronized public static LogItem[] getlogbuffer() { - - // The stoned way of java to return an array from a vector - // brought to you by eclipse auto complete - return (LogItem[]) logbuffer.toArray(new LogItem[logbuffer.size()]); - - } - public static void logBuilderConfig(String[] bconfig) { - mBconfig = bconfig; - } - public static void triggerLogBuilderConfig() { - if(mBconfig==null) { - logMessage(0, "", "No active interface"); - } else { - for (String item : mBconfig) { - logMessage(0, "", item); - } - } - - } - - public static void updateStateString (String state, String msg) { - int rid = getLocalizedState(state); - updateStateString(state, msg,rid); - } - - public synchronized static void updateStateString(String state, String msg, int resid) { - if (! "BYTECOUNT".equals(state)) { - mLaststate= state; - mLaststatemsg = msg; - mLastStateresid = resid; - - for (StateListener sl : stateListener) { - sl.updateState(state,msg,resid); - } - } - } - - public static void logInfo(String message) { - newlogItem(new LogItem(LogItem.INFO, message)); - } - - public static void logInfo(int ressourceId, Object... args) { - newlogItem(new LogItem(LogItem.INFO, ressourceId, args)); - } - - private static void newlogItem(LogItem logItem) { - logbuffer.addLast(logItem); - if(logbuffer.size()>MAXLOGENTRIES) - logbuffer.removeFirst(); - - for (LogListener ll : logListener) { - ll.newLog(logItem); - } - } - - public static void logError(String msg) { - newlogItem(new LogItem(LogItem.ERROR, msg)); - - } - - public static void logError(int ressourceId) { - newlogItem(new LogItem(LogItem.ERROR, ressourceId)); - } - public static void logError(int ressourceId, Object... args) { - newlogItem(new LogItem(LogItem.ERROR, ressourceId,args)); - } - -} diff --git a/app/src/main/java/se/leap/openvpn/OpenVPNThread.java b/app/src/main/java/se/leap/openvpn/OpenVPNThread.java deleted file mode 100644 index ffd21732..00000000 --- a/app/src/main/java/se/leap/openvpn/OpenVPNThread.java +++ /dev/null @@ -1,130 +0,0 @@ -package se.leap.openvpn; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.LinkedList; - -import se.leap.bitmaskclient.R; - -import android.util.Log; -import se.leap.openvpn.OpenVPN.LogItem; - -public class OpenVPNThread implements Runnable { - private static final String DUMP_PATH_STRING = "Dump path: "; - private static final String TAG = "OpenVPN"; - private String[] mArgv; - private Process mProcess; - private String mNativeDir; - private OpenVpnService mService; - private String mDumpPath; - - public OpenVPNThread(OpenVpnService service,String[] argv, String nativelibdir) - { - mArgv = argv; - mNativeDir = nativelibdir; - mService = service; - } - - public void stopProcess() { - mProcess.destroy(); - } - - - - @Override - public void run() { - try { - Log.i(TAG, "Starting openvpn"); - startOpenVPNThreadArgs(mArgv); - Log.i(TAG, "Giving up"); - } catch (Exception e) { - e.printStackTrace(); - Log.e(TAG, "OpenVPNThread Got " + e.toString()); - } finally { - int exitvalue = 0; - try { - exitvalue = mProcess.waitFor(); - } catch ( IllegalThreadStateException ite) { - OpenVPN.logError("Illegal Thread state: " + ite.getLocalizedMessage()); - } catch (InterruptedException ie) { - OpenVPN.logError("InterruptedException: " + ie.getLocalizedMessage()); - } - if( exitvalue != 0) - OpenVPN.logError("Process exited with exit value " + exitvalue); - -// OpenVPN.updateStateString("NOPROCESS","No process running.", R.string.state_noprocess); fixes bug #4565 - if(mDumpPath!=null) { - try { - BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log")); - for(LogItem li :OpenVPN.getlogbuffer()){ - logout.write(li.getString(null) + "\n"); - } - logout.close(); - OpenVPN.logError(R.string.minidump_generated); - } catch (IOException e) { - OpenVPN.logError("Writing minidump log: " +e.getLocalizedMessage()); - } - } - - mService.processDied(); - Log.i(TAG, "Exiting"); - } - } - - private void startOpenVPNThreadArgs(String[] argv) { - LinkedList argvlist = new LinkedList(); - - for(String arg:argv) - argvlist.add(arg); - - ProcessBuilder pb = new ProcessBuilder(argvlist); - // Hack O rama - - // Hack until I find a good way to get the real library path - String applibpath = argv[0].replace("/cache/" + VpnProfile.MINIVPN , "/lib"); - - String lbpath = pb.environment().get("LD_LIBRARY_PATH"); - if(lbpath==null) - lbpath = applibpath; - else - lbpath = lbpath + ":" + applibpath; - - if (!applibpath.equals(mNativeDir)) { - lbpath = lbpath + ":" + mNativeDir; - } - - pb.environment().put("LD_LIBRARY_PATH", lbpath); - pb.redirectErrorStream(true); - try { - mProcess = pb.start(); - // Close the output, since we don't need it - mProcess.getOutputStream().close(); - InputStream in = mProcess.getInputStream(); - BufferedReader br = new BufferedReader(new InputStreamReader(in)); - - while(true) { - String logline = br.readLine(); - if(logline==null) - return; - - if (logline.startsWith(DUMP_PATH_STRING)) - mDumpPath = logline.substring(DUMP_PATH_STRING.length()); - - - OpenVPN.logMessage(0, "P:", logline); - } - - - } catch (IOException e) { - OpenVPN.logMessage(0, "", "Error reading from output of OpenVPN process"+ e.getLocalizedMessage()); - e.printStackTrace(); - stopProcess(); - } - - - } -} diff --git a/app/src/main/java/se/leap/openvpn/OpenVpnManagementThread.java b/app/src/main/java/se/leap/openvpn/OpenVpnManagementThread.java deleted file mode 100644 index 27a3db65..00000000 --- a/app/src/main/java/se/leap/openvpn/OpenVpnManagementThread.java +++ /dev/null @@ -1,592 +0,0 @@ -package se.leap.openvpn; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.util.LinkedList; -import java.util.Vector; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; - -import se.leap.bitmaskclient.R; -import android.content.SharedPreferences; -import android.net.LocalServerSocket; -import android.net.LocalSocket; -import android.os.Build; -import android.os.ParcelFileDescriptor; -import android.preference.PreferenceManager; -import android.util.Base64; -import android.util.Log; - -public class OpenVpnManagementThread implements Runnable { - - private static final String TAG = "openvpn"; - private LocalSocket mSocket; - private VpnProfile mProfile; - private OpenVpnService mOpenVPNService; - private LinkedList mFDList=new LinkedList(); - private int mBytecountinterval=2; - private long mLastIn=0; - private long mLastOut=0; - private LocalServerSocket mServerSocket; - private boolean mReleaseHold=true; - private boolean mWaitingForRelease=false; - private long mLastHoldRelease=0; - - private static Vector active=new Vector(); - - static private native void jniclose(int fdint); - static private native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException; - - public OpenVpnManagementThread(VpnProfile profile, LocalServerSocket mgmtsocket, OpenVpnService openVpnService) { - mProfile = profile; - mServerSocket = mgmtsocket; - mOpenVPNService = openVpnService; - - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(openVpnService); - boolean managemeNetworkState = prefs.getBoolean("netchangereconnect", true); - if(managemeNetworkState) - mReleaseHold=false; - - } - - static { - System.loadLibrary("opvpnutil"); - } - - public void managmentCommand(String cmd) { - if(mSocket!=null) { - try { - mSocket.getOutputStream().write(cmd.getBytes()); - mSocket.getOutputStream().flush(); - } catch (IOException e) { - // Ignore socket stack traces - } - } - } - - - @Override - public void run() { - Log.i(TAG, "Managment Socket Thread started"); - byte [] buffer =new byte[2048]; - // mSocket.setSoTimeout(5); // Setting a timeout cannot be that bad - - String pendingInput=""; - active.add(this); - - try { - // Wait for a client to connect - mSocket= mServerSocket.accept(); - InputStream instream = mSocket.getInputStream(); - - while(true) { - int numbytesread = instream.read(buffer); - if(numbytesread==-1) - return; - - FileDescriptor[] fds = null; - try { - fds = mSocket.getAncillaryFileDescriptors(); - } catch (IOException e) { - OpenVPN.logMessage(0, "", "Error reading fds from socket" + e.getLocalizedMessage()); - e.printStackTrace(); - } - if(fds!=null){ - - for (FileDescriptor fd : fds) { - - mFDList.add(fd); - } - } - - String input = new String(buffer,0,numbytesread,"UTF-8"); - - pendingInput += input; - - pendingInput=processInput(pendingInput); - - - - } - } catch (IOException e) { - e.printStackTrace(); - } - active.remove(this); - } - - //! Hack O Rama 2000! - private void protectFileDescriptor(FileDescriptor fd) { - Exception exp=null; - try { - Method getInt = FileDescriptor.class.getDeclaredMethod("getInt$"); - int fdint = (Integer) getInt.invoke(fd); - - // You can even get more evil by parsing toString() and extract the int from that :) - - mOpenVPNService.protect(fdint); - - //ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(fdint); - //pfd.close(); - jniclose(fdint); - return; - } catch (NoSuchMethodException e) { - exp =e; - } catch (IllegalArgumentException e) { - exp =e; - } catch (IllegalAccessException e) { - exp =e; - } catch (InvocationTargetException e) { - exp =e; - } catch (NullPointerException e) { - exp =e; - } - if(exp!=null) { - exp.printStackTrace(); - Log.d("Openvpn", "Failed to retrieve fd from socket: " + fd); - OpenVPN.logMessage(0, "", "Failed to retrieve fd from socket: " + exp.getLocalizedMessage()); - } - } - - private String processInput(String pendingInput) { - - - while(pendingInput.contains("\n")) { - String[] tokens = pendingInput.split("\\r?\\n", 2); - processCommand(tokens[0]); - if(tokens.length == 1) - // No second part, newline was at the end - pendingInput=""; - else - pendingInput=tokens[1]; - } - return pendingInput; - } - - - private void processCommand(String command) { - Log.d(TAG, "processCommand: " + command); - - if (command.startsWith(">") && command.contains(":")) { - String[] parts = command.split(":",2); - String cmd = parts[0].substring(1); - String argument = parts[1]; - if(cmd.equals("INFO")) { - // Ignore greeting from mgmt - //logStatusMessage(command); - }else if (cmd.equals("PASSWORD")) { - processPWCommand(argument); - } else if (cmd.equals("HOLD")) { - handleHold(); - } else if (cmd.equals("NEED-OK")) { - processNeedCommand(argument); - } else if (cmd.equals("BYTECOUNT")){ - processByteCount(argument); - } else if (cmd.equals("STATE")) { - processState(argument); - } else if (cmd.equals("FATAL")){ - processState(","+cmd+","); //handles FATAL as state - } else if (cmd.equals("PROXY")) { - processProxyCMD(argument); - } else if (cmd.equals("LOG")) { - String[] args = argument.split(",",3); - // 0 unix time stamp - // 1 log level N,I,E etc. - // 2 log message - OpenVPN.logMessage(0, "", args[2]); - } else if (cmd.equals("RSA_SIGN")) { - processSignCommand(argument); - } else { - OpenVPN.logMessage(0, "MGMT:", "Got unrecognized command" + command); - Log.i(TAG, "Got unrecognized command" + command); - } - } else if (command.startsWith("SUCCESS:")) { //Fixes bug LEAP #4565 - if (command.equals("SUCCESS: signal SIGINT thrown")){ - Log.d(TAG, "SUCCESS: signal SIGINT thrown"); - processState(",EXITING,SIGINT,,"); - } - } else { - Log.i(TAG, "Got unrecognized line from managment" + command); - OpenVPN.logMessage(0, "MGMT:", "Got unrecognized line from management:" + command); - } - } - private void handleHold() { - if(mReleaseHold) { - releaseHoldCmd(); - } else { - mWaitingForRelease=true; - OpenVPN.updateStateString("NONETWORK", "",R.string.state_nonetwork); - } - } - private void releaseHoldCmd() { - if ((System.currentTimeMillis()- mLastHoldRelease) < 5000) { - try { - Thread.sleep(3000); - } catch (InterruptedException e) {} - - } - mWaitingForRelease=false; - mLastHoldRelease = System.currentTimeMillis(); - managmentCommand("hold release\n"); - managmentCommand("bytecount " + mBytecountinterval + "\n"); - managmentCommand("state on\n"); - } - - public void releaseHold() { - mReleaseHold=true; - if(mWaitingForRelease) - releaseHoldCmd(); - - } - - private void processProxyCMD(String argument) { - String[] args = argument.split(",",3); - SocketAddress proxyaddr = ProxyDetection.detectProxy(mProfile); - - - if(args.length >= 2) { - String proto = args[1]; - if(proto.equals("UDP")) { - proxyaddr=null; - } - } - - if(proxyaddr instanceof InetSocketAddress ){ - InetSocketAddress isa = (InetSocketAddress) proxyaddr; - - OpenVPN.logInfo(R.string.using_proxy, isa.getHostName(),isa.getPort()); - - String proxycmd = String.format("proxy HTTP %s %d\n", isa.getHostName(),isa.getPort()); - managmentCommand(proxycmd); - } else { - managmentCommand("proxy NONE\n"); - } - - } - private void processState(String argument) { - String[] args = argument.split(",",3); - String currentstate = args[1]; - if(args[2].equals(",,")){ - OpenVPN.updateStateString(currentstate,""); - } - else if (args[2].endsWith(",,")){ //fixes LEAP Bug #4546 - args[2] = (String) args[2].subSequence(0, args[2].length()-2); - Log.d(TAG, "processState() STATE: "+ currentstate + " msg: " + args[2]); - OpenVPN.updateStateString(currentstate,args[2]); - } - else{ - OpenVPN.updateStateString(currentstate,args[2]); - } - } - - private static int repeated_byte_counts = 0; - private void processByteCount(String argument) { - // >BYTECOUNT:{BYTES_IN},{BYTES_OUT} - int comma = argument.indexOf(','); - long in = Long.parseLong(argument.substring(0, comma)); - long out = Long.parseLong(argument.substring(comma+1)); - - long diffin = in - mLastIn; - long diffout = out - mLastOut; - if(diffin == 0 && diffout == 0) - repeated_byte_counts++; - if(repeated_byte_counts > 3) - Log.d("OpenVPN log", "Repeated byte count = " + repeated_byte_counts); - mLastIn=in; - mLastOut=out; - - String netstat = String.format("In: %8s, %8s/s Out %8s, %8s/s", - humanReadableByteCount(in, false), - humanReadableByteCount(diffin, false), - humanReadableByteCount(out, false), - humanReadableByteCount(diffout, false)); - OpenVPN.updateStateString("BYTECOUNT",netstat); - - - } - - // From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java - public static String humanReadableByteCount(long bytes, boolean si) { - int unit = si ? 1000 : 1024; - if (bytes < unit) return bytes + " B"; - int exp = (int) (Math.log(bytes) / Math.log(unit)); - String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); - return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); - } - - private void processNeedCommand(String argument) { - int p1 =argument.indexOf('\''); - int p2 = argument.indexOf('\'',p1+1); - - String needed = argument.substring(p1+1, p2); - String extra = argument.split(":",2)[1]; - - String status = "ok"; - - - if (needed.equals("PROTECTFD")) { - FileDescriptor fdtoprotect = mFDList.pollFirst(); - protectFileDescriptor(fdtoprotect); - } else if (needed.equals("DNSSERVER")) { - mOpenVPNService.addDNS(extra); - }else if (needed.equals("DNSDOMAIN")){ - mOpenVPNService.setDomain(extra); - } else if (needed.equals("ROUTE")) { - String[] routeparts = extra.split(" "); - mOpenVPNService.addRoute(routeparts[0], routeparts[1]); - } else if (needed.equals("ROUTE6")) { - mOpenVPNService.addRoutev6(extra); - } else if (needed.equals("IFCONFIG")) { - String[] ifconfigparts = extra.split(" "); - int mtu = Integer.parseInt(ifconfigparts[2]); - mOpenVPNService.setLocalIP(ifconfigparts[0], ifconfigparts[1],mtu,ifconfigparts[3]); - } else if (needed.equals("IFCONFIG6")) { - mOpenVPNService.setLocalIPv6(extra); - - } else if (needed.equals("OPENTUN")) { - if(sendTunFD(needed,extra)) - return; - else - status="cancel"; - // This not nice or anything but setFileDescriptors accepts only FilDescriptor class :( - - } else { - Log.e(TAG,"Unkown needok command " + argument); - return; - } - - String cmd = String.format("needok '%s' %s\n", needed, status); - managmentCommand(cmd); - } - - private boolean sendTunFD (String needed, String extra) { - Exception exp = null; - if(!extra.equals("tun")) { - // We only support tun - String errmsg = String.format("Devicetype %s requested, but only tun is possible with the Android API, sorry!",extra); - OpenVPN.logMessage(0, "", errmsg ); - - return false; - } - ParcelFileDescriptor pfd = mOpenVPNService.openTun(); - if(pfd==null) - return false; - - Method setInt; - int fdint = pfd.getFd(); - try { - setInt = FileDescriptor.class.getDeclaredMethod("setInt$",int.class); - FileDescriptor fdtosend = new FileDescriptor(); - - setInt.invoke(fdtosend,fdint); - - FileDescriptor[] fds = {fdtosend}; - mSocket.setFileDescriptorsForSend(fds); - - Log.d("Openvpn", "Sending FD tosocket: " + fdtosend + " " + fdint + " " + pfd); - // Trigger a send so we can close the fd on our side of the channel - // The API documentation fails to mention that it will not reset the file descriptor to - // be send and will happily send the file descriptor on every write ... - String cmd = String.format("needok '%s' %s\n", needed, "ok"); - managmentCommand(cmd); - - // Set the FileDescriptor to null to stop this mad behavior - mSocket.setFileDescriptorsForSend(null); - - pfd.close(); - - return true; - } catch (NoSuchMethodException e) { - exp =e; - } catch (IllegalArgumentException e) { - exp =e; - } catch (IllegalAccessException e) { - exp =e; - } catch (InvocationTargetException e) { - exp =e; - } catch (IOException e) { - exp =e; - } - if(exp!=null) { - OpenVPN.logMessage(0,"", "Could not send fd over socket:" + exp.getLocalizedMessage()); - exp.printStackTrace(); - } - return false; - } - - private void processPWCommand(String argument) { - //argument has the form Need 'Private Key' password - // or ">PASSWORD:Verification Failed: '%s' ['%s']" - String needed; - - - - try{ - - int p1 = argument.indexOf('\''); - int p2 = argument.indexOf('\'',p1+1); - needed = argument.substring(p1+1, p2); - if (argument.startsWith("Verification Failed")) { - proccessPWFailed(needed, argument.substring(p2+1)); - return; - } - } catch (StringIndexOutOfBoundsException sioob) { - OpenVPN.logMessage(0, "", "Could not parse management Password command: " + argument); - return; - } - - String pw=null; - - if(needed.equals("Private Key")) { - pw = mProfile.getPasswordPrivateKey(); - } else if (needed.equals("Auth")) { - String usercmd = String.format("username '%s' %s\n", - needed, VpnProfile.openVpnEscape(mProfile.mUsername)); - managmentCommand(usercmd); - pw = mProfile.getPasswordAuth(); - } - if(pw!=null) { - String cmd = String.format("password '%s' %s\n", needed, VpnProfile.openVpnEscape(pw)); - managmentCommand(cmd); - } else { - OpenVPN.logMessage(0, OpenVPN.MANAGMENT_PREFIX, String.format("Openvpn requires Authentication type '%s' but no password/key information available", needed)); - } - - } - - - - - private void proccessPWFailed(String needed, String args) { - OpenVPN.updateStateString("AUTH_FAILED", needed + args,R.string.state_auth_failed); - } - private void logStatusMessage(String command) { - OpenVPN.logMessage(0,"MGMT:", command); - } - - - public static boolean stopOpenVPN() { - boolean sendCMD=false; - for (OpenVpnManagementThread mt: active){ - mt.managmentCommand("signal SIGINT\n"); - sendCMD=true; - try { - if(mt.mSocket !=null) - mt.mSocket.close(); - } catch (IOException e) { - // Ignore close error on already closed socket - } - } - return sendCMD; - } - - public void signalusr1() { - mReleaseHold=false; - if(!mWaitingForRelease) - managmentCommand("signal SIGUSR1\n"); - } - - public void reconnect() { - signalusr1(); - releaseHold(); - } - - private void processSignCommand(String b64data) { - - PrivateKey privkey = mProfile.getKeystoreKey(); - Exception err =null; - - byte[] data = Base64.decode(b64data, Base64.DEFAULT); - - // The Jelly Bean *evil* Hack - // 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider - if(Build.VERSION.SDK_INT==16){ - processSignJellyBeans(privkey,data); - return; - } - - - try{ - - - Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); - - rsasinger.init(Cipher.ENCRYPT_MODE, privkey); - - byte[] signed_bytes = rsasinger.doFinal(data); - String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - managmentCommand("rsa-sig\n"); - managmentCommand(signed_string); - managmentCommand("\nEND\n"); - } catch (NoSuchAlgorithmException e){ - err =e; - } catch (InvalidKeyException e) { - err =e; - } catch (NoSuchPaddingException e) { - err =e; - } catch (IllegalBlockSizeException e) { - err =e; - } catch (BadPaddingException e) { - err =e; - } - if(err !=null) { - OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); - } - - } - - - private void processSignJellyBeans(PrivateKey privkey, byte[] data) { - Exception err =null; - try { - Method[] allm = privkey.getClass().getSuperclass().getDeclaredMethods(); - System.out.println(allm); - Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey"); - getKey.setAccessible(true); - - // Real object type is OpenSSLKey - Object opensslkey = getKey.invoke(privkey); - - getKey.setAccessible(false); - - Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext"); - - // integer pointer to EVP_pkey - getPkeyContext.setAccessible(true); - int pkey = (Integer) getPkeyContext.invoke(opensslkey); - getPkeyContext.setAccessible(false); - - byte[] signed_bytes = rsasign(data, pkey); - String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - managmentCommand("rsa-sig\n"); - managmentCommand(signed_string); - managmentCommand("\nEND\n"); - - } catch (NoSuchMethodException e) { - err=e; - } catch (IllegalArgumentException e) { - err=e; - } catch (IllegalAccessException e) { - err=e; - } catch (InvocationTargetException e) { - err=e; - } catch (InvalidKeyException e) { - err=e; - } - if(err !=null) { - OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); - } - - } -} diff --git a/app/src/main/java/se/leap/openvpn/OpenVpnService.java b/app/src/main/java/se/leap/openvpn/OpenVpnService.java deleted file mode 100644 index deec8518..00000000 --- a/app/src/main/java/se/leap/openvpn/OpenVpnService.java +++ /dev/null @@ -1,513 +0,0 @@ -package se.leap.openvpn; - - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.LocalServerSocket; -import android.net.LocalSocket; -import android.net.LocalSocketAddress; -import android.net.VpnService; -import android.os.Binder; -import android.os.Build; -import android.os.Handler.Callback; -import android.os.IBinder; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Vector; -import se.leap.bitmaskclient.Dashboard; -import se.leap.bitmaskclient.R; -import se.leap.openvpn.OpenVPN.StateListener; - -public class OpenVpnService extends VpnService implements StateListener, Callback { - public static final String START_SERVICE = "se.leap.openvpn.START_SERVICE"; - public static final String RETRIEVE_SERVICE = "se.leap.openvpn.RETRIEVE_SERVICE"; - - private Thread mProcessThread=null; - - private Vector mDnslist=new Vector(); - - private VpnProfile mProfile; - - private String mDomain=null; - - private Vector mRoutes=new Vector(); - private Vector mRoutesv6=new Vector(); - - private CIDRIP mLocalIP=null; - - private OpenVpnManagementThread mSocketManager; - - private Thread mSocketManagerThread; - private int mMtu; - private String mLocalIPv6=null; - private NetworkSateReceiver mNetworkStateReceiver; - private NotificationManager mNotificationManager; - - private boolean mDisplayBytecount=false; - - private boolean mStarting=false; - - private long mConnecttime; - - - private static final int OPENVPN_STATUS = 1; - - public static final int PROTECT_FD = 0; - - private final IBinder mBinder = new LocalBinder(); - - public class LocalBinder extends Binder { - public OpenVpnService getService() { - // Return this instance of LocalService so clients can call public methods - return OpenVpnService.this; - } - } - - @Override - public IBinder onBind(Intent intent) { - String action = intent.getAction(); - if( action !=null && (action.equals(START_SERVICE) || action.equals(RETRIEVE_SERVICE)) ) - return mBinder; - else - return super.onBind(intent); - } - - @Override - public void onRevoke() { - OpenVpnManagementThread.stopOpenVPN(); - endVpnService(); - } - - // Similar to revoke but do not try to stop process - public void processDied() { - endVpnService(); - } - - private void endVpnService() { - mProcessThread=null; - OpenVPN.logBuilderConfig(null); - ProfileManager.setConntectedVpnProfileDisconnected(this); - if(!mStarting) { - stopSelf(); - stopForeground(true); - } - } - - private void showNotification(String state, String msg, String tickerText, boolean lowpriority, long when, boolean persistant) { - String ns = Context.NOTIFICATION_SERVICE; - mNotificationManager = (NotificationManager) getSystemService(ns); - int icon; - if (state.equals("NOPROCESS") || state.equals("AUTH_FAILED") || state.equals("NONETWORK") || state.equals("EXITING")){ - icon = R.drawable.ic_vpn_disconnected; - }else{ - icon = R.drawable.ic_stat_vpn; - } - - android.app.Notification.Builder nbuilder = new Notification.Builder(this); - - nbuilder.setContentTitle(getString(R.string.notifcation_title,mProfile.mLocation)); - nbuilder.setContentText(msg); - nbuilder.setOnlyAlertOnce(true); - nbuilder.setOngoing(persistant); - nbuilder.setContentIntent(getLogPendingIntent()); - nbuilder.setSmallIcon(icon); - if(when !=0) - nbuilder.setWhen(when); - - - // Try to set the priority available since API 16 (Jellybean) - jbNotificationExtras(lowpriority, nbuilder); - if(tickerText!=null) - nbuilder.setTicker(tickerText); - - @SuppressWarnings("deprecation") - Notification notification = nbuilder.getNotification(); - - - mNotificationManager.notify(OPENVPN_STATUS, notification); - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private void jbNotificationExtras(boolean lowpriority, - android.app.Notification.Builder nbuilder) { - try { - if(lowpriority) { - Method setpriority = nbuilder.getClass().getMethod("setPriority", int.class); - // PRIORITY_MIN == -2 - setpriority.invoke(nbuilder, -2 ); - - nbuilder.setUsesChronometer(true); - /* PendingIntent cancelconnet=null; - - nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, - getString(R.string.cancel_connection),cancelconnet); */ - } - - //ignore exception - } catch (NoSuchMethodException nsm) { - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { - } catch (InvocationTargetException e) { - } - - } - - PendingIntent getLogPendingIntent() { - // Let the configure Button show the Dashboard - Intent intent = new Intent(getApplicationContext(),Dashboard.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent startLW = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - return startLW; - - } - - - private LocalServerSocket openManagmentInterface(int tries) { - // Could take a while to open connection - String socketname = (getCacheDir().getAbsolutePath() + "/" + "mgmtsocket"); - LocalSocket sock = new LocalSocket(); - - while(tries > 0 && !sock.isConnected()) { - try { - sock.bind(new LocalSocketAddress(socketname, - LocalSocketAddress.Namespace.FILESYSTEM)); - } catch (IOException e) { - // wait 300 ms before retrying - try { Thread.sleep(300); - } catch (InterruptedException e1) {} - - } - tries--; - } - - try { - LocalServerSocket lss = new LocalServerSocket(sock.getFileDescriptor()); - return lss; - } catch (IOException e) { - e.printStackTrace(); - } - return null; - - - } - - void registerNetworkStateReceiver() { - // Registers BroadcastReceiver to track network connection changes. - IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - mNetworkStateReceiver = new NetworkSateReceiver(mSocketManager); - this.registerReceiver(mNetworkStateReceiver, filter); - } - - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - - if( intent != null && intent.getAction() !=null && - (intent.getAction().equals(START_SERVICE) || intent.getAction().equals(RETRIEVE_SERVICE)) ) - return START_NOT_STICKY; - - - // Extract information from the intent. - String prefix = getPackageName(); - String[] argv = intent.getStringArrayExtra(prefix + ".ARGV"); - String nativelibdir = intent.getStringExtra(prefix + ".nativelib"); - String profileUUID = intent.getStringExtra(prefix + ".profileUUID"); - - mProfile = ProfileManager.get(profileUUID); - - //showNotification("Starting VPN " + mProfile.mName,"Starting VPN " + mProfile.mName, false,0); - - - OpenVPN.addStateListener(this); - - // Set a flag that we are starting a new VPN - mStarting=true; - // Stop the previous session by interrupting the thread. - if(OpenVpnManagementThread.stopOpenVPN()){ - // an old was asked to exit, wait 2s - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - } - - if (mProcessThread!=null) { - mProcessThread.interrupt(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - } - // An old running VPN should now be exited - mStarting=false; - - - // Open the Management Interface - LocalServerSocket mgmtsocket = openManagmentInterface(8); - - if(mgmtsocket!=null) { - // start a Thread that handles incoming messages of the managment socket - mSocketManager = new OpenVpnManagementThread(mProfile,mgmtsocket,this); - mSocketManagerThread = new Thread(mSocketManager,"OpenVPNMgmtThread"); - mSocketManagerThread.start(); - OpenVPN.logInfo("started Socket Thread"); - registerNetworkStateReceiver(); - } - - - // Start a new session by creating a new thread. - OpenVPNThread processThread = new OpenVPNThread(this, argv,nativelibdir); - - mProcessThread = new Thread(processThread, "OpenVPNProcessThread"); - mProcessThread.start(); - - ProfileManager.setConnectedVpnProfile(this, mProfile); - - return START_NOT_STICKY; - } - - @Override - public void onDestroy() { - if (mProcessThread != null) { - mSocketManager.managmentCommand("signal SIGINT\n"); - - mProcessThread.interrupt(); - - } - if (mNetworkStateReceiver!= null) { - this.unregisterReceiver(mNetworkStateReceiver); - } - - } - - - - public ParcelFileDescriptor openTun() { - Builder builder = new Builder(); - - if(mLocalIP==null && mLocalIPv6==null) { - OpenVPN.logMessage(0, "", getString(R.string.opentun_no_ipaddr)); - return null; - } - - if(mLocalIP!=null) { - builder.addAddress(mLocalIP.mIp, mLocalIP.len); - } - - if(mLocalIPv6!=null) { - String[] ipv6parts = mLocalIPv6.split("/"); - builder.addAddress(ipv6parts[0],Integer.parseInt(ipv6parts[1])); - } - - - for (String dns : mDnslist ) { - try { - builder.addDnsServer(dns); - } catch (IllegalArgumentException iae) { - OpenVPN.logError(R.string.dns_add_error, dns,iae.getLocalizedMessage()); - } - } - - - builder.setMtu(mMtu); - - - for (CIDRIP route:mRoutes) { - try { - builder.addRoute(route.mIp, route.len); - } catch (IllegalArgumentException ia) { - OpenVPN.logMessage(0, "", getString(R.string.route_rejected) + route + " " + ia.getLocalizedMessage()); - } - } - - for(String v6route:mRoutesv6) { - try { - String[] v6parts = v6route.split("/"); - builder.addRoute(v6parts[0],Integer.parseInt(v6parts[1])); - } catch (IllegalArgumentException ia) { - OpenVPN.logMessage(0, "", getString(R.string.route_rejected) + v6route + " " + ia.getLocalizedMessage()); - } - } - - if(mDomain!=null) - builder.addSearchDomain(mDomain); - - String bconfig[] = new String[6]; - - bconfig[0]= getString(R.string.last_openvpn_tun_config); - bconfig[1] = getString(R.string.local_ip_info,mLocalIP.mIp,mLocalIP.len,mLocalIPv6, mMtu); - bconfig[2] = getString(R.string.dns_server_info, joinString(mDnslist)); - bconfig[3] = getString(R.string.dns_domain_info, mDomain); - bconfig[4] = getString(R.string.routes_info, joinString(mRoutes)); - bconfig[5] = getString(R.string.routes_info6, joinString(mRoutesv6)); - - String session = mProfile.mLocation; - /* we don't want the IP address in the notification bar - if(mLocalIP!=null && mLocalIPv6!=null) - session = getString(R.string.session_ipv6string,session, mLocalIP, mLocalIPv6); - else if (mLocalIP !=null) - session= getString(R.string.session_ipv4string, session, mLocalIP); - */ - builder.setSession(session); - - - OpenVPN.logBuilderConfig(bconfig); - - // No DNS Server, log a warning - if(mDnslist.size()==0) - OpenVPN.logInfo(R.string.warn_no_dns); - - // Reset information - mDnslist.clear(); - mRoutes.clear(); - mRoutesv6.clear(); - mLocalIP=null; - mLocalIPv6=null; - mDomain=null; - - builder.setConfigureIntent(getLogPendingIntent()); - - try { - ParcelFileDescriptor pfd = builder.establish(); - return pfd; - } catch (Exception e) { - OpenVPN.logMessage(0, "", getString(R.string.tun_open_error)); - OpenVPN.logMessage(0, "", getString(R.string.error) + e.getLocalizedMessage()); - OpenVPN.logMessage(0, "", getString(R.string.tun_error_helpful)); - return null; - } - - } - - - // Ugly, but java has no such method - private String joinString(Vector vec) { - String ret = ""; - if(vec.size() > 0){ - ret = vec.get(0).toString(); - for(int i=1;i < vec.size();i++) { - ret = ret + ", " + vec.get(i).toString(); - } - } - return ret; - } - - - - - - - public void addDNS(String dns) { - mDnslist.add(dns); - } - - - public void setDomain(String domain) { - if(mDomain==null) { - mDomain=domain; - } - } - - - public void addRoute(String dest, String mask) { - CIDRIP route = new CIDRIP(dest, mask); - if(route.len == 32 && !mask.equals("255.255.255.255")) { - OpenVPN.logMessage(0, "", getString(R.string.route_not_cidr,dest,mask)); - } - - if(route.normalise()) - OpenVPN.logMessage(0, "", getString(R.string.route_not_netip,dest,route.len,route.mIp)); - - mRoutes.add(route); - } - - public void addRoutev6(String extra) { - mRoutesv6.add(extra); - } - - - public void setLocalIP(String local, String netmask,int mtu, String mode) { - mLocalIP = new CIDRIP(local, netmask); - mMtu = mtu; - - if(mLocalIP.len == 32 && !netmask.equals("255.255.255.255")) { - // get the netmask as IP - long netint = CIDRIP.getInt(netmask); - if(Math.abs(netint - mLocalIP.getInt()) ==1) { - if(mode.equals("net30")) - mLocalIP.len=30; - else - mLocalIP.len=31; - } else { - OpenVPN.logMessage(0, "", getString(R.string.ip_not_cidr, local,netmask,mode)); - } - } - } - - public void setLocalIPv6(String ipv6addr) { - mLocalIPv6 = ipv6addr; - } - - public boolean isRunning() { - if (mStarting == true || mProcessThread != null) - return true; - else - return false; - } - - @Override - public void updateState(String state,String logmessage, int resid) { - // If the process is not running, ignore any state, - // Notification should be invisible in this state - android.util.Log.d("OpenVpnService", "updateState(" + state + ","+logmessage); - - if(mProcessThread==null) { - if(mNotificationManager != null) - mNotificationManager.cancel(OPENVPN_STATUS); - return; - } - if("CONNECTED".equalsIgnoreCase(state)) { - mNotificationManager.cancel(OPENVPN_STATUS); - } else if(!"BYTECOUNT".equals(state)) { - - // Other notifications are shown, - // This also mean we are no longer connected, ignore bytecount messages until next - // CONNECTED - String ticker = getString(resid); - boolean persist = false; - if (("NOPROCESS".equals(state) ) || ("EXITING").equals(state)){ - showNotification(state, getString(R.string.eip_state_not_connected), ticker, false, 0, persist); - if(getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE) != null) - getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).edit().putBoolean(Dashboard.START_ON_BOOT, false).commit(); - } - else if (state.equals("GET_CONFIG") || state.equals("ASSIGN_IP")){ //don't show them in the notification message - } - else{ - persist = true; - showNotification(state, getString(resid) +" " + logmessage,ticker,false,0,persist); - } - } - } - - @Override - public boolean handleMessage(Message msg) { - Runnable r = msg.getCallback(); - if(r!=null){ - r.run(); - return true; - } else { - return false; - } - } -} diff --git a/app/src/main/java/se/leap/openvpn/ProfileManager.java b/app/src/main/java/se/leap/openvpn/ProfileManager.java deleted file mode 100644 index 07a4087a..00000000 --- a/app/src/main/java/se/leap/openvpn/ProfileManager.java +++ /dev/null @@ -1,221 +0,0 @@ -package se.leap.openvpn; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.StreamCorruptedException; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.preference.PreferenceManager; - -public class ProfileManager { - private static final String PREFS_NAME = "VPNList"; - - - - private static final String ONBOOTPROFILE = "onBootProfile"; - - - - private static ProfileManager instance; - - - - private static VpnProfile mLastConnectedVpn=null; - private HashMap profiles=new HashMap(); - private static VpnProfile tmpprofile=null; - - - public static VpnProfile get(String key) { - if (tmpprofile!=null && tmpprofile.getUUIDString().equals(key)) - return tmpprofile; - - if(instance==null) - return null; - return instance.profiles.get(key); - - } - - - - private ProfileManager() { } - - private static void checkInstance(Context context) { - if(instance == null) { - instance = new ProfileManager(); - instance.loadVPNList(context); - } - } - - synchronized public static ProfileManager getInstance(Context context) { - checkInstance(context); - return instance; - } - - public static void setConntectedVpnProfileDisconnected(Context c) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - Editor prefsedit = prefs.edit(); - prefsedit.putString(ONBOOTPROFILE, null); - prefsedit.apply(); - - } - - public static void setConnectedVpnProfile(Context c, VpnProfile connectedrofile) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - Editor prefsedit = prefs.edit(); - - //prefsedit.putString(ONBOOTPROFILE, connectedrofile.getUUIDString()); - prefsedit.putString(ONBOOTPROFILE, VpnProfile.EXTRA_PROFILEUUID); - prefsedit.apply(); - mLastConnectedVpn=connectedrofile; - - } - - public static VpnProfile getOnBootProfile(Context c) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - - boolean useStartOnBoot = prefs.getBoolean("restartvpnonboot", false); - - - String mBootProfileUUID = prefs.getString(ONBOOTPROFILE,null); - if(useStartOnBoot && mBootProfileUUID!=null) - return get(c, mBootProfileUUID); - else - return null; - } - - - - - public Collection getProfiles() { - return profiles.values(); - } - - public VpnProfile getProfileByName(String name) { - for (VpnProfile vpnp : profiles.values()) { - if(vpnp.getName().equals(name)) { - return vpnp; - } - } - return null; - } - - public void saveProfileList(Context context) { - SharedPreferences sharedprefs = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); - Editor editor = sharedprefs.edit(); - editor.putStringSet("vpnlist", profiles.keySet()); - - // For reasing I do not understand at all - // Android saves my prefs file only one time - // if I remove the debug code below :( - int counter = sharedprefs.getInt("counter", 0); - editor.putInt("counter", counter+1); - editor.apply(); - - } - - public void addProfile(VpnProfile profile) { - profiles.put(profile.getUUID().toString(),profile); - - } - - public static void setTemporaryProfile(VpnProfile tmp) { - ProfileManager.tmpprofile = tmp; - } - - - public void saveProfile(Context context,VpnProfile profile) { - // First let basic settings save its state - - ObjectOutputStream vpnfile; - try { - vpnfile = new ObjectOutputStream(context.openFileOutput((profile.getUUID().toString() + ".vp"),Activity.MODE_PRIVATE)); - - vpnfile.writeObject(profile); - vpnfile.flush(); - vpnfile.close(); - } catch (FileNotFoundException e) { - - e.printStackTrace(); - throw new RuntimeException(e); - } catch (IOException e) { - - e.printStackTrace(); - throw new RuntimeException(e); - - } - } - - - private void loadVPNList(Context context) { - profiles = new HashMap(); - SharedPreferences listpref = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); - Set vlist = listpref.getStringSet("vpnlist", null); - Exception exp =null; - if(vlist==null){ - vlist = new HashSet(); - } - - for (String vpnentry : vlist) { - try { - ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp")); - VpnProfile vp = ((VpnProfile) vpnfile.readObject()); - - // Sanity check - if(vp==null || vp.mName==null || vp.getUUID()==null) - continue; - - profiles.put(vp.getUUID().toString(), vp); - - } catch (StreamCorruptedException e) { - exp=e; - } catch (FileNotFoundException e) { - exp=e; - } catch (IOException e) { - exp=e; - } catch (ClassNotFoundException e) { - exp=e; - } - if(exp!=null) { - exp.printStackTrace(); - } - } - } - - public int getNumberOfProfiles() { - return profiles.size(); - } - - - - public void removeProfile(Context context,VpnProfile profile) { - String vpnentry = profile.getUUID().toString(); - profiles.remove(vpnentry); - saveProfileList(context); - context.deleteFile(vpnentry + ".vp"); - if(mLastConnectedVpn==profile) - mLastConnectedVpn=null; - - } - - - - public static VpnProfile get(Context context, String profileUUID) { - checkInstance(context); - return get(profileUUID); - } - - - - public static VpnProfile getLastConnectedVpn() { - return mLastConnectedVpn; - } - -} diff --git a/app/src/main/java/se/leap/openvpn/ProxyDetection.java b/app/src/main/java/se/leap/openvpn/ProxyDetection.java deleted file mode 100644 index c7b3d196..00000000 --- a/app/src/main/java/se/leap/openvpn/ProxyDetection.java +++ /dev/null @@ -1,54 +0,0 @@ -package se.leap.openvpn; - -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.Proxy; -import java.net.ProxySelector; -import java.net.SocketAddress; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.List; - -import se.leap.bitmaskclient.R; - -public class ProxyDetection { - static SocketAddress detectProxy(VpnProfile vp) { - // Construct a new url with https as protocol - try { - URL url = new URL(String.format("https://%s:%s",vp.mServerName,vp.mServerPort)); - Proxy proxy = getFirstProxy(url); - - if(proxy==null) - return null; - SocketAddress addr = proxy.address(); - if (addr instanceof InetSocketAddress) { - return addr; - } - - } catch (MalformedURLException e) { - OpenVPN.logError(R.string.getproxy_error,e.getLocalizedMessage()); - } catch (URISyntaxException e) { - OpenVPN.logError(R.string.getproxy_error,e.getLocalizedMessage()); - } - return null; - } - - static Proxy getFirstProxy(URL url) throws URISyntaxException { - System.setProperty("java.net.useSystemProxies", "true"); - - List proxylist = ProxySelector.getDefault().select(url.toURI()); - - - if (proxylist != null) { - for (Proxy proxy: proxylist) { - SocketAddress addr = proxy.address(); - - if (addr != null) { - return proxy; - } - } - - } - return null; - } -} \ No newline at end of file diff --git a/app/src/main/java/se/leap/openvpn/VPNLaunchHelper.java b/app/src/main/java/se/leap/openvpn/VPNLaunchHelper.java deleted file mode 100644 index 418cf7e9..00000000 --- a/app/src/main/java/se/leap/openvpn/VPNLaunchHelper.java +++ /dev/null @@ -1,76 +0,0 @@ -package se.leap.openvpn; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import se.leap.bitmaskclient.R; - -import android.content.Context; -import android.content.Intent; -import android.os.Build; - -public class VPNLaunchHelper { - static private boolean writeMiniVPN(Context context) { - File mvpnout = new File(context.getCacheDir(),VpnProfile.MINIVPN); - if (mvpnout.exists() && mvpnout.canExecute()) - return true; - - IOException e2 = null; - - try { - InputStream mvpn; - - try { - mvpn = context.getAssets().open("minivpn." + Build.CPU_ABI); - } - catch (IOException errabi) { - OpenVPN.logInfo("Failed getting assets for archicture " + Build.CPU_ABI); - e2=errabi; - mvpn = context.getAssets().open("minivpn." + Build.CPU_ABI2); - - } - - - FileOutputStream fout = new FileOutputStream(mvpnout); - - byte buf[]= new byte[4096]; - - int lenread = mvpn.read(buf); - while(lenread> 0) { - fout.write(buf, 0, lenread); - lenread = mvpn.read(buf); - } - fout.close(); - - if(!mvpnout.setExecutable(true)) { - OpenVPN.logMessage(0, "","Failed to set minivpn executable"); - return false; - } - - - return true; - } catch (IOException e) { - if(e2!=null) - OpenVPN.logMessage(0, "",e2.getLocalizedMessage()); - OpenVPN.logMessage(0, "",e.getLocalizedMessage()); - e.printStackTrace(); - return false; - } - } - - - public static void startOpenVpn(VpnProfile startprofile, Context context) { - if(!writeMiniVPN(context)) { - OpenVPN.logMessage(0, "", "Error writing minivpn binary"); - return; - } - OpenVPN.logMessage(0, "", context.getString(R.string.building_configration)); - - Intent startVPN = startprofile.prepareIntent(context); - if(startVPN!=null) - context.startService(startVPN); - - } -} diff --git a/app/src/main/java/se/leap/openvpn/VpnProfile.java b/app/src/main/java/se/leap/openvpn/VpnProfile.java deleted file mode 100644 index 481819ad..00000000 --- a/app/src/main/java/se/leap/openvpn/VpnProfile.java +++ /dev/null @@ -1,758 +0,0 @@ -package se.leap.openvpn; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Collection; -import java.util.UUID; -import java.util.Vector; - -import org.spongycastle.util.io.pem.PemObject; -import org.spongycastle.util.io.pem.PemWriter; - -import se.leap.bitmaskclient.ConfigHelper; -import se.leap.bitmaskclient.Dashboard; -import se.leap.bitmaskclient.EIP; -import se.leap.bitmaskclient.Provider; -import se.leap.bitmaskclient.R; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.preference.PreferenceManager; -import android.security.KeyChain; -import android.security.KeyChainException; - -public class VpnProfile implements Serializable{ - // Parcable - /** - * - */ - private static final long serialVersionUID = 7085688938959334563L; - static final int TYPE_CERTIFICATES=0; - static final int TYPE_PKCS12=1; - static final int TYPE_KEYSTORE=2; - public static final int TYPE_USERPASS = 3; - public static final int TYPE_STATICKEYS = 4; - public static final int TYPE_USERPASS_CERTIFICATES = 5; - public static final int TYPE_USERPASS_PKCS12 = 6; - public static final int TYPE_USERPASS_KEYSTORE = 7; - - // Don't change this, not all parts of the program use this constant - public static final String EXTRA_PROFILEUUID = "se.leap.bitmaskclient.profileUUID"; // TODO this feels wrong. See Issue #1494 - public static final String INLINE_TAG = "[[INLINE]]"; - private static final String OVPNCONFIGFILE = "android.conf"; - - protected transient String mTransientPW=null; - protected transient String mTransientPCKS12PW=null; - private transient PrivateKey mPrivateKey; - protected boolean profileDleted=false; - - - public static String DEFAULT_DNS1="131.234.137.23"; - public static String DEFAULT_DNS2="131.234.137.24"; - - // Public attributes, since I got mad with getter/setter - // set members to default values - private UUID mUuid; - public int mAuthenticationType = TYPE_CERTIFICATES ; - public String mName; - public String mLocation; - public String mAlias; - public String mClientCertFilename; - public String mTLSAuthDirection=""; - public String mTLSAuthFilename; - 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; - public String mIPv6Address; - public boolean mOverrideDNS=false; - public String mSearchDomain="blinkt.de"; - public boolean mUseDefaultRoute=true; - public boolean mUsePull=true; - public String mCustomRoutes; - public boolean mCheckRemoteCN=false; - public boolean mExpectTLSCert=true; - public String mRemoteCN=""; - public String mPassword=""; - public String mUsername=""; - public boolean mRoutenopull=false; - public boolean mUseRandomHostname=false; - public boolean mUseFloat=false; - public boolean mUseCustomConfig=false; - public String mCustomConfigOptions=""; - public String mVerb="1"; - public String mCipher=""; - public boolean mNobind=false; - public boolean mUseDefaultRoutev6=true; - public String mCustomRoutesv6=""; - public String mKeyPassword=""; - public boolean mPersistTun = false; - public String mConnectRetryMax="5"; - public String mConnectRetry="10"; - public boolean mUserEditable=true; - - static final String MINIVPN = "miniopenvpn"; - - - - - - - public void clearDefaults() { - mServerName="unkown"; - mUsePull=false; - mUseLzo=false; - mUseDefaultRoute=false; - mUseDefaultRoutev6=false; - mExpectTLSCert=false; - mPersistTun = false; - } - - - public static String openVpnEscape(String unescaped) { - if(unescaped==null) - return null; - String escapedString = unescaped.replace("\\", "\\\\"); - escapedString = escapedString.replace("\"","\\\""); - escapedString = escapedString.replace("\n","\\n"); - - if (escapedString.equals(unescaped) && !escapedString.contains(" ") && !escapedString.contains("#")) - return unescaped; - else - return '"' + escapedString + '"'; - } - - - static final String OVPNCONFIGCA = "android-ca.pem"; - static final String OVPNCONFIGUSERCERT = "android-user.pem"; - - - public VpnProfile(String name) { - mUuid = UUID.randomUUID(); - mName = name; - } - - public UUID getUUID() { - return mUuid; - - } - - public String getName() { - return mName; - } - - - public String getConfigFile(Context context) - { - - File cacheDir= context.getCacheDir(); - String cfg=""; - - // Enable managment interface - cfg += "# Enables connection to GUI\n"; - cfg += "management "; - - cfg +=cacheDir.getAbsolutePath() + "/" + "mgmtsocket"; - cfg += " unix\n"; - cfg += "management-client\n"; - // Not needed, see updated man page in 2.3 - //cfg += "management-signal\n"; - cfg += "management-query-passwords\n"; - cfg += "management-hold\n\n"; - - /* tmp-dir patched out :) - cfg+="# /tmp does not exist on Android\n"; - cfg+="tmp-dir "; - cfg+=cacheDir.getAbsolutePath(); - cfg+="\n\n"; */ - - cfg+="# Log window is better readable this way\n"; - cfg+="suppress-timestamps\n"; - - - - boolean useTLSClient = (mAuthenticationType != TYPE_STATICKEYS); - - if(useTLSClient && mUsePull) - cfg+="client\n"; - else if (mUsePull) - cfg+="pull\n"; - else if(useTLSClient) - cfg+="tls-client\n"; - - - cfg+="verb " + mVerb + "\n"; - - if(mConnectRetryMax ==null) { - mConnectRetryMax="5"; - } - - if(!mConnectRetryMax.equals("-1")) - cfg+="connect-retry-max " + mConnectRetryMax+ "\n"; - - if(mConnectRetry==null) - mConnectRetry="10"; - - - cfg+="connect-retry " + mConnectRetry + "\n"; - - cfg+="resolv-retry 60\n"; - - - - // 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"; - - - - - switch(mAuthenticationType) { - case VpnProfile.TYPE_USERPASS_CERTIFICATES: - cfg+="auth-user-pass\n"; - case VpnProfile.TYPE_CERTIFICATES: - /*// Ca - cfg+=insertFileData("ca",mCaFilename); - - // Client Cert + Key - cfg+=insertFileData("key",mClientKeyFilename); - cfg+=insertFileData("cert",mClientCertFilename); -*/ - // FIXME This is all we need...The whole switch statement can go... - SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE); - cfg+="\n"+preferences.getString(Provider.CA_CERT, "")+"\n\n"; - cfg+="\n"+preferences.getString(EIP.PRIVATE_KEY, "")+"\n\n"; - cfg+="\n"+preferences.getString(EIP.CERTIFICATE, "")+"\n\n"; - - break; - case VpnProfile.TYPE_USERPASS_PKCS12: - cfg+="auth-user-pass\n"; - case VpnProfile.TYPE_PKCS12: - cfg+=insertFileData("pkcs12",mPKCS12Filename); - break; - - case VpnProfile.TYPE_USERPASS_KEYSTORE: - cfg+="auth-user-pass\n"; - case VpnProfile.TYPE_KEYSTORE: - cfg+="ca " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGCA + "\n"; - cfg+="cert " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGUSERCERT + "\n"; - cfg+="management-external-key\n"; - - break; - case VpnProfile.TYPE_USERPASS: - cfg+="auth-user-pass\n"; - cfg+=insertFileData("ca",mCaFilename); - } - - if(mUseLzo) { - cfg+="comp-lzo\n"; - } - - if(mUseTLSAuth) { - if(mAuthenticationType==TYPE_STATICKEYS) - cfg+=insertFileData("secret",mTLSAuthFilename); - else - cfg+=insertFileData("tls-auth",mTLSAuthFilename); - - if(nonNull(mTLSAuthDirection)) { - cfg+= "key-direction "; - cfg+= mTLSAuthDirection; - cfg+="\n"; - } - - } - - if(!mUsePull ) { - if(nonNull(mIPv4Address)) - cfg +="ifconfig " + cidrToIPAndNetmask(mIPv4Address) + "\n"; - - if(nonNull(mIPv6Address)) - cfg +="ifconfig-ipv6 " + mIPv6Address + "\n"; - } - - if(mUsePull && mRoutenopull) - cfg += "route-nopull\n"; - - String routes = ""; - int numroutes=0; - if(mUseDefaultRoute) - routes += "route 0.0.0.0 0.0.0.0\n"; - else - for(String route:getCustomRoutes()) { - routes += "route " + route + "\n"; - numroutes++; - } - - - if(mUseDefaultRoutev6) - cfg += "route-ipv6 ::/0\n"; - else - for(String route:getCustomRoutesv6()) { - routes += "route-ipv6 " + route + "\n"; - numroutes++; - } - - // Round number to next 100 - if(numroutes> 90) { - numroutes = ((numroutes / 100)+1) * 100; - cfg+="# Alot of routes are set, increase max-routes\n"; - cfg+="max-routes " + numroutes + "\n"; - } - cfg+=routes; - - if(mOverrideDNS || !mUsePull) { - if(nonNull(mDNS1)) - cfg+="dhcp-option DNS " + mDNS1 + "\n"; - if(nonNull(mDNS2)) - cfg+="dhcp-option DNS " + mDNS2 + "\n"; - if(nonNull(mSearchDomain)) - cfg+="dhcp-option DOMAIN " + mSearchDomain + "\n"; - - } - - if(mNobind) - cfg+="nobind\n"; - - - - // Authentication - if(mCheckRemoteCN) { - if(mRemoteCN == null || mRemoteCN.equals("") ) - cfg+="tls-remote " + mServerName + "\n"; - else - cfg += "tls-remote " + openVpnEscape(mRemoteCN) + "\n"; - } - if(mExpectTLSCert) - cfg += "remote-cert-tls server\n"; - - - if(nonNull(mCipher)){ - cfg += "cipher " + mCipher + "\n"; - } - - - // Obscure Settings dialog - if(mUseRandomHostname) - cfg += "#my favorite options :)\nremote-random-hostname\n"; - - if(mUseFloat) - cfg+= "float\n"; - - if(mPersistTun) { - cfg+= "persist-tun\n"; - cfg+= "# persist-tun also sets persist-remote-ip to avoid DNS resolve problem\n"; - cfg+= "persist-remote-ip\n"; - } - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean usesystemproxy = prefs.getBoolean("usesystemproxy", true); - if(usesystemproxy) { - cfg+= "# Use system proxy setting\n"; - cfg+= "management-query-proxy\n"; - } - - - if(mUseCustomConfig) { - cfg += "# Custom configuration options\n"; - cfg += "# You are on your on own here :)\n"; - cfg += mCustomConfigOptions; - cfg += "\n"; - - } - - - - return cfg; - } - - //! Put inline data inline and other data as normal escaped filename - private String insertFileData(String cfgentry, String filedata) { - if(filedata==null) { - return String.format("%s %s\n",cfgentry,"missing"); - }else if(filedata.startsWith(VpnProfile.INLINE_TAG)){ - String datawoheader = filedata.substring(VpnProfile.INLINE_TAG.length()); - return String.format("<%s>\n%s\n\n",cfgentry,datawoheader,cfgentry); - } else { - return String.format("%s %s\n",cfgentry,openVpnEscape(filedata)); - } - } - - private boolean nonNull(String val) { - if(val == null || val.equals("")) - return false; - else - return true; - } - - private Collection getCustomRoutes() { - Vector cidrRoutes=new Vector(); - if(mCustomRoutes==null) { - // No routes set, return empty vector - return cidrRoutes; - } - for(String route:mCustomRoutes.split("[\n \t]")) { - if(!route.equals("")) { - String cidrroute = cidrToIPAndNetmask(route); - if(cidrRoutes == null) - return null; - - cidrRoutes.add(cidrroute); - } - } - - return cidrRoutes; - } - - private Collection getCustomRoutesv6() { - Vector cidrRoutes=new Vector(); - if(mCustomRoutesv6==null) { - // No routes set, return empty vector - return cidrRoutes; - } - for(String route:mCustomRoutesv6.split("[\n \t]")) { - if(!route.equals("")) { - cidrRoutes.add(route); - } - } - - return cidrRoutes; - } - - - - private String cidrToIPAndNetmask(String route) { - String[] parts = route.split("/"); - - // No /xx, assume /32 as netmask - if (parts.length ==1) - parts = (route + "/32").split("/"); - - if (parts.length!=2) - return null; - int len; - try { - len = Integer.parseInt(parts[1]); - } catch(NumberFormatException ne) { - return null; - } - if (len <0 || len >32) - return null; - - - long nm = 0xffffffffl; - nm = (nm << (32-len)) & 0xffffffffl; - - String netmask =String.format("%d.%d.%d.%d", (nm & 0xff000000) >> 24,(nm & 0xff0000) >> 16, (nm & 0xff00) >> 8 ,nm & 0xff ); - return parts[0] + " " + netmask; - } - - - - private String[] buildOpenvpnArgv(File cacheDir) - { - Vector args = new Vector(); - - // Add fixed paramenters - //args.add("/data/data/se.leap.openvpn/lib/openvpn"); - args.add(cacheDir.getAbsolutePath() +"/" + VpnProfile.MINIVPN); - - args.add("--config"); - args.add(cacheDir.getAbsolutePath() + "/" + OVPNCONFIGFILE); - // Silences script security warning - - args.add("script-security"); - args.add("0"); - - - return (String[]) args.toArray(new String[args.size()]); - } - - public Intent prepareIntent(Context context) { - String prefix = context.getPackageName(); - - Intent intent = new Intent(context,OpenVpnService.class); - - if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { - /*if(!saveCertificates(context)) - return null;*/ - } - - intent.putExtra(prefix + ".ARGV" , buildOpenvpnArgv(context.getCacheDir())); - intent.putExtra(prefix + ".profileUUID", mUuid.toString()); - - ApplicationInfo info = context.getApplicationInfo(); - intent.putExtra(prefix +".nativelib",info.nativeLibraryDir); - - try { - FileWriter cfg = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); - cfg.write(getConfigFile(context)); - cfg.flush(); - cfg.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - return intent; - } - - private boolean saveCertificates(Context context) { - PrivateKey privateKey = null; - X509Certificate[] cachain=null; - try { - privateKey = KeyChain.getPrivateKey(context,mAlias); - mPrivateKey = privateKey; - - cachain = KeyChain.getCertificateChain(context, mAlias); - if(cachain.length <= 1 && !nonNull(mCaFilename)) - OpenVPN.logMessage(0, "", context.getString(R.string.keychain_nocacert)); - - for(X509Certificate cert:cachain) { - OpenVPN.logInfo(R.string.cert_from_keystore,cert.getSubjectDN()); - } - - - - - if(nonNull(mCaFilename)) { - try { - Certificate cacert = getCacertFromFile(); - X509Certificate[] newcachain = new X509Certificate[cachain.length+1]; - for(int i=0;i= 1){ - X509Certificate usercert = cachain[0]; - - FileWriter userout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGUSERCERT); - - PemWriter upw = new PemWriter(userout); - upw.writeObject(new PemObject("CERTIFICATE", usercert.getEncoded())); - upw.close(); - - } - - return true; - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (CertificateException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (KeyChainException e) { - OpenVPN.logMessage(0,"",context.getString(R.string.keychain_access)); - } - return false; - } - private Certificate getCacertFromFile() throws FileNotFoundException, CertificateException { - CertificateFactory certFact = CertificateFactory.getInstance("X.509"); - - InputStream inStream; - - if(mCaFilename.startsWith(INLINE_TAG)) - inStream = new ByteArrayInputStream(mCaFilename.replace(INLINE_TAG,"").getBytes()); - else - inStream = new FileInputStream(mCaFilename); - - return certFact.generateCertificate(inStream); - } - - - //! Return an error if somethign is wrong - public int checkProfile(Context context) { -/* if(mAuthenticationType==TYPE_KEYSTORE || mAuthenticationType==TYPE_USERPASS_KEYSTORE) { - if(mAlias==null) - return R.string.no_keystore_cert_selected; - }*/ - - if(!mUsePull) { - if(mIPv4Address == null || cidrToIPAndNetmask(mIPv4Address) == null) - return R.string.ipv4_format_error; - } - if(isUserPWAuth() && !nonNull(mUsername)) { - return R.string.error_empty_username; - } - if(!mUseDefaultRoute && getCustomRoutes()==null) - return R.string.custom_route_format_error; - - // Everything okay - return R.string.no_error_found; - - } - - //! Openvpn asks for a "Private Key", this should be pkcs12 key - // - public String getPasswordPrivateKey() { - if(mTransientPCKS12PW!=null) { - String pwcopy = mTransientPCKS12PW; - mTransientPCKS12PW=null; - return pwcopy; - } - switch (mAuthenticationType) { - case TYPE_PKCS12: - case TYPE_USERPASS_PKCS12: - return mPKCS12Password; - - case TYPE_CERTIFICATES: - case TYPE_USERPASS_CERTIFICATES: - return mKeyPassword; - - case TYPE_USERPASS: - case TYPE_STATICKEYS: - default: - return null; - } - } - private boolean isUserPWAuth() { - switch(mAuthenticationType) { - case TYPE_USERPASS: - case TYPE_USERPASS_CERTIFICATES: - case TYPE_USERPASS_KEYSTORE: - case TYPE_USERPASS_PKCS12: - return true; - default: - return false; - - } - } - - - public boolean requireTLSKeyPassword() { - if(!nonNull(mClientKeyFilename)) - return false; - - String data = ""; - if(mClientKeyFilename.startsWith(INLINE_TAG)) - data = mClientKeyFilename; - else { - char[] buf = new char[2048]; - FileReader fr; - try { - fr = new FileReader(mClientKeyFilename); - int len = fr.read(buf); - while(len > 0 ) { - data += new String(buf,0,len); - len = fr.read(buf); - } - fr.close(); - } catch (FileNotFoundException e) { - return false; - } catch (IOException e) { - return false; - } - - } - - if(data.contains("Proc-Type: 4,ENCRYPTED")) - return true; - else if(data.contains("-----BEGIN ENCRYPTED PRIVATE KEY-----")) - return true; - else - return false; - } - - public int needUserPWInput() { - if((mAuthenticationType == TYPE_PKCS12 || mAuthenticationType == TYPE_USERPASS_PKCS12)&& - (mPKCS12Password == null || mPKCS12Password.equals(""))) { - if(mTransientPCKS12PW==null) - return R.string.pkcs12_file_encryption_key; - } - - if(mAuthenticationType == TYPE_CERTIFICATES || mAuthenticationType == TYPE_USERPASS_CERTIFICATES) { - if(requireTLSKeyPassword() && !nonNull(mKeyPassword)) - if(mTransientPCKS12PW==null) { - return R.string.private_key_password; - } - } - - if(isUserPWAuth() && (mPassword.equals("") || mPassword == null)) { - if(mTransientPW==null) - return R.string.password; - - } - return 0; - } - - public String getPasswordAuth() { - if(mTransientPW!=null) { - String pwcopy = mTransientPW; - mTransientPW=null; - return pwcopy; - } else { - return mPassword; - } - } - - - // Used by the Array Adapter - @Override - public String toString() { - return mName; - } - - - public String getUUIDString() { - return mUuid.toString(); - } - - - public PrivateKey getKeystoreKey() { - return mPrivateKey; - } - - - -} - - - - -- cgit v1.2.3 From 80dc0167cf9fb91cd9373bdd2a93793f71b901dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 15 May 2014 17:41:41 +0200 Subject: Copy some necessary icons from ics-openvpn. I'm hardcoding their values based on the compilation errors (i.e., the drawables referenced by de.blinkt.openvpn.core.OpenVpnService). If a new drawable were introduced, build.gradle should be updated accordingly. --- app/src/main/java/se/leap/bitmaskclient/EIP.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index 8b95a586..d5d3c55f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -56,7 +56,7 @@ import android.util.Log; * Internet Proxy connection. Connections are started, stopped, and queried through * this IntentService. * Contains logic for parsing eip-service.json from the provider, configuring and selecting - * gateways, and controlling {@link .openvpn.OpenVpnService} connections. + * gateways, and controlling {@link de.blinkt.openvpn.core.OpenVpnService} connections. * * @author Sean Leonard */ -- cgit v1.2.3 From 2ee8fb46dc2b719426e9735ba4a80729f1edc1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 29 May 2014 10:45:00 +0200 Subject: Thread management has changed. Updated. Now the thread managment doesn't happen statically, but through the binded openvpn service. --- app/src/main/java/se/leap/bitmaskclient/EIP.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index d5d3c55f..7d001865 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -136,7 +136,7 @@ public final class EIP extends IntentService { */ private boolean retreiveVpnService() { Intent bindIntent = new Intent(this,OpenVpnService.class); - bindIntent.setAction(OpenVpnService.RETRIEVE_SERVICE); + bindIntent.setAction(OpenVpnService.START_SERVICE); return bindService(bindIntent, mVpnServiceConn, BIND_AUTO_CREATE); } @@ -256,7 +256,7 @@ public final class EIP extends IntentService { if (mBound) mVpnService.onRevoke(); else - OpenVpnManagementThread.stopOpenVPN(); + mVpnService.getManagement().stopVPN(); if (mReceiver != null){ Bundle resultData = new Bundle(); -- cgit v1.2.3 From e50339824809da28beabfaf9ecea7414c131cbfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 29 May 2014 20:19:24 +0200 Subject: ics-openvpn receives ifconfig from the server. Refactored AndroidManifest to include launchvpn and openvpnservice. Imported changes from ics-openvpn-upstream --- app/src/main/java/se/leap/bitmaskclient/EIP.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index 7d001865..0058eff2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -536,7 +536,10 @@ public final class EIP extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); } - + + // We are always client, because the ifconfig will be received by a needed command + options.put("client", null); + try { arg.add(remote); arg.add(mGateway.getString(remote)); -- cgit v1.2.3 From 3e121542d8b7ab5201c47bbd3ba5611a23c54759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 11 Jun 2014 11:56:59 +0200 Subject: Correctly connects to millipede. Location keyword on android.cfg isn't supported, EIP corresponding code has been commented out. I think we should support it in ics-openvpn, so that we can show the location instead of the server name. I've updated all opensssl, openvpn, etc. subprojects from rev 813 of ics-openvpn, and jni too. --- app/src/main/java/se/leap/bitmaskclient/EIP.java | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index 0058eff2..345917b9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -554,22 +554,22 @@ public final class EIP extends IntentService { - try { - - arg.add(location_key); - String locationText = ""; - locationText = eipDefinition.getJSONObject(locations).getJSONObject(mGateway.getString(location_key)).getString("name"); - arg.add(locationText); + // try { + // arg.add(location_key); + // String locationText = ""; + // locationText = eipDefinition.getJSONObject(locations).getJSONObject(mGateway.getString(location_key)).getString("name"); + // arg.add(locationText); + // Log.d(TAG, "location = " + locationText); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - args.add((Vector) arg.clone()); - options.put("location", (Vector>) args.clone() ); + // } catch (JSONException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // args.add((Vector) arg.clone()); + // options.put("location", (Vector>) args.clone() ); - arg.clear(); - args.clear(); + // arg.clear(); + // args.clear(); JSONArray protocolsJSON = null; arg.add("proto"); try { -- cgit v1.2.3 From ac43a914c9720e6950708d3c22d17f8f6cd0aae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 12 Jun 2014 10:39:43 +0200 Subject: Hide logwindow by default. Next step: show it when an error occurs. --- app/src/main/java/se/leap/bitmaskclient/EIP.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index 345917b9..c9125f5c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -243,6 +243,7 @@ public final class EIP extends IntentService { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(LaunchVPN.EXTRA_KEY, activeGateway.mVpnProfile.getUUID().toString() ); intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() ); + intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); intent.putExtra(RECEIVER_TAG, mReceiver); startActivity(intent); mPending = ACTION_START_EIP; -- cgit v1.2.3 From 4a020a0116f1d3b8ea2a87e64cc8e6a926c0c179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 12 Jun 2014 11:25:49 +0200 Subject: Menu option to show the log window. In case there is an error, user will not be prompted with a strange log window, but the app will provide it if s/he really wants to see it. --- .../main/java/se/leap/bitmaskclient/Dashboard.java | 6 ++++++ .../se/leap/bitmaskclient/EipServiceFragment.java | 20 ++++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java index 6f18b79a..f2763d84 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java +++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java @@ -22,6 +22,7 @@ import org.json.JSONObject; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver; import se.leap.bitmaskclient.SignUpDialog; +import de.blinkt.openvpn.activities.LogWindow; import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; @@ -228,6 +229,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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.getInstance().hasEIP()){ if (getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getBoolean(EIP.AUTHED_EIP, false)){ diff --git a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java index 89319ea1..b72f9ff9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java @@ -204,7 +204,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe } @Override - public void updateState(final String state, final String logmessage, final int localizedResId, ConnectionStatus level) { + public void updateState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) { // Note: "states" are not organized anywhere...collected state strings: // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) getActivity().runOnUiThread(new Runnable() { @@ -215,26 +215,17 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe boolean switchState = true; String statusMessage = ""; String prefix = getString(localizedResId); - if (state.equals("CONNECTED")){ - + if (level == ConnectionStatus.LEVEL_CONNECTED){ statusMessage = getString(R.string.eip_state_connected); getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); mEipStartPending = false; - } else if (state.equals("BYTECOUNT")) { - statusMessage = getString(R.string.eip_state_connected); getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); - mEipStartPending = false; - - } else if ( (state.equals("NOPROCESS") && !mEipStartPending ) || state.equals("EXITING") && !mEipStartPending || state.equals("FATAL")) { + } else if ( level == ConnectionStatus.LEVEL_NONETWORK || level == ConnectionStatus.LEVEL_NOTCONNECTED || level == ConnectionStatus.LEVEL_AUTH_FAILED) { statusMessage = getString(R.string.eip_state_not_connected); getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); mEipStartPending = false; switchState = false; - } else if (state.equals("NOPROCESS")){ - statusMessage = logmessage; - } else if (state.equals("ASSIGN_IP")){ //don't show assigning message in eipStatus - statusMessage = (String) eipStatus.getText(); - } - else { + } else if (level == ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED) { + if(state.equals("AUTH") || state.equals("GET_CONFIG")) statusMessage = prefix + " " + logmessage; } @@ -279,6 +270,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe switch (resultCode){ case Activity.RESULT_OK: checked = true; + eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); break; case Activity.RESULT_CANCELED: checked = false; -- cgit v1.2.3 From 3de8647fb934dc07279f9fbc014f57e1e74f79f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 12 Jun 2014 12:02:44 +0200 Subject: Notify the user we're waiting for a server reply --- app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java index b72f9ff9..446ba1d9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java @@ -227,6 +227,8 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe } else if (level == ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED) { if(state.equals("AUTH") || state.equals("GET_CONFIG")) statusMessage = prefix + " " + logmessage; + } else if (level == ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET) { + statusMessage = prefix + " " + logmessage; } eipAutoSwitched = true; -- cgit v1.2.3 From 36247e71df88fa13c6c5a887de3b11d9a883615f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Fri, 13 Jun 2014 11:31:36 +0200 Subject: Disconnect works, eip status receiver. Disconnect uses the ics-openvpn activity, and the dialog prompting the user to confirm the disconnection is only shown when eip is connected or is trying to connect. --- app/src/main/java/se/leap/bitmaskclient/EIP.java | 19 ++++++++++--------- .../java/se/leap/bitmaskclient/EipStatusReceiver.java | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java (limited to 'app/src/main/java/se') diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index c9125f5c..59faf93f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -31,6 +31,7 @@ import org.json.JSONException; import org.json.JSONObject; import se.leap.bitmaskclient.R; +import de.blinkt.openvpn.activities.DisconnectVPN; import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; import de.blinkt.openvpn.LaunchVPN; @@ -68,6 +69,7 @@ public final class EIP extends IntentService { public final static String ACTION_UPDATE_EIP_SERVICE = "se.leap.bitmaskclient.UPDATE_EIP_SERVICE"; public final static String ACTION_IS_EIP_RUNNING = "se.leap.bitmaskclient.IS_RUNNING"; public final static String EIP_NOTIFICATION = "EIP_NOTIFICATION"; + public final static String STATUS = "eip status"; public final static String ALLOWED_ANON = "allow_anonymous"; public final static String CERTIFICATE = "cert"; public final static String PRIVATE_KEY = "private_key"; @@ -200,8 +202,9 @@ public final class EIP extends IntentService { Bundle resultData = new Bundle(); resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); int resultCode = Activity.RESULT_CANCELED; + boolean is_connected = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(STATUS, "").equalsIgnoreCase("LEVEL_CONNECTED"); if (mBound) { - resultCode = (mVpnService.isRunning()) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; + resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; if (mReceiver != null){ mReceiver.send(resultCode, resultData); @@ -215,12 +218,7 @@ public final class EIP extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); } - boolean running = false; - try { - running = mVpnService.isRunning(); - } catch (NullPointerException e){ - e.printStackTrace(); - } + boolean running = is_connected; if (retrieved_vpn_service && running && mReceiver != null){ mReceiver.send(Activity.RESULT_OK, resultData); @@ -256,8 +254,11 @@ public final class EIP extends IntentService { private void stopEIP() { if (mBound) mVpnService.onRevoke(); - else - mVpnService.getManagement().stopVPN(); + else if(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(STATUS, "").startsWith("LEVEL_CONNECT")){ + Intent disconnect_vpn = new Intent(this, DisconnectVPN.class); + disconnect_vpn.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(disconnect_vpn); + } if (mReceiver != null){ Bundle resultData = new Bundle(); diff --git a/app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java b/app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java new file mode 100644 index 00000000..8793cf36 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java @@ -0,0 +1,17 @@ +package se.leap.bitmaskclient; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + + +public class EipStatusReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals("de.blinkt.openvpn.VPN_STATUS")) { + context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE).edit().putString(EIP.STATUS, intent.getStringExtra("status")).commit(); + } + } +} -- cgit v1.2.3