From d0a2ac4569bb15c097ba2c542ae1748ba1edbdc1 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 13 May 2012 01:16:27 +0200 Subject: Config Import useable (closes issue #14) Correct save/restore state in Basic Settings (closes issue #17) --- res/drawable-hdpi/ic_menu_archive.png | Bin 0 -> 1094 bytes res/drawable-mdpi/ic_menu_archive.png | Bin 0 -> 831 bytes res/drawable-xhdpi/ic_menu_archive.png | Bin 0 -> 1398 bytes res/values/strings.xml | 6 +- res/xml/vpn_ipsettings.xml | 9 +- src/de/blinkt/openvpn/CIDRIP.java | 56 ++++++++++ src/de/blinkt/openvpn/ConfigConverter.java | 41 ++++---- src/de/blinkt/openvpn/ConfigParser.java | 152 +++++++++++++++++++++------- src/de/blinkt/openvpn/FileSelect.java | 11 +- src/de/blinkt/openvpn/FileSelectLayout.java | 14 ++- src/de/blinkt/openvpn/OpenVpnService.java | 56 +--------- src/de/blinkt/openvpn/Settings_Basic.java | 2 + src/de/blinkt/openvpn/Settings_IP.java | 8 +- src/de/blinkt/openvpn/VPNProfileList.java | 22 ++-- src/de/blinkt/openvpn/VpnProfile.java | 24 +++-- todo.txt | 10 -- 16 files changed, 256 insertions(+), 155 deletions(-) create mode 100644 res/drawable-hdpi/ic_menu_archive.png create mode 100644 res/drawable-mdpi/ic_menu_archive.png create mode 100644 res/drawable-xhdpi/ic_menu_archive.png create mode 100644 src/de/blinkt/openvpn/CIDRIP.java diff --git a/res/drawable-hdpi/ic_menu_archive.png b/res/drawable-hdpi/ic_menu_archive.png new file mode 100644 index 0000000..e2d9bc1 Binary files /dev/null and b/res/drawable-hdpi/ic_menu_archive.png differ diff --git a/res/drawable-mdpi/ic_menu_archive.png b/res/drawable-mdpi/ic_menu_archive.png new file mode 100644 index 0000000..49ac569 Binary files /dev/null and b/res/drawable-mdpi/ic_menu_archive.png differ diff --git a/res/drawable-xhdpi/ic_menu_archive.png b/res/drawable-xhdpi/ic_menu_archive.png new file mode 100644 index 0000000..b1be9d5 Binary files /dev/null and b/res/drawable-xhdpi/ic_menu_archive.png differ diff --git a/res/values/strings.xml b/res/values/strings.xml index a5a8821..e2121d4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -206,5 +206,9 @@ Importing config file from source %1$s Your config file specified a pkcs12 file. Please import the file by selecting select in the Basic Settings configuration of the converted VPN Your configuration had a few configuration options that could be parsed. These options were added as custom configuration options. The custom configuration is displayed below: - Done reading config file. + Done reading config file. + Do not bind to local address and port + No local binding + Please not that the config importer is an experimental feature. + Import configuration file diff --git a/res/xml/vpn_ipsettings.xml b/res/xml/vpn_ipsettings.xml index 00774b6..fe55e8b 100644 --- a/res/xml/vpn_ipsettings.xml +++ b/res/xml/vpn_ipsettings.xml @@ -18,7 +18,14 @@ android:dependency="usePull" android:dialogMessage="@string/ipv6_dialog_tile" android:key="ipv6_address" - android:title="@string/ipv6_address" /> + android:title="@string/ipv6_address" + android:enabled="false"/> + + > 1; + } + // Check if rest of netmask is only 1s + if(netmask != (0x1ffffffffl >> lenZeros)) { + // Asume no CIDR, set /32 + len=32; + } else { + len =32 -lenZeros; + } + + } + @Override + public String toString() { + return String.format("%s/%d",mIp,len); + } + + public boolean normalise(){ + long ip=0; + + String[] ipt = mIp.split("\\."); + + ip += Long.parseLong(ipt[0])<< 24; + ip += Integer.parseInt(ipt[1])<< 16; + ip += Integer.parseInt(ipt[2])<< 8; + ip += Integer.parseInt(ipt[3]); + + 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; + } + } +} \ No newline at end of file diff --git a/src/de/blinkt/openvpn/ConfigConverter.java b/src/de/blinkt/openvpn/ConfigConverter.java index 1973e0a..686a4e4 100644 --- a/src/de/blinkt/openvpn/ConfigConverter.java +++ b/src/de/blinkt/openvpn/ConfigConverter.java @@ -24,7 +24,7 @@ public class ConfigConverter extends ListActivity { private VpnProfile mResult; private ArrayAdapter mArrayAdapter; - + @Override protected void onCreate(Bundle savedInstanceState) { @@ -32,7 +32,7 @@ public class ConfigConverter extends ListActivity { Toast.makeText(this, "Got called!", Toast.LENGTH_LONG).show(); } - + @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId()==R.id.cancel){ @@ -41,6 +41,7 @@ public class ConfigConverter extends ListActivity { } else if(item.getItemId()==R.id.ok) { if(mResult==null) { log("Importing the config had error, cannot save it"); + return true; } Intent result = new Intent(); ProfileManager vpl = ProfileManager.getInstance(this); @@ -48,6 +49,7 @@ public class ConfigConverter extends ListActivity { result.putExtra(VpnProfile.EXTRA_PROFILEUUID,mResult.getUUID().toString()); setResult(Activity.RESULT_OK, result); finish(); + return true; } return super.onOptionsItemSelected(item); @@ -61,7 +63,7 @@ public class ConfigConverter extends ListActivity { return true; } - + private String embedFile(String filename) { if(filename == null || filename.equals("")) @@ -69,7 +71,7 @@ public class ConfigConverter extends ListActivity { // Already embedded, nothing to do if(filename.startsWith(VpnProfile.INLINE_TAG)) return filename; - + // Try diffent path relative to /mnt/sdcard File sdcard = Environment.getExternalStorageDirectory(); File root = new File("/"); @@ -82,15 +84,15 @@ public class ConfigConverter extends ListActivity { suffix = fileparts[i]; else suffix = fileparts[i] + "/" + suffix; - + File possibleFile = new File(rootdir,suffix); if(!possibleFile.canRead()) continue; - + // read the file inline String filedata = VpnProfile.INLINE_TAG; byte[] buf =new byte[2048]; - + log(R.string.trying_to_read, possibleFile.getAbsolutePath()); try { FileInputStream fis = new FileInputStream(possibleFile); @@ -105,25 +107,25 @@ public class ConfigConverter extends ListActivity { } catch (IOException e) { log(e.getLocalizedMessage()); } - - + + } } log(R.string.import_could_not_open,filename); return null; } - + void embedFiles() { // This where I would like to have a c++ style // void embedFile(std::string & option) - + mResult.mCaFilename = embedFile(mResult.mCaFilename); mResult.mClientCertFilename = embedFile(mResult.mClientCertFilename); mResult.mClientKeyFilename = embedFile(mResult.mClientKeyFilename); mResult.mTLSAuthFilename = embedFile(mResult.mTLSAuthFilename); } - - + + @Override protected void onStart() { super.onStart(); @@ -137,6 +139,7 @@ public class ConfigConverter extends ListActivity { final android.net.Uri data = intent.getData (); if (data != null) { + log(R.string.import_experimental); log(R.string.importing_config,data.toString()); try { InputStream is = getContentResolver().openInputStream(data); @@ -146,14 +149,14 @@ public class ConfigConverter extends ListActivity { } } } - + return; } private void log(String logmessage) { mArrayAdapter.add(logmessage); } - + private void doImport(InputStream is) { ConfigParser cp = new ConfigParser(); try { @@ -164,7 +167,7 @@ public class ConfigConverter extends ListActivity { displayWarnings(); log(R.string.import_done); return; - + } catch (IOException e) { log(R.string.error_reading_config_file); log(e.getLocalizedMessage()); @@ -173,7 +176,7 @@ public class ConfigConverter extends ListActivity { log(e.getLocalizedMessage()); } mResult=null; - + } private void displayWarnings() { @@ -181,11 +184,11 @@ public class ConfigConverter extends ListActivity { log(R.string.import_warning_custom_options); log(mResult.mCustomConfigOptions); } - + if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE) { log(R.string.import_pkcs12_to_keystore); } - + } diff --git a/src/de/blinkt/openvpn/ConfigParser.java b/src/de/blinkt/openvpn/ConfigParser.java index 8fde12b..a64fb40 100644 --- a/src/de/blinkt/openvpn/ConfigParser.java +++ b/src/de/blinkt/openvpn/ConfigParser.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; -import java.util.Map.Entry; import java.util.Vector; //! Openvpn Config FIle Parser, probably not 100% accurate but close enough @@ -17,7 +16,7 @@ import java.util.Vector; public class ConfigParser { - private HashMap> options = new HashMap>(); + private HashMap>> options = new HashMap>>(); public void parseConfig(InputStream inputStream) throws IOException, ConfigParseError { @@ -37,13 +36,16 @@ public class ConfigParser { continue; - if(args.get(0).startsWith("--")) args.set(0, args.get(0).substring(2)); checkinlinefile(args,br); - options.put(args.get(0), args); + String optionname = args.get(0); + if(!options.containsKey(optionname)) { + options.put(optionname, new Vector>()); + } + options.get(optionname).add(args); } } @@ -213,12 +215,18 @@ public class ConfigParser { "route-up", "ipchange", "route-up", - "auth-user-pass-verify" + "auth-user-pass-verify", + "route-gateway", + "topology", + "persist-tun", + "route-metric" + }; - // Missing - // proto tcp-client|udp - + + + // This method is far too long VpnProfile convertProfile() throws ConfigParseError{ + boolean noauthtypeset=true; VpnProfile np = new VpnProfile("converted Profile"); // Pull, client, tls-client np.clearDefaults(); @@ -228,17 +236,34 @@ public class ConfigParser { options.remove("pull"); options.remove("client"); } - + Vector secret = getOption("secret", 1, 2); if(secret!=null) { np.mAuthenticationType=VpnProfile.TYPE_STATICKEYS; + noauthtypeset=false; np.mUseTLSAuth=true; np.mTLSAuthFilename=secret.get(1); if(secret.size()==3) np.mTLSAuthDirection=secret.get(2); + } - + + Vector> routes = getAllOption("route", 1, 4); + if(routes!=null) { + String routeopt = ""; + for(Vector route:routes){ + String netmask = "255.255.255.255"; + if(route.size() >= 3) + netmask = route.get(2); + String net = route.get(1); + + CIDRIP cidr = new CIDRIP(net, netmask); + routeopt+=cidr.toString() + " "; + } + np.mCustomRoutes=routeopt; + } + Vector tlsauth = getOption("tls-auth", 1, 2); if(tlsauth!=null) { @@ -252,12 +277,9 @@ public class ConfigParser { if(direction!=null) np.mTLSAuthDirection=direction.get(1); - if(options.containsKey("redirect-gateway")) { - options.remove("redirect-gateway"); - np.mUseDefaultRoute=true; - } else { + + if(getAllOption("redirect-gateway", 0, 5) != null) np.mUseDefaultRoute=true; - } Vector dev =getOption("dev",1,1); Vector devtype =getOption("dev-type",1,1); @@ -296,24 +318,41 @@ public class ConfigParser { np.mServerName = remote.get(1); } } + + Vector port = getOption("port", 1,1); + if(port!=null){ + np.mServerPort = port.get(1); + } - Vector proto = getOption("proto, ", 1,1); + Vector proto = getOption("proto", 1,1); if(proto!=null){ if(proto.get(1).equals("udp")) np.mUseUdp=true; - else if (proto.get(1).equals("tcp-client")) + else if (proto.get(1).equals("tcp-client") || + proto.get(1).equals("tcp")) np.mUseUdp=false; else throw new ConfigParseError("Unsupported option to --proto " + proto.get(1)); - + } - - Vector dhcpoption = getOption("dhcp-options", 1, 3); - if(dhcpoption!=null) { - String type=dhcpoption.get(1); + Vector> dhcpoptions = getAllOption("dhcp-options", 2, 2); + if(dhcpoptions!=null) { + for(Vector dhcpoption:dhcpoptions) { + String type=dhcpoption.get(1); + String arg = dhcpoption.get(2); + if(type.equals("DOMAIN")) { + np.mSearchDomain=dhcpoption.get(2); + } else if(type.equals("DNS")) { + np.mOverrideDNS=true; + if(np.mDNS1.equals(VpnProfile.DEFAULT_DNS1)) + np.mDNS1=arg; + else + np.mDNS2=arg; + } + } } - + if(getOption("remote-random-hostname", 0, 0)!=null) np.mUseRandomHostname=true; @@ -336,6 +375,7 @@ public class ConfigParser { if(cert!=null){ np.mClientCertFilename = cert.get(1); np.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES; + noauthtypeset=false; } Vector key= getOption("key",1,1); if(key!=null) @@ -345,6 +385,7 @@ public class ConfigParser { if(pkcs12!=null) { np.mPKCS12Filename = pkcs12.get(1); np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; + noauthtypeset=false; } Vector tlsremote = getOption("tls-remote",1,1); @@ -352,14 +393,36 @@ public class ConfigParser { np.mRemoteCN = tlsremote.get(1); np.mCheckRemoteCN=true; } - + Vector verb = getOption("verb",1,1); if(verb!=null){ np.mVerb=verb.get(1); } + + if(getOption("nobind", 0, 0) != null) + np.mNobind=true; + + if(getOption("auth-user-pass",0,1) != 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; + } + } + + // Check the other options + checkIgnoreAndInvalidOptions(np); + fixup(np); + + return np; + } + + 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)); @@ -369,24 +432,23 @@ public class ConfigParser { options.remove(option); if(options.size()> 0) { - String custom = "# These Options were found in the config file but not parsed:\n"; - for(Entry> option:options.entrySet()) { - for (String arg : option.getValue()) { - custom+= arg + " "; + String custom = "# These Options were found in the config file do not map to config settings:\n"; + + for(Vector> option:options.values()) { + for(Vector optionsline: option) { + for (String arg : optionsline) + custom+= arg + " "; } custom+="\n"; + } np.mCustomConfigOptions = custom; np.mUseCustomConfig=true; } - - - fixup(np); - - return np; } + private void fixup(VpnProfile np) { if(np.mRemoteCN.equals(np.mServerName)) { np.mRemoteCN=""; @@ -394,14 +456,26 @@ public class ConfigParser { } private Vector getOption(String option, int minarg, int maxarg) throws ConfigParseError { - Vector args = options.get(option); + Vector> alloptions = getAllOption(option, minarg, maxarg); + if(alloptions==null) + return null; + else + return alloptions.lastElement(); + } + + + private Vector> getAllOption(String option, int minarg, int maxarg) throws ConfigParseError { + Vector> args = options.get(option); if(args==null) return null; - if(args.size()< (minarg+1) || args.size() > maxarg+1) { - String err = String.format("Option %s has %d parameters, expected between %d and %d", - option,args.size()-1,minarg,maxarg ); - throw new ConfigParseError(err); - } + + for(Vector optionline:args) + + if(optionline.size()< (minarg+1) || optionline.size() > maxarg+1) { + String err = String.format("Option %s has %d parameters, expected between %d and %d", + option,args.size()-1,minarg,maxarg ); + throw new ConfigParseError(err); + } options.remove(option); return args; } diff --git a/src/de/blinkt/openvpn/FileSelect.java b/src/de/blinkt/openvpn/FileSelect.java index 12a3ae0..cc8f55f 100644 --- a/src/de/blinkt/openvpn/FileSelect.java +++ b/src/de/blinkt/openvpn/FileSelect.java @@ -19,6 +19,7 @@ import android.os.Bundle; public class FileSelect extends Activity { public static final String RESULT_DATA = "RESULT_PATH"; public static final String START_DATA = "START_DATA"; + public static final String WINDOW_TITLE = "WINDOW_TILE"; public static final String NO_INLINE_SELECTION = "de.blinkt.openvpn.NO_INLINE_SELECTION"; private FileSelectionFragment mFSFragment; private InlineFileTab mInlineFragment; @@ -26,7 +27,8 @@ public class FileSelect extends Activity { private Tab inlineFileTab; private Tab fileExplorerTab; private boolean mNoInline; - + + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -36,6 +38,13 @@ public class FileSelect extends Activity { if(mData==null) mData="/sdcard"; + String title = getIntent().getStringExtra(WINDOW_TITLE); + int titleId = getIntent().getIntExtra(WINDOW_TITLE, 0); + if(titleId!=0) + title =getString(titleId); + if(title!=null) + setTitle(title); + mNoInline = getIntent().getBooleanExtra(NO_INLINE_SELECTION, false); ActionBar bar = getActionBar(); diff --git a/src/de/blinkt/openvpn/FileSelectLayout.java b/src/de/blinkt/openvpn/FileSelectLayout.java index 0be099a..1a60d13 100644 --- a/src/de/blinkt/openvpn/FileSelectLayout.java +++ b/src/de/blinkt/openvpn/FileSelectLayout.java @@ -19,6 +19,8 @@ public class FileSelectLayout extends LinearLayout implements OnClickListener { private Fragment mFragment; private int mTaskId; private Button mSelectButton; + private boolean mNoInline; + private String mTitle; public FileSelectLayout( Context context,AttributeSet attrset) { super(context,attrset); @@ -26,10 +28,10 @@ public class FileSelectLayout extends LinearLayout implements OnClickListener { TypedArray ta = context.obtainStyledAttributes(attrset,R.styleable.FileSelectLayout); - String title = ta.getString(R.styleable.FileSelectLayout_title); + mTitle = ta.getString(R.styleable.FileSelectLayout_title); TextView tview = (TextView) findViewById(R.id.file_title); - tview.setText(title); + tview.setText(mTitle); mDataView = (TextView) findViewById(R.id.file_selected_item); mSelectButton = (Button) findViewById(R.id.file_select_button); @@ -46,7 +48,9 @@ public class FileSelectLayout extends LinearLayout implements OnClickListener { public void getCertificateFileDialog() { Intent startFC = new Intent(getContext(),FileSelect.class); startFC.putExtra(FileSelect.START_DATA, mData); - + startFC.putExtra(FileSelect.WINDOW_TITLE,mTitle); + if(mNoInline) + startFC.putExtra(FileSelect.NO_INLINE_SELECTION, true); mFragment.startActivityForResult(startFC,mTaskId); } @@ -73,5 +77,9 @@ public class FileSelectLayout extends LinearLayout implements OnClickListener { } } + public void setNoline() { + mNoInline=true; + } + } diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index fb60d84..8a884fc 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.List; import java.util.Vector; + import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.app.PendingIntent; @@ -54,61 +55,6 @@ public class OpenVpnService extends VpnService implements Handler.Callback { - class CIDRIP{ - String mIp; - int len; - public CIDRIP(String ip, String mask){ - mIp=ip; - String[] ipt = mask.split("\\."); - long netmask=0; - - netmask += Long.parseLong(ipt[0])<< 24; - netmask += Integer.parseInt(ipt[1])<< 16; - netmask += Integer.parseInt(ipt[2])<< 8; - netmask += Integer.parseInt(ipt[3]); - - // Add 33. bit to ensure the loop terminates - netmask += 1l << 32; - - int lenZeros = 0; - while((netmask & 0x1) == 0) { - lenZeros++; - netmask = netmask >> 1; - } - // Check if rest of netmask is only 1s - if(netmask != (0x1ffffffffl >> lenZeros)) { - // Asume no CIDR, set /32 - len=32; - } else { - len =32 -lenZeros; - } - - } - @Override - public String toString() { - return String.format("%s/%d",mIp,len); - } - - public boolean normalise(){ - long ip=0; - - String[] ipt = mIp.split("\\."); - - ip += Long.parseLong(ipt[0])<< 24; - ip += Integer.parseInt(ipt[1])<< 16; - ip += Integer.parseInt(ipt[2])<< 8; - ip += Integer.parseInt(ipt[3]); - - 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; - } - } - } - @Override public void onRevoke() { OpenVpnManagementThread.stopOpenVPN(); diff --git a/src/de/blinkt/openvpn/Settings_Basic.java b/src/de/blinkt/openvpn/Settings_Basic.java index 7586b27..0066317 100644 --- a/src/de/blinkt/openvpn/Settings_Basic.java +++ b/src/de/blinkt/openvpn/Settings_Basic.java @@ -124,6 +124,7 @@ public class Settings_Basic extends Fragment implements View.OnClickListener, On addFileSelectLayout(mClientCert); addFileSelectLayout(mClientKey); addFileSelectLayout(mpkcs12); + mpkcs12.setNoline(); loadPreferences(); @@ -285,6 +286,7 @@ public class Settings_Basic extends Fragment implements View.OnClickListener, On @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); + savePreferences(); outState.putString(getActivity().getPackageName() + "profileUUID", mProfile.getUUID().toString()); } diff --git a/src/de/blinkt/openvpn/Settings_IP.java b/src/de/blinkt/openvpn/Settings_IP.java index de625d2..52dcc5d 100644 --- a/src/de/blinkt/openvpn/Settings_IP.java +++ b/src/de/blinkt/openvpn/Settings_IP.java @@ -20,6 +20,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang private CheckBoxPreference mUseDefaultRoute; private VpnProfile mProfile; private CheckBoxPreference mRouteNoPull; + private CheckBoxPreference mNobind; @Override public void onCreate(Bundle savedInstanceState) { @@ -47,6 +48,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang mCustomRoutes = (EditTextPreference) findPreference("customRoutes"); mUseDefaultRoute = (CheckBoxPreference) findPreference("useDefaultRoute"); mRouteNoPull = (CheckBoxPreference) findPreference("routenopull"); + mNobind = (CheckBoxPreference) findPreference("nobind"); mIPv4.setOnPreferenceChangeListener(this); mIPv6.setOnPreferenceChangeListener(this); @@ -56,10 +58,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang mOverrideDNS.setOnPreferenceChangeListener(this); mSearchdomain.setOnPreferenceChangeListener(this); mCustomRoutes.setOnPreferenceChangeListener(this); - - - - + loadSettings(); } @@ -109,6 +108,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang mProfile.mUseDefaultRoute = mUseDefaultRoute.isChecked(); mProfile.mCustomRoutes = mCustomRoutes.getText(); mProfile.mRoutenopull = mRouteNoPull.isChecked(); + mProfile.mNobind = mNobind.isChecked(); } diff --git a/src/de/blinkt/openvpn/VPNProfileList.java b/src/de/blinkt/openvpn/VPNProfileList.java index a14c835..beadf53 100644 --- a/src/de/blinkt/openvpn/VPNProfileList.java +++ b/src/de/blinkt/openvpn/VPNProfileList.java @@ -1,6 +1,5 @@ package de.blinkt.openvpn; -import de.blinkt.openvpn.FileSelect.MyTabsListener; import android.app.Activity; import android.app.AlertDialog; import android.app.ListFragment; @@ -95,6 +94,10 @@ public class VPNProfileList extends ListFragment { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); + setListAdapter(); + } + + private void setListAdapter() { mArrayadapter = new VPNArrayAdapter(getActivity(),R.layout.vpn_list_item,R.id.vpn_item_title); mArrayadapter.addAll(getPM().getProfiles()); @@ -112,8 +115,8 @@ public class VPNProfileList extends ListFragment { | MenuItem.SHOW_AS_ACTION_WITH_TEXT); menu.add(0, MENU_IMPORT_PROFILE, 0, R.string.menu_import) - .setIcon(android.R.drawable.ic_menu_myplaces) - .setAlphabeticShortcut('a') + .setIcon(R.drawable.ic_menu_archive) + .setAlphabeticShortcut('i') .setTitleCondensed(getActivity().getString(R.string.menu_import_short)) .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT ); @@ -129,6 +132,7 @@ public class VPNProfileList extends ListFragment { } else if (itemId == MENU_IMPORT_PROFILE) { Intent intent = new Intent(getActivity(),FileSelect.class); intent.putExtra(FileSelect.NO_INLINE_SELECTION, true); + intent.putExtra(FileSelect.WINDOW_TITLE, R.string.import_configuration_file); startActivityForResult(intent, SELECT_PROFILE); return true; } else { @@ -185,12 +189,7 @@ public class VPNProfileList extends ListFragment { }); - dialog.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }); + dialog.setNegativeButton(android.R.string.cancel, null); dialog.create().show(); } @@ -224,8 +223,9 @@ public class VPNProfileList extends ListFragment { VpnProfile profile = ProfileManager.get(configuredVPN); getPM().saveProfile(getActivity(), profile); - // Name could be modified - + // Name could be modified, reset List adapter + setListAdapter(); + } else if(requestCode== SELECT_PROFILE) { String filedata = data.getStringExtra(FileSelect.RESULT_DATA); Intent startImport = new Intent(getActivity(),ConfigConverter.class); diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index b7297e8..aed9ca0 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -37,14 +37,10 @@ public class VpnProfile implements Serializable{ public static final int TYPE_USERPASS_CERTIFICATES = 5; public static final int TYPE_USERPASS_PKCS12 = 6; public static final int TYPE_USERPASS_KEYSTORE = 7; - + // Don't change this, not all parts of the program use this constant public static final String EXTRA_PROFILEUUID = "de.blinkt.openvpn.profileUUID"; - - - - - + public static final String INLINE_TAG = "[[INLINE]]"; private static final String OVPNCONFIGFILE = "android.conf"; protected transient String mTransientPW=null; @@ -52,6 +48,8 @@ public class VpnProfile implements Serializable{ private static transient String mTempPKCS12Password; + public static String DEFAULT_DNS1="131.234.137.23"; + public static String DEFAULT_DNS2="131.234.137.24"; // Public attributes, since I got mad with getter/setter // set members to default values @@ -71,8 +69,8 @@ public class VpnProfile implements 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 mDNS1=DEFAULT_DNS1; + public String mDNS2=DEFAULT_DNS2; public String mIPv4Address; public String mIPv6Address; public boolean mOverrideDNS=false; @@ -92,9 +90,8 @@ public class VpnProfile implements Serializable{ public String mCustomConfigOptions=""; public String mVerb="1"; public String mCipher=""; - public static final String INLINE_TAG = "[[INLINE]]"; + public boolean mNobind=false; - public void clearDefaults() { mServerName="unkown"; @@ -266,6 +263,9 @@ public class VpnProfile implements Serializable{ cfg+="dhcp-option DNS " + mDNS2 + "\n"; } + + if(mNobind) + cfg+="nobind\n"; @@ -307,7 +307,9 @@ public class VpnProfile implements Serializable{ //! Put inline data inline and other data as normal escaped filename private String insertFileData(String cfgentry, String filedata) { - if(filedata.startsWith(VpnProfile.INLINE_TAG)){ + if(filedata==null) { + return String.format("%s %s\n",cfgentry,"missing"); + }else if(filedata.startsWith(VpnProfile.INLINE_TAG)){ String datawoheader = filedata.substring(VpnProfile.INLINE_TAG.length()); return String.format("<%s>\n%s\n\n",cfgentry,datawoheader,cfgentry); } else { diff --git a/todo.txt b/todo.txt index 6e3f8b7..2bafaff 100644 --- a/todo.txt +++ b/todo.txt @@ -1,9 +1,4 @@ Ideas: - -- Implement tabbed filebrowser with - 1. tab file selection - 2. tab inline file for safer storage - - implement security notice fragment - explain plain text storage of all data except for android keystore - explain even more insecure of storage on sd card @@ -11,9 +6,6 @@ Ideas: - implement a small app that can do cert+key+ca => p12 or suggest an app on the market - Implementation in ICS OpenVpn would require SD_WRITE permission which I would like to avoid -- finish .ovpn -> configuration importer - - depends on inline file storage, since config files can include inline files - - implement an encryption for profiles, so no sensitive data has be stored in plain text - encrypt/decrypt with android private storage key (+no user input required) @@ -42,8 +34,6 @@ Tap support: - need to chose right mac of receiver Requested by users: -cipher auth mtu-link -nobind -- cgit v1.2.3