diff options
21 files changed, 844 insertions, 443 deletions
diff --git a/res/layout/basic_settings.xml b/res/layout/basic_settings.xml index cfe8c6e3..4e6f549f 100644 --- a/res/layout/basic_settings.xml +++ b/res/layout/basic_settings.xml @@ -27,6 +27,20 @@ <TextView style="@style/item" + android:text="@string/profilename" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + <EditText + android:id="@+id/profilename" + style="@style/item" + android:inputType="text" + /> + + + + + <TextView + style="@style/item" android:text="@string/address" android:textAppearance="?android:attr/textAppearanceSmall" /> @@ -38,7 +52,7 @@ <!-- <requestFocus /> --> </EditText> - + <TextView style="@style/item" android:text="@string/port" diff --git a/res/layout/viewconfig.xml b/res/layout/viewconfig.xml new file mode 100644 index 00000000..5ae34ef0 --- /dev/null +++ b/res/layout/viewconfig.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" > + + <TextView + android:id="@+id/configview" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + +</ScrollView>
\ No newline at end of file diff --git a/res/layout/vpn_preference_layout.xml b/res/layout/vpn_preference_layout.xml index 15fc91ab..fbb18115 100644 --- a/res/layout/vpn_preference_layout.xml +++ b/res/layout/vpn_preference_layout.xml @@ -22,7 +22,7 @@ android:minHeight="?android:attr/listPreferredItemHeight" > <LinearLayout - android:id="@+id/inputmethod_pref" + android:id="@+id/vpnconfig_pref" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" diff --git a/res/values/strings.xml b/res/values/strings.xml index 79b7f8a7..ee2a4113 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -96,6 +96,7 @@ <string name="menu_add_profile">Add Profile</string> <string name="add_profile_name_prompt">Enter a name identifying the new Profile</string> <string name="duplicate_profile_name">Duplicate Profile Name</string> + <string name="profilename">Profile Name</string> </resources> diff --git a/res/xml/vpn_authentification.xml b/res/xml/vpn_authentification.xml index 949093d6..3781211f 100644 --- a/res/xml/vpn_authentification.xml +++ b/res/xml/vpn_authentification.xml @@ -5,7 +5,15 @@ android:key="remoteServerTLS" android:summary="Checks whether the server uses a TLS Server Certificate" android:title="Except TLS Server" /> + <CheckBoxPreference + android:key="checkRemoteCN" + android:summary="Checks the Remote Server Certificate CN against a String" + android:title="Certificate Hostname Check" /> + + <EditTextPreference + android:dependency="checkRemoteCN" + android:dialogMessage="Enter the String against which the remote Server is checked. Openvpn will use prefix matching. "Server" matches "Server-1" and "Server-2"" + android:title="Remote Hostname(CN)" + android:key="remotecn"/> - - <CheckBoxPreference android:key="useTLSAuth"/> </PreferenceScreen>
\ No newline at end of file diff --git a/res/xml/vpn_headers.xml b/res/xml/vpn_headers.xml index 424b4411..faaa6cdd 100644 --- a/res/xml/vpn_headers.xml +++ b/res/xml/vpn_headers.xml @@ -2,34 +2,30 @@ <preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > <header + android:tag="BasicSettings" android:fragment="de.blinkt.openvpn.BasicSettings" android:summary="Server, port and authentication method. Normally you should only settings specified here." - android:title="Basic Settings" /> + android:title="Basic Settings" + android:id="@+id/basicsettingsid"/> <!-- android:icon="@drawable/ic_settings_applications" --> <header - android:fragment="de.blinkt.openvpn.VPNPreferences$IP_Settings" + android:fragment="de.blinkt.openvpn.Settings_IP" android:summary="IP Address and Routing" android:title="IP Settings" /> <header - android:fragment="de.blinkt.openvpn.VPNPreferences$Authentication" + android:fragment="de.blinkt.openvpn.Settings_Authentication" android:summary="Authentication" android:title="Authentication" /> <!-- android:icon="@drawable/ic_settings_display" --> - <header - android:fragment="de.blinkt.openvpn.VPNPreferences$Obscure" + <!-- + <header + android:fragment="de.blinkt.openvpn.Settings_Obscure" android:summary="Obscure OpenVPN Settings. Normaly not needed." android:title="Obscure" > - - <!-- - Arbitrary key/value pairs can be included with a header as - arguments to its fragment. - --> - <extra - android:name="someKey" - android:value="someHeaderValue" /> </header> + --> <header android:fragment="de.blinkt.openvpn.ShowConfigFragment" android:summary="Shows the generated openvpn Configuration File" diff --git a/res/xml/vpn_ipsettings.xml b/res/xml/vpn_ipsettings.xml index 8aacaaca..79356e69 100644 --- a/res/xml/vpn_ipsettings.xml +++ b/res/xml/vpn_ipsettings.xml @@ -4,7 +4,9 @@ <SwitchPreference android:disableDependentsState="true" android:key="usePull" - android:title="Pull Settings" /> + android:title="Pull Settings" + android:summaryOn="Requests IP addresses, routes and timing options from the server." + android:summaryOff="No information is requested from the server. Settings need to be specified below." /> <PreferenceCategory android:title="IP" > <EditTextPreference @@ -29,9 +31,11 @@ android:title="searchDomain" /> <EditTextPreference android:key="dns1" + android:dialogMessage="DNS Server to be used." android:title="DNS Server" /> <EditTextPreference android:key="dns2" + android:dialogMessage="Secondary DNS Server used if the normal DNS Server cannot be reached." android:title="Backup DNS Server" /> </PreferenceCategory> <PreferenceCategory android:title="Routing" > diff --git a/src/de/blinkt/openvpn/BasicSettings.java b/src/de/blinkt/openvpn/BasicSettings.java index 8f4fc770..e80651e5 100644 --- a/src/de/blinkt/openvpn/BasicSettings.java +++ b/src/de/blinkt/openvpn/BasicSettings.java @@ -40,18 +40,10 @@ import android.widget.ToggleButton; import de.blinkt.openvpn.R.id; public class BasicSettings extends Fragment implements View.OnClickListener, OnItemSelectedListener, Callback, OnCheckedChangeListener { - private static final String TAG = "OpenVpnClient"; - - - private static final int START_OPENVPN = 0; private static final int CHOOSE_FILE_OFFSET = 1000; private static final int UPDATE_ALIAS = 20; - private static final String PREFS_NAME = "OVPN_SERVER"; - - private static final String OVPNCONFIGFILE = "android.conf"; - private static final String OVPNCONFIGPKCS12 = "android.pkcs12"; - + private TextView mServerAddress; private TextView mServerPort; @@ -92,6 +84,7 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI private VpnProfile mProfile; + private EditText mProfileName; @@ -100,17 +93,22 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI fileselects.put(i, fsl); fsl.setActivity(getActivity(),i); } - + + public void onCreate(Bundle savedInstanceState) { + Bundle foo = getArguments(); + String profileuuid =getArguments().getString(getActivity().getPackageName() + ".profileUUID"); + mProfile=ProfileManager.get(profileuuid); super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + mView = inflater.inflate(R.layout.basic_settings,container,false); - - + + mProfileName = (EditText) mView.findViewById(R.id.profilename); mServerAddress = (TextView) mView.findViewById(R.id.address); mServerPort = (TextView) mView.findViewById(R.id.port); mClientCert = (FileSelectLayout) mView.findViewById(R.id.certselect); @@ -130,6 +128,8 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI mUserName = (EditText) mView.findViewById(R.id.auth_username); mPassword = (EditText) mView.findViewById(R.id.auth_password); + + addFileSelectLayout(mCaCert); addFileSelectLayout(mClientCert); @@ -152,9 +152,15 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI if (mHandler == null) { mHandler = new Handler(this); } + return mView; } + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + ((VPNPreferences) getActivity()).setmBS(this); + } @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { @@ -194,8 +200,7 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI } private void loadPreferences() { - mProfile = ((VPNPreferences)getActivity()).getVPNProfile(); - + mProfileName.setText(mProfile.mName); mClientCert.setData(mProfile.mClientCertFilename); mClientKey.setData(mProfile.mClientKeyFilename); mCaCert.setData(mProfile.mCaFilename); @@ -217,11 +222,11 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI } - private void savePreferences() { + void savePreferences() { // We need an Editor object to make preference changes. // All objects are from android.context.Context - + mProfile.mName = mProfileName.getText().toString(); mProfile.mCaFilename = mCaCert.getData(); mProfile.mClientCertFilename = mClientCert.getData(); mProfile.mClientKeyFilename = mClientKey.getData(); @@ -303,5 +308,6 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI } else if (buttonView == mUseTlsAuth) { mView.findViewById(R.id.tlsauth_options).setVisibility(visibility); } + } } diff --git a/src/de/blinkt/openvpn/MainActivity.java b/src/de/blinkt/openvpn/MainActivity.java index fd4fc6a2..5eaf146c 100644 --- a/src/de/blinkt/openvpn/MainActivity.java +++ b/src/de/blinkt/openvpn/MainActivity.java @@ -2,11 +2,22 @@ package de.blinkt.openvpn; import java.util.List; +import android.content.Intent; import android.preference.PreferenceActivity; public class MainActivity extends PreferenceActivity { + @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.main_headers, target); } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + System.out.println(data); + + + } } diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index 7385726b..b49bdf68 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -72,6 +72,9 @@ public class OpenVPN { public static void foo() { } synchronized public static String[] getlogbuffer() { + + // The stoned way of java to return an array from a vector + // brought to you by eclipse auto complete return (String[]) logbuffer.toArray(new String[logbuffer.size()]); } diff --git a/src/de/blinkt/openvpn/OpenVPNClient.java b/src/de/blinkt/openvpn/OpenVPNClient.java index 5af0ae8f..db6dd95a 100644 --- a/src/de/blinkt/openvpn/OpenVPNClient.java +++ b/src/de/blinkt/openvpn/OpenVPNClient.java @@ -16,25 +16,16 @@ package de.blinkt.openvpn; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.HashMap; -import java.util.Random; -import java.util.Vector; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.net.VpnService; @@ -44,7 +35,6 @@ import android.os.Handler.Callback; import android.os.Message; import android.security.KeyChain; import android.security.KeyChainAliasCallback; -import android.security.KeyChainException; import android.util.Log; import android.view.View; import android.widget.AdapterView; @@ -71,8 +61,6 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI private static final String PREFS_NAME = "OVPN_SERVER"; - private static final String OVPNCONFIGFILE = "android.conf"; - private static final String OVPNCONFIGPKCS12 = "android.pkcs12"; private TextView mServerAddress; @@ -117,133 +105,14 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI } - public void writeConfigFile() - { - - try { - FileWriter cfg = new FileWriter(getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); - - - - // TODO "--remote-cert-eku", "TLS Web Server Authentication" - - - // The stoned way of java to return an array from a vector - // brought to you by eclipse auto complete - - cfg.write("client\n"); - cfg.write("verb 2\n"); - - - // /tmp does not exist on Android - cfg.write("tmp-dir "); - cfg.write(getCacheDir().getAbsolutePath()); - cfg.write("\n"); - - // quit after 5 tries - cfg.write("--connect-retry-max 5\n"); - cfg.write("--resolv-retry 5\n"); - - - - // We cannot use anything else than tun - cfg.write("dev tun\n"); - - // Server Address - cfg.write("remote "); - cfg.write(mServerAddress.getText().toString()); - cfg.write(" "); - cfg.write(mServerPort.getText().toString()); - if(mTcpUdp.isChecked()) - cfg.write(" udp\n"); - else - cfg.write(" tcp\n"); - - - - switch(mType.getSelectedItemPosition()) { - case VpnProfile.TYPE_CERTIFICATES: - // Ca - cfg.write("ca "); - cfg.write(mCaCert.getData()); - cfg.write("\n"); - - // Client Cert + Key - cfg.write("key "); - cfg.write(mClientKey.getData()); - cfg.write("\n"); - cfg.write("cert "); - cfg.write(mClientCert.getData()); - cfg.write("\n"); - break; - case VpnProfile.TYPE_PKCS12: - cfg.write("pkcs12 "); - cfg.write(mpkcs12.getData()); - cfg.write("\n"); - cfg.write("management-query-passwords\n"); - break; - - case VpnProfile.TYPE_KEYSTORE: - cfg.write("pkcs12 "); - cfg.write(getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGPKCS12); - cfg.write("\n"); - cfg.write("management-query-passwords\n"); - break; - - } - - if(mUseLzo.isChecked()) { - cfg.write("comp-lzo\n"); - } - - if(mUseTlsAuth.isChecked()) { - cfg.write("tls-auth "); - cfg.write(mTlsFile.getData()); - int tlsdir= mTLSDirection.getSelectedItemPosition(); - // 2 is unspecified - if(tlsdir == 1 || tlsdir==2) { - cfg.write(" "); - cfg.write(new Integer(tlsdir).toString()); - } - cfg.write("\n"); - } - cfg.flush(); - cfg.close(); - - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - + private void addFileSelectLayout (FileSelectLayout fsl) { int i = fileselects.size() + CHOOSE_FILE_OFFSET; fileselects.put(i, fsl); fsl.setActivity(this,i); } - public String[] buildOpenvpnArgv() - { - Vector<String> args = new Vector<String>(); - // Add fixed paramenters - args.add("openvpn"); - - // Enable managment interface to - // stop openvpn - args.add("--management"); - - args.add(getCacheDir().getAbsolutePath() + "/" + "mgmtsocket"); - args.add("unix"); - //args.add("--management-hold"); - - args.add("--config"); - args.add(getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); - - - return (String[]) args.toArray(new String[args.size()]); - } @@ -415,52 +284,7 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI null); // alias to preselect, null if unavailable } - private String getRandomPW() { - String pw= ""; - // Put enough digits togher to make a password :) - Random r = new Random(); - for(int i=0;i < 4;i++) { - pw += new Integer(r.nextInt(1000)).toString(); - } - - return pw; - - } - - private String savePKCS12() { - Context context = getBaseContext(); - PrivateKey privateKey = null; - X509Certificate[] cachain=null; - try { - privateKey = KeyChain.getPrivateKey(context,certalias); - cachain = KeyChain.getCertificateChain(context, certalias); - - KeyStore ks = KeyStore.getInstance("PKCS12"); - ks.load(null, null); - ks.setKeyEntry("usercert", privateKey, null, cachain); - String mypw = getRandomPW(); - FileOutputStream fout = new FileOutputStream(getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGPKCS12); - ks.store(fout,mypw.toCharArray()); - fout.flush(); fout.close(); - return mypw; - } catch (KeyChainException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (KeyStoreException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } catch (CertificateException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - return "ERROR"; - - } + public void testGetallCerts() throws NoSuchAlgorithmException, KeyStoreException { TrustManagerFactory tmf = TrustManagerFactory @@ -497,32 +321,7 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI } } - void startOpenVpn() { - String prefix = getPackageName(); - writeConfigFile(); - - Intent intent = new Intent(this, OpenVpnService.class) - .putExtra(prefix + ".ARGV" , buildOpenvpnArgv()); - if(mType.getSelectedItemPosition()== VpnProfile.TYPE_PKCS12){ - intent.putExtra(prefix + ".PKCS12PASS", - mPKCS12Password.getText().toString()); - } - - if(mType.getSelectedItemPosition() == VpnProfile.TYPE_KEYSTORE) { - String pkcs12pw = savePKCS12(); - intent.putExtra(prefix + ".PKCS12PASS", pkcs12pw); - } - - if(mType.getSelectedItemPosition() == VpnProfile.TYPE_USERPASS) { - intent.putExtra(prefix + ".USERNAME", mUserName.getText().toString()); - intent.putExtra(prefix + ".PASSWORD", mPassword.getText().toString()); - } - - startService(intent); - Intent startLW = new Intent(getBaseContext(),LogWindow.class); - startActivity(startLW); - } /* (non-Javadoc) * @see android.app.Activity#onActivityResult(int, int, android.content.Intent) @@ -550,7 +349,7 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI @Override public void run() { - startOpenVpn(); + // startOpenVpn(); } } diff --git a/src/de/blinkt/openvpn/ProfileManager.java b/src/de/blinkt/openvpn/ProfileManager.java new file mode 100644 index 00000000..078403e1 --- /dev/null +++ b/src/de/blinkt/openvpn/ProfileManager.java @@ -0,0 +1,96 @@ +package de.blinkt.openvpn; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.StreamCorruptedException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; + +public class ProfileManager { + private static final String PREFS_NAME = "VPNList"; + + + + private static ProfileManager instance; + private HashMap<String,VpnProfile> profiles=new HashMap<String, VpnProfile>(); + + public static VpnProfile get(String key) { + checkInstance(); + return instance.profiles.get(key); + + } + + private ProfileManager() { } + + private static void checkInstance() { + if(instance == null) + instance = new ProfileManager(); + } + + public static ProfileManager getInstance() { + checkInstance(); + return instance; + } + + + + 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(Activity activity) { + SharedPreferences sharedprefs = activity.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); + Editor editor = sharedprefs.edit(); + editor.putStringSet("vpnlist", profiles.keySet()); + editor.commit(); + } + + public void addProfile(VpnProfile profile) { + profiles.put(profile.getUUID().toString(),profile); + + } + void loadVPNList(Context context) { + profiles = new HashMap<String, VpnProfile>(); + SharedPreferences settings =context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); + Set<String> vlist = settings.getStringSet("vpnlist", 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()); + + profiles.put(vp.getUUID().toString(), vp); + + } catch (StreamCorruptedException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/src/de/blinkt/openvpn/Settings_Authentication.java b/src/de/blinkt/openvpn/Settings_Authentication.java new file mode 100644 index 00000000..1f96c6ca --- /dev/null +++ b/src/de/blinkt/openvpn/Settings_Authentication.java @@ -0,0 +1,66 @@ +package de.blinkt.openvpn; + +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.PreferenceFragment; + +public class Settings_Authentication extends PreferenceFragment implements OnPreferenceChangeListener { + private CheckBoxPreference mExpectTLSCert; + private CheckBoxPreference mCheckRemoteCN; + private EditTextPreference mRemoteCN; + private VpnProfile mProfile; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.vpn_authentification); + + mExpectTLSCert = (CheckBoxPreference) findPreference("remoteServerTLS"); + mCheckRemoteCN = (CheckBoxPreference) findPreference("checkRemoteCN"); + mRemoteCN = (EditTextPreference) findPreference("remotecn"); + mRemoteCN.setOnPreferenceChangeListener(this); + String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID"); + mProfile = ProfileManager.get(profileUUID); + + loadSettings(); + + } + + private void loadSettings() { + + mExpectTLSCert.setChecked(mProfile.mExpectTLSCert); + mCheckRemoteCN.setChecked(mProfile.mCheckRemoteCN); + mRemoteCN.setText(mProfile.mRemoteCN); + onPreferenceChange(mRemoteCN, mProfile.mRemoteCN); + + } + + private void saveSettings() { + mProfile.mExpectTLSCert=mExpectTLSCert.isChecked(); + mProfile.mCheckRemoteCN=mCheckRemoteCN.isChecked(); + mProfile.mRemoteCN=mRemoteCN.getText(); + } + + @Override + public void onPause() { + super.onPause(); + saveSettings(); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if(preference==mRemoteCN) { + if ("".equals(newValue)) + preference.setSummary(mProfile.mServerName); + else + preference.setSummary((String)newValue); + } + saveSettings(); + return true; + } +}
\ No newline at end of file diff --git a/src/de/blinkt/openvpn/Settings_IP.java b/src/de/blinkt/openvpn/Settings_IP.java new file mode 100644 index 00000000..a1bb16e0 --- /dev/null +++ b/src/de/blinkt/openvpn/Settings_IP.java @@ -0,0 +1,146 @@ +package de.blinkt.openvpn; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; +import android.preference.SwitchPreference; + +public class Settings_IP extends PreferenceFragment implements OnPreferenceChangeListener { + private EditTextPreference mIPv4; + private EditTextPreference mIPv6; + private SwitchPreference mUsePull; + private CheckBoxPreference mOverrideDNS; + private EditTextPreference mSearchdomain; + private EditTextPreference mDNS1; + private EditTextPreference mDNS2; + private EditTextPreference mCustomRoutes; + private CheckBoxPreference mUseDefaultRoute; + private VpnProfile mProfile; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID"); + mProfile = ProfileManager.get(profileUUID); + + + // Make sure default values are applied. In a real app, you would + // want this in a shared function that is used to retrieve the + // SharedPreferences wherever they are needed. + PreferenceManager.setDefaultValues(getActivity(), + R.xml.vpn_ipsettings, false); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.vpn_ipsettings); + mIPv4 = (EditTextPreference) findPreference("ipv4_address"); + mIPv6 = (EditTextPreference) findPreference("ipv6_address"); + mUsePull = (SwitchPreference) findPreference("usePull"); + mOverrideDNS = (CheckBoxPreference) findPreference("overrideDNS"); + mSearchdomain =(EditTextPreference) findPreference("searchdomain"); + mDNS1 = (EditTextPreference) findPreference("dns1"); + mDNS2 = (EditTextPreference) findPreference("dns2"); + mCustomRoutes = (EditTextPreference) findPreference("customRoutes"); + mUseDefaultRoute = (CheckBoxPreference) findPreference("useDefaultRoute"); + + mIPv4.setOnPreferenceChangeListener(this); + mIPv6.setOnPreferenceChangeListener(this); + mDNS1.setOnPreferenceChangeListener(this); + mDNS2.setOnPreferenceChangeListener(this); + mUsePull.setOnPreferenceChangeListener(this); + mOverrideDNS.setOnPreferenceChangeListener(this); + mSearchdomain.setOnPreferenceChangeListener(this); + mCustomRoutes.setOnPreferenceChangeListener(this); + + + + + loadSettings(); + } + + private void loadSettings() { + + mUsePull.setChecked(mProfile.mUsePull); + mIPv4.setText(mProfile.mIPv4Address); + mIPv6.setText(mProfile.mIPv6Address); + mDNS1.setText(mProfile.mDNS1); + mDNS2.setText(mProfile.mDNS2); + mOverrideDNS.setChecked(mProfile.mOverrideDNS); + mSearchdomain.setText(mProfile.mSearchDomain); + mUseDefaultRoute.setChecked(mProfile.mUseDefaultRoute); + mCustomRoutes.setText(mProfile.mCustomRoutes); + + // Sets Summary + onPreferenceChange(mIPv4, mIPv4.getText()); + onPreferenceChange(mIPv6, mIPv6.getText()); + onPreferenceChange(mDNS1, mDNS1.getText()); + onPreferenceChange(mDNS2, mDNS2.getText()); + onPreferenceChange(mSearchdomain, mSearchdomain.getText()); + onPreferenceChange(mCustomRoutes, mCustomRoutes.getText()); + + setDNSState(); + } + + public void onSaveInstanceState (Bundle outState) { + saveSettings(); + } + + @Override + public void onStop() { + saveSettings(); + super.onStop(); + + } + + private void saveSettings() { + mProfile.mUsePull = mUsePull.isChecked(); + mProfile.mIPv4Address = mIPv4.getText(); + mProfile.mIPv6Address = mIPv6.getText(); + mProfile.mDNS1 = mDNS1.getText(); + mProfile.mDNS2 = mDNS2.getText(); + mProfile.mOverrideDNS = mOverrideDNS.isChecked(); + mProfile.mSearchDomain = mSearchdomain.getText(); + mProfile.mUseDefaultRoute = mUseDefaultRoute.isChecked(); + mProfile.mCustomRoutes = mCustomRoutes.getText(); + + + } + + @Override + public boolean onPreferenceChange(Preference preference, + Object newValue) { + if(preference==mIPv4 || preference == mIPv6 + || preference==mDNS1 || preference == mDNS2 + || preference == mSearchdomain || preference == mCustomRoutes + ) + + preference.setSummary((String)newValue); + + if(preference== mUsePull || preference == mOverrideDNS) + setDNSState(); + + saveSettings(); + return true; + } + + private void setDNSState() { + boolean enabled; + mOverrideDNS.setEnabled(mUsePull.isChecked()); + if(!mUsePull.isChecked()) + enabled =true; + else if (mOverrideDNS.isChecked()) + enabled = true; + else + enabled = false; + + mDNS1.setEnabled(enabled); + mDNS2.setEnabled(enabled); + mSearchdomain.setEnabled(enabled); + + } + + + }
\ No newline at end of file diff --git a/src/de/blinkt/openvpn/Settings_Obscure.java b/src/de/blinkt/openvpn/Settings_Obscure.java new file mode 100644 index 00000000..83754663 --- /dev/null +++ b/src/de/blinkt/openvpn/Settings_Obscure.java @@ -0,0 +1,21 @@ +package de.blinkt.openvpn; + +import android.os.Bundle; +import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; + +public class Settings_Obscure extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Make sure default values are applied. In a real app, you would + // want this in a shared function that is used to retrieve the + // SharedPreferences wherever they are needed. + PreferenceManager.setDefaultValues(getActivity(), + R.xml.vpn_ipsettings, false); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.vpn_obscure); + } +}
\ No newline at end of file diff --git a/src/de/blinkt/openvpn/ShowConfigFragment.java b/src/de/blinkt/openvpn/ShowConfigFragment.java index 91471e84..a69d835a 100644 --- a/src/de/blinkt/openvpn/ShowConfigFragment.java +++ b/src/de/blinkt/openvpn/ShowConfigFragment.java @@ -1,8 +1,22 @@ package de.blinkt.openvpn; import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; public class ShowConfigFragment extends Fragment { - + public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID"); + VpnProfile vp = ProfileManager.get(profileUUID); + String cfg=vp.getConfigFile(getActivity().getCacheDir()); + View v=inflater.inflate(R.layout.viewconfig, container,false); + TextView cv = (TextView) v.findViewById(R.id.configview); + cv.setText(cfg); + return v; + }; } diff --git a/src/de/blinkt/openvpn/VPNConfigPreference.java b/src/de/blinkt/openvpn/VPNConfigPreference.java index 0387ebdb..aebc8bc0 100644 --- a/src/de/blinkt/openvpn/VPNConfigPreference.java +++ b/src/de/blinkt/openvpn/VPNConfigPreference.java @@ -7,28 +7,48 @@ import android.view.View.OnClickListener; import android.widget.ImageView; public class VPNConfigPreference extends Preference implements OnClickListener { + class startClickListener implements OnClickListener{ + private VPNConfigPreference mvp; + public startClickListener(VPNConfigPreference vp) { + mvp = vp; + } - private OnQuickSettingsClickListener mOnQuickSettingsListener; + @Override + public void onClick(View v) { + mOnQuickSettingsListener.onStartVPNClick(mvp); + } + + } + + private VpnPreferencesClickListener mOnQuickSettingsListener; private ImageView mQuickPrefButton; public VPNConfigPreference(VPNProfileList vpnProfileList, Bundle args) { - super(vpnProfileList.getActivity()); - setWidgetLayoutResource(R.layout.vpn_preference_layout); - - + setLayoutResource(R.layout.vpn_preference_layout); + } + + private View mProfilesPref; @Override protected void onBindView(View view) { super.onBindView(view); + mProfilesPref = view.findViewById(R.id.vpnconfig_pref); + mProfilesPref.setOnClickListener(new startClickListener(this)); + mProfilesPref.setClickable(true); + mQuickPrefButton = (ImageView) view.findViewById(R.id.quickedit_settings); mQuickPrefButton.setOnClickListener(this); + + // Quick Fix, until I know what really goes wrong here :( + //view.findViewById(android.R.id.widget_frame).setOnClickListener(this); } + - public interface OnQuickSettingsClickListener { + public interface VpnPreferencesClickListener { /** * Called when a Preference has been clicked. * @@ -36,19 +56,19 @@ public class VPNConfigPreference extends Preference implements OnClickListener { * @return True if the click was handled. */ boolean onQuickSettingsClick(Preference preference); + + void onStartVPNClick(VPNConfigPreference vpnConfigPreference); } + - public void setOnQuickSettingsClickListener(OnQuickSettingsClickListener onQuickSettingsListener) { + public void setOnQuickSettingsClickListener(VpnPreferencesClickListener onQuickSettingsListener) { mOnQuickSettingsListener = onQuickSettingsListener; } @Override public void onClick(View v) { - if (mOnQuickSettingsListener != null) { - mOnQuickSettingsListener.onQuickSettingsClick(this); - } - + mOnQuickSettingsListener.onQuickSettingsClick(this); } diff --git a/src/de/blinkt/openvpn/VPNPreferenceFragment.java b/src/de/blinkt/openvpn/VPNPreferenceFragment.java deleted file mode 100644 index e69de29b..00000000 --- a/src/de/blinkt/openvpn/VPNPreferenceFragment.java +++ /dev/null diff --git a/src/de/blinkt/openvpn/VPNPreferences.java b/src/de/blinkt/openvpn/VPNPreferences.java index 27731453..75788d74 100644 --- a/src/de/blinkt/openvpn/VPNPreferences.java +++ b/src/de/blinkt/openvpn/VPNPreferences.java @@ -1,151 +1,104 @@ package de.blinkt.openvpn; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectOutputStream; import java.util.List; +import android.app.Activity; +import android.content.Intent; import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.EditTextPreference; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceActivity; -import android.preference.PreferenceFragment; -import android.preference.PreferenceManager; -import android.preference.SwitchPreference; import android.widget.Button; public class VPNPreferences extends PreferenceActivity { private VpnProfile mProfile; + private BasicSettings mBS; + public void setmBS(BasicSettings mBS) { + this.mBS = mBS; + } + public VPNPreferences() { super(); + + } + + + protected void onPause() { + super.onPause(); + saveSettings(); + + } + + + @Override + protected void onStop() { + super.onStop(); + }; + + + private void saveSettings() { + // First let basic settings save its state + if(mBS!=null) + mBS.savePreferences(); + + ObjectOutputStream vpnfile; + try { + vpnfile = new ObjectOutputStream(openFileOutput((mProfile.getUUID().toString() + ".vp"),Activity.MODE_PRIVATE)); + + vpnfile.writeObject(mProfile); + vpnfile.flush(); + vpnfile.close(); + } catch (FileNotFoundException e) { + + e.printStackTrace(); + } catch (IOException e) { + + e.printStackTrace(); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putSerializable(getPackageName() + ".VpnProfile",mProfile); } + + @Override + protected void onRestoreInstanceState(Bundle state) { + super.onRestoreInstanceState(state); + mProfile = (VpnProfile) state.getSerializable(getPackageName() + ".VpnProfile"); + } + + @Override protected void onCreate(Bundle savedInstanceState) { + mProfile = (VpnProfile) getIntent().getSerializableExtra(getPackageName() + ".VpnProfile"); super.onCreate(savedInstanceState); - mProfile = getIntent().getParcelableExtra("VpnProfile"); + if (hasHeaders()) { Button button = new Button(this); - button.setText("Some action"); + button.setText("Save"); setListFooter(button); } } + + @Override public void onBuildHeaders(List<Header> target) { - loadHeadersFromResource(R.xml.vpn_headers, target); - } - - public static class IP_Settings extends PreferenceFragment implements OnPreferenceChangeListener { - private EditTextPreference mIPv4; - private EditTextPreference mIPv6; - private SwitchPreference mUsePull; - private CheckBoxPreference mOverrideDNS; - private Preference mSearchdomain; - private Preference mDNS1; - private Preference mDNS2; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - - // Make sure default values are applied. In a real app, you would - // want this in a shared function that is used to retrieve the - // SharedPreferences wherever they are needed. - PreferenceManager.setDefaultValues(getActivity(), - R.xml.vpn_ipsettings, false); - - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.vpn_ipsettings); - mIPv4 = (EditTextPreference) findPreference("ipv4_address"); - mIPv6 = (EditTextPreference) findPreference("ipv6_address"); - mUsePull = (SwitchPreference) findPreference("usePull"); - mOverrideDNS = (CheckBoxPreference) findPreference("overrideDNS"); - mSearchdomain =findPreference("searchdomain"); - mDNS1 = findPreference("dns1"); - mDNS2 = findPreference("dns2"); - - mIPv4.setOnPreferenceChangeListener(this); - mIPv6.setOnPreferenceChangeListener(this); - mDNS1.setOnPreferenceChangeListener(this); - mDNS2.setOnPreferenceChangeListener(this); - mUsePull.setOnPreferenceChangeListener(this); - mOverrideDNS.setOnPreferenceChangeListener(this); - - - VpnProfile vp = ((VPNPreferences) getActivity()).getVPNProfile(); - - - setDNSState(); - - + loadHeadersFromResource(R.xml.vpn_headers, target); + for (Header header : target) { + if(header.fragmentArguments==null) + header.fragmentArguments = new Bundle(); + header.fragmentArguments.putString(getPackageName() + ".profileUUID",mProfile.getUUID().toString()); + if(header.extras==null) + header.extras = new Bundle(); + header.extras.putString(getPackageName() + ".profileUUID",mProfile.getUUID().toString()); } - - @Override - public boolean onPreferenceChange(Preference preference, - Object newValue) { - if(preference==mIPv4 || preference == mIPv6 || - preference==mDNS1 || preference == mDNS2) - preference.setSummary((String)newValue); - - if(preference== mUsePull || preference == mOverrideDNS) - setDNSState(); - - return true; - } - - private void setDNSState() { - boolean enabled; - mOverrideDNS.setEnabled(mUsePull.isChecked()); - if(!mUsePull.isChecked()) - enabled =true; - else if (mOverrideDNS.isChecked()) - enabled = true; - else - enabled = false; - - mDNS1.setEnabled(enabled); - mDNS2.setEnabled(enabled); - mSearchdomain.setEnabled(enabled); - - } - - - } - public static class Authentication extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Make sure default values are applied. In a real app, you would - // want this in a shared function that is used to retrieve the - // SharedPreferences wherever they are needed. - PreferenceManager.setDefaultValues(getActivity(), - R.xml.vpn_authentification, false); - - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.vpn_authentification); - } - } - public static class Obscure extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Make sure default values are applied. In a real app, you would - // want this in a shared function that is used to retrieve the - // SharedPreferences wherever they are needed. - PreferenceManager.setDefaultValues(getActivity(), - R.xml.vpn_ipsettings, false); - - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.vpn_obscure); - } - } - public VpnProfile getVPNProfile() { - return mProfile; } } diff --git a/src/de/blinkt/openvpn/VPNProfileList.java b/src/de/blinkt/openvpn/VPNProfileList.java index 59e231cc..48c7a7a2 100644 --- a/src/de/blinkt/openvpn/VPNProfileList.java +++ b/src/de/blinkt/openvpn/VPNProfileList.java @@ -2,24 +2,16 @@ package de.blinkt.openvpn; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.io.StreamCorruptedException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; +import android.net.VpnService; import android.os.Bundle; -import android.os.Parcelable; import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; import android.view.Menu; @@ -27,15 +19,15 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.widget.EditText; import android.widget.Toast; -import de.blinkt.openvpn.VPNConfigPreference.OnQuickSettingsClickListener; - -public class VPNProfileList extends PreferenceFragment implements OnPreferenceClickListener, OnQuickSettingsClickListener { - private static final String PREFS_NAME = "VPNList"; +import de.blinkt.openvpn.VPNConfigPreference.VpnPreferencesClickListener; +public class VPNProfileList extends PreferenceFragment implements VpnPreferencesClickListener { private static final int MENU_ADD_PROFILE = Menu.FIRST; + private static final int START_VPN_PROFILECONFIG = 70; + - private HashMap<String,VpnProfile> profiles; + private VpnProfile mSelectedVPN; @Override public void onCreate(Bundle savedInstanceState) { @@ -56,10 +48,10 @@ public class VPNProfileList extends PreferenceFragment implements OnPreferenceCl @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.add(0, MENU_ADD_PROFILE, 0, R.string.menu_add_profile) - .setIcon(android.R.drawable.ic_menu_add) - .setAlphabeticShortcut('a') - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM - | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + .setIcon(android.R.drawable.ic_menu_add) + .setAlphabeticShortcut('a') + .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM + | MenuItem.SHOW_AS_ACTION_WITH_TEXT); } @@ -91,7 +83,7 @@ public class VPNProfileList extends PreferenceFragment implements OnPreferenceCl @Override public void onClick(DialogInterface dialog, int which) { String name = entry.getText().toString(); - if (getProfileByName(name)==null) { + if (getPM().getProfileByName(name)==null) { VpnProfile profile = new VpnProfile(name); addProfile(profile); refreshList(); @@ -113,20 +105,10 @@ public class VPNProfileList extends PreferenceFragment implements OnPreferenceCl } - public VpnProfile getProfileByName(String name) { - for (VpnProfile vpnp : profiles.values()) { - if(vpnp.getName().equals(name)) { - return vpnp; - } - } - return null; - } - + private void addProfile(VpnProfile profile) { - profiles.put(profile.getUUID().toString(),profile); - Editor editor = getActivity().getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE).edit(); - editor.putStringSet("vpnlist", profiles.keySet()); - editor.commit(); + getPM().addProfile(profile); + getPM().saveProfileList(getActivity()); saveProfile(profile); } @@ -149,81 +131,99 @@ public class VPNProfileList extends PreferenceFragment implements OnPreferenceCl } } - private void loadVPNList() { - profiles = new HashMap<String, VpnProfile>(); - SharedPreferences settings =getActivity().getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); - Set<String> vlist = settings.getStringSet("vpnlist", null); - if(vlist==null){ - vlist = new HashSet<String>(); - } - - for (String vpnentry : vlist) { - try { - ObjectInputStream vpnfile = new ObjectInputStream(getActivity().openFileInput(vpnentry + ".vp")); - VpnProfile vp = ((VpnProfile) vpnfile.readObject()); - - profiles.put(vp.getUUID().toString(), vp); - - } catch (StreamCorruptedException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } - } - + public void refreshList() { PreferenceScreen plist = getPreferenceScreen(); if (plist != null) { plist.removeAll(); - loadVPNList(); + getPM().loadVPNList(getActivity()); - for (VpnProfile vpnprofile: profiles.values()) { + for (VpnProfile vpnprofile: getPM().getProfiles()) { Bundle args = new Bundle(); //TODO String profileuuid = vpnprofile.getUUID().toString(); - args.putParcelable("Profile", vpnprofile); + args.putSerializable(getActivity().getPackageName() + ".VpnProfile", vpnprofile); //args.putString("name", vpnentry); VPNConfigPreference vpref = new VPNConfigPreference(this, args); vpref.setKey(profileuuid); vpref.setTitle(vpnprofile.getName()); vpref.setPersistent(false); // vpref.setSelectable(true); - vpref.setOnPreferenceClickListener(this); vpref.setOnQuickSettingsClickListener(this); plist.addPreference(vpref); } + } } - @Override - public boolean onPreferenceClick(Preference preference) { - String key= preference.getKey(); - return true; - + private ProfileManager getPM() { + return ProfileManager.getInstance(); } @Override public boolean onQuickSettingsClick(Preference preference) { String key = preference.getKey(); - VpnProfile vprofile = profiles.get(key); + VpnProfile vprofile = ProfileManager.get(key); Intent vprefintent = new Intent(getActivity(),VPNPreferences.class) - .putExtra("VpnProfile", (Parcelable)vprofile); + .putExtra(getActivity().getPackageName() + ".VpnProfile", vprofile); - startActivity(vprefintent); + startActivityForResult(vprefintent,START_VPN_PROFILECONFIG); return true; } + + + + + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if(requestCode==START_VPN_PROFILECONFIG) { + new startOpenVpnThread().start();; + + } + + } + + private class startOpenVpnThread extends Thread { + + @Override + public void run() { + startOpenVpn(); + } + + void startOpenVpn() { + Intent startVPN = mSelectedVPN.prepareIntent(getActivity()); + + getActivity().startService(startVPN); + Intent startLW = new Intent(getActivity().getBaseContext(),LogWindow.class); + startActivity(startLW); + getActivity().finish(); + } + } + + @Override + public void onStartVPNClick(VPNConfigPreference preference) { + // Query the System for permission + mSelectedVPN = getPM().get(preference.getKey()); + Intent intent = VpnService.prepare(getActivity()); + + if (intent != null) { + // Start the query + intent.putExtra("FOO", "WAR BIER"); + startActivityForResult(intent, 0); + } else { + onActivityResult(START_VPN_PROFILECONFIG, Activity.RESULT_OK, null); + } + + } } diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 0eddabaa..c199cf8b 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -1,12 +1,31 @@ package de.blinkt.openvpn; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; import java.io.Serializable; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Random; import java.util.UUID; +import java.util.Vector; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; import android.os.Parcel; import android.os.Parcelable; +import android.security.KeyChain; +import android.security.KeyChainException; -public class VpnProfile implements Parcelable, Serializable{ +public class VpnProfile implements Serializable{ + // Parcable /** * */ @@ -16,7 +35,8 @@ public class VpnProfile implements Parcelable, Serializable{ static final int TYPE_KEYSTORE=2; public static final int TYPE_USERPASS = 3; public static final int TYPE_STATICKEYS = 4; - + + private static final String OVPNCONFIGFILE = "android.conf"; // Keep in order of parceling // Public attributes, since I got mad with getter/setter @@ -37,6 +57,20 @@ public class VpnProfile implements Parcelable, Serializable{ public String mPKCS12Password; public boolean mUseTLSAuth = false; public String mServerName = "openvpn.blinkt.de" ; + public String mDNS1="131.234.137.23"; + public String mDNS2="131.234.137.24"; + public String mIPv4Address; + public String mIPv6Address; + public boolean mOverrideDNS=false; + public String mSearchDomain="blinkt.de"; + public boolean mUseDefaultRoute=true; + public boolean mUsePull=true; + public String mCustomRoutes; + public boolean mCheckRemoteCN=false; + public boolean mExpectTLSCert=true; + public String mRemoteCN=""; + private String mPassword; + private String mUsername; public int describeContents() { @@ -93,6 +127,9 @@ public class VpnProfile implements Parcelable, Serializable{ } }; + + static final String OVPNCONFIGPKCS12 = "android.pkcs12"; + public VpnProfile(String name) { mUuid = UUID.randomUUID(); mName = name; @@ -108,7 +145,202 @@ public class VpnProfile implements Parcelable, Serializable{ return mName; } + + public String getConfigFile(File cacheDir) + { + + String cfg=""; + + + // TODO "--remote-cert-eku", "TLS Web Server Authentication" + + + + cfg+="client\n"; + cfg+="verb 2\n"; + + + // /tmp does not exist on Android + cfg+="tmp-dir "; + cfg+=cacheDir.getAbsolutePath(); + cfg+="\n"; + + // quit after 5 tries + cfg+="connect-retry-max 5\n"; + cfg+="resolv-retry 5\n"; + + + + // We cannot use anything else than tun + cfg+="dev tun\n"; + + // Server Address + cfg+="remote "; + cfg+=mServerName; + cfg+=" "; + cfg+=mServerPort; + if(mUseUdp) + cfg+=" udp\n"; + else + cfg+=" tcp\n"; + + + switch(mAuthenticationType) { + case VpnProfile.TYPE_CERTIFICATES: + // Ca + cfg+="ca "; + cfg+=mCaFilename; + cfg+="\n"; + + // Client Cert + Key + cfg+="key "; + cfg+=mClientKeyFilename; + cfg+="\n"; + cfg+="cert "; + cfg+=mClientCertFilename; + cfg+="\n"; + break; + case VpnProfile.TYPE_PKCS12: + cfg+="pkcs12 "; + cfg+=mPKCS12Filename; + cfg+="\n"; + cfg+="management-query-passwords\n"; + break; + + case VpnProfile.TYPE_KEYSTORE: + cfg+="pkcs12 "; + cfg+=cacheDir.getAbsolutePath() + "/" + OVPNCONFIGPKCS12; + cfg+="\n"; + cfg+="management-query-passwords\n"; + break; + + } + + if(mUseLzo) { + cfg+="comp-lzo\n"; + } + + if(mUseTLSAuth) { + cfg+="tls-auth "; + cfg+=mTLSAuthFilename; + int tlsdir= mTLSAuthDirection; + // 2 is unspecified + if(tlsdir == 0 || tlsdir==1) { + cfg+=" "; + cfg+=new Integer(tlsdir).toString(); + } + cfg+="\n"; + } + + return cfg; + } + private String[] buildOpenvpnArgv(File cacheDir) + { + Vector<String> args = new Vector<String>(); + + // Add fixed paramenters + args.add("openvpn"); + + // Enable managment interface to + // stop openvpn + args.add("--management"); + + args.add(cacheDir.getAbsolutePath() + "/" + "mgmtsocket"); + args.add("unix"); + //args.add("--management-hold"); + + args.add("--config"); + args.add(cacheDir.getAbsolutePath() + "/" + OVPNCONFIGFILE); + + + return (String[]) args.toArray(new String[args.size()]); + } + + public Intent prepareIntent(Activity activity) { + String prefix = activity.getPackageName(); + + Intent intent = new Intent(activity,OpenVpnService.class); + + intent.putExtra(prefix + ".ARGV" , buildOpenvpnArgv(activity.getCacheDir())); + + if(mAuthenticationType == TYPE_PKCS12){ + intent.putExtra(prefix + ".PKCS12PASS", + mPKCS12Password); + } + + if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE) { + String pkcs12pw = savePKCS12(activity); + intent.putExtra(prefix + ".PKCS12PASS", pkcs12pw); + } + + if(mAuthenticationType == VpnProfile.TYPE_USERPASS) { + intent.putExtra(prefix + ".USERNAME", mUsername); + intent.putExtra(prefix + ".PASSWORD", mPassword); + } + + try { + FileWriter cfg = new FileWriter(activity.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); + cfg.write(getConfigFile(activity.getCacheDir())); + cfg.flush(); + cfg.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + return intent; + } + + private String getRandomPW() { + String pw= ""; + // Put enough digits togher to make a password :) + Random r = new Random(); + for(int i=0;i < 4;i++) { + pw += new Integer(r.nextInt(1000)).toString(); + } + + return pw; + + } + + private String savePKCS12(Context context) { + PrivateKey privateKey = null; + X509Certificate[] cachain=null; + try { + privateKey = KeyChain.getPrivateKey(context,mAlias); + cachain = KeyChain.getCertificateChain(context, mAlias); + + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + ks.setKeyEntry("usercert", privateKey, null, cachain); + String mypw = getRandomPW(); + FileOutputStream fout = new FileOutputStream(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGPKCS12); + ks.store(fout,mypw.toCharArray()); + fout.flush(); fout.close(); + return mypw; + } catch (KeyChainException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (CertificateException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return "ERROR"; + + } + } + + + + |