diff options
author | Parménides GV <parmegv@sdf.org> | 2015-02-14 11:48:37 +0100 |
---|---|---|
committer | Parménides GV <parmegv@sdf.org> | 2015-02-14 11:48:37 +0100 |
commit | c198dbd9dd583d980ae7e70118f67d09bed8de55 (patch) | |
tree | c2863f28134af00f26299c97bb6a81ed0aa4ed96 /ics-openvpn-stripped/main/src/main/java/de | |
parent | 9d346be65e6808710b9e814d2899e5888984b4ab (diff) | |
parent | 4028c100a59c45913cb569c4967faaddc090b1f9 (diff) |
Merge branch 'develop'0.9.2
Diffstat (limited to 'ics-openvpn-stripped/main/src/main/java/de')
22 files changed, 0 insertions, 7034 deletions
diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java deleted file mode 100644 index 706a932f..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn; - -import se.leap.bitmaskclient.R; - -import android.app.Activity; -import android.app.AlertDialog; -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.preference.PreferenceManager; -import android.text.InputType; -import android.text.TextUtils; -import android.text.method.PasswordTransformationMethod; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; - -import java.io.IOException; - -import de.blinkt.openvpn.activities.LogWindow; -import de.blinkt.openvpn.core.ProfileManager; -import de.blinkt.openvpn.core.VPNLaunchHelper; -import de.blinkt.openvpn.core.VpnStatus; -import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; - -/** - * 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 Activity { - - public static final String EXTRA_KEY = "de.blinkt.openvpn.shortcutProfileUUID"; - public static final String EXTRA_NAME = "de.blinkt.openvpn.shortcutProfileName"; - public static final String EXTRA_HIDELOG = "de.blinkt.openvpn.showNoLogWindow"; - - private static final int START_VPN_PROFILE= 70; - - - 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 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(this,shortcutUUID); - if(shortcutName != null && profileToConnect ==null) - profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName); - - if(profileToConnect ==null) { - VpnStatus.logError(R.string.shortcut_profile_notfound); - // show Log window to display error - showLogWindow(); - finish(); - return; - } - - mSelectedProfile = profileToConnect; - launchVPN(); - - } - } - - @Override - protected void onActivityResult (int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if(requestCode==START_VPN_PROFILE) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean showLogWindow = prefs.getBoolean("showlogwindow", true); - - if(!mhideLog && showLogWindow) - showLogWindow(); - new startOpenVpnThread().start(); - } else if (resultCode == Activity.RESULT_CANCELED) { - // User does not want us to start, so we just vanish - VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled, - ConnectionStatus.LEVEL_NOTCONNECTED); - - 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) { - VpnStatus.updateStateString("USER_VPN_PERMISSION", "", R.string.state_user_vpn_permission, - ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT); - // 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 - VpnStatus.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("su","-c",command); - try { - Process p = pb.start(); - int ret = p.waitFor(); - if(ret ==0) - mCmfixed=true; - } catch (InterruptedException e) { - VpnStatus.logException("SU command", e); - - } catch (IOException e) { - VpnStatus.logException("SU command", e); - } - } - - private class startOpenVpnThread extends Thread { - - @Override - public void run() { - VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext()); - finish(); - - } - - } - - -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/VpnProfile.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/VpnProfile.java deleted file mode 100644 index 165bef33..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn; - -import se.leap.bitmaskclient.R; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.os.Build; -import android.preference.PreferenceManager; -import android.security.KeyChain; -import android.security.KeyChainException; -import android.text.TextUtils; -import android.util.Base64; - -import org.spongycastle.util.io.pem.PemObject; -import org.spongycastle.util.io.pem.PemWriter; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Serializable; -import java.io.StringWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Collection; -import java.util.HashSet; -import java.util.Locale; -import java.util.UUID; -import java.util.Vector; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; - -import de.blinkt.openvpn.core.Connection; -import de.blinkt.openvpn.core.NativeUtils; -import de.blinkt.openvpn.core.OpenVPNService; -import de.blinkt.openvpn.core.VPNLaunchHelper; -import de.blinkt.openvpn.core.VpnStatus; -import de.blinkt.openvpn.core.X509Utils; - -public class VpnProfile implements Serializable, Cloneable { - // Note that this class cannot be moved to core where it belongs since - // the profile loading depends on it being here - // The Serializable documentation mentions that class name change are possible - // but the how is unclear - // - transient public static final long MAX_EMBED_FILE_SIZE = 2048*1024; // 2048kB - // Don't change this, not all parts of the program use this constant - public static final String EXTRA_PROFILEUUID = "de.blinkt.openvpn.profileUUID"; - public static final String INLINE_TAG = "[[INLINE]]"; - public static final String DISPLAYNAME_TAG = "[[NAME]]"; - - private static final long serialVersionUID = 7085688938959334563L; - public static final int MAXLOGLEVEL = 4; - public static final int CURRENT_PROFILE_VERSION = 5; - public static final int DEFAULT_MSSFIX_SIZE = 1450; - public static String DEFAULT_DNS1 = "8.8.8.8"; - public static String DEFAULT_DNS2 = "8.8.4.4"; - - public transient String mTransientPW = null; - public transient String mTransientPCKS12PW = null; - - - public static final int TYPE_CERTIFICATES = 0; - public static final int TYPE_PKCS12 = 1; - public 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; - public static final int X509_VERIFY_TLSREMOTE = 0; - public static final int X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING = 1; - public static final int X509_VERIFY_TLSREMOTE_DN = 2; - public static final int X509_VERIFY_TLSREMOTE_RDN = 3; - public static final int X509_VERIFY_TLSREMOTE_RDN_PREFIX = 4; - // variable named wrong and should haven beeen transient - // but needs to keep wrong name to guarante loading of old - // profiles - public transient boolean profileDleted = false; - public int mAuthenticationType = TYPE_KEYSTORE; - public String mName; - public String mAlias; - public String mClientCertFilename; - public String mTLSAuthDirection = ""; - public String mTLSAuthFilename; - public String mClientKeyFilename; - public String mCaFilename; - public boolean mUseLzo = true; - public String mPKCS12Filename; - public String mPKCS12Password; - public boolean mUseTLSAuth = false; - - 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 = true; - public boolean mExpectTLSCert = false; - 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"; //ignored - 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 = "5"; - public boolean mUserEditable = true; - public String mAuth = ""; - public int mX509AuthType = X509_VERIFY_TLSREMOTE_RDN; - private transient PrivateKey mPrivateKey; - // Public attributes, since I got mad with getter/setter - // set members to default values - private UUID mUuid; - public boolean mAllowLocalLAN; - private int mProfileVersion; - public String mExcludedRoutes; - public String mExcludedRoutesv6; - public int mMssFix =0; // -1 is default, - public Connection[] mConnections = new Connection[0]; - public boolean mRemoteRandom=false; - public HashSet<String> mAllowedAppsVpn = new HashSet<String>(); - public boolean mAllowedAppsVpnAreDisallowed = true; - - - /* Options no long used in new profiles */ - public String mServerName = "openvpn.blinkt.de"; - public String mServerPort = "1194"; - public boolean mUseUdp = true; - - - - public VpnProfile(String name) { - mUuid = UUID.randomUUID(); - mName = name; - mProfileVersion = CURRENT_PROFILE_VERSION; - - mConnections = new Connection[1]; - mConnections[0] = new Connection(); - } - - 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("#") && !escapedString.contains(";") - && !escapedString.equals("")) - return unescaped; - else - return '"' + escapedString + '"'; - } - - public void clearDefaults() { - mServerName = "unknown"; - mUsePull = false; - mUseLzo = false; - mUseDefaultRoute = false; - mUseDefaultRoutev6 = false; - mExpectTLSCert = false; - mCheckRemoteCN = false; - mPersistTun = false; - mAllowLocalLAN = true; - mMssFix = 0; - } - - public UUID getUUID() { - return mUuid; - - } - - public String getName() { - if (mName==null) - return "No profile name"; - return mName; - } - - public void upgradeProfile(){ - if(mProfileVersion< 2) { - /* default to the behaviour the OS used */ - mAllowLocalLAN = Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT; - } - - if (mProfileVersion < 4) { - moveOptionsToConnection(); - mAllowedAppsVpnAreDisallowed=true; - } - if (mAllowedAppsVpn==null) - mAllowedAppsVpn = new HashSet<String>(); - if (mConnections ==null) - mConnections = new Connection[0]; - - mProfileVersion= CURRENT_PROFILE_VERSION; - - } - - private void moveOptionsToConnection() { - mConnections = new Connection[1]; - Connection conn = new Connection(); - - conn.mServerName = mServerName; - conn.mServerPort = mServerPort; - conn.mUseUdp = mUseUdp; - conn.mCustomConfiguration = ""; - - mConnections[0] = conn; - - } - - public String getConfigFile(Context context, boolean configForOvpn3) { - - File cacheDir = context.getCacheDir(); - String cfg = ""; - - // Enable management 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"; - - if (!configForOvpn3) - cfg += String.format("setenv IV_GUI_VER %s \n", openVpnEscape(getVersionEnvString(context))); - - cfg += "machine-readable-output\n"; - - // Users are confused by warnings that are misleading... - cfg += "ifconfig-nowarn\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"; - cfg += "verb " + MAXLOGLEVEL + "\n"; - - if (mConnectRetryMax == null) { - mConnectRetryMax = "5"; - } - - if (!mConnectRetryMax.equals("-1")) - cfg += "connect-retry-max " + mConnectRetryMax + "\n"; - - if (mConnectRetry == null) - mConnectRetry = "5"; - - - cfg += "connect-retry " + mConnectRetry + "\n"; - - cfg += "resolv-retry 60\n"; - - - // We cannot use anything else than tun - cfg += "dev tun\n"; - - - boolean canUsePlainRemotes = true; - - if (mConnections.length==1) { - cfg += mConnections[0].getConnectionBlock(); - } else { - for (Connection conn : mConnections) { - canUsePlainRemotes = canUsePlainRemotes && conn.isOnlyRemote(); - } - - if (mRemoteRandom) - cfg+="remote-random\n"; - - if (canUsePlainRemotes) { - for (Connection conn : mConnections) { - if (conn.mEnabled) { - cfg += conn.getConnectionBlock(); - } - } - } - } - - - switch (mAuthenticationType) { - 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); - - 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: - if (!configForOvpn3) { - String[] ks = getKeyStoreCertificates(context); - cfg += "### From Keystore ####\n"; - if (ks != null) { - cfg += "<ca>\n" + ks[0] + "\n</ca>\n"; - if (ks[1] != null) - cfg += "<extra-certs>\n" + ks[1] + "\n</extra-certs>\n"; - cfg += "<cert>\n" + ks[2] + "\n</cert>\n"; - cfg += "management-external-key\n"; - } else { - cfg += context.getString(R.string.keychain_access) + "\n"; - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) - if (!mAlias.matches("^[a-zA-Z0-9]$")) - cfg += context.getString(R.string.jelly_keystore_alphanumeric_bug) + "\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 (!TextUtils.isEmpty(mTLSAuthDirection)) { - cfg += "key-direction "; - cfg += mTLSAuthDirection; - cfg += "\n"; - } - - } - - if (!mUsePull) { - if (!TextUtils.isEmpty(mIPv4Address)) - cfg += "ifconfig " + cidrToIPAndNetmask(mIPv4Address) + "\n"; - - if (!TextUtils.isEmpty(mIPv6Address)) - cfg += "ifconfig-ipv6 " + mIPv6Address + "\n"; - } - - if (mUsePull && mRoutenopull) - cfg += "route-nopull\n"; - - String routes = ""; - - if (mUseDefaultRoute) - routes += "route 0.0.0.0 0.0.0.0 vpn_gateway\n"; - else - { - for (String route : getCustomRoutes(mCustomRoutes)) { - routes += "route " + route + " vpn_gateway\n"; - } - - for (String route: getCustomRoutes(mExcludedRoutes)) { - routes += "route " + route + " net_gateway\n"; - } - } - - - if (mUseDefaultRoutev6) - cfg += "route-ipv6 ::/0\n"; - else - for (String route : getCustomRoutesv6(mCustomRoutesv6)) { - routes += "route-ipv6 " + route + "\n"; - } - - cfg += routes; - - if (mOverrideDNS || !mUsePull) { - if (!TextUtils.isEmpty(mDNS1)) - cfg += "dhcp-option DNS " + mDNS1 + "\n"; - if (!TextUtils.isEmpty(mDNS2)) - cfg += "dhcp-option DNS " + mDNS2 + "\n"; - if (!TextUtils.isEmpty(mSearchDomain)) - cfg += "dhcp-option DOMAIN " + mSearchDomain + "\n"; - - } - - if (mMssFix !=0){ - if (mMssFix!=1450) - cfg+=String.format("mssfix %d\n", mMssFix, Locale.US); - else - cfg+="mssfix\n"; - } - - if (mNobind) - cfg += "nobind\n"; - - - // Authentication - if (mAuthenticationType != TYPE_STATICKEYS) { - if (mCheckRemoteCN) { - if (mRemoteCN == null || mRemoteCN.equals("")) - cfg += "verify-x509-name " + mConnections[0].mServerName + " name\n"; - else - switch (mX509AuthType) { - - // 2.2 style x509 checks - case X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING: - cfg += "compat-names no-remapping\n"; - case X509_VERIFY_TLSREMOTE: - cfg += "tls-remote " + openVpnEscape(mRemoteCN) + "\n"; - break; - - case X509_VERIFY_TLSREMOTE_RDN: - cfg += "verify-x509-name " + openVpnEscape(mRemoteCN) + " name\n"; - break; - - case X509_VERIFY_TLSREMOTE_RDN_PREFIX: - cfg += "verify-x509-name " + openVpnEscape(mRemoteCN) + " name-prefix\n"; - break; - - case X509_VERIFY_TLSREMOTE_DN: - cfg += "verify-x509-name " + openVpnEscape(mRemoteCN) + "\n"; - break; - } - } - if (mExpectTLSCert) - cfg += "remote-cert-tls server\n"; - } - - if (!TextUtils.isEmpty(mCipher)) { - cfg += "cipher " + mCipher + "\n"; - } - - if (!TextUtils.isEmpty(mAuth)) { - cfg += "auth " + mAuth + "\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 enables pre resolving to avoid DNS resolve problem\n"; - cfg += "preresolve\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"; - - } - - if (!canUsePlainRemotes) { - cfg += "# Connection Options are at the end to allow global options (and global custom options) to influence connection blocks\n"; - for (Connection conn : mConnections) { - if (conn.mEnabled) { - cfg += "<connection>\n"; - cfg += conn.getConnectionBlock(); - cfg += "</connection>\n"; - } - } - } - - - - - return cfg; - } - - public String getVersionEnvString(Context c) { - String version = "unknown"; - try { - PackageInfo packageinfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0); - version = packageinfo.versionName; - } catch (PackageManager.NameNotFoundException e) { - VpnStatus.logException(e); - } - return String.format(Locale.US, "%s %s", c.getPackageName(), version); - - } - - //! Put inline data inline and other data as normal escaped filename - private String insertFileData(String cfgentry, String filedata) { - if (filedata == null) { - // TODO: generate good error - return String.format("%s %s\n", cfgentry, "missing"); - } else if (isEmbedded(filedata)) { - String dataWithOutHeader = getEmbeddedContent(filedata); - return String.format(Locale.ENGLISH, "<%s>\n%s\n</%s>\n", cfgentry, dataWithOutHeader, cfgentry); - } else { - return String.format(Locale.ENGLISH, "%s %s\n", cfgentry, openVpnEscape(filedata)); - } - } - - private Collection<String> getCustomRoutes(String routes) { - Vector<String> cidrRoutes = new Vector<String>(); - if (routes == null) { - // No routes set, return empty vector - return cidrRoutes; - } - for (String route : routes.split("[\n \t]")) { - if (!route.equals("")) { - String cidrroute = cidrToIPAndNetmask(route); - if (cidrroute == null) - return null; - - cidrRoutes.add(cidrroute); - } - } - - return cidrRoutes; - } - - private Collection<String> getCustomRoutesv6(String routes) { - Vector<String> cidrRoutes = new Vector<String>(); - if (routes == null) { - // No routes set, return empty vector - return cidrRoutes; - } - for (String route : routes.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(Locale.ENGLISH, "%d.%d.%d.%d", (nm & 0xff000000) >> 24, (nm & 0xff0000) >> 16, (nm & 0xff00) >> 8, nm & 0xff); - return parts[0] + " " + netmask; - } - - - - - public Intent prepareStartService(Context context) { - Intent intent = getStartServiceIntent(context); - - - if (mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { - if (getKeyStoreCertificates(context) == null) - return null; - } - - - try { - FileWriter cfg = new FileWriter(VPNLaunchHelper.getConfigFilePath(context)); - cfg.write(getConfigFile(context, false)); - cfg.flush(); - cfg.close(); - } catch (IOException e) { - VpnStatus.logException(e); - } - - return intent; - } - - public Intent getStartServiceIntent(Context context) { - String prefix = context.getPackageName(); - - Intent intent = new Intent(context, OpenVPNService.class); - intent.putExtra(prefix + ".ARGV", VPNLaunchHelper.buildOpenvpnArgv(context)); - intent.putExtra(prefix + ".profileUUID", mUuid.toString()); - - ApplicationInfo info = context.getApplicationInfo(); - intent.putExtra(prefix + ".nativelib", info.nativeLibraryDir); - return intent; - } - - public String[] getKeyStoreCertificates(Context context) { - return getKeyStoreCertificates(context, 5); - } - - public static String getDisplayName(String embeddedFile) { - int start = DISPLAYNAME_TAG.length(); - int end = embeddedFile.indexOf(INLINE_TAG); - return embeddedFile.substring(start,end); - } - - public static String getEmbeddedContent(String data) - { - if (!data.contains(INLINE_TAG)) - return data; - - int start = data.indexOf(INLINE_TAG) + INLINE_TAG.length(); - return data.substring(start); - } - - public static boolean isEmbedded(String data) { - if (data==null) - return false; - if (data.startsWith(INLINE_TAG) || data.startsWith(DISPLAYNAME_TAG)) - return true; - else - return false; - } - - public void checkForRestart(final Context context) { - /* This method is called when OpenVPNService is restarted */ - - if ((mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) - && mPrivateKey==null) { - new Thread( new Runnable() { - @Override - public void run() { - getKeyStoreCertificates(context); - - } - }).start(); - } - } - - @Override - protected VpnProfile clone() throws CloneNotSupportedException { - VpnProfile copy = (VpnProfile) super.clone(); - copy.mUuid = UUID.randomUUID(); - copy.mConnections = mConnections.clone(); - copy.mAllowedAppsVpn = (HashSet<String>) mAllowedAppsVpn.clone(); - return copy; - } - - public VpnProfile copy(String name) { - try { - VpnProfile copy = (VpnProfile) clone(); - copy.mName = name; - return copy; - - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - return null; - } - } - - - class NoCertReturnedException extends Exception { - public NoCertReturnedException (String msg) { - super(msg); - } - } - - synchronized String[] getKeyStoreCertificates(Context context,int tries) { - PrivateKey privateKey = null; - X509Certificate[] caChain; - Exception exp; - try { - privateKey = KeyChain.getPrivateKey(context, mAlias); - mPrivateKey = privateKey; - - String keystoreChain = null; - - - caChain = KeyChain.getCertificateChain(context, mAlias); - if(caChain == null) - throw new NoCertReturnedException("No certificate returned from Keystore"); - - if (caChain.length <= 1 && TextUtils.isEmpty(mCaFilename)) { - VpnStatus.logMessage(VpnStatus.LogLevel.ERROR, "", context.getString(R.string.keychain_nocacert)); - } else { - StringWriter ksStringWriter = new StringWriter(); - - PemWriter pw = new PemWriter(ksStringWriter); - for (int i = 1; i < caChain.length; i++) { - X509Certificate cert = caChain[i]; - pw.writeObject(new PemObject("CERTIFICATE", cert.getEncoded())); - } - pw.close(); - keystoreChain = ksStringWriter.toString(); - } - - - String caout = null; - if (!TextUtils.isEmpty(mCaFilename)) { - try { - Certificate cacert = X509Utils.getCertificateFromFile(mCaFilename); - StringWriter caoutWriter = new StringWriter(); - PemWriter pw = new PemWriter(caoutWriter); - - pw.writeObject(new PemObject("CERTIFICATE", cacert.getEncoded())); - pw.close(); - caout= caoutWriter.toString(); - - } catch (Exception e) { - VpnStatus.logError("Could not read CA certificate" + e.getLocalizedMessage()); - } - } - - - StringWriter certout = new StringWriter(); - - - if (caChain.length >= 1) { - X509Certificate usercert = caChain[0]; - - PemWriter upw = new PemWriter(certout); - upw.writeObject(new PemObject("CERTIFICATE", usercert.getEncoded())); - upw.close(); - - } - String user = certout.toString(); - - - String ca, extra; - if(caout==null) { - ca =keystoreChain; - extra=null; - } else { - ca = caout; - extra=keystoreChain; - } - - return new String[]{ca, extra, user}; - } catch (InterruptedException e) { - exp=e; - } catch (FileNotFoundException e) { - exp=e; - } catch (CertificateException e) { - exp=e; - } catch (IOException e) { - exp=e; - } catch (KeyChainException e) { - exp=e; - } catch (NoCertReturnedException e) { - exp =e; - } catch (IllegalArgumentException e) { - exp =e; - } catch (AssertionError e) { - if (tries ==0) - return null; - VpnStatus.logError(String.format("Failure getting Keystore Keys (%s), retrying",e.getLocalizedMessage())); - try { - Thread.sleep(3000); - } catch (InterruptedException e1) { - VpnStatus.logException(e1); - } - return getKeyStoreCertificates(context, tries-1); - } - - exp.printStackTrace(); - VpnStatus.logError(R.string.keyChainAccessError, exp.getLocalizedMessage()); - - VpnStatus.logError(R.string.keychain_access); - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) { - if (!mAlias.matches("^[a-zA-Z0-9]$")) { - VpnStatus.logError(R.string.jelly_keystore_alphanumeric_bug); - } - } - return null; - } - - //! 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 || mAuthenticationType == TYPE_STATICKEYS) { - if (mIPv4Address == null || cidrToIPAndNetmask(mIPv4Address) == null) - return R.string.ipv4_format_error; - } - if (!mUseDefaultRoute && (getCustomRoutes(mCustomRoutes) == null || getCustomRoutes(mExcludedRoutes) ==null)) - return R.string.custom_route_format_error; - - boolean noRemoteEnabled = true; - for (Connection c : mConnections) - if (c.mEnabled) - noRemoteEnabled = false; - - if(noRemoteEnabled) - return R.string.remote_no_server_selected; - - // Everything okay - return R.string.no_error_found; - - } - - //! 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; - } - } - - public 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 (TextUtils.isEmpty(mClientKeyFilename)) - return false; - - String data = ""; - if (isEmbedded(mClientKeyFilename)) - 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(boolean ignoreTransient) { - if ((mAuthenticationType == TYPE_PKCS12 || mAuthenticationType == TYPE_USERPASS_PKCS12) && - (mPKCS12Password == null || mPKCS12Password.equals(""))) { - if (ignoreTransient || mTransientPCKS12PW == null) - return R.string.pkcs12_file_encryption_key; - } - - if (mAuthenticationType == TYPE_CERTIFICATES || mAuthenticationType == TYPE_USERPASS_CERTIFICATES) { - if (requireTLSKeyPassword() && TextUtils.isEmpty(mKeyPassword)) - if (ignoreTransient || mTransientPCKS12PW == null) { - return R.string.private_key_password; - } - } - - if (isUserPWAuth() && - (TextUtils.isEmpty(mUsername) || - (TextUtils.isEmpty(mPassword) && (mTransientPW == null || ignoreTransient)))) { - 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; - } - - public String getSignedData(String b64data) { - PrivateKey privkey = getKeystoreKey(); - Exception err; - - 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 == Build.VERSION_CODES.JELLY_BEAN) { - return processSignJellyBeans(privkey, data); - } - - - try { - - /* ECB is perfectly fine in this special case, since we are using it for - the public/private part in the TLS exchange - */ - @SuppressLint("GetInstance") - Cipher rsaSigner = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); - - rsaSigner.init(Cipher.ENCRYPT_MODE, privkey); - - byte[] signed_bytes = rsaSigner.doFinal(data); - return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - - } 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; - } - - VpnStatus.logError(R.string.error_rsa_sign, err.getClass().toString(), err.getLocalizedMessage()); - - return null; - - } - - private String processSignJellyBeans(PrivateKey privkey, byte[] data) { - Exception err; - try { - 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); - - // 112 with TLS 1.2 (172 back with 4.3), 36 with TLS 1.0 - byte[] signed_bytes = NativeUtils.rsasign(data, pkey); - return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - - } 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; - } - VpnStatus.logError(R.string.error_rsa_sign, err.getClass().toString(), err.getLocalizedMessage()); - - return null; - - } - - -} - - - - diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java deleted file mode 100644 index dfd815e4..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.activities; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.*; -import android.os.IBinder; - -import se.leap.bitmaskclient.R; -import de.blinkt.openvpn.core.OpenVPNService; -import de.blinkt.openvpn.core.ProfileManager; - -/** - * Created by arne on 13.10.13. - */ -public class DisconnectVPN extends Activity implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener { - protected OpenVPNService mService; - - private ServiceConnection mConnection = new ServiceConnection() { - - - @Override - public void onServiceConnected(ComponentName className, - IBinder service) { - // We've bound to LocalService, cast the IBinder and get LocalService instance - OpenVPNService.LocalBinder binder = (OpenVPNService.LocalBinder) service; - mService = binder.getService(); - } - - @Override - public void onServiceDisconnected(ComponentName arg0) { - mService =null; - } - - }; - - @Override - protected void onResume() { - super.onResume(); - Intent intent = new Intent(this, OpenVPNService.class); - intent.setAction(OpenVPNService.START_SERVICE); - bindService(intent, mConnection, Context.BIND_AUTO_CREATE); - showDisconnectDialog(); - } - - @Override - protected void onPause() { - super.onPause(); - unbindService(mConnection); - } - - // if (getIntent() !=null && OpenVpnService.DISCONNECT_VPN.equals(getIntent().getAction())) - - // setIntent(null); - - /* - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - setIntent(intent); - } - */ - - private void showDisconnectDialog() { - AlertDialog.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, this); - builder.setPositiveButton(android.R.string.yes,this); - builder.setOnCancelListener(this); - - builder.show(); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - ProfileManager.setConntectedVpnProfileDisconnected(this); - if (mService != null && mService.getManagement() != null) - mService.getManagement().stopVPN(); - } - finish(); - } - - @Override - public void onCancel(DialogInterface dialog) { - finish(); - } -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/activities/LogWindow.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/activities/LogWindow.java deleted file mode 100644 index 45f09c8e..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/activities/LogWindow.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.activities; - -import android.app.Activity; -import android.os.Bundle; -import android.view.MenuItem; - -import se.leap.bitmaskclient.R; -import de.blinkt.openvpn.fragments.LogFragment; - -/** - * Created by arne on 13.10.13. - */ -public class LogWindow extends Activity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.log_window); - getActionBar().setDisplayHomeAsUpEnabled(true); - - if (savedInstanceState == null) { - getFragmentManager().beginTransaction() - .add(R.id.container, new LogFragment()) - .commit(); - } - - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); - } -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/CIDRIP.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/CIDRIP.java deleted file mode 100644 index e525abd5..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/CIDRIP.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import java.util.Locale; - -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; - } - - } - - public CIDRIP(String address, int prefix_length) { - len = prefix_length; - mIp = address; - } - - @Override - public String toString() { - return String.format(Locale.ENGLISH, "%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/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ConfigParser.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ConfigParser.java deleted file mode 100644 index 5dc96bbc..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ConfigParser.java +++ /dev/null @@ -1,880 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import android.text.TextUtils; -import android.util.Pair; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.util.Collections; -import java.util.HashMap; -import java.util.Locale; -import java.util.Vector; - -import de.blinkt.openvpn.VpnProfile; - -//! Openvpn Config FIle Parser, probably not 100% accurate but close enough - -// And remember, this is valid :) -// --<foo> -// bar -// </foo> -public class ConfigParser { - - - public static final String CONVERTED_PROFILE = "converted Profile"; - private HashMap<String, Vector<Vector<String>>> options = new HashMap<String, Vector<Vector<String>>>(); - private HashMap<String, Vector<String>> meta = new HashMap<String, Vector<String>>(); - - public void parseConfig(Reader reader) throws IOException, ConfigParseError { - - - BufferedReader br = new BufferedReader(reader); - - int lineno = 0; - try { - while (true) { - String line = br.readLine(); - lineno++; - if (line == null) - break; - - if (lineno == 1 && (line.startsWith("PK\003\004") - || (line.startsWith("PK\007\008")))) - throw new ConfigParseError("Input looks like a ZIP Archive. Import is only possible for OpenVPN config files (.ovpn/.conf)"); - - // Check for OpenVPN Access Server Meta information - if (line.startsWith("# OVPN_ACCESS_SERVER_")) { - Vector<String> metaarg = parsemeta(line); - meta.put(metaarg.get(0), metaarg); - continue; - } - Vector<String> args = parseline(line); - - 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<Vector<String>>()); - } - options.get(optionname).add(args); - } - } catch (java.lang.OutOfMemoryError memoryError) { - throw new ConfigParseError("File too large to parse: " + memoryError.getLocalizedMessage()); - } - } - - private Vector<String> parsemeta(String line) { - String meta = line.split("#\\sOVPN_ACCESS_SERVER_", 2)[1]; - String[] parts = meta.split("=",2); - Vector<String> rval = new Vector<String>(); - Collections.addAll(rval, parts); - return rval; - - } - - private void checkinlinefile(Vector<String> args, BufferedReader br) throws IOException, ConfigParseError { - String arg0 = args.get(0).trim(); - // CHeck for <foo> - if(arg0.startsWith("<") && arg0.endsWith(">")) { - String argname = arg0.substring(1, arg0.length()-1); - String inlinefile = VpnProfile.INLINE_TAG; - - String endtag = String.format("</%s>",argname); - do { - String line = br.readLine(); - if(line==null){ - throw new ConfigParseError(String.format("No endtag </%s> for starttag <%s> found",argname,argname)); - } - if(line.trim().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<String> parseline(String line) throws ConfigParseError { - Vector<String> parameters = new Vector<String>(); - - 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", - "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", - "group", - "ip-win32", - "management-hold", - "management", - "management-client", - "management-query-remote", - "management-query-passwords", - "management-query-proxy", - "management-external-key", - "management-forget-disconnect", - "management-signal", - "management-log-cache", - "management-up-down", - "management-client-user", - "management-client-group", - "pause-exit", - "plugin", - "machine-readable-output", - "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", - "user", - "win-sys", - - }; - - final String[][] ignoreOptionsWithArg = - { - {"setenv", "IV_GUI_VER"}, - {"setenv", "IV_OPENVPN_GUI_VERSION"} - }; - - final String[] connectionOptions = { - "local", - "remote", - "float", - "port", - "connect-retry", - "connect-timeout", - "connect-retry-max", - "link-mtu", - "tun-mtu", - "tun-mtu-extra", - "fragment", - "mtu-disc", - "local-port", - "remote-port", - "bind", - "nobind", - "proto", - "http-proxy", - "http-proxy-retry", - "http-proxy-timeout", - "http-proxy-option", - "socks-proxy", - "socks-proxy-retry", - "explicit-exit-notify", - "mssfix" - }; - - - // This method is far too long - @SuppressWarnings("ConstantConditions") - public VpnProfile convertProfile() throws ConfigParseError, IOException { - boolean noauthtypeset=true; - VpnProfile np = new VpnProfile(CONVERTED_PROFILE); - // Pull, client, tls-client - np.clearDefaults(); - - if(options.containsKey("client") || options.containsKey("pull")) { - np.mUsePull=true; - options.remove("pull"); - options.remove("client"); - } - - Vector<String> 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<Vector<String>> routes = getAllOption("route", 1, 4); - if(routes!=null) { - String routeopt = ""; - String routeExcluded = ""; - for(Vector<String> route:routes){ - String netmask = "255.255.255.255"; - String gateway = "vpn_gateway"; - - if(route.size() >= 3) - netmask = route.get(2); - if (route.size() >= 4) - gateway = route.get(3); - - String net = route.get(1); - try { - CIDRIP cidr = new CIDRIP(net, netmask); - if (gateway.equals("net_gateway")) - routeExcluded += cidr.toString() + " "; - else - 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; - np.mExcludedRoutes=routeExcluded; - } - - Vector<Vector<String>> routesV6 = getAllOption("route-ipv6", 1, 4); - if (routesV6!=null) { - String customIPv6Routes = ""; - for (Vector<String> route:routesV6){ - customIPv6Routes += route.get(1) + " "; - } - - np.mCustomRoutesv6 = customIPv6Routes; - } - - // Also recognize tls-auth [inline] direction ... - Vector<Vector<String>> tlsauthoptions = getAllOption("tls-auth", 1, 2); - if(tlsauthoptions!=null) { - for(Vector<String> 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<String> direction = getOption("key-direction", 1, 1); - if(direction!=null) - np.mTLSAuthDirection=direction.get(1); - - Vector<Vector<String>> defgw = getAllOption("redirect-gateway", 0, 5); - if(defgw != null) - { - np.mUseDefaultRoute=true; - checkRedirectParameters(np, defgw); - } - - Vector<Vector<String>> redirectPrivate = getAllOption("redirect-private",0,5); - if (redirectPrivate != null) - { - checkRedirectParameters(np,redirectPrivate); - } - Vector<String> dev =getOption("dev",1,1); - Vector<String> 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<String> mssfix = getOption("mssfix",0,1); - - if (mssfix!=null) { - if (mssfix.size()>=2) { - try { - np.mMssFix=Integer.parseInt(mssfix.get(1)); - } catch(NumberFormatException e) { - throw new ConfigParseError("Argument to --mssfix has to be an integer"); - } - } else { - np.mMssFix = VpnProfile.DEFAULT_MSSFIX_SIZE; - } - } - - - Vector<String> 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<Vector<String>> dhcpoptions = getAllOption("dhcp-option", 2, 2); - if(dhcpoptions!=null) { - for(Vector<String> 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<String> ifconfig = getOption("ifconfig", 2, 2); - if(ifconfig!=null) { - try { - CIDRIP cidr = new CIDRIP(ifconfig.get(1), ifconfig.get(2)); - np.mIPv4Address=cidr.toString(); - } catch (NumberFormatException nfe) { - throw new ConfigParseError("Could not pase ifconfig IP address: " + nfe.getLocalizedMessage()); - } - - } - - 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<String> cipher = getOption("cipher", 1, 1); - if(cipher!=null) - np.mCipher= cipher.get(1); - - Vector<String> auth = getOption("auth", 1, 1); - if(auth!=null) - np.mAuth = auth.get(1); - - - Vector<String> ca = getOption("ca",1,1); - if(ca!=null){ - np.mCaFilename = ca.get(1); - } - - Vector<String> cert = getOption("cert",1,1); - if(cert!=null){ - np.mClientCertFilename = cert.get(1); - np.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES; - noauthtypeset=false; - } - Vector<String> key= getOption("key",1,1); - if(key!=null) - np.mClientKeyFilename=key.get(1); - - Vector<String> pkcs12 = getOption("pkcs12",1,1); - if(pkcs12!=null) { - np.mPKCS12Filename = pkcs12.get(1); - np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; - noauthtypeset=false; - } - - Vector<String> cryptoapicert = getOption("cryptoapicert",1,1); - if(cryptoapicert!=null) { - np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; - noauthtypeset=false; - } - - Vector<String> compatnames = getOption("compat-names",1,2); - Vector<String> nonameremapping = getOption("no-name-remapping",1,1); - Vector<String> tlsremote = getOption("tls-remote",1,1); - if(tlsremote!=null){ - np.mRemoteCN = tlsremote.get(1); - np.mCheckRemoteCN=true; - np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE; - - if((compatnames!=null && compatnames.size() > 2) || - (nonameremapping!=null)) - np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING; - } - - Vector<String> verifyx509name = getOption("verify-x509-name",1,2); - if(verifyx509name!=null){ - np.mRemoteCN = verifyx509name.get(1); - np.mCheckRemoteCN=true; - if(verifyx509name.size()>2) { - if (verifyx509name.get(2).equals("name")) - np.mX509AuthType=VpnProfile.X509_VERIFY_TLSREMOTE_RDN; - else if (verifyx509name.get(2).equals("name-prefix")) - np.mX509AuthType=VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX; - else - throw new ConfigParseError("Unknown parameter to x509-verify-name: " + verifyx509name.get(2) ); - } else { - np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_DN; - } - - } - - - Vector<String> verb = getOption("verb",1,1); - 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<String> connectretry = getOption("connect-retry", 1, 1); - if(connectretry!=null) - np.mConnectRetry =connectretry.get(1); - - Vector<String> connectretrymax = getOption("connect-retry-max", 1, 1); - if(connectretrymax!=null) - np.mConnectRetryMax =connectretrymax.get(1); - - Vector<Vector<String>> remotetls = getAllOption("remote-cert-tls", 1, 1); - if(remotetls!=null) - if(remotetls.get(0).get(1).equals("server")) - np.mExpectTLSCert=true; - else - options.put("remotetls",remotetls); - - Vector<String> 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 embed later. - np.mUsername=null; - useEmbbedUserAuth(np, authuser.get(1)); - } - } - - Pair<Connection, Connection[]> conns = parseConnectionOptions(null); - np.mConnections =conns.second; - - Vector<Vector<String>> connectionBlocks = getAllOption("connection", 1, 1); - - if (np.mConnections.length > 0 && connectionBlocks !=null ) { - throw new ConfigParseError("Using a <connection> block and --remote is not allowed."); - } - - if (connectionBlocks!=null) { - np.mConnections = new Connection[connectionBlocks.size()]; - - int connIndex = 0; - for (Vector<String> conn : connectionBlocks) { - Pair<Connection, Connection[]> connectionBlockConnection = - parseConnection(conn.get(1), conns.first); - - if (connectionBlockConnection.second.length != 1) - throw new ConfigParseError("A <connection> block must have exactly one remote"); - np.mConnections[connIndex] = connectionBlockConnection.second[0]; - connIndex++; - } - } - if(getOption("remote-random", 0, 0) != null) - np.mRemoteRandom=true; - - Vector<String> protoforce = getOption("proto-force", 1, 1); - if(protoforce!=null) { - boolean disableUDP; - String protoToDisable = protoforce.get(1); - if (protoToDisable.equals("udp")) - disableUDP=true; - else if (protoToDisable.equals("tcp")) - disableUDP=false; - else - throw new ConfigParseError(String.format("Unknown protocol %s in proto-force", protoToDisable)); - - for (Connection conn:np.mConnections) - if(conn.mUseUdp==disableUDP) - conn.mEnabled=false; - } - - // Parse OpenVPN Access Server extra - Vector<String> friendlyname = meta.get("FRIENDLY_NAME"); - if(friendlyname !=null && friendlyname.size() > 1) - np.mName=friendlyname.get(1); - - - Vector<String> ocusername = meta.get("USERNAME"); - if(ocusername !=null && ocusername.size() > 1) - np.mUsername=ocusername.get(1); - - checkIgnoreAndInvalidOptions(np); - fixup(np); - - return np; - } - - private Pair<Connection, Connection[]> parseConnection(String connection, Connection defaultValues) throws IOException, ConfigParseError { - // Parse a connection Block as a new configuration file - - - ConfigParser connectionParser = new ConfigParser(); - StringReader reader = new StringReader(connection.substring(VpnProfile.INLINE_TAG.length())); - connectionParser.parseConfig(reader); - - Pair<Connection, Connection[]> conn = connectionParser.parseConnectionOptions(defaultValues); - - return conn; - } - - private Pair<Connection, Connection[]> parseConnectionOptions(Connection connDefault) throws ConfigParseError { - Connection conn; - if (connDefault!=null) - try { - conn = connDefault.clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - return null; - } - else - conn = new Connection(); - - Vector<String> port = getOption("port", 1,1); - if(port!=null){ - conn.mServerPort = port.get(1); - } - - Vector<String> rport = getOption("rport", 1,1); - if(rport!=null){ - conn.mServerPort = rport.get(1); - } - - Vector<String> proto = getOption("proto", 1,1); - if(proto!=null){ - conn.mUseUdp=isUdpProto(proto.get(1)); - } - - - // Parse remote config - Vector<Vector<String>> remotes = getAllOption("remote",1,3); - - - // Assume that we need custom options if connectionDefault are set - if(connDefault!=null) { - for (Vector<Vector<String>> option : options.values()) { - - conn.mCustomConfiguration += getOptionStrings(option); - - } - if (!TextUtils.isEmpty(conn.mCustomConfiguration)) - conn.mUseCustomConfig = true; - } - // Make remotes empty to simplify code - if (remotes==null) - remotes = new Vector<Vector<String>>(); - - Connection[] connections = new Connection[remotes.size()]; - - - int i=0; - for (Vector<String> remote: remotes) { - try { - connections[i] = conn.clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - switch (remote.size()) { - case 4: - connections[i].mUseUdp=isUdpProto(remote.get(3)); - case 3: - connections[i].mServerPort = remote.get(2); - case 2: - connections[i].mServerName = remote.get(1); - } - i++; - } - return Pair.create(conn, connections); - - } - - private void checkRedirectParameters(VpnProfile np, Vector<Vector<String>> defgw) { - for (Vector<String> redirect: defgw) - for (int i=1;i<redirect.size();i++){ - if (redirect.get(i).equals("block-local")) - np.mAllowLocalLAN=false; - else if (redirect.get(i).equals("unblock-local")) - np.mAllowLocalLAN=true; - } - } - - 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 = VpnProfile.getEmbeddedContent(inlinedata); - 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) { - np.mCustomConfigOptions += "# These Options were found in the config file do not map to config settings:\n"; - - for(Vector<Vector<String>> option:options.values()) { - - np.mCustomConfigOptions += getOptionStrings(option); - - } - np.mUseCustomConfig=true; - - } - } - - - boolean ignoreThisOption(Vector<String> option) { - for (String[] ignoreOption : ignoreOptionsWithArg) { - - if (option.size() < ignoreOption.length) - continue; - - boolean ignore = true; - for (int i = 0; i < ignoreOption.length; i++) { - if (!ignoreOption[i].equals(option.get(i))) - ignore = false; - } - if (ignore) - return true; - - } - return false; - } - - private String getOptionStrings(Vector<Vector<String>> option) { - String custom = ""; - for (Vector<String> optionsline : option) { - if (!ignoreThisOption(optionsline)) { - for (String arg : optionsline) - custom += VpnProfile.openVpnEscape(arg) + " "; - custom += "\n"; - } - } - return custom; - } - - - private void fixup(VpnProfile np) { - if(np.mRemoteCN.equals(np.mServerName)) { - np.mRemoteCN=""; - } - } - - private Vector<String> getOption(String option, int minarg, int maxarg) throws ConfigParseError { - Vector<Vector<String>> alloptions = getAllOption(option, minarg, maxarg); - if(alloptions==null) - return null; - else - return alloptions.lastElement(); - } - - - private Vector<Vector<String>> getAllOption(String option, int minarg, int maxarg) throws ConfigParseError { - Vector<Vector<String>> args = options.get(option); - if(args==null) - return null; - - for(Vector<String> 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/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java deleted file mode 100644 index 4ccf5472..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import android.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; -import de.blinkt.openvpn.core.VpnStatus.ByteCountListener; - -import java.util.LinkedList; - -import static de.blinkt.openvpn.core.OpenVPNManagement.pauseReason; - -public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountListener { - private int lastNetwork = -1; - private OpenVPNManagement mManagement; - - // Window time in s - private final int TRAFFIC_WINDOW = 60; - // Data traffic limit in bytes - private final long TRAFFIC_LIMIT = 64 * 1024; - - - connectState network = connectState.DISCONNECTED; - connectState screen = connectState.SHOULDBECONNECTED; - connectState userpause = connectState.SHOULDBECONNECTED; - - private String lastStateMsg = null; - - enum connectState { - SHOULDBECONNECTED, - PENDINGDISCONNECT, - DISCONNECTED - } - - static class Datapoint { - private Datapoint(long t, long d) { - timestamp = t; - data = d; - } - - long timestamp; - long data; - } - - LinkedList<Datapoint> trafficdata = new LinkedList<DeviceStateReceiver.Datapoint>(); - - @Override - public void updateByteCount(long in, long out, long diffIn, long diffOut) { - if (screen != connectState.PENDINGDISCONNECT) - return; - - long total = diffIn + diffOut; - trafficdata.add(new Datapoint(System.currentTimeMillis(), total)); - - while (trafficdata.getFirst().timestamp <= (System.currentTimeMillis() - TRAFFIC_WINDOW * 1000)) { - trafficdata.removeFirst(); - } - - long windowtraffic = 0; - for (Datapoint dp : trafficdata) - windowtraffic += dp.data; - - if (windowtraffic < TRAFFIC_LIMIT) { - screen = connectState.DISCONNECTED; - VpnStatus.logInfo(R.string.screenoff_pause, - OpenVPNService.humanReadableByteCount(TRAFFIC_LIMIT, false), TRAFFIC_WINDOW); - - mManagement.pause(getPauseReason()); - } - } - - - public void userPause(boolean pause) { - if (pause) { - userpause = connectState.DISCONNECTED; - // Check if we should disconnect - mManagement.pause(getPauseReason()); - } else { - boolean wereConnected = shouldBeConnected(); - userpause = connectState.SHOULDBECONNECTED; - if (shouldBeConnected() && !wereConnected) - mManagement.resume(); - else - // Update the reason why we currently paused - mManagement.pause(getPauseReason()); - } - } - - public DeviceStateReceiver(OpenVPNManagement magnagement) { - super(); - mManagement = magnagement; - } - - - @Override - public void onReceive(Context context, Intent intent) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - - if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { - networkStateChange(context); - } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { - boolean screenOffPause = prefs.getBoolean("screenoff", false); - - if (screenOffPause) { - if (ProfileManager.getLastConnectedVpn()!=null && !ProfileManager.getLastConnectedVpn().mPersistTun) - VpnStatus.logError(R.string.screen_nopersistenttun); - - screen = connectState.PENDINGDISCONNECT; - fillTrafficData(); - if (network == connectState.DISCONNECTED || userpause == connectState.DISCONNECTED) - screen = connectState.DISCONNECTED; - } - } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) { - // Network was disabled because screen off - boolean connected = shouldBeConnected(); - screen = connectState.SHOULDBECONNECTED; - - /* should be connected has changed because the screen is on now, connect the VPN */ - if (shouldBeConnected() != connected) - mManagement.resume(); - else if (!shouldBeConnected()) - /*Update the reason why we are still paused */ - mManagement.pause(getPauseReason()); - - } - } - - - private void fillTrafficData() { - trafficdata.add(new Datapoint(System.currentTimeMillis(), TRAFFIC_LIMIT)); - } - - - public void networkStateChange(Context context) { - 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(); - network = connectState.SHOULDBECONNECTED; - - if (lastNetwork != newnet) { - if (screen == connectState.PENDINGDISCONNECT) - screen = connectState.DISCONNECTED; - - if (shouldBeConnected()) { - if (lastNetwork == -1) { - mManagement.resume(); - } else { - mManagement.networkChange(); - - } - } - - lastNetwork = newnet; - } - } else if (networkInfo == null) { - // Not connected, stop openvpn, set last connected network to no network - lastNetwork = -1; - if (sendusr1) { - network = connectState.DISCONNECTED; - - // Set screen state to be disconnected if disconnect pending - if (screen == connectState.PENDINGDISCONNECT) - screen = connectState.DISCONNECTED; - - mManagement.pause(getPauseReason()); - } - } - - - if (!netstatestring.equals(lastStateMsg)) - VpnStatus.logInfo(R.string.netstatus, netstatestring); - lastStateMsg = netstatestring; - - } - - public boolean isUserPaused() { - return userpause == connectState.DISCONNECTED; - } - - private boolean shouldBeConnected() { - return (screen == connectState.SHOULDBECONNECTED && userpause == connectState.SHOULDBECONNECTED && - network == connectState.SHOULDBECONNECTED); - } - - private pauseReason getPauseReason() { - if (userpause == connectState.DISCONNECTED) - return pauseReason.userPause; - - if (screen == connectState.DISCONNECTED) - return pauseReason.screenOff; - - if (network == connectState.DISCONNECTED) - return pauseReason.noNetwork; - - return pauseReason.userPause; - } - - private NetworkInfo getCurrentNetworkInfo(Context context) { - ConnectivityManager conn = (ConnectivityManager) - context.getSystemService(Context.CONNECTIVITY_SERVICE); - - return conn.getActiveNetworkInfo(); - } -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java deleted file mode 100644 index 56a574dc..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; -import android.app.Application; - -/* -import org.acra.ACRA; -import org.acra.ReportingInteractionMode; -import org.acra.annotation.ReportsCrashes; -*/ - -import se.leap.bitmaskclient.BuildConfig; -import se.leap.bitmaskclient.R; -import de.blinkt.openvpn.core.PRNGFixes; - -/* -@ReportsCrashes( - formKey = "", - formUri = "http://reports.blinkt.de/report-icsopenvpn", - reportType = org.acra.sender.HttpSender.Type.JSON, - httpMethod = org.acra.sender.HttpSender.Method.PUT, - formUriBasicAuthLogin="report-icsopenvpn", - formUriBasicAuthPassword="Tohd4neiF9Ai!!!!111eleven", - mode = ReportingInteractionMode.TOAST, - resToastText = R.string.crash_toast_text -) -*/ -public class ICSOpenVPNApplication extends Application { - @Override - public void onCreate() { - super.onCreate(); - PRNGFixes.apply(); - - if (BuildConfig.DEBUG) { - //ACRA.init(this); - } - } - -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/NativeUtils.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/NativeUtils.java deleted file mode 100644 index f67b7730..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/NativeUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import java.security.InvalidKeyException; - -public class NativeUtils { - public static native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException; - public static native String[] getIfconfig() throws IllegalArgumentException; - static native void jniclose(int fdint); - - static { - System.loadLibrary("stlport_shared"); - System.loadLibrary("opvpnutil"); - } -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java deleted file mode 100644 index 26354689..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import android.os.Build; -import android.text.TextUtils; - -import junit.framework.Assert; - -import org.jetbrains.annotations.NotNull; - -import java.math.BigInteger; -import java.net.Inet6Address; -import java.util.*; - -import se.leap.bitmaskclient.BuildConfig; - -public class NetworkSpace { - - - - - static class ipAddress implements Comparable<ipAddress> { - private BigInteger netAddress; - public int networkMask; - private boolean included; - private boolean isV4; - private BigInteger firstAddress; - private BigInteger lastAddress; - - - /** - * sorts the networks with following criteria: - * 1. compares first 1 of the network - * 2. smaller networks are returned as smaller - */ - @Override - public int compareTo(@NotNull ipAddress another) { - int comp = getFirstAddress().compareTo(another.getFirstAddress()); - if (comp != 0) - return comp; - - - if (networkMask > another.networkMask) - return -1; - else if (another.networkMask == networkMask) - return 0; - else - return 1; - } - - /** - * Warning ignores the included integer - * - * @param o - * the object to compare this instance with. - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof ipAddress)) - return super.equals(o); - - - ipAddress on = (ipAddress) o; - return (networkMask == on.networkMask) && on.getFirstAddress().equals(getFirstAddress()); - } - - public ipAddress(CIDRIP ip, boolean include) { - included = include; - netAddress = BigInteger.valueOf(ip.getInt()); - networkMask = ip.len; - isV4 = true; - } - - public ipAddress(Inet6Address address, int mask, boolean include) { - networkMask = mask; - included = include; - - int s = 128; - - netAddress = BigInteger.ZERO; - for (byte b : address.getAddress()) { - s -= 8; - netAddress = netAddress.add(BigInteger.valueOf((b & 0xFF)).shiftLeft(s)); - } - } - - public BigInteger getLastAddress() { - if(lastAddress ==null) - lastAddress = getMaskedAddress(true); - return lastAddress; - } - - - public BigInteger getFirstAddress() { - if (firstAddress ==null) - firstAddress =getMaskedAddress(false); - return firstAddress; - } - - - private BigInteger getMaskedAddress(boolean one) { - BigInteger numAddress = netAddress; - - int numBits; - if (isV4) { - numBits = 32 - networkMask; - } else { - numBits = 128 - networkMask; - } - - for (int i = 0; i < numBits; i++) { - if (one) - numAddress = numAddress.setBit(i); - else - numAddress = numAddress.clearBit(i); - } - return numAddress; - } - - - @Override - public String toString() { - //String in = included ? "+" : "-"; - if (isV4) - return String.format(Locale.US,"%s/%d", getIPv4Address(), networkMask); - else - return String.format(Locale.US, "%s/%d", getIPv6Address(), networkMask); - } - - ipAddress(BigInteger baseAddress, int mask, boolean included, boolean isV4) { - this.netAddress = baseAddress; - this.networkMask = mask; - this.included = included; - this.isV4 = isV4; - } - - - public ipAddress[] split() { - ipAddress firstHalf = new ipAddress(getFirstAddress(), networkMask + 1, included, isV4); - ipAddress secondHalf = new ipAddress(firstHalf.getLastAddress().add(BigInteger.ONE), networkMask + 1, included, isV4); - if (BuildConfig.DEBUG) Assert.assertTrue(secondHalf.getLastAddress().equals(getLastAddress())); - return new ipAddress[]{firstHalf, secondHalf}; - } - - String getIPv4Address() { - if (BuildConfig.DEBUG) { - Assert.assertTrue (isV4); - Assert.assertTrue (netAddress.longValue() <= 0xffffffffl); - Assert.assertTrue (netAddress.longValue() >= 0); - } - long ip = netAddress.longValue(); - return String.format(Locale.US, "%d.%d.%d.%d", (ip >> 24) % 256, (ip >> 16) % 256, (ip >> 8) % 256, ip % 256); - } - - String getIPv6Address() { - if (BuildConfig.DEBUG) Assert.assertTrue (!isV4); - BigInteger r = netAddress; - if (r.compareTo(BigInteger.ZERO)==0 && networkMask==0) - return "::"; - - Vector<String> parts = new Vector<String>(); - while (r.compareTo(BigInteger.ZERO) == 1) { - parts.add(0, String.format(Locale.US, "%x", r.mod(BigInteger.valueOf(0x10000)).longValue())); - r = r.shiftRight(16); - } - - return TextUtils.join(":", parts); - } - - public boolean containsNet(ipAddress network) { - return getFirstAddress().compareTo(network.getFirstAddress()) != 1 && - getLastAddress().compareTo(network.getLastAddress()) != -1; - } - } - - - TreeSet<ipAddress> mIpAddresses = new TreeSet<ipAddress>(); - - - public Collection<ipAddress> getNetworks(boolean included) { - Vector<ipAddress> ips = new Vector<ipAddress>(); - for (ipAddress ip : mIpAddresses) { - if (ip.included == included) - ips.add(ip); - } - return ips; - } - - public void clear() { - mIpAddresses.clear(); - } - - - void addIP(CIDRIP cidrIp, boolean include) { - - mIpAddresses.add(new ipAddress(cidrIp, include)); - } - - public void addIPSplit(CIDRIP cidrIp, boolean include) { - ipAddress newIP = new ipAddress(cidrIp, include); - ipAddress[] splitIps = newIP.split(); - for (ipAddress split: splitIps) - mIpAddresses.add(split); - } - - void addIPv6(Inet6Address address, int mask, boolean included) { - mIpAddresses.add(new ipAddress(address, mask, included)); - } - - TreeSet<ipAddress> generateIPList() { - - PriorityQueue<ipAddress> networks = new PriorityQueue<ipAddress>(mIpAddresses); - - TreeSet<ipAddress> ipsDone = new TreeSet<ipAddress>(); - - ipAddress currentNet = networks.poll(); - if (currentNet==null) - return ipsDone; - - while (currentNet!=null) { - // Check if it and the next of it are compatible - ipAddress nextNet = networks.poll(); - - if (BuildConfig.DEBUG) Assert.assertNotNull(currentNet); - if (nextNet== null || currentNet.getLastAddress().compareTo(nextNet.getFirstAddress()) == -1) { - // Everything good, no overlapping nothing to do - ipsDone.add(currentNet); - - currentNet = nextNet; - } else { - // This network is smaller or equal to the next but has the same base address - if (currentNet.getFirstAddress().equals(nextNet.getFirstAddress()) && currentNet.networkMask >= nextNet.networkMask) { - if (currentNet.included == nextNet.included) { - // Included in the next next and same type - // Simply forget our current network - currentNet=nextNet; - } else { - // our currentNet is included in next and types differ. Need to split the next network - ipAddress[] newNets = nextNet.split(); - - - // TODO: The contains method of the Priority is stupid linear search - - // First add the second half to keep the order in networks - if (!networks.contains(newNets[1])) - networks.add(newNets[1]); - - if (newNets[0].getLastAddress().equals(currentNet.getLastAddress())) { - if (BuildConfig.DEBUG) Assert.assertEquals (newNets[0].networkMask, currentNet.networkMask); - // Don't add the lower half that would conflict with currentNet - } else { - if (!networks.contains(newNets[0])) - networks.add(newNets[0]); - } - // Keep currentNet as is - } - } else { - if (BuildConfig.DEBUG) { - Assert.assertTrue(currentNet.networkMask < nextNet.networkMask); - Assert.assertTrue (nextNet.getFirstAddress().compareTo(currentNet.getFirstAddress()) == 1); - Assert.assertTrue (currentNet.getLastAddress().compareTo(nextNet.getLastAddress()) != -1); - } - // This network is bigger than the next and last ip of current >= next - - //noinspection StatementWithEmptyBody - if (currentNet.included == nextNet.included) { - // Next network is in included in our network with the same type, - // simply ignore the next and move on - } else { - // We need to split our network - ipAddress[] newNets = currentNet.split(); - - - if (newNets[1].networkMask == nextNet.networkMask) { - if (BuildConfig.DEBUG) { - Assert.assertTrue (newNets[1].getFirstAddress().equals(nextNet.getFirstAddress())); - Assert.assertTrue (newNets[1].getLastAddress().equals(currentNet.getLastAddress())); - // split second equal the next network, do not add it - } - networks.add(nextNet); - } else { - // Add the smaller network first - networks.add(newNets[1]); - networks.add(nextNet); - } - currentNet = newNets[0]; - - } - } - } - - } - - return ipsDone; - } - - Collection<ipAddress> getPositiveIPList() { - TreeSet<ipAddress> ipsSorted = generateIPList(); - - Vector<ipAddress> ips = new Vector<ipAddress>(); - for (ipAddress ia : ipsSorted) { - if (ia.included) - ips.add(ia); - } - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - // Include postive routes from the original set under < 4.4 since these might overrule the local - // network but only if no smaller negative route exists - for(ipAddress origIp: mIpAddresses){ - if (!origIp.included) - continue; - - // The netspace exists - if(ipsSorted.contains(origIp)) - continue; - - boolean skipIp=false; - // If there is any smaller net that is excluded we may not add the positive route back - for (ipAddress calculatedIp: ipsSorted) { - if(!calculatedIp.included && origIp.containsNet(calculatedIp)) { - skipIp=true; - break; - } - } - if (skipIp) - continue; - - // It is safe to include the IP - ips.add(origIp); - } - - } - - return ips; - } - -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java deleted file mode 100644 index 1f28c77d..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -public interface OpenVPNManagement { - enum pauseReason { - noNetwork, - userPause, - screenOff - } - - int mBytecountInterval =2; - - void reconnect(); - - void pause(pauseReason reason); - - void resume(); - - boolean stopVPN(); - - /* - * Rebind the interface - */ - void networkChange(); -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java deleted file mode 100644 index 578d95e7..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ /dev/null @@ -1,934 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import android.Manifest.permission; -import android.annotation.TargetApi; -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.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.NetworkRequest; -import android.net.VpnService; -import android.os.Binder; -import android.os.Build; -import android.os.Handler.Callback; -import android.os.IBinder; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import android.preference.PreferenceManager; -import android.system.OsConstants; -import android.text.TextUtils; -import android.util.Log; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Locale; -import java.util.Vector; - -import se.leap.bitmaskclient.BuildConfig; -import se.leap.bitmaskclient.R; -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.activities.DisconnectVPN; -import de.blinkt.openvpn.core.VpnStatus.ByteCountListener; -import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; -import de.blinkt.openvpn.core.VpnStatus.StateListener; - -import static de.blinkt.openvpn.core.NetworkSpace.ipAddress; -import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTED; -import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_NONETWORK; -import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED; -import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; -import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; -import se.leap.bitmaskclient.Dashboard; - -public class OpenVPNService extends VpnService implements StateListener, Callback, ByteCountListener { - - public static final String START_SERVICE = "de.blinkt.openvpn.START_SERVICE"; - public static final String START_SERVICE_STICKY = "de.blinkt.openvpn.START_SERVICE_STICKY"; - public static final String ALWAYS_SHOW_NOTIFICATION = "de.blinkt.openvpn.NOTIFICATION_ALWAYS_VISIBLE"; - public static final String DISCONNECT_VPN = "de.blinkt.openvpn.DISCONNECT_VPN"; - private static final String PAUSE_VPN = "de.blinkt.openvpn.PAUSE_VPN"; - private static final String RESUME_VPN = "se.leap.bitmaskclient.RESUME_VPN"; - private static final int OPENVPN_STATUS = 1; - private static boolean mNotificationAlwaysVisible = false; - private final Vector<String> mDnslist = new Vector<String>(); - private final NetworkSpace mRoutes = new NetworkSpace(); - private final NetworkSpace mRoutesv6 = new NetworkSpace(); - private final IBinder mBinder = new LocalBinder(); - private Thread mProcessThread = null; - private VpnProfile mProfile; - private String mDomain = null; - private CIDRIP mLocalIP = null; - private int mMtu; - private String mLocalIPv6 = null; - private DeviceStateReceiver mDeviceStateReceiver; - private boolean mDisplayBytecount = false; - private boolean mStarting = false; - private long mConnecttime; - private boolean mOvpn3 = false; - private OpenVPNManagement mManagement; - private String mLastTunCfg; - private String mRemoteGW; - private final Object mProcessLock = new Object(); - private LollipopDeviceStateListener mLollipopDeviceStateListener; - - // From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java - public static String humanReadableByteCount(long bytes, boolean mbit) { - if (mbit) - bytes = bytes * 8; - int unit = mbit ? 1000 : 1024; - if (bytes < unit) - return bytes + (mbit ? " bit" : " B"); - - int exp = (int) (Math.log(bytes) / Math.log(unit)); - String pre = (mbit ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (mbit ? "" : ""); - if (mbit) - return String.format(Locale.getDefault(), "%.1f %sbit", bytes / Math.pow(unit, exp), pre); - else - return String.format(Locale.getDefault(), "%.1f %sB", bytes / Math.pow(unit, exp), pre); - } - - @Override - public IBinder onBind(Intent intent) { - String action = intent.getAction(); - if (action != null && action.equals(START_SERVICE)) - return mBinder; - else - return super.onBind(intent); - } - - @Override - public void onRevoke() { - mManagement.stopVPN(); - endVpnService(); - } - - // Similar to revoke but do not try to stop process - public void processDied() { - endVpnService(); - } - - private void endVpnService() { - synchronized (mProcessLock) { - mProcessThread = null; - } - mConnecttime = 0; - VpnStatus.removeByteCountListener(this); - unregisterDeviceStateReceiver(); - ProfileManager.setConntectedVpnProfileDisconnected(this); - if (!mStarting) { - stopForeground(!mNotificationAlwaysVisible); - - if (!mNotificationAlwaysVisible) { - stopSelf(); - VpnStatus.removeStateListener(this); - } - } - } - - private void showNotification(String msg, String tickerText, boolean lowpriority, long when, ConnectionStatus status) { - String ns = Context.NOTIFICATION_SERVICE; - NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); - - - int icon = getIconByConnectionStatus(status); - - android.app.Notification.Builder nbuilder = new Notification.Builder(this); - - if (mProfile != null) - nbuilder.setContentTitle(getString(R.string.notifcation_title, mProfile.mName)); - else - nbuilder.setContentTitle(getString(R.string.notifcation_title_notconnect)); - - nbuilder.setContentText(msg); - nbuilder.setOnlyAlertOnce(true); - nbuilder.setOngoing(true); - nbuilder.setContentIntent(getLogPendingIntent()); - nbuilder.setSmallIcon(icon); - - - if (when != 0) - nbuilder.setWhen(when); - - - // Try to set the priority available since API 16 (Jellybean) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) - jbNotificationExtras(lowpriority, nbuilder); - - if (tickerText != null && !tickerText.equals("")) - nbuilder.setTicker(tickerText); - - @SuppressWarnings("deprecation") - Notification notification = nbuilder.getNotification(); - - - mNotificationManager.notify(OPENVPN_STATUS, notification); - //startForeground(OPENVPN_STATUS, notification); - } - - private int getIconByConnectionStatus(ConnectionStatus level) { - switch (level) { - case LEVEL_CONNECTED: - return R.drawable.ic_stat_vpn; - case LEVEL_AUTH_FAILED: - case LEVEL_NONETWORK: - case LEVEL_NOTCONNECTED: - return R.drawable.ic_stat_vpn_offline; - case LEVEL_CONNECTING_NO_SERVER_REPLY_YET: - case LEVEL_WAITING_FOR_USER_INPUT: - return R.drawable.ic_stat_vpn_outline; - case LEVEL_CONNECTING_SERVER_REPLIED: - return R.drawable.ic_stat_vpn_empty_halo; - case LEVEL_VPNPAUSED: - return android.R.drawable.ic_media_pause; - case UNKNOWN_LEVEL: - default: - return R.drawable.ic_stat_vpn; - - } - } - - @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); - - Method setUsesChronometer = nbuilder.getClass().getMethod("setUsesChronometer", boolean.class); - setUsesChronometer.invoke(nbuilder, true); - - } - - Intent disconnectVPN = new Intent(this, DisconnectVPN.class); - disconnectVPN.setAction(DISCONNECT_VPN); - PendingIntent disconnectPendingIntent = PendingIntent.getActivity(this, 0, disconnectVPN, 0); - - nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, - getString(R.string.cancel_connection), disconnectPendingIntent); - - Intent pauseVPN = new Intent(this, OpenVPNService.class); - if (mDeviceStateReceiver == null || !mDeviceStateReceiver.isUserPaused()) { - pauseVPN.setAction(PAUSE_VPN); - PendingIntent pauseVPNPending = PendingIntent.getService(this, 0, pauseVPN, 0); - nbuilder.addAction(android.R.drawable.ic_media_pause, - getString(R.string.pauseVPN), pauseVPNPending); - - } else { - pauseVPN.setAction(RESUME_VPN); - PendingIntent resumeVPNPending = PendingIntent.getService(this, 0, pauseVPN, 0); - nbuilder.addAction(android.R.drawable.ic_media_play, - getString(R.string.resumevpn), resumeVPNPending); - } - - - //ignore exception - } catch (NoSuchMethodException nsm) { - VpnStatus.logException(nsm); - } catch (IllegalArgumentException e) { - VpnStatus.logException(e); - } catch (IllegalAccessException e) { - VpnStatus.logException(e); - } catch (InvocationTargetException e) { - VpnStatus.logException(e); - } - - } - - PendingIntent getLogPendingIntent() { - // Let the configure Button show the Log - Intent intent = new Intent(getBaseContext(), Dashboard.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - PendingIntent startLW = PendingIntent.getActivity(this, 0, intent, 0); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - return startLW; - - } - - synchronized void registerDeviceStateReceiver(OpenVPNManagement magnagement) { - // Registers BroadcastReceiver to track network connection changes. - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(Intent.ACTION_SCREEN_ON); - mDeviceStateReceiver = new DeviceStateReceiver(magnagement); - registerReceiver(mDeviceStateReceiver, filter); - VpnStatus.addByteCountListener(mDeviceStateReceiver); - - /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - addLollipopCMListener(); */ - } - - synchronized void unregisterDeviceStateReceiver() { - if (mDeviceStateReceiver != null) - try { - VpnStatus.removeByteCountListener(mDeviceStateReceiver); - this.unregisterReceiver(mDeviceStateReceiver); - } catch (IllegalArgumentException iae) { - // I don't know why this happens: - // java.lang.IllegalArgumentException: Receiver not registered: de.blinkt.openvpn.NetworkSateReceiver@41a61a10 - // Ignore for now ... - iae.printStackTrace(); - } - mDeviceStateReceiver = null; - - /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - removeLollipopCMListener();*/ - - } - - public void userPause(boolean shouldBePaused) { - if (mDeviceStateReceiver != null) - mDeviceStateReceiver.userPause(shouldBePaused); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - - if (intent != null && intent.getBooleanExtra(ALWAYS_SHOW_NOTIFICATION, false)) - mNotificationAlwaysVisible = true; - - VpnStatus.addStateListener(this); - VpnStatus.addByteCountListener(this); - - if (intent != null && PAUSE_VPN.equals(intent.getAction())) { - if (mDeviceStateReceiver != null) - mDeviceStateReceiver.userPause(true); - return START_NOT_STICKY; - } - - if (intent != null && RESUME_VPN.equals(intent.getAction())) { - if (mDeviceStateReceiver != null) - mDeviceStateReceiver.userPause(false); - return START_NOT_STICKY; - } - - - if (intent != null && START_SERVICE.equals(intent.getAction())) - return START_NOT_STICKY; - if (intent != null && START_SERVICE_STICKY.equals(intent.getAction())) { - return START_REDELIVER_INTENT; - } - - /* The intent is null when the service has been restarted */ - if (intent == null) { - mProfile = ProfileManager.getLastConnectedProfile(this, false); - - /* Got no profile, just stop */ - if (mProfile == null) { - Log.d("OpenVPN", "Got no last connected profile on null intent. Stopping"); - stopSelf(startId); - return START_NOT_STICKY; - } - /* Do the asynchronous keychain certificate stuff */ - mProfile.checkForRestart(this); - - /* Recreate the intent */ - intent = mProfile.getStartServiceIntent(this); - - } else { - String profileUUID = intent.getStringExtra(getPackageName() + ".profileUUID"); - mProfile = ProfileManager.get(this, profileUUID); - } - - - // Extract information from the intent. - String prefix = getPackageName(); - String[] argv = intent.getStringArrayExtra(prefix + ".ARGV"); - String nativeLibraryDirectory = intent.getStringExtra(prefix + ".nativelib"); - - String startTitle = getString(R.string.start_vpn_title, mProfile.mName); - String startTicker = getString(R.string.start_vpn_ticker, mProfile.mName); - showNotification(startTitle, startTicker, - false, 0, LEVEL_CONNECTING_NO_SERVER_REPLY_YET); - - // Set a flag that we are starting a new VPN - mStarting = true; - // Stop the previous session by interrupting the thread. - if (mManagement != null && mManagement.stopVPN()) - // an old was asked to exit, wait 1s - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - //ignore - } - - synchronized (mProcessLock) { - if (mProcessThread != null) { - mProcessThread.interrupt(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - //ignore - } - } - } - // An old running VPN should now be exited - mStarting = false; - - // Start a new session by creating a new thread. - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - - mOvpn3 = prefs.getBoolean("ovpn3", false); - if (!"ovpn3".equals(BuildConfig.FLAVOR)) - mOvpn3 = false; - - - // Open the Management Interface - if (!mOvpn3) { - - // start a Thread that handles incoming messages of the managment socket - OpenVpnManagementThread ovpnManagementThread = new OpenVpnManagementThread(mProfile, this); - if (ovpnManagementThread.openManagementInterface(this)) { - - Thread mSocketManagerThread = new Thread(ovpnManagementThread, "OpenVPNManagementThread"); - mSocketManagerThread.start(); - mManagement = ovpnManagementThread; - VpnStatus.logInfo("started Socket Thread"); - } else { - return START_NOT_STICKY; - } - } - - - Runnable processThread; - if (mOvpn3) { - - OpenVPNManagement mOpenVPN3 = instantiateOpenVPN3Core(); - processThread = (Runnable) mOpenVPN3; - mManagement = mOpenVPN3; - - - } else { - HashMap<String, String> env = new HashMap<String, String>(); - processThread = new OpenVPNThread(this, argv, env, nativeLibraryDirectory); - } - - synchronized (mProcessLock) { - mProcessThread = new Thread(processThread, "OpenVPNProcessThread"); - mProcessThread.start(); - } - if (mDeviceStateReceiver != null) - unregisterDeviceStateReceiver(); - - registerDeviceStateReceiver(mManagement); - - - ProfileManager.setConnectedVpnProfile(this, mProfile); - /* TODO: At the moment we have no way to handle asynchronous PW input - * Fixing will also allow to handle challenge/responsee authentication */ - if (mProfile.needUserPWInput(true) != 0) - return START_NOT_STICKY; - - return START_STICKY; - } - - private OpenVPNManagement instantiateOpenVPN3Core() { - try { - Class cl = Class.forName("de.blinkt.openvpn.core.OpenVPNThreadv3"); - return (OpenVPNManagement) cl.getConstructor(OpenVPNService.class, VpnProfile.class).newInstance(this, mProfile); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public void onDestroy() { - synchronized (mProcessLock) { - if (mProcessThread != null) { - mManagement.stopVPN(); - } - } - - if (mDeviceStateReceiver != null) { - this.unregisterReceiver(mDeviceStateReceiver); - } - // Just in case unregister for state - VpnStatus.removeStateListener(this); - - } - - private String getTunConfigString() { - // The format of the string is not important, only that - // two identical configurations produce the same result - String cfg = "TUNCFG UNQIUE STRING ips:"; - - if (mLocalIP != null) - cfg += mLocalIP.toString(); - if (mLocalIPv6 != null) - cfg += mLocalIPv6; - - - cfg += "routes: " + TextUtils.join("|", mRoutes.getNetworks(true)) + TextUtils.join("|", mRoutesv6.getNetworks(true)); - cfg += "excl. routes:" + TextUtils.join("|", mRoutes.getNetworks(false)) + TextUtils.join("|", mRoutesv6.getNetworks(false)); - cfg += "dns: " + TextUtils.join("|", mDnslist); - cfg += "domain: " + mDomain; - cfg += "mtu: " + mMtu; - return cfg; - } - - public ParcelFileDescriptor openTun() { - - //Debug.startMethodTracing(getExternalFilesDir(null).toString() + "/opentun.trace", 40* 1024 * 1024); - - Builder builder = new Builder(); - - VpnStatus.logInfo(R.string.last_openvpn_tun_config); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mProfile.mAllowLocalLAN) - { - allowAllAFFamilies(builder); - } - - if (mLocalIP == null && mLocalIPv6 == null) { - VpnStatus.logError(getString(R.string.opentun_no_ipaddr)); - return null; - } - - if (mLocalIP != null) { - addLocalNetworksToRoutes(); - try { - builder.addAddress(mLocalIP.mIp, mLocalIP.len); - } catch (IllegalArgumentException iae) { - VpnStatus.logError(R.string.dns_add_error, mLocalIP, iae.getLocalizedMessage()); - return null; - } - } - - if (mLocalIPv6 != null) { - String[] ipv6parts = mLocalIPv6.split("/"); - try { - builder.addAddress(ipv6parts[0], Integer.parseInt(ipv6parts[1])); - } catch (IllegalArgumentException iae) { - VpnStatus.logError(R.string.ip_add_error, mLocalIPv6, iae.getLocalizedMessage()); - return null; - } - - } - - - for (String dns : mDnslist) { - try { - builder.addDnsServer(dns); - } catch (IllegalArgumentException iae) { - VpnStatus.logError(R.string.dns_add_error, dns, iae.getLocalizedMessage()); - } - } - - String release = Build.VERSION.RELEASE; - if ((Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && !release.startsWith("4.4.3") - && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6")) - && mMtu < 1280) { - VpnStatus.logInfo(String.format(Locale.US, "Forcing MTU to 1280 instead of %d to workaround Android Bug #70916", mMtu)); - builder.setMtu(1280); - } else { - builder.setMtu(mMtu); - } - - Collection<ipAddress> positiveIPv4Routes = mRoutes.getPositiveIPList(); - Collection<ipAddress> positiveIPv6Routes = mRoutesv6.getPositiveIPList(); - - for (NetworkSpace.ipAddress route : positiveIPv4Routes) { - try { - builder.addRoute(route.getIPv4Address(), route.networkMask); - } catch (IllegalArgumentException ia) { - VpnStatus.logError(getString(R.string.route_rejected) + route + " " + ia.getLocalizedMessage()); - } - } - - for (NetworkSpace.ipAddress route6 : positiveIPv6Routes) { - try { - builder.addRoute(route6.getIPv6Address(), route6.networkMask); - } catch (IllegalArgumentException ia) { - VpnStatus.logError(getString(R.string.route_rejected) + route6 + " " + ia.getLocalizedMessage()); - } - } - - if (mDomain != null) - builder.addSearchDomain(mDomain); - - VpnStatus.logInfo(R.string.local_ip_info, mLocalIP.mIp, mLocalIP.len, mLocalIPv6, mMtu); - VpnStatus.logInfo(R.string.dns_server_info, TextUtils.join(", ", mDnslist), mDomain); - VpnStatus.logInfo(R.string.routes_info_incl, TextUtils.join(", ", mRoutes.getNetworks(true)), TextUtils.join(", ", mRoutesv6.getNetworks(true))); - VpnStatus.logInfo(R.string.routes_info_excl, TextUtils.join(", ", mRoutes.getNetworks(false)), TextUtils.join(", ", mRoutesv6.getNetworks(false))); - VpnStatus.logDebug(R.string.routes_debug, TextUtils.join(", ", positiveIPv4Routes), TextUtils.join(", ", positiveIPv6Routes)); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - setAllowedVpnPackages(builder); - } - - - String session = mProfile.mName; - if (mLocalIP != null && mLocalIPv6 != null) - session = getString(R.string.session_ipv6string, session, mLocalIP, mLocalIPv6); - else if (mLocalIP != null) - session = getString(R.string.session_ipv4string, session, mLocalIP); - - builder.setSession(session); - - // No DNS Server, log a warning - if (mDnslist.size() == 0) - VpnStatus.logInfo(R.string.warn_no_dns); - - mLastTunCfg = getTunConfigString(); - - // Reset information - mDnslist.clear(); - mRoutes.clear(); - mRoutesv6.clear(); - mLocalIP = null; - mLocalIPv6 = null; - mDomain = null; - - builder.setConfigureIntent(getLogPendingIntent()); - - try { - //Debug.stopMethodTracing(); - return builder.establish(); - } catch (Exception e) { - VpnStatus.logError(R.string.tun_open_error); - VpnStatus.logError(getString(R.string.error) + e.getLocalizedMessage()); - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1) { - VpnStatus.logError(R.string.tun_error_helpful); - } - return null; - } - - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private void allowAllAFFamilies(Builder builder) { - builder.allowFamily(OsConstants.AF_INET); - builder.allowFamily(OsConstants.AF_INET6); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - void removeLollipopCMListener() { - ConnectivityManager cm = (ConnectivityManager) getBaseContext().getSystemService(CONNECTIVITY_SERVICE); - cm.unregisterNetworkCallback(mLollipopDeviceStateListener); - mLollipopDeviceStateListener = null; - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - void addLollipopCMListener() { - ConnectivityManager cm = (ConnectivityManager) getBaseContext().getSystemService(CONNECTIVITY_SERVICE); - NetworkRequest.Builder nrb = new NetworkRequest.Builder(); - - mLollipopDeviceStateListener = new LollipopDeviceStateListener(); - cm.registerNetworkCallback(nrb.build(), mLollipopDeviceStateListener); - } - - private void addLocalNetworksToRoutes() { - - // Add local network interfaces - String[] localRoutes = NativeUtils.getIfconfig(); - - // The format of mLocalRoutes is kind of broken because I don't really like JNI - for (int i = 0; i < localRoutes.length; i += 3) { - String intf = localRoutes[i]; - String ipAddr = localRoutes[i + 1]; - String netMask = localRoutes[i + 2]; - - if (intf == null || intf.equals("lo") || - intf.startsWith("tun") || intf.startsWith("rmnet")) - continue; - - if (ipAddr==null || netMask == null) { - VpnStatus.logError("Local routes are broken?! (Report to author) " + TextUtils.join("|", localRoutes)); - continue; - } - - if (ipAddr.equals(mLocalIP.mIp)) - continue; - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT && !mProfile.mAllowLocalLAN) { - mRoutes.addIPSplit(new CIDRIP(ipAddr, netMask), true); - - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && mProfile.mAllowLocalLAN) - mRoutes.addIP(new CIDRIP(ipAddr, netMask), false); - } - } - - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private void setAllowedVpnPackages(Builder builder) { - for (String pkg : mProfile.mAllowedAppsVpn) { - try { - if (mProfile.mAllowedAppsVpnAreDisallowed) { - builder.addDisallowedApplication(pkg); - } else { - builder.addAllowedApplication(pkg); - } - } catch (PackageManager.NameNotFoundException e) { - mProfile.mAllowedAppsVpn.remove(pkg); - VpnStatus.logInfo(R.string.app_no_longer_exists, pkg); - } - } - - if (mProfile.mAllowedAppsVpnAreDisallowed) { - VpnStatus.logDebug(R.string.disallowed_vpn_apps_info, TextUtils.join(", ", mProfile.mAllowedAppsVpn)); - } else { - VpnStatus.logDebug(R.string.allowed_vpn_apps_info, TextUtils.join(", ", mProfile.mAllowedAppsVpn)); - } - } - - public void addDNS(String dns) { - mDnslist.add(dns); - } - - public void setDomain(String domain) { - if (mDomain == null) { - mDomain = domain; - } - } - - /** - * Route that is always included, used by the v3 core - */ - public void addRoute(CIDRIP route) { - mRoutes.addIP(route, true); - } - - public void addRoute(String dest, String mask, String gateway, String device) { - CIDRIP route = new CIDRIP(dest, mask); - boolean include = isAndroidTunDevice(device); - - NetworkSpace.ipAddress gatewayIP = new NetworkSpace.ipAddress(new CIDRIP(gateway, 32), false); - - if (mLocalIP == null) { - VpnStatus.logError("Local IP address unset but adding route?! This is broken! Please contact author with log"); - return; - } - NetworkSpace.ipAddress localNet = new NetworkSpace.ipAddress(mLocalIP, true); - if (localNet.containsNet(gatewayIP)) - include = true; - - if (gateway != null && - (gateway.equals("255.255.255.255") || gateway.equals(mRemoteGW))) - include = true; - - - if (route.len == 32 && !mask.equals("255.255.255.255")) { - VpnStatus.logWarning(R.string.route_not_cidr, dest, mask); - } - - if (route.normalise()) - VpnStatus.logWarning(R.string.route_not_netip, dest, route.len, route.mIp); - - mRoutes.addIP(route, include); - } - - public void addRoutev6(String network, String device) { - String[] v6parts = network.split("/"); - boolean included = isAndroidTunDevice(device); - - // Tun is opened after ROUTE6, no device name may be present - - try { - Inet6Address ip = (Inet6Address) InetAddress.getAllByName(v6parts[0])[0]; - int mask = Integer.parseInt(v6parts[1]); - mRoutesv6.addIPv6(ip, mask, included); - - } catch (UnknownHostException e) { - VpnStatus.logException(e); - } - - - } - - private boolean isAndroidTunDevice(String device) { - return device != null && - (device.startsWith("tun") || "(null)".equals(device) || "vpnservice-tun".equals(device)); - } - - public void setMtu(int mtu) { - mMtu = mtu; - } - - public void setLocalIP(CIDRIP cdrip) { - mLocalIP = cdrip; - } - - public void setLocalIP(String local, String netmask, int mtu, String mode) { - mLocalIP = new CIDRIP(local, netmask); - mMtu = mtu; - mRemoteGW = null; - - long netMaskAsInt = CIDRIP.getInt(netmask); - - if (mLocalIP.len == 32 && !netmask.equals("255.255.255.255")) { - // get the netmask as IP - - int masklen; - long mask; - if ("net30".equals(mode)) { - masklen = 30; - mask = 0xfffffffc; - } else { - masklen = 31; - mask = 0xfffffffe; - } - - // Netmask is Ip address +/-1, assume net30/p2p with small net - if ((netMaskAsInt & mask) == (mLocalIP.getInt() & mask)) { - mLocalIP.len = masklen; - } else { - mLocalIP.len = 32; - if (!"p2p".equals(mode)) - VpnStatus.logWarning(R.string.ip_not_cidr, local, netmask, mode); - } - } - if (("p2p".equals(mode) && mLocalIP.len < 32) || ("net30".equals(mode) && mLocalIP.len < 30)) { - VpnStatus.logWarning(R.string.ip_looks_like_subnet, local, netmask, mode); - } - - - /* Workaround for Lollipop, it does not route traffic to the VPNs own network mask */ - if (mLocalIP.len <= 31 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - addRoute(mLocalIP); - - - // Configurations are sometimes really broken... - mRemoteGW = netmask; - } - - public void setLocalIPv6(String ipv6addr) { - mLocalIPv6 = ipv6addr; - } - - @Override - public void updateState(String state, String logmessage, int resid, ConnectionStatus level) { - // If the process is not running, ignore any state, - // Notification should be invisible in this state - - doSendBroadcast(state, level); - if (mProcessThread == null && !mNotificationAlwaysVisible) - return; - - boolean lowpriority = false; - // Display byte count only after being connected - - { - if (level == LEVEL_WAITING_FOR_USER_INPUT) { - // The user is presented a dialog of some kind, no need to inform the user - // with a notifcation - return; - } else if (level == LEVEL_CONNECTED) { - mDisplayBytecount = true; - mConnecttime = System.currentTimeMillis(); - lowpriority = true; - if(mProfile.mPersistTun) { - NotificationManager ns = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - ns.cancel(OPENVPN_STATUS); - return; - } - } else if (level == LEVEL_NONETWORK || level == LEVEL_NOTCONNECTED) { - NotificationManager ns = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - ns.cancel(OPENVPN_STATUS); - return; - } else if (level != LEVEL_NOTCONNECTED && mConnecttime > 0) { - mDisplayBytecount = false; - String msg = "Traffic is blocked until the VPN becomes active."; - String ticker = msg; - showNotification(msg, ticker, lowpriority , 0, level); - return; - } else { - mDisplayBytecount = false; - } - - // Other notifications are shown, - // This also mean we are no longer connected, ignore bytecount messages until next - // CONNECTED - // Does not work :( - String msg = getString(resid); - String ticker = msg; - showNotification(msg + " " + logmessage, ticker, lowpriority , 0, level); - } - } - - private void doSendBroadcast(String state, ConnectionStatus level) { - Intent vpnstatus = new Intent(); - vpnstatus.setAction("de.blinkt.openvpn.VPN_STATUS"); - vpnstatus.putExtra("status", level.toString()); - vpnstatus.putExtra("detailstatus", state); - sendBroadcast(vpnstatus, permission.ACCESS_NETWORK_STATE); - } - - @Override - public void updateByteCount(long in, long out, long diffIn, long diffOut) { - if (mDisplayBytecount) { - String netstat = String.format(getString(R.string.statusline_bytecount), - humanReadableByteCount(in, false), - humanReadableByteCount(diffIn / OpenVPNManagement.mBytecountInterval, true), - humanReadableByteCount(out, false), - humanReadableByteCount(diffOut / OpenVPNManagement.mBytecountInterval, true)); - - boolean lowpriority = !mNotificationAlwaysVisible; - //showNotification(netstat, null, lowpriority, mConnecttime, LEVEL_CONNECTED); - } - - } - - @Override - public boolean handleMessage(Message msg) { - Runnable r = msg.getCallback(); - if (r != null) { - r.run(); - return true; - } else { - return false; - } - } - - public OpenVPNManagement getManagement() { - return mManagement; - } - - public String getTunReopenStatus() { - String currentConfiguration = getTunConfigString(); - if (currentConfiguration.equals(mLastTunCfg)) { - return "NOACTION"; - } else { - String release = Build.VERSION.RELEASE; - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && !release.startsWith("4.4.3") - && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6")) - // There will be probably no 4.4.4 or 4.4.5 version, so don't waste effort to do parsing here - return "OPEN_AFTER_CLOSE"; - else - return "OPEN_BEFORE_CLOSE"; - } - } - - public class LocalBinder extends Binder { - public OpenVPNService getService() { - // Return this instance of LocalService so clients can call public methods - return OpenVPNService.this; - } - } -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java deleted file mode 100644 index 298a6c40..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import android.annotation.SuppressLint; -import android.util.Log; - -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.text.SimpleDateFormat; -import java.util.Collections; -import java.util.Date; -import java.util.LinkedList; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import se.leap.bitmaskclient.R; -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; -import de.blinkt.openvpn.core.VpnStatus.LogItem; - -public class OpenVPNThread implements Runnable { - private static final String DUMP_PATH_STRING = "Dump path: "; - @SuppressLint("SdCardPath") - private static final String BROKEN_PIE_SUPPORT = "/data/data/de.blinkt.openvpn/cache/pievpn[1]: syntax error:"; - private static final String TAG = "OpenVPN"; - public static final int M_FATAL = (1 << 4); - public static final int M_NONFATAL = (1 << 5); - public static final int M_WARN = (1 << 6); - public static final int M_DEBUG = (1 << 7); - private String[] mArgv; - private Process mProcess; - private String mNativeDir; - private OpenVPNService mService; - private String mDumpPath; - private Map<String, String> mProcessEnv; - private boolean mBrokenPie=false; - - public OpenVPNThread(OpenVPNService service,String[] argv, Map<String,String> processEnv, String nativelibdir) - { - mArgv = argv; - mNativeDir = nativelibdir; - mService = service; - mProcessEnv = processEnv; - } - - public void stopProcess() { - mProcess.destroy(); - } - - @Override - public void run() { - try { - Log.i(TAG, "Starting openvpn"); - startOpenVPNThreadArgs(mArgv, mProcessEnv); - Log.i(TAG, "Giving up"); - } catch (Exception e) { - VpnStatus.logException("Starting OpenVPN Thread" ,e); - Log.e(TAG, "OpenVPNThread Got " + e.toString()); - } finally { - int exitvalue = 0; - try { - if (mProcess!=null) - exitvalue = mProcess.waitFor(); - } catch ( IllegalThreadStateException ite) { - VpnStatus.logError("Illegal Thread state: " + ite.getLocalizedMessage()); - } catch (InterruptedException ie) { - VpnStatus.logError("InterruptedException: " + ie.getLocalizedMessage()); - } - if( exitvalue != 0) { - VpnStatus.logError("Process exited with exit value " + exitvalue); - if (mBrokenPie) { - /* This will probably fail since the NoPIE binary is probably not written */ - String[] noPieArgv = VPNLaunchHelper.replacePieWithNoPie(mArgv); - - // We are already noPIE, nothing to gain - if (!noPieArgv.equals(mArgv)) { - mArgv = noPieArgv; - VpnStatus.logInfo("PIE Version could not be executed. Trying no PIE version"); - run(); - return; - } - - } - - } - - VpnStatus.updateStateString("NOPROCESS", "No process running.", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED); - if(mDumpPath!=null) { - try { - BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log")); - SimpleDateFormat timeformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.GERMAN); - for(LogItem li : VpnStatus.getlogbuffer()){ - String time = timeformat.format(new Date(li.getLogtime())); - logout.write(time +" " + li.getString(mService) + "\n"); - } - logout.close(); - VpnStatus.logError(R.string.minidump_generated); - } catch (IOException e) { - VpnStatus.logError("Writing minidump log: " + e.getLocalizedMessage()); - } - } - - mService.processDied(); - Log.i(TAG, "Exiting"); - } - } - - private void startOpenVPNThreadArgs(String[] argv, Map<String, String> env) { - LinkedList<String> argvlist = new LinkedList<String>(); - - Collections.addAll(argvlist, argv); - - ProcessBuilder pb = new ProcessBuilder(argvlist); - // Hack O rama - - String lbpath = genLibraryPath(argv, pb); - - pb.environment().put("LD_LIBRARY_PATH", lbpath); - - // Add extra variables - for(Entry<String,String> e:env.entrySet()){ - pb.environment().put(e.getKey(), e.getValue()); - } - 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()); - - if (logline.startsWith(BROKEN_PIE_SUPPORT)) - mBrokenPie = true; - - - // 1380308330.240114 18000002 Send to HTTP proxy: 'X-Online-Host: bla.blabla.com' - - Pattern p = Pattern.compile("(\\d+).(\\d+) ([0-9a-f])+ (.*)"); - Matcher m = p.matcher(logline); - if(m.matches()) { - int flags = Integer.parseInt(m.group(3),16); - String msg = m.group(4); - int logLevel = flags & 0x0F; - - VpnStatus.LogLevel logStatus = VpnStatus.LogLevel.INFO; - - if ((flags & M_FATAL) != 0) - logStatus = VpnStatus.LogLevel.ERROR; - else if ((flags & M_NONFATAL)!=0) - logStatus = VpnStatus.LogLevel.WARNING; - else if ((flags & M_WARN)!=0) - logStatus = VpnStatus.LogLevel.WARNING; - else if ((flags & M_DEBUG)!=0) - logStatus = VpnStatus.LogLevel.VERBOSE; - - if (msg.startsWith("MANAGEMENT: CMD")) - logLevel = Math.max(4, logLevel); - - - VpnStatus.logMessageOpenVPN(logStatus,logLevel,msg); - } else { - VpnStatus.logInfo("P:" + logline); - } - } - - - } catch (IOException e) { - VpnStatus.logException("Error reading from output of OpenVPN process" , e); - stopProcess(); - } - - - } - - private String genLibraryPath(String[] argv, ProcessBuilder pb) { - // Hack until I find a good way to get the real library path - String applibpath = argv[0].replaceFirst("/cache/.*$" , "/lib"); - - String lbpath = pb.environment().get("LD_LIBRARY_PATH"); - if(lbpath==null) - lbpath = applibpath; - else - lbpath = applibpath + ":" + lbpath; - - if (!applibpath.equals(mNativeDir)) { - lbpath = mNativeDir + ":" + lbpath; - } - return lbpath; - } -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java deleted file mode 100644 index 1c3b3362..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import android.content.Context; -import android.content.SharedPreferences; -import android.net.LocalServerSocket; -import android.net.LocalSocket; -import android.net.LocalSocketAddress; -import android.os.ParcelFileDescriptor; -import android.preference.PreferenceManager; -import android.util.Log; - -import junit.framework.Assert; - -import org.jetbrains.annotations.NotNull; - -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.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.Locale; -import java.util.Vector; - -import se.leap.bitmaskclient.BuildConfig; -import se.leap.bitmaskclient.R; -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; - -public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { - - private static final String TAG = "openvpn"; - private LocalSocket mSocket; - private VpnProfile mProfile; - private OpenVPNService mOpenVPNService; - private LinkedList<FileDescriptor> mFDList = new LinkedList<FileDescriptor>(); - private LocalServerSocket mServerSocket; - private boolean mReleaseHold = true; - private boolean mWaitingForRelease = false; - private long mLastHoldRelease = 0; - - private static final Vector<OpenVpnManagementThread> active = new Vector<OpenVpnManagementThread>(); - private LocalSocket mServerSocketLocal; - - private pauseReason lastPauseReason = pauseReason.noNetwork; - - public OpenVpnManagementThread(VpnProfile profile, OpenVPNService openVpnService) { - mProfile = profile; - mOpenVPNService = openVpnService; - - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(openVpnService); - boolean managemeNetworkState = prefs.getBoolean("netchangereconnect", true); - if (managemeNetworkState) - mReleaseHold = false; - - } - - public boolean openManagementInterface(@NotNull Context c) { - // Could take a while to open connection - int tries = 8; - - String socketName = (c.getCacheDir().getAbsolutePath() + "/" + "mgmtsocket"); - // The mServerSocketLocal is transferred to the LocalServerSocket, ignore warning - - mServerSocketLocal = new LocalSocket(); - - while (tries > 0 && !mServerSocketLocal.isConnected()) { - try { - mServerSocketLocal.bind(new LocalSocketAddress(socketName, - LocalSocketAddress.Namespace.FILESYSTEM)); - } catch (IOException e) { - // wait 300 ms before retrying - try { - Thread.sleep(300); - } catch (InterruptedException e1) { - } - - } - tries--; - } - - try { - - mServerSocket = new LocalServerSocket(mServerSocketLocal.getFileDescriptor()); - return true; - } catch (IOException e) { - VpnStatus.logException(e); - } - return false; - - - } - - public void managmentCommand(String cmd) { - try { - if (mSocket != null && mSocket.getOutputStream() != null) { - mSocket.getOutputStream().write(cmd.getBytes()); - mSocket.getOutputStream().flush(); - } - } catch (IOException e) { - // Ignore socket stack traces - } - } - - - @Override - public void run() { - byte[] buffer = new byte[2048]; - // mSocket.setSoTimeout(5); // Setting a timeout cannot be that bad - - String pendingInput = ""; - synchronized (active) { - active.add(this); - } - - try { - // Wait for a client to connect - mSocket = mServerSocket.accept(); - InputStream instream = mSocket.getInputStream(); - // Close the management socket after client connected - - mServerSocket.close(); - // Closing one of the two sockets also closes the other - //mServerSocketLocal.close(); - - while (true) { - int numbytesread = instream.read(buffer); - if (numbytesread == -1) - return; - - FileDescriptor[] fds = null; - try { - fds = mSocket.getAncillaryFileDescriptors(); - } catch (IOException e) { - VpnStatus.logException("Error reading fds from socket", e); - } - if (fds != null) { - Collections.addAll(mFDList, fds); - } - - String input = new String(buffer, 0, numbytesread, "UTF-8"); - - pendingInput += input; - - pendingInput = processInput(pendingInput); - - - } - } catch (IOException e) { - if (!e.getMessage().equals("socket closed") && !e.getMessage().equals("Connection reset by peer")) - VpnStatus.logException(e); - } - synchronized (active) { - active.remove(this); - } - } - - //! Hack O Rama 2000! - private void protectFileDescriptor(FileDescriptor fd) { - Exception exp; - 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 :) - - boolean result = mOpenVPNService.protect(fdint); - if (!result) - VpnStatus.logWarning("Could not protect VPN socket"); - - - //ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(fdint); - //pfd.close(); - NativeUtils.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; - } - - Log.d("Openvpn", "Failed to retrieve fd from socket: " + fd); - VpnStatus.logException("Failed to retrieve fd from socket (" + fd + ")", exp); - } - - 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.i(TAG, "Line from managment" + 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 management */ - return; - } 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("PROXY")) { - processProxyCMD(argument); - } else if (cmd.equals("LOG")) { - processLogMessage(argument); - } else if (cmd.equals("RSA_SIGN")) { - processSignCommand(argument); - } else { - VpnStatus.logWarning("MGMT: Got unrecognized command" + command); - Log.i(TAG, "Got unrecognized command" + command); - } - } else if (command.startsWith("SUCCESS:")) { - /* Ignore this kind of message too */ - return; - } else if (command.startsWith("PROTECTFD: ")) { - FileDescriptor fdtoprotect = mFDList.pollFirst(); - if (fdtoprotect != null) - protectFileDescriptor(fdtoprotect); - } else { - Log.i(TAG, "Got unrecognized line from managment" + command); - VpnStatus.logWarning("MGMT: Got unrecognized line from management:" + command); - } - } - - private void processLogMessage(String argument) { - String[] args = argument.split(",", 4); - // 0 unix time stamp - // 1 log level N,I,E etc. - /* - (b) zero or more message flags in a single string: - I -- informational - F -- fatal error - N -- non-fatal error - W -- warning - D -- debug, and - */ - // 2 log message - - Log.d("OpenVPN", argument); - - VpnStatus.LogLevel level; - if (args[1].equals("I")) { - level = VpnStatus.LogLevel.INFO; - } else if (args[1].equals("W")) { - level = VpnStatus.LogLevel.WARNING; - } else if (args[1].equals("D")) { - level = VpnStatus.LogLevel.VERBOSE; - } else if (args[1].equals("F")) { - level = VpnStatus.LogLevel.ERROR; - } else { - level = VpnStatus.LogLevel.INFO; - } - - int ovpnlevel = Integer.parseInt(args[2]) & 0x0F; - String msg = args[3]; - - if (msg.startsWith("MANAGEMENT: CMD")) - ovpnlevel = Math.max(4, ovpnlevel); - - VpnStatus.logMessageOpenVPN(level, ovpnlevel, msg); - } - - private void handleHold() { - if (mReleaseHold) { - releaseHoldCmd(); - } else { - mWaitingForRelease = true; - - VpnStatus.updateStatePause(lastPauseReason); - - - } - } - - private void releaseHoldCmd() { - if ((System.currentTimeMillis() - mLastHoldRelease) < 5000) { - try { - Thread.sleep(3000); - } catch (InterruptedException ignored) { - } - - } - mWaitingForRelease = false; - mLastHoldRelease = System.currentTimeMillis(); - managmentCommand("hold release\n"); - managmentCommand("bytecount " + mBytecountInterval + "\n"); - managmentCommand("state on\n"); - //managmentCommand("log on all\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; - - VpnStatus.logInfo(R.string.using_proxy, isa.getHostName(), isa.getPort()); - - String proxycmd = String.format(Locale.ENGLISH, "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(",,")) - VpnStatus.updateStateString(currentstate, ""); - else - VpnStatus.updateStateString(currentstate, args[2]); - } - - - 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)); - - VpnStatus.updateByteCount(in, out); - - } - - - 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(" "); - - /* - buf_printf (&out, "%s %s %s dev %s", network, netmask, gateway, rgi->iface); - else - buf_printf (&out, "%s %s %s", network, netmask, gateway); - */ - - if (routeparts.length == 5) { - if (BuildConfig.DEBUG) Assert.assertEquals("dev", routeparts[3]); - mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], routeparts[4]); - } else if (routeparts.length >= 3) { - mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], null); - } else { - VpnStatus.logError("Unrecognized ROUTE cmd:" + Arrays.toString(routeparts) + " | " + argument); - } - - } else if (needed.equals("ROUTE6")) { - String[] routeparts = extra.split(" "); - mOpenVPNService.addRoutev6(routeparts[0], routeparts[1]); - } 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("PERSIST_TUN_ACTION")) { - // check if tun cfg stayed the same - status = mOpenVPNService.getTunReopenStatus(); - } 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; - if (!extra.equals("tun")) { - // We only support tun - VpnStatus.logError(String.format("Device type %s requested, but only tun is possible with the Android API, sorry!", extra)); - - 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); - - // 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; - } - VpnStatus.logException("Could not send fd over socket", exp); - - 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) { - VpnStatus.logError("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 { - VpnStatus.logError(String.format("Openvpn requires Authentication type '%s' but no password/key information available", needed)); - } - - } - - - private void proccessPWFailed(String needed, String args) { - VpnStatus.updateStateString("AUTH_FAILED", needed + args, R.string.state_auth_failed, ConnectionStatus.LEVEL_AUTH_FAILED); - } - - - private static boolean stopOpenVPN() { - synchronized (active) { - 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; - } - } - - @Override - public void networkChange() { - if (!mWaitingForRelease) - managmentCommand("network-change\n"); - } - - public void signalusr1() { - mReleaseHold = false; - - if (!mWaitingForRelease) - managmentCommand("signal SIGUSR1\n"); - else - // If signalusr1 is called update the state string - // if there is another for stopping - VpnStatus.updateStatePause(lastPauseReason); - } - - public void reconnect() { - signalusr1(); - releaseHold(); - } - - private void processSignCommand(String b64data) { - - String signed_string = mProfile.getSignedData(b64data); - if (signed_string == null) { - managmentCommand("rsa-sig\n"); - managmentCommand("\nEND\n"); - stopOpenVPN(); - return; - } - managmentCommand("rsa-sig\n"); - managmentCommand(signed_string); - managmentCommand("\nEND\n"); - } - - @Override - public void pause(pauseReason reason) { - lastPauseReason = reason; - signalusr1(); - } - - @Override - public void resume() { - releaseHold(); - /* Reset the reason why we are disconnected */ - lastPauseReason = pauseReason.noNetwork; - } - - @Override - public boolean stopVPN() { - return stopOpenVPN(); - } -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java deleted file mode 100644 index a788426a..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core;/* - * This software is provided 'as-is', without any express or implied - * warranty. In no event will Google be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, as long as the origin is not misrepresented. - */ - -import android.os.Build; -import android.os.Process; -import android.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.SecureRandomSpi; -import java.security.Security; - -/** - * Fixes for the output of the default PRNG having low entropy. - * - * The fixes need to be applied via {@link #apply()} before any use of Java - * Cryptography Architecture primitives. A good place to invoke them is in the - * application's {@code onCreate}. - */ -public final class PRNGFixes { - - private static final int VERSION_CODE_JELLY_BEAN = 16; - private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18; - private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL = - getBuildFingerprintAndDeviceSerial(); - - /** Hidden constructor to prevent instantiation. */ - private PRNGFixes() {} - - /** - * Applies all fixes. - * - * @throws SecurityException if a fix is needed but could not be applied. - */ - public static void apply() { - applyOpenSSLFix(); - installLinuxPRNGSecureRandom(); - } - - /** - * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the - * fix is not needed. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - private static void applyOpenSSLFix() throws SecurityException { - if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN) - || (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) { - // No need to apply the fix - return; - } - - try { - // Mix in the device- and invocation-specific seed. - Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto") - .getMethod("RAND_seed", byte[].class) - .invoke(null, generateSeed()); - - // Mix output of Linux PRNG into OpenSSL's PRNG - int bytesRead = (Integer) Class.forName( - "org.apache.harmony.xnet.provider.jsse.NativeCrypto") - .getMethod("RAND_load_file", String.class, long.class) - .invoke(null, "/dev/urandom", 1024); - if (bytesRead != 1024) { - throw new IOException( - "Unexpected number of bytes read from Linux PRNG: " - + bytesRead); - } - } catch (Exception e) { - throw new SecurityException("Failed to seed OpenSSL PRNG", e); - } - } - - /** - * Installs a Linux PRNG-backed {@code SecureRandom} implementation as the - * default. Does nothing if the implementation is already the default or if - * there is not need to install the implementation. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - private static void installLinuxPRNGSecureRandom() - throws SecurityException { - if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) { - // No need to apply the fix - return; - } - - // Install a Linux PRNG-based SecureRandom implementation as the - // default, if not yet installed. - Provider[] secureRandomProviders = - Security.getProviders("SecureRandom.SHA1PRNG"); - if ((secureRandomProviders == null) - || (secureRandomProviders.length < 1) - || (!LinuxPRNGSecureRandomProvider.class.equals( - secureRandomProviders[0].getClass()))) { - Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1); - } - - // Assert that new SecureRandom() and - // SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed - // by the Linux PRNG-based SecureRandom implementation. - SecureRandom rng1 = new SecureRandom(); - if (!LinuxPRNGSecureRandomProvider.class.equals( - rng1.getProvider().getClass())) { - throw new SecurityException( - "new SecureRandom() backed by wrong Provider: " - + rng1.getProvider().getClass()); - } - - SecureRandom rng2; - try { - rng2 = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - throw new SecurityException("SHA1PRNG not available", e); - } - if (!LinuxPRNGSecureRandomProvider.class.equals( - rng2.getProvider().getClass())) { - throw new SecurityException( - "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong" - + " Provider: " + rng2.getProvider().getClass()); - } - } - - /** - * {@code Provider} of {@code SecureRandom} engines which pass through - * all requests to the Linux PRNG. - */ - private static class LinuxPRNGSecureRandomProvider extends Provider { - - public LinuxPRNGSecureRandomProvider() { - super("LinuxPRNG", - 1.0, - "A Linux-specific random number provider that uses" - + " /dev/urandom"); - // Although /dev/urandom is not a SHA-1 PRNG, some apps - // explicitly request a SHA1PRNG SecureRandom and we thus need to - // prevent them from getting the default implementation whose output - // may have low entropy. - put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName()); - put("SecureRandom.SHA1PRNG ImplementedIn", "Software"); - } - } - - /** - * {@link SecureRandomSpi} which passes all requests to the Linux PRNG - * ({@code /dev/urandom}). - */ - public static class LinuxPRNGSecureRandom extends SecureRandomSpi { - - /* - * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed - * are passed through to the Linux PRNG (/dev/urandom). Instances of - * this class seed themselves by mixing in the current time, PID, UID, - * build fingerprint, and hardware serial number (where available) into - * Linux PRNG. - * - * Concurrency: Read requests to the underlying Linux PRNG are - * serialized (on sLock) to ensure that multiple threads do not get - * duplicated PRNG output. - */ - - private static final File URANDOM_FILE = new File("/dev/urandom"); - - private static final Object sLock = new Object(); - - /** - * Input stream for reading from Linux PRNG or {@code null} if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private static DataInputStream sUrandomIn; - - /** - * Output stream for writing to Linux PRNG or {@code null} if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private static OutputStream sUrandomOut; - - /** - * Whether this engine instance has been seeded. This is needed because - * each instance needs to seed itself if the client does not explicitly - * seed it. - */ - private boolean mSeeded; - - @Override - protected void engineSetSeed(byte[] bytes) { - try { - OutputStream out; - synchronized (sLock) { - out = getUrandomOutputStream(); - } - out.write(bytes); - out.flush(); - } catch (IOException e) { - // On a small fraction of devices /dev/urandom is not writable. - // Log and ignore. - Log.w(PRNGFixes.class.getSimpleName(), - "Failed to mix seed into " + URANDOM_FILE); - } finally { - mSeeded = true; - } - } - - @Override - protected void engineNextBytes(byte[] bytes) { - if (!mSeeded) { - // Mix in the device- and invocation-specific seed. - engineSetSeed(generateSeed()); - } - - try { - DataInputStream in; - synchronized (sLock) { - in = getUrandomInputStream(); - } - synchronized (in) { - in.readFully(bytes); - } - } catch (IOException e) { - throw new SecurityException( - "Failed to read from " + URANDOM_FILE, e); - } - } - - @Override - protected byte[] engineGenerateSeed(int size) { - byte[] seed = new byte[size]; - engineNextBytes(seed); - return seed; - } - - private DataInputStream getUrandomInputStream() { - synchronized (sLock) { - if (sUrandomIn == null) { - // NOTE: Consider inserting a BufferedInputStream between - // DataInputStream and FileInputStream if you need higher - // PRNG output performance and can live with future PRNG - // output being pulled into this process prematurely. - try { - sUrandomIn = new DataInputStream( - new FileInputStream(URANDOM_FILE)); - } catch (IOException e) { - throw new SecurityException("Failed to open " - + URANDOM_FILE + " for reading", e); - } - } - return sUrandomIn; - } - } - - private OutputStream getUrandomOutputStream() throws IOException { - synchronized (sLock) { - if (sUrandomOut == null) { - sUrandomOut = new FileOutputStream(URANDOM_FILE); - } - return sUrandomOut; - } - } - } - - /** - * Generates a device- and invocation-specific seed to be mixed into the - * Linux PRNG. - */ - private static byte[] generateSeed() { - try { - ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream(); - DataOutputStream seedBufferOut = - new DataOutputStream(seedBuffer); - seedBufferOut.writeLong(System.currentTimeMillis()); - seedBufferOut.writeLong(System.nanoTime()); - seedBufferOut.writeInt(Process.myPid()); - seedBufferOut.writeInt(Process.myUid()); - seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL); - seedBufferOut.close(); - return seedBuffer.toByteArray(); - } catch (IOException e) { - throw new SecurityException("Failed to generate seed", e); - } - } - - /** - * Gets the hardware serial number of this device. - * - * @return serial number or {@code null} if not available. - */ - private static String getDeviceSerialNumber() { - // We're using the Reflection API because Build.SERIAL is only available - // since API Level 9 (Gingerbread, Android 2.3). - try { - return (String) Build.class.getField("SERIAL").get(null); - } catch (Exception ignored) { - return null; - } - } - - private static byte[] getBuildFingerprintAndDeviceSerial() { - StringBuilder result = new StringBuilder(); - String fingerprint = Build.FINGERPRINT; - if (fingerprint != null) { - result.append(fingerprint); - } - String serial = getDeviceSerialNumber(); - if (serial != null) { - result.append(serial); - } - try { - return result.toString().getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 encoding not supported"); - } - } -}
\ No newline at end of file diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ProfileManager.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ProfileManager.java deleted file mode 100644 index 1ebc0a57..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ProfileManager.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import 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 de.blinkt.openvpn.VpnProfile; - -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 LAST_CONNECTED_PROFILE = "lastConnectedProfile"; - - - - private static ProfileManager instance; - - - - private static VpnProfile mLastConnectedVpn=null; - private HashMap<String,VpnProfile> profiles=new HashMap<String, VpnProfile>(); - private static VpnProfile tmpprofile=null; - - - private 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(LAST_CONNECTED_PROFILE, null); - prefsedit.apply(); - - } - - public static void setConnectedVpnProfile(Context c, VpnProfile connectedrofile) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - Editor prefsedit = prefs.edit(); - - prefsedit.putString(LAST_CONNECTED_PROFILE, connectedrofile.getUUIDString()); - prefsedit.apply(); - mLastConnectedVpn=connectedrofile; - - } - - public static VpnProfile getLastConnectedProfile(Context c, boolean onBoot) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - - boolean useStartOnBoot = prefs.getBoolean("restartvpnonboot", false); - - if (onBoot && !useStartOnBoot) - return null; - - String lastConnectedProfile = prefs.getString(LAST_CONNECTED_PROFILE, null); - if(lastConnectedProfile!=null) - return get(c, lastConnectedProfile); - else - return null; - } - - - - - public Collection<VpnProfile> 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) { - - VpnStatus.logException("saving VPN profile", e); - throw new RuntimeException(e); - } catch (IOException e) { - VpnStatus.logException("saving VPN profile", e); - throw new RuntimeException(e); - } - } - - - private void loadVPNList(Context context) { - profiles = new HashMap<String, VpnProfile>(); - SharedPreferences listpref = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); - Set<String> vlist = listpref.getStringSet("vpnlist", null); - Exception exp =null; - if(vlist==null){ - vlist = new HashSet<String>(); - } - - 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; - - vp.upgradeProfile(); - 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) { - VpnStatus.logException("Loading VPN List",exp); - } - } - } - - 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/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java deleted file mode 100644 index 6e2abb13..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import 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; -import de.blinkt.openvpn.VpnProfile; - -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) { - VpnStatus.logError(R.string.getproxy_error, e.getLocalizedMessage()); - } catch (URISyntaxException e) { - VpnStatus.logError(R.string.getproxy_error, e.getLocalizedMessage()); - } - return null; - } - - static Proxy getFirstProxy(URL url) throws URISyntaxException { - System.setProperty("java.net.useSystemProxies", "true"); - - List<Proxy> 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/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java deleted file mode 100644 index 73ed05bc..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.os.Build; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Vector; - -import se.leap.bitmaskclient.R; -import de.blinkt.openvpn.VpnProfile; - -public class VPNLaunchHelper { - private static final String MININONPIEVPN = "nopievpn"; - private static final String MINIPIEVPN = "pievpn"; - private static final String OVPNCONFIGFILE = "android.conf"; - - - - static private String writeMiniVPN(Context context) { - String[] abis; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - abis = getSupportedAbisLollipop(); - else - abis = new String[]{Build.CPU_ABI, Build.CPU_ABI2}; - - for (String abi: abis) { - - File mvpnout = new File(context.getCacheDir(), getMiniVPNExecutableName() + "." + abi); - if ((mvpnout.exists() && mvpnout.canExecute()) || writeMiniVPNBinary(context, abi, mvpnout)) { - return mvpnout.getPath(); - } - } - - return null; - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private static String[] getSupportedAbisLollipop() { - return Build.SUPPORTED_ABIS; - } - - private static String getMiniVPNExecutableName() - { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) - return MINIPIEVPN; - else - return MININONPIEVPN; - } - - - public static String[] replacePieWithNoPie(String[] mArgv) - { - mArgv[0] = mArgv[0].replace(MINIPIEVPN, MININONPIEVPN); - return mArgv; - } - - - public static String[] buildOpenvpnArgv(Context c) { - Vector<String> args = new Vector<String>(); - - // Add fixed paramenters - //args.add("/data/data/de.blinkt.openvpn/lib/openvpn"); - args.add(writeMiniVPN(c)); - - args.add("--config"); - args.add(c.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); - - return args.toArray(new String[args.size()]); - } - - private static boolean writeMiniVPNBinary(Context context, String abi, File mvpnout) { - try { - InputStream mvpn; - - try { - mvpn = context.getAssets().open(getMiniVPNExecutableName() + "." + abi); - } - catch (IOException errabi) { - VpnStatus.logInfo("Failed getting assets for archicture " + abi); - return false; - } - - - 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)) { - VpnStatus.logError("Failed to make OpenVPN executable"); - return false; - } - - - return true; - } catch (IOException e) { - VpnStatus.logException(e); - return false; - } - - } - - - public static void startOpenVpn(VpnProfile startprofile, Context context) { - if(writeMiniVPN(context)==null) { - VpnStatus.logError("Error writing minivpn binary"); - return; - } - - VpnStatus.logInfo(R.string.building_configration); - - Intent startVPN = startprofile.prepareStartService(context); - if(startVPN!=null) - context.startService(startVPN); - - } - - public static String getConfigFilePath(Context context) { - return context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE; - } - -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java deleted file mode 100644 index ffc8097d..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.Signature; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import se.leap.bitmaskclient.R; - -import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.FormatFlagsConversionMismatchException; -import java.util.LinkedList; -import java.util.Locale; -import java.util.UnknownFormatConversionException; -import java.util.Vector; - -public class VpnStatus { - - - public static LinkedList<LogItem> logbuffer; - - private static Vector<LogListener> logListener; - private static Vector<StateListener> stateListener; - private static Vector<ByteCountListener> byteCountListener; - - private static String mLaststatemsg=""; - - private static String mLaststate = "NOPROCESS"; - - private static int mLastStateresid=R.string.state_noprocess; - - private static long mlastByteCount[]={0,0,0,0}; - - public static void logException(LogLevel ll, String context, Exception e) { - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - LogItem li; - if (context !=null) { - li = new LogItem(ll, R.string.unhandled_exception_context, e.getMessage(), sw.toString(), context); - } else { - li = new LogItem(ll, R.string.unhandled_exception, e.getMessage(), sw.toString()); - } - newLogItem(li); - } - - public static void logException(Exception e) { - logException(LogLevel.ERROR, null, e); - } - - public static void logException(String context, Exception e) { - logException(LogLevel.ERROR, context, e); - } - - private static final int MAXLOGENTRIES = 1000; - - public static final String MANAGMENT_PREFIX = "M:"; - - public enum ConnectionStatus { - LEVEL_CONNECTED, - LEVEL_VPNPAUSED, - LEVEL_CONNECTING_SERVER_REPLIED, - LEVEL_CONNECTING_NO_SERVER_REPLY_YET, - LEVEL_NONETWORK, - LEVEL_NOTCONNECTED, - LEVEL_AUTH_FAILED, - LEVEL_WAITING_FOR_USER_INPUT, - UNKNOWN_LEVEL - } - - public enum LogLevel { - INFO(2), - ERROR(-2), - WARNING(1), - VERBOSE(3), - DEBUG(4); - - protected int mValue; - LogLevel(int value) { - mValue = value; - } - - public int getInt() { - return mValue; - } - - public static LogLevel getEnumByValue(int value) { - switch (value) { - case 1: return INFO; - case 2: return ERROR; - case 3: return WARNING; - case 4: return DEBUG; - default: return null; - } - } - } - - // keytool -printcert -jarfile de.blinkt.openvpn_85.apk - public static final byte[] officalkey = {-58, -42, -44, -106, 90, -88, -87, -88, -52, -124, 84, 117, 66, 79, -112, -111, -46, 86, -37, 109}; - public static final byte[] officaldebugkey = {-99, -69, 45, 71, 114, -116, 82, 66, -99, -122, 50, -70, -56, -111, 98, -35, -65, 105, 82, 43}; - public static final byte[] amazonkey = {-116, -115, -118, -89, -116, -112, 120, 55, 79, -8, -119, -23, 106, -114, -85, -56, -4, 105, 26, -57}; - public static final byte[] fdroidkey = {-92, 111, -42, -46, 123, -96, -60, 79, -27, -31, 49, 103, 11, -54, -68, -27, 17, 2, 121, 104}; - - - private static ConnectionStatus mLastLevel=ConnectionStatus.LEVEL_NOTCONNECTED; - - static { - logbuffer = new LinkedList<LogItem>(); - logListener = new Vector<VpnStatus.LogListener>(); - stateListener = new Vector<VpnStatus.StateListener>(); - byteCountListener = new Vector<VpnStatus.ByteCountListener>(); - logInformation(); - } - - - public static class LogItem implements Parcelable { - - - private Object [] mArgs = null; - private String mMessage = null; - private int mRessourceId; - // Default log priority - LogLevel mLevel = LogLevel.INFO; - private long logtime = System.currentTimeMillis(); - private int mVerbosityLevel = -1; - - private LogItem(int ressourceId, Object[] args) { - mRessourceId = ressourceId; - mArgs = args; - } - - public LogItem(LogLevel level, int verblevel, String message) { - mMessage=message; - mLevel = level; - mVerbosityLevel = verblevel; - } - - @Override - public int describeContents() { - return 0; - } - - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeArray(mArgs); - dest.writeString(mMessage); - dest.writeInt(mRessourceId); - dest.writeInt(mLevel.getInt()); - dest.writeInt(mVerbosityLevel); - - dest.writeLong(logtime); - } - - public LogItem(Parcel in) { - mArgs = in.readArray(Object.class.getClassLoader()); - mMessage = in.readString(); - mRessourceId = in.readInt(); - mLevel = LogLevel.getEnumByValue(in.readInt()); - mVerbosityLevel = in.readInt(); - logtime = in.readLong(); - } - - public static final Parcelable.Creator<LogItem> CREATOR - = new Parcelable.Creator<LogItem>() { - public LogItem createFromParcel(Parcel in) { - return new LogItem(in); - } - - public LogItem[] newArray(int size) { - return new LogItem[size]; - } - }; - - public LogItem(LogLevel loglevel,int ressourceId, Object... args) { - mRessourceId = ressourceId; - mArgs =args; - mLevel = loglevel; - } - - - public LogItem(LogLevel loglevel, String msg) { - mLevel = loglevel; - mMessage = msg; - } - - - public LogItem(LogLevel loglevel, int ressourceId) { - mRessourceId =ressourceId; - mLevel = loglevel; - } - - public String getString(Context c) { - try { - if(mMessage !=null) { - return mMessage; - } else { - if(c!=null) { - if(mRessourceId==R.string.mobile_info) - return getMobileInfoString(c); - 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; - } - } - } catch (UnknownFormatConversionException e) { - if (c != null) - throw new UnknownFormatConversionException(e.getLocalizedMessage() + getString(null)); - else - throw e; - } catch (java.util.FormatFlagsConversionMismatchException e) { - if (c != null) - throw new FormatFlagsConversionMismatchException(e.getLocalizedMessage() + getString(null),e.getConversion()); - else - throw e; - } - - } - - public LogLevel getLogLevel() - { - return mLevel; - } - - // The lint is wrong here - @SuppressLint("StringFormatMatches") - private String getMobileInfoString(Context c) { - c.getPackageManager(); - String apksign="error getting package signature"; - - String version="error getting version"; - try { - Signature raw = c.getPackageManager().getPackageInfo(c.getPackageName(), PackageManager.GET_SIGNATURES).signatures[0]; - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray())); - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] der = cert.getEncoded(); - md.update(der); - byte[] digest = md.digest(); - - if (Arrays.equals(digest, officalkey)) - apksign = c.getString(R.string.official_build); - else if (Arrays.equals(digest, officaldebugkey)) - apksign = c.getString(R.string.debug_build); - else if (Arrays.equals(digest, amazonkey)) - apksign = "amazon version"; - else if (Arrays.equals(digest, fdroidkey)) - apksign = "F-Droid built and signed version"; - else - apksign = c.getString(R.string.built_by,cert.getSubjectX500Principal().getName()); - - PackageInfo packageinfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0); - version = packageinfo.versionName; - - } catch (NameNotFoundException e) { - } catch (CertificateException e) { - } catch (NoSuchAlgorithmException e) { - } - - Object[] argsext = Arrays.copyOf(mArgs, mArgs.length+2); - argsext[argsext.length-1]=apksign; - argsext[argsext.length-2]=version; - - return c.getString(R.string.mobile_info_extended, argsext); - - } - - public long getLogtime() { - return logtime; - } - - - public int getVerbosityLevel() { - if (mVerbosityLevel==-1) { - // Hack: - // For message not from OpenVPN, report the status level as log level - return mLevel.getInt(); - } - return mVerbosityLevel; - } - } - - - - public interface LogListener { - void newLog(LogItem logItem); - } - - public interface StateListener { - void updateState(String state, String logmessage, int localizedResId, ConnectionStatus level); - } - - public interface ByteCountListener { - void updateByteCount(long in, long out, long diffIn, long diffOut); - } - - public synchronized static void logMessage(LogLevel level,String prefix, String message) - { - newLogItem(new LogItem(level, prefix + message)); - - } - - public 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 addByteCountListener(ByteCountListener bcl) { - bcl.updateByteCount(mlastByteCount[0], mlastByteCount[1], mlastByteCount[2], mlastByteCount[3]); - byteCountListener.add(bcl); - } - - public synchronized static void removeByteCountListener(ByteCountListener bcl) { - byteCountListener.remove(bcl); - } - - - public synchronized static void addStateListener(StateListener sl){ - if(!stateListener.contains(sl)){ - stateListener.add(sl); - if(mLaststate!=null) - sl.updateState(mLaststate, mLaststatemsg, mLastStateresid, mLastLevel); - } - } - - 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("DISCONNECTED")) - return R.string.state_disconnected; - 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 - return R.string.unknown_state; - - } - - public static void updateStatePause(OpenVPNManagement.pauseReason pauseReason) { - switch (pauseReason) { - case noNetwork: - VpnStatus.updateStateString("NONETWORK", "", R.string.state_nonetwork, ConnectionStatus.LEVEL_NONETWORK); - break; - case screenOff: - VpnStatus.updateStateString("SCREENOFF", "", R.string.state_screenoff, ConnectionStatus.LEVEL_VPNPAUSED); - break; - case userPause: - VpnStatus.updateStateString("USERPAUSE", "", R.string.state_userpause, ConnectionStatus.LEVEL_VPNPAUSED); - break; - } - - } - - private static ConnectionStatus getLevel(String state){ - String[] noreplyet = {"CONNECTING","WAIT", "RECONNECTING", "RESOLVE", "TCP_CONNECT"}; - String[] reply = {"AUTH","GET_CONFIG","ASSIGN_IP","ADD_ROUTES"}; - String[] connected = {"CONNECTED"}; - String[] notconnected = {"DISCONNECTED", "EXITING"}; - - for(String x:noreplyet) - if(state.equals(x)) - return ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; - - for(String x:reply) - if(state.equals(x)) - return ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED; - - for(String x:connected) - if(state.equals(x)) - return ConnectionStatus.LEVEL_CONNECTED; - - for(String x:notconnected) - if(state.equals(x)) - return ConnectionStatus.LEVEL_NOTCONNECTED; - - return ConnectionStatus.UNKNOWN_LEVEL; - - } - - - - - 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 logbuffer.toArray(new LogItem[logbuffer.size()]); - - } - - public static void updateStateString (String state, String msg) { - int rid = getLocalizedState(state); - ConnectionStatus level = getLevel(state); - updateStateString(state, msg, rid, level); - } - - public synchronized static void updateStateString(String state, String msg, int resid, ConnectionStatus level) { - // Workound for OpenVPN doing AUTH and wait and being connected - // Simply ignore these state - if (mLastLevel == ConnectionStatus.LEVEL_CONNECTED && - (state.equals("WAIT") || state.equals("AUTH"))) - { - newLogItem(new LogItem((LogLevel.DEBUG), String.format("Ignoring OpenVPN Status in CONNECTED state (%s->%s): %s",state,level.toString(),msg))); - return; - } - - mLaststate= state; - mLaststatemsg = msg; - mLastStateresid = resid; - mLastLevel = level; - - - - for (StateListener sl : stateListener) { - sl.updateState(state,msg,resid,level); - } - //newLogItem(new LogItem((LogLevel.DEBUG), String.format("New OpenVPN Status (%s->%s): %s",state,level.toString(),msg))); - } - - public static void logInfo(String message) { - newLogItem(new LogItem(LogLevel.INFO, message)); - } - - public static void logDebug(String message) { - newLogItem(new LogItem(LogLevel.DEBUG, message)); - } - - public static void logInfo(int resourceId, Object... args) { - newLogItem(new LogItem(LogLevel.INFO, resourceId, args)); - } - - public static void logDebug(int resourceId, Object... args) { - newLogItem(new LogItem(LogLevel.DEBUG, resourceId, args)); - } - - - private synchronized 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(LogLevel.ERROR, msg)); - - } - - public static void logWarning(int resourceId, Object... args) { - newLogItem(new LogItem(LogLevel.WARNING, resourceId, args)); - } - - public static void logWarning(String msg) { - newLogItem(new LogItem(LogLevel.WARNING, msg)); - } - - - public static void logError(int resourceId) { - newLogItem(new LogItem(LogLevel.ERROR, resourceId)); - } - public static void logError(int resourceId, Object... args) { - newLogItem(new LogItem(LogLevel.ERROR, resourceId, args)); - } - - public static void logMessageOpenVPN(LogLevel level, int ovpnlevel, String message) { - newLogItem(new LogItem(level, ovpnlevel, message)); - - } - - - public static synchronized void updateByteCount(long in, long out) { - long lastIn = mlastByteCount[0]; - long lastOut = mlastByteCount[1]; - long diffIn = mlastByteCount[2] = in - lastIn; - long diffOut = mlastByteCount[3] = out - lastOut; - - - - mlastByteCount = new long[] {in,out,diffIn,diffOut}; - for(ByteCountListener bcl:byteCountListener){ - bcl.updateByteCount(in, out, diffIn,diffOut); - } - } - - - -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java deleted file mode 100644 index 0786967b..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core; - -import android.content.Context; -import android.text.TextUtils; - -import se.leap.bitmaskclient.R; -import de.blinkt.openvpn.VpnProfile; -import org.spongycastle.util.io.pem.PemObject; -import org.spongycastle.util.io.pem.PemReader; - - -import javax.security.auth.x500.X500Principal; -import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Hashtable; - -public class X509Utils { - public static Certificate getCertificateFromFile(String certfilename) throws FileNotFoundException, CertificateException { - CertificateFactory certFact = CertificateFactory.getInstance("X.509"); - - InputStream inStream; - - if(VpnProfile.isEmbedded(certfilename)) { - // The java certifcate reader is ... kind of stupid - // It does NOT ignore chars before the --BEGIN ... - int subIndex = certfilename.indexOf("-----BEGIN CERTIFICATE-----"); - subIndex = Math.max(0,subIndex); - inStream = new ByteArrayInputStream(certfilename.substring(subIndex).getBytes()); - - - } else { - inStream = new FileInputStream(certfilename); - } - - - return certFact.generateCertificate(inStream); - } - - public static PemObject readPemObjectFromFile (String keyfilename) throws IOException { - - Reader inStream; - - if(VpnProfile.isEmbedded(keyfilename)) - inStream = new StringReader(VpnProfile.getEmbeddedContent(keyfilename)); - else - inStream = new FileReader(new File(keyfilename)); - - PemReader pr = new PemReader(inStream); - PemObject r = pr.readPemObject(); - pr.close(); - return r; - } - - - - - public static String getCertificateFriendlyName (Context c, String filename) { - if(!TextUtils.isEmpty(filename)) { - try { - X509Certificate cert = (X509Certificate) getCertificateFromFile(filename); - - return getCertificateFriendlyName(cert); - - } catch (Exception e) { - VpnStatus.logError("Could not read certificate" + e.getLocalizedMessage()); - } - } - return c.getString(R.string.cannotparsecert); - } - - public static String getCertificateFriendlyName(X509Certificate cert) { - X500Principal principal = cert.getSubjectX500Principal(); - byte[] encodedSubject = principal.getEncoded(); - String friendlyName=null; - - /* Hack so we do not have to ship a whole Spongy/bouncycastle */ - Exception exp=null; - try { - Class X509NameClass = Class.forName("com.android.org.bouncycastle.asn1.x509.X509Name"); - Method getInstance = X509NameClass.getMethod("getInstance",Object.class); - - Hashtable defaultSymbols = (Hashtable) X509NameClass.getField("DefaultSymbols").get(X509NameClass); - - if (!defaultSymbols.containsKey("1.2.840.113549.1.9.1")) - defaultSymbols.put("1.2.840.113549.1.9.1","eMail"); - - Object subjectName = getInstance.invoke(X509NameClass, encodedSubject); - - Method toString = X509NameClass.getMethod("toString",boolean.class,Hashtable.class); - - friendlyName= (String) toString.invoke(subjectName,true,defaultSymbols); - - } catch (ClassNotFoundException e) { - exp =e ; - } catch (NoSuchMethodException e) { - exp =e; - } catch (InvocationTargetException e) { - exp =e; - } catch (IllegalAccessException e) { - exp =e; - } catch (NoSuchFieldException e) { - exp =e; - } - if (exp!=null) - VpnStatus.logException("Getting X509 Name from certificate", exp); - - /* Fallback if the reflection method did not work */ - if(friendlyName==null) - friendlyName = principal.getName(); - - - // Really evil hack to decode email address - // See: http://code.google.com/p/android/issues/detail?id=21531 - - String[] parts = friendlyName.split(","); - for (int i=0;i<parts.length;i++){ - String part = parts[i]; - if (part.startsWith("1.2.840.113549.1.9.1=#16")) { - parts[i] = "email=" + ia5decode(part.replace("1.2.840.113549.1.9.1=#16", "")); - } - } - friendlyName = TextUtils.join(",", parts); - return friendlyName; - } - - public static boolean isPrintableChar(char c) { - Character.UnicodeBlock block = Character.UnicodeBlock.of( c ); - return (!Character.isISOControl(c)) && - block != null && - block != Character.UnicodeBlock.SPECIALS; - } - - private static String ia5decode(String ia5string) { - String d = ""; - for (int i=1;i<ia5string.length();i=i+2) { - String hexstr = ia5string.substring(i-1,i+1); - char c = (char) Integer.parseInt(hexstr,16); - if (isPrintableChar(c)) { - d+=c; - } else if (i==1 && (c==0x12 || c==0x1b)) { - ; // ignore - } else { - d += "\\x" + hexstr; - } - } - return d; - } - - -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java deleted file mode 100644 index 92bf9ad3..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.fragments; - -import se.leap.bitmaskclient.R; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ListFragment; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.database.DataSetObserver; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Handler; -import android.os.Handler.Callback; -import android.os.Message; -import android.text.SpannableString; -import android.text.format.DateFormat; -import android.text.style.ImageSpan; -import android.view.LayoutInflater; -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.LinearLayout; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.RadioGroup; -import android.widget.SeekBar; -import android.widget.TextView; -import android.widget.Toast; - -import org.jetbrains.annotations.Nullable; - -import java.text.SimpleDateFormat; -import java.util.Collections; -import java.util.Date; -import java.util.Locale; -import java.util.Vector; - -import de.blinkt.openvpn.LaunchVPN; -import se.leap.bitmaskclient.R; -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.activities.DisconnectVPN; -import de.blinkt.openvpn.core.OpenVPNManagement; -import de.blinkt.openvpn.core.OpenVPNService; -import de.blinkt.openvpn.core.ProfileManager; -import de.blinkt.openvpn.core.VpnStatus; -import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; -import de.blinkt.openvpn.core.VpnStatus.LogItem; -import de.blinkt.openvpn.core.VpnStatus.LogListener; -import de.blinkt.openvpn.core.VpnStatus.StateListener; - -import static de.blinkt.openvpn.core.OpenVPNService.humanReadableByteCount; - -import se.leap.bitmaskclient.Dashboard; - -public class LogFragment extends ListFragment implements StateListener, SeekBar.OnSeekBarChangeListener, RadioGroup.OnCheckedChangeListener, VpnStatus.ByteCountListener { - private static final String LOGTIMEFORMAT = "logtimeformat"; - private static final int START_VPN_CONFIG = 0; - private static final String VERBOSITYLEVEL = "verbositylevel"; - - - private SeekBar mLogLevelSlider; - private LinearLayout mOptionsLayout; - private RadioGroup mTimeRadioGroup; - private TextView mUpStatus; - private TextView mDownStatus; - private TextView mConnectStatus; - private boolean mShowOptionsLayout; - - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - ladapter.setLogLevel(progress+1); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onCheckedChanged(RadioGroup group, int checkedId) { - switch (checkedId) { - case R.id.radioISO: - ladapter.setTimeFormat(LogWindowListAdapter.TIME_FORMAT_ISO); - break; - case R.id.radioNone: - ladapter.setTimeFormat(LogWindowListAdapter.TIME_FORMAT_NONE); - break; - case R.id.radioShort: - ladapter.setTimeFormat(LogWindowListAdapter.TIME_FORMAT_SHORT); - break; - - } - } - - @Override - public void updateByteCount(long in, long out, long diffIn, long diffOut) { - //%2$s/s %1$s - ↑%4$s/s %3$s - final String down = String.format("%2$s/s %1$s", humanReadableByteCount(in, false), humanReadableByteCount(diffIn / OpenVPNManagement.mBytecountInterval, true)); - final String up = String.format("%2$s/s %1$s", humanReadableByteCount(out, false), humanReadableByteCount(diffOut / OpenVPNManagement.mBytecountInterval, true)); - - if (mUpStatus != null && mDownStatus != null) { - if (getActivity() != null) { - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - mUpStatus.setText(up); - mDownStatus.setText(down); - } - }); - } - } - - } - - - class LogWindowListAdapter implements ListAdapter, LogListener, Callback { - - private static final int MESSAGE_NEWLOG = 0; - - private static final int MESSAGE_CLEARLOG = 1; - - private static final int MESSAGE_NEWTS = 2; - private static final int MESSAGE_NEWLOGLEVEL = 3; - - public static final int TIME_FORMAT_NONE = 0; - public static final int TIME_FORMAT_SHORT = 1; - public static final int TIME_FORMAT_ISO = 2; - private static final int MAX_STORED_LOG_ENTRIES = 1000; - - private Vector<LogItem> allEntries=new Vector<LogItem>(); - - private Vector<LogItem> currentLevelEntries=new Vector<LogItem>(); - - private Handler mHandler; - - private Vector<DataSetObserver> observers=new Vector<DataSetObserver>(); - - private int mTimeFormat=0; - private int mLogLevel=3; - - - public LogWindowListAdapter() { - initLogBuffer(); - if (mHandler == null) { - mHandler = new Handler(this); - } - - VpnStatus.addLogListener(this); - } - - - - private void initLogBuffer() { - allEntries.clear(); - Collections.addAll(allEntries, VpnStatus.getlogbuffer()); - initCurrentMessages(); - } - - String getLogStr() { - String str = ""; - for(LogItem entry:allEntries) { - str+=getTime(entry, TIME_FORMAT_ISO) + entry.getString(getActivity()) + '\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.ics_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 currentLevelEntries.size(); - } - - @Override - public Object getItem(int position) { - return currentLevelEntries.get(position); - } - - @Override - public long getItemId(int position) { - return ((Object)currentLevelEntries.get(position)).hashCode(); - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - TextView v; - if(convertView==null) - v = new TextView(getActivity()); - else - v = (TextView) convertView; - - LogItem le = currentLevelEntries.get(position); - String msg = le.getString(getActivity()); - String time = getTime(le, mTimeFormat); - msg = time + msg; - - int spanStart = time.length(); - - SpannableString t = new SpannableString(msg); - - //t.setSpan(getSpanImage(le,(int)v.getTextSize()),spanStart,spanStart+1, Spanned.SPAN_INCLUSIVE_INCLUSIVE); - v.setText(t); - return v; - } - - private String getTime(LogItem le, int time) { - if (time != TIME_FORMAT_NONE) { - Date d = new Date(le.getLogtime()); - java.text.DateFormat timeformat; - if (time== TIME_FORMAT_ISO) - timeformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); - else - timeformat = DateFormat.getTimeFormat(getActivity()); - - return timeformat.format(d) + " "; - - } else { - return ""; - } - - } - - private ImageSpan getSpanImage(LogItem li, int imageSize) { - int imageRes = android.R.drawable.ic_menu_call; - - switch (li.getLogLevel()) { - case ERROR: - imageRes = android.R.drawable.ic_notification_clear_all; - break; - case INFO: - imageRes = android.R.drawable.ic_menu_compass; - break; - case VERBOSE: - imageRes = android.R.drawable.ic_menu_info_details; - break; - case WARNING: - imageRes = android.R.drawable.ic_menu_camera; - break; - } - - Drawable d = getResources().getDrawable(imageRes); - - - //d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); - d.setBounds(0, 0, imageSize, imageSize); - ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BOTTOM); - - return span; - } - - @Override - public int getItemViewType(int position) { - return 0; - } - - @Override - public int getViewTypeCount() { - return 1; - } - - @Override - public boolean isEmpty() { - return currentLevelEntries.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(); - assert (msg!=null); - msg.what=MESSAGE_NEWLOG; - Bundle bundle=new Bundle(); - bundle.putParcelable("logmessage", logMessage); - msg.setData(bundle); - mHandler.sendMessage(msg); - } - - @Override - public boolean handleMessage(Message msg) { - // We have been called - if(msg.what==MESSAGE_NEWLOG) { - - LogItem logMessage = msg.getData().getParcelable("logmessage"); - if(addLogMessage(logMessage)) - for (DataSetObserver observer : observers) { - observer.onChanged(); - } - } else if (msg.what == MESSAGE_CLEARLOG) { - for (DataSetObserver observer : observers) { - observer.onInvalidated(); - } - initLogBuffer(); - } else if (msg.what == MESSAGE_NEWTS) { - for (DataSetObserver observer : observers) { - observer.onInvalidated(); - } - } else if (msg.what == MESSAGE_NEWLOGLEVEL) { - initCurrentMessages(); - - for (DataSetObserver observer: observers) { - observer.onChanged(); - } - - } - - return true; - } - - private void initCurrentMessages() { - currentLevelEntries.clear(); - for(LogItem li: allEntries) { - if (li.getVerbosityLevel() <= mLogLevel || - mLogLevel == VpnProfile.MAXLOGLEVEL) - currentLevelEntries.add(li); - } - } - - /** - * - * @param logmessage - * @return True if the current entries have changed - */ - private boolean addLogMessage(LogItem logmessage) { - allEntries.add(logmessage); - - if (allEntries.size() > MAX_STORED_LOG_ENTRIES) { - Vector<LogItem> oldAllEntries = allEntries; - allEntries = new Vector<LogItem>(allEntries.size()); - for (int i=50;i<oldAllEntries.size();i++) { - allEntries.add(oldAllEntries.elementAt(i)); - } - initCurrentMessages(); - return true; - } else { - if (logmessage.getVerbosityLevel() <= mLogLevel) { - currentLevelEntries.add(logmessage); - return true; - } else { - return false; - } - } - } - - void clearLog() { - // Actually is probably called from GUI Thread as result of the user - // pressing a button. But better safe than sorry - VpnStatus.clearLog(); - VpnStatus.logInfo(R.string.logCleared); - mHandler.sendEmptyMessage(MESSAGE_CLEARLOG); - } - - - - public void setTimeFormat(int newTimeFormat) { - mTimeFormat= newTimeFormat; - mHandler.sendEmptyMessage(MESSAGE_NEWTS); - } - - public void setLogLevel(int logLevel) { - mLogLevel = logLevel; - mHandler.sendEmptyMessage(MESSAGE_NEWLOGLEVEL); - } - - } - - - - 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){ - Intent intent = new Intent(getActivity(),DisconnectVPN.class); - startActivity(intent); - return true; - } else if(item.getItemId()==R.id.send) { - ladapter.shareLog(); - } else if(item.getItemId()==R.id.edit_vpn) { - VpnProfile lastConnectedprofile = ProfileManager.getLastConnectedVpn(); - - if(lastConnectedprofile!=null) { - Intent vprefintent = new Intent(getActivity(),Dashboard.class) - .putExtra(VpnProfile.EXTRA_PROFILEUUID,lastConnectedprofile.getUUIDString()); - startActivityForResult(vprefintent,START_VPN_CONFIG); - } else { - Toast.makeText(getActivity(), R.string.log_no_last_vpn, Toast.LENGTH_LONG).show(); - } - } else if(item.getItemId() == R.id.toggle_time) { - showHideOptionsPanel(); - } else if(item.getItemId() == android.R.id.home) { - // This is called when the Home (Up) button is pressed - // in the Action Bar. - Intent parentActivityIntent = new Intent(getActivity(), Dashboard.class); - parentActivityIntent.addFlags( - Intent.FLAG_ACTIVITY_CLEAR_TOP | - Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(parentActivityIntent); - getActivity().finish(); - return true; - - } - return super.onOptionsItemSelected(item); - - } - - private void showHideOptionsPanel() { - boolean optionsVisible = (mOptionsLayout.getVisibility() != View.GONE); - - ObjectAnimator anim; - if (optionsVisible) { - anim = ObjectAnimator.ofFloat(mOptionsLayout,"alpha",1.0f, 0f); - anim.addListener(collapseListener); - - } else { - mOptionsLayout.setVisibility(View.VISIBLE); - anim = ObjectAnimator.ofFloat(mOptionsLayout,"alpha", 0f, 1.0f); - //anim = new TranslateAnimation(0.0f, 0.0f, mOptionsLayout.getHeight(), 0.0f); - - } - - //anim.setInterpolator(new AccelerateInterpolator(1.0f)); - //anim.setDuration(300); - //mOptionsLayout.startAnimation(anim); - anim.start(); - - } - - AnimatorListenerAdapter collapseListener = new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animator) { - mOptionsLayout.setVisibility(View.GONE); - } - - }; - - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.logmenu, menu); - if (getResources().getBoolean(R.bool.logSildersAlwaysVisible)) - menu.removeItem(R.id.toggle_time); - } - - - @Override - public void onResume() { - super.onResume(); - VpnStatus.addStateListener(this); - VpnStatus.addByteCountListener(this); - Intent intent = new Intent(getActivity(), OpenVPNService.class); - intent.setAction(OpenVPNService.START_SERVICE); - - } - - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == START_VPN_CONFIG && resultCode== Activity.RESULT_OK) { - String configuredVPN = data.getStringExtra(VpnProfile.EXTRA_PROFILEUUID); - - final VpnProfile profile = ProfileManager.get(getActivity(),configuredVPN); - ProfileManager.getInstance(getActivity()).saveProfile(getActivity(), profile); - // Name could be modified, reset List adapter - - AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity()); - 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(getActivity(), 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 - public void onStop() { - super.onStop(); - VpnStatus.removeStateListener(this); - VpnStatus.removeByteCountListener(this); - - getActivity().getPreferences(0).edit().putInt(LOGTIMEFORMAT, ladapter.mTimeFormat) - .putInt(VERBOSITYLEVEL, ladapter.mLogLevel).apply(); - - } - - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - ListView lv = getListView(); - - lv.setOnItemLongClickListener(new OnItemLongClickListener() { - - @Override - public boolean onItemLongClick(AdapterView<?> parent, View view, - int position, long id) { - ClipboardManager clipboard = (ClipboardManager) - getActivity().getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("Log Entry",((TextView) view).getText()); - clipboard.setPrimaryClip(clip); - Toast.makeText(getActivity(), R.string.copied_entry, Toast.LENGTH_SHORT).show(); - return true; - } - }); - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.log_fragment, container, false); - - setHasOptionsMenu(true); - - ladapter = new LogWindowListAdapter(); - ladapter.mTimeFormat = getActivity().getPreferences(0).getInt(LOGTIMEFORMAT, 0); - int logLevel = getActivity().getPreferences(0).getInt(VERBOSITYLEVEL, 0); - ladapter.setLogLevel(logLevel); - - setListAdapter(ladapter); - - mTimeRadioGroup = (RadioGroup) v.findViewById(R.id.timeFormatRadioGroup); - mTimeRadioGroup.setOnCheckedChangeListener(this); - - if(ladapter.mTimeFormat== LogWindowListAdapter.TIME_FORMAT_ISO) { - mTimeRadioGroup.check(R.id.radioISO); - } else if (ladapter.mTimeFormat == LogWindowListAdapter.TIME_FORMAT_NONE) { - mTimeRadioGroup.check(R.id.radioNone); - } else if (ladapter.mTimeFormat == LogWindowListAdapter.TIME_FORMAT_SHORT) { - mTimeRadioGroup.check(R.id.radioShort); - } - - mSpeedView = (TextView) v.findViewById(R.id.speed); - - mOptionsLayout = (LinearLayout) v.findViewById(R.id.logOptionsLayout); - mLogLevelSlider = (SeekBar) v.findViewById(R.id.LogLevelSlider); - mLogLevelSlider.setMax(VpnProfile.MAXLOGLEVEL-1); - mLogLevelSlider.setProgress(logLevel-1); - - mLogLevelSlider.setOnSeekBarChangeListener(this); - - if(getResources().getBoolean(R.bool.logSildersAlwaysVisible)) - mOptionsLayout.setVisibility(View.VISIBLE); - - mUpStatus = (TextView) v.findViewById(R.id.speedUp); - mDownStatus = (TextView) v.findViewById(R.id.speedDown); - mConnectStatus = (TextView) v.findViewById(R.id.speedStatus); - if (mShowOptionsLayout) - mOptionsLayout.setVisibility(View.VISIBLE); - return v; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - if(getResources().getBoolean(R.bool.logSildersAlwaysVisible)) { - mShowOptionsLayout=true; - if (mOptionsLayout!= null) - mOptionsLayout.setVisibility(View.VISIBLE); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - //getActionBar().setDisplayHomeAsUpEnabled(true); - - } - - - @Override - public void updateState(final String status, final String logMessage, final int resId, final ConnectionStatus level) { - if (isAdded()) { - getActivity().runOnUiThread(new Runnable() { - - @Override - public void run() { - if (isAdded()) { - String prefix = getString(resId) + ":"; - if (status.equals("BYTECOUNT") || status.equals("NOPROCESS")) - prefix = ""; - if (resId == R.string.unknown_state) - prefix += status; - if (mSpeedView != null) - mSpeedView.setText(prefix + logMessage); - - if (mConnectStatus != null) - mConnectStatus.setText(getString(resId)); - } - } - }); - } - } - - - @Override - public void onDestroy() { - VpnStatus.removeLogListener(ladapter); - super.onDestroy(); - } - -} diff --git a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/views/SeekBarTicks.java b/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/views/SeekBarTicks.java deleted file mode 100644 index 82378b00..00000000 --- a/ics-openvpn-stripped/main/src/main/java/de/blinkt/openvpn/views/SeekBarTicks.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.views; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.ViewConfiguration; -import android.widget.SeekBar; - -public class SeekBarTicks extends SeekBar { - private Paint mTickPaint; - private float mTickHeight; - - private float tickHeightRatio = 0.6f; - - public SeekBarTicks(Context context, AttributeSet attrs) { - super (context, attrs); - - initTicks (context, attrs, android.R.attr.seekBarStyle); - } - - - public SeekBarTicks(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - initTicks (context, attrs, defStyle); - - /*mTickHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - tickHeightDP, - ctx.getResources().getDisplayMetrics()); */ - } - - private void initTicks(Context context, AttributeSet attrs, int defStyle) { - TypedArray a = context.obtainStyledAttributes(attrs, - new int[] { android.R.attr.secondaryProgress }, defStyle, 0); - - - int tickColor = a.getColor(0, android.R.color.black); - mTickPaint = new Paint(); - mTickPaint.setColor( context.getResources().getColor(tickColor)); - a.recycle(); - } - - - @Override - protected synchronized void onDraw(Canvas canvas) { - drawTicks(canvas); - super.onDraw(canvas); - } - - private void drawTicks(Canvas canvas) { - - final int available = getWidth() - getPaddingLeft() - getPaddingRight(); - final int availableHeight = getHeight() - getPaddingBottom() - getPaddingTop(); - - int extrapadding = (int) ((availableHeight- (availableHeight * tickHeightRatio))/2); - - int tickSpacing = available / (getMax() ); - - for (int i = 1; i < getMax(); i++) { - final float x = getPaddingLeft() + i * tickSpacing; - - canvas.drawLine(x, getPaddingTop()+extrapadding, x, getHeight()-getPaddingBottom()-extrapadding, mTickPaint); - } - } -} |