diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/de/blinkt/openvpn/ConfigConverter.java | 59 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/ConfigParser.java | 36 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/FaqFragment.java | 5 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/FileProvider.java | 157 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/LaunchVPN.java | 4 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/LogWindow.java | 5 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/MainActivity.java | 14 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/NetworkSateReceiver.java | 4 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVPN.java | 60 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVPNThread.java | 31 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnManagementThread.java | 22 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 43 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/ProfileManager.java | 2 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/SendDumpActivity.java | 60 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/Settings_Obscure.java | 43 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/VpnProfile.java | 27 | 
16 files changed, 473 insertions, 99 deletions
| diff --git a/src/de/blinkt/openvpn/ConfigConverter.java b/src/de/blinkt/openvpn/ConfigConverter.java index 3f204368..40aa24e0 100644 --- a/src/de/blinkt/openvpn/ConfigConverter.java +++ b/src/de/blinkt/openvpn/ConfigConverter.java @@ -6,6 +6,7 @@ import java.io.FileInputStream;  import java.io.FileNotFoundException;  import java.io.IOException;  import java.io.InputStream; +import java.io.InputStreamReader;  import java.util.List;  import java.util.Vector; @@ -143,23 +144,22 @@ public class ConfigConverter extends ListActivity {  	private Intent installPKCS12() {  		if(!((CheckBox)findViewById(R.id.importpkcs12)).isChecked()) { -			embedPKCS12File(); +			setAuthTypeToEmbeddedPKCS12();  			return null; +			  		} -		 -		File possiblepkcs12 = findFile(mResult.mPKCS12Filename); -		if(possiblepkcs12!=null) { +		String pkcs12datastr = mResult.mPKCS12Filename; +		if(pkcs12datastr!=null && pkcs12datastr.startsWith(VpnProfile.INLINE_TAG)) {  			Intent inkeyintent = KeyChain.createInstallIntent(); -			byte[] pkcs12data; -			try { -				pkcs12data = readBytesFromFile(possiblepkcs12); -			} catch (IOException e) { -				return null; -			} +			 +			pkcs12datastr= pkcs12datastr.substring(VpnProfile.INLINE_TAG.length()); +			 +			 +			byte[] pkcs12data = Base64.decode(pkcs12datastr, Base64.DEFAULT); +  			inkeyintent.putExtra(KeyChain.EXTRA_PKCS12,pkcs12data ); -			mAliasName = possiblepkcs12.getName().replace(".p12", "");  			if(mAliasName.equals(""))  				mAliasName=null; @@ -174,9 +174,8 @@ public class ConfigConverter extends ListActivity { -	private void embedPKCS12File() { -		mResult.mPKCS12Filename = embedFile(mResult.mPKCS12Filename,true); -		if(mResult.mPKCS12Filename.startsWith(VpnProfile.INLINE_TAG)) { +	private void setAuthTypeToEmbeddedPKCS12() { +		if(mResult.mPKCS12Filename!=null && mResult.mPKCS12Filename.startsWith(VpnProfile.INLINE_TAG)) {  			if(mResult.mAuthenticationType==VpnProfile.TYPE_USERPASS_KEYSTORE)  				mResult.mAuthenticationType=VpnProfile.TYPE_USERPASS_PKCS12; @@ -228,13 +227,24 @@ public class ConfigConverter extends ListActivity {  		File possibleFile = findFile(filename);  		if(possibleFile==null) -			return null; +			return filename;  		else  			return readFileContent(possibleFile,base64encode);  	} -	private File findFile(String filename) +	private File findFile(String filename) { +		File foundfile =findFileRaw(filename); +		 +		if (foundfile==null && filename!=null && !filename.equals("")) +			log(R.string.import_could_not_open,filename); + +		return foundfile; +	} + + + +	private File findFileRaw(String filename)  	{  		if(filename == null || filename.equals(""))  			return null; @@ -274,7 +284,6 @@ public class ConfigConverter extends ListActivity {  			}  		} -		log(R.string.import_could_not_open,filename);  		return null;  	} @@ -324,10 +333,22 @@ public class ConfigConverter extends ListActivity {  		// This where I would like to have a c++ style  		// void embedFile(std::string & option) +		if (mResult.mPKCS12Filename!=null) { +			File pkcs12file = findFileRaw(mResult.mPKCS12Filename); +			if(pkcs12file!=null) { +				mAliasName = pkcs12file.getName().replace(".p12", ""); +			} else { +				mAliasName = "Imported PKCS12"; +			} +		} +			 +		  		mResult.mCaFilename = embedFile(mResult.mCaFilename);  		mResult.mClientCertFilename = embedFile(mResult.mClientCertFilename);  		mResult.mClientKeyFilename = embedFile(mResult.mClientKeyFilename);  		mResult.mTLSAuthFilename = embedFile(mResult.mTLSAuthFilename); +		mResult.mPKCS12Filename = embedFile(mResult.mPKCS12Filename,true); +		  		if(mResult.mUsername != null && !mResult.mUsername.equals("")){  			String data =embedFile(mResult.mUsername); @@ -387,7 +408,9 @@ public class ConfigConverter extends ListActivity {  	private void doImport(InputStream is) {  		ConfigParser cp = new ConfigParser();  		try { -			cp.parseConfig(is); +			InputStreamReader isr = new InputStreamReader(is); + +			cp.parseConfig(isr);  			VpnProfile vp = cp.convertProfile();  			mResult = vp;  			embedFiles(); diff --git a/src/de/blinkt/openvpn/ConfigParser.java b/src/de/blinkt/openvpn/ConfigParser.java index 3d20bc31..cdec964e 100644 --- a/src/de/blinkt/openvpn/ConfigParser.java +++ b/src/de/blinkt/openvpn/ConfigParser.java @@ -4,7 +4,9 @@ import java.io.BufferedReader;  import java.io.IOException;  import java.io.InputStream;  import java.io.InputStreamReader; +import java.io.Reader;  import java.util.HashMap; +import java.util.Locale;  import java.util.Vector;  //! Openvpn Config FIle Parser, probably not 100% accurate but close enough @@ -17,11 +19,10 @@ public class ConfigParser {  	private HashMap<String, Vector<Vector<String>>> options = new HashMap<String, Vector<Vector<String>>>(); -	public void parseConfig(InputStream inputStream) throws IOException, ConfigParseError { +	public void parseConfig(Reader reader) throws IOException, ConfigParseError { -		InputStreamReader fr = new InputStreamReader(inputStream); -		BufferedReader br =new BufferedReader(fr); +		BufferedReader br =new BufferedReader(reader);  		@SuppressWarnings("unused")  		int lineno=0; @@ -85,7 +86,7 @@ public class ConfigParser {  	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.isSpace(c) || c == '\0'; +		return Character.isWhitespace(c) || c == '\0';  	} @@ -229,10 +230,14 @@ public class ConfigParser {  			"route-gateway",  			"route-metric",  			"route-method", +			"status", +			"script-security",  			"show-net-up",  			"suppress-timestamps",  			"tmp-dir", +			"tun-ipv6",  			"topology", +			"win-sys",  	}; @@ -351,10 +356,12 @@ public class ConfigParser {  		Vector<String> proto = getOption("proto", 1,1);  		if(proto!=null){ -			if(proto.get(1).equals("udp")) +			if(proto.get(1).equals("udp") || proto.get(1).equals("udp6"))  				np.mUseUdp=true;  			else if (proto.get(1).equals("tcp-client") || -					proto.get(1).equals("tcp")) +					proto.get(1).equals("tcp")  ||  +					proto.get(1).equals("tcp6") || +					proto.get(1).endsWith("tcp6-client"))  				np.mUseUdp=false;  			else   				throw new ConfigParseError("Unsupported option to --proto " + proto.get(1)); @@ -437,6 +444,21 @@ public class ConfigParser {  		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){ @@ -512,7 +534,7 @@ public class ConfigParser {  		for(Vector<String> 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", +				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);  			} diff --git a/src/de/blinkt/openvpn/FaqFragment.java b/src/de/blinkt/openvpn/FaqFragment.java index 79029757..a358dc9a 100644 --- a/src/de/blinkt/openvpn/FaqFragment.java +++ b/src/de/blinkt/openvpn/FaqFragment.java @@ -22,9 +22,10 @@ public class FaqFragment extends Fragment  {      		Bundle savedInstanceState) {      	View v= inflater.inflate(R.layout.faq, container, false); -    	insertHtmlEntry(v,R.id.brokenimages,R.string.broken_images_faq); +    	insertHtmlEntry(v,R.id.broken_images_faq,R.string.broken_images_faq);      	insertHtmlEntry(v,R.id.faq_howto,R.string.faq_howto); -    	insertHtmlEntry(v, R.id.faq_battery, R.string.baterry_consumption);    	 +    	insertHtmlEntry(v, R.id.baterry_consumption, R.string.baterry_consumption);   +    	insertHtmlEntry(v, R.id.faq_tethering, R.string.faq_tethering);  		return v; diff --git a/src/de/blinkt/openvpn/FileProvider.java b/src/de/blinkt/openvpn/FileProvider.java new file mode 100644 index 00000000..e86b544f --- /dev/null +++ b/src/de/blinkt/openvpn/FileProvider.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.blinkt.openvpn; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import android.content.ContentProvider; +import android.content.ContentProvider.PipeDataWriter; +import android.content.ContentValues; +import android.content.res.AssetFileDescriptor; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.provider.OpenableColumns; +import android.util.Log; + +/** + * A very simple content provider that can serve arbitrary asset files from + * our .apk. + */ +public class FileProvider extends ContentProvider +implements PipeDataWriter<InputStream> { +	@Override +	public boolean onCreate() { +		return true; +	} + +	@Override +	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, +			String sortOrder) { +		try { +			File dumpfile = getFileFromURI(uri); + + +			MatrixCursor c = new MatrixCursor(projection); + +			Object[] row = new Object[projection.length]; +			int i=0; +			for (String r:projection) { +				if(r.equals(OpenableColumns.SIZE)) +					row[i] = dumpfile.length(); +				if(r.equals(OpenableColumns.DISPLAY_NAME)) +					row[i] = dumpfile.getName(); +				i++; +			} +			c.addRow(row); +			return c; +		} catch (FileNotFoundException e) { +			e.printStackTrace(); +			return null; +		} + + +	} + +	@Override +	public Uri insert(Uri uri, ContentValues values) { +		// Don't support inserts. +		return null; +	} + +	@Override +	public int delete(Uri uri, String selection, String[] selectionArgs) { +		// Don't support deletes. +		return 0; +	} + +	@Override +	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { +		// Don't support updates. +		return 0; +	} + +	@Override +	public String getType(Uri uri) { +		// For this sample, assume all files are .apks. +		return "application/octet-stream"; +	} + +	@Override +	public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { +		File dumpfile = getFileFromURI(uri); + +		try { + +			InputStream is = new FileInputStream(dumpfile); +			// Start a new thread that pipes the stream data back to the caller. +			return new AssetFileDescriptor( +					openPipeHelper(uri, null, null, is, this), 0, +					dumpfile.length()); +		} catch (IOException e) { +			FileNotFoundException fnf = new FileNotFoundException("Unable to open minidump " + uri); +			throw fnf; +		} +	} + +	private File getFileFromURI(Uri uri) throws FileNotFoundException { +		// Try to open an asset with the given name. +		String path = uri.getPath(); +		if(path.startsWith("/")) +			path = path.replaceFirst("/", "");        + +		// I think this already random enough, no need for magic secure cookies +		// 1f9563a4-a1f5-2165-255f2219-111823ef.dmp +		if (!path.matches("^[0-9a-z-.]*(dmp|dmp.log)$")) +			throw new FileNotFoundException("url not in expect format " + uri); +		File cachedir = getContext().getCacheDir(); +		File dumpfile = new File(cachedir,path); +		return dumpfile; +	} + +	@Override +	public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType, +			Bundle opts, InputStream args) { +		// Transfer data from the asset to the pipe the client is reading. +		byte[] buffer = new byte[8192]; +		int n; +		FileOutputStream fout = new FileOutputStream(output.getFileDescriptor()); +		try { +			while ((n=args.read(buffer)) >= 0) { +				fout.write(buffer, 0, n); +			} +		} catch (IOException e) { +			Log.i("OpenVPNFileProvider", "Failed transferring", e); +		} finally { +			try { +				args.close(); +			} catch (IOException e) { +			} +			try { +				fout.close(); +			} catch (IOException e) { +			} +		} +	} +} diff --git a/src/de/blinkt/openvpn/LaunchVPN.java b/src/de/blinkt/openvpn/LaunchVPN.java index c89704fa..bc0a4cf2 100644 --- a/src/de/blinkt/openvpn/LaunchVPN.java +++ b/src/de/blinkt/openvpn/LaunchVPN.java @@ -73,8 +73,8 @@ import android.widget.TextView;   */  public class LaunchVPN extends ListActivity implements OnItemClickListener { -	static final String EXTRA_KEY = "de.blinkt.openvpn.shortcutProfileUUID"; -	static final String EXTRA_NAME = "de.blinkt.openvpn.shortcutProfileName"; +	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; diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java index 8d228cf1..790e143a 100644 --- a/src/de/blinkt/openvpn/LogWindow.java +++ b/src/de/blinkt/openvpn/LogWindow.java @@ -76,6 +76,7 @@ public class LogWindow extends ListActivity implements StateListener  {  			return str;  		} +  		private void shareLog() {  			Intent shareIntent = new Intent(Intent.ACTION_SEND);  			shareIntent.putExtra(Intent.EXTRA_TEXT, getLogStr()); @@ -215,12 +216,13 @@ public class LogWindow extends ListActivity implements StateListener  {  					OpenVpnManagementThread.stopOpenVPN();		  				}  			}); -			 +  			builder.show();  			return true;  		} else if(item.getItemId()==R.id.info) {  			if(mBconfig==null)  				OpenVPN.triggerLogBuilderConfig(); +  		} else if(item.getItemId()==R.id.send) {  			ladapter.shareLog();  		} else if(item.getItemId()==R.id.edit_vpn) { @@ -252,6 +254,7 @@ public class LogWindow extends ListActivity implements StateListener  {  		return true;  	} +  	@Override  	protected void onResume() {  		super.onResume(); diff --git a/src/de/blinkt/openvpn/MainActivity.java b/src/de/blinkt/openvpn/MainActivity.java index 9b329817..32cf575b 100644 --- a/src/de/blinkt/openvpn/MainActivity.java +++ b/src/de/blinkt/openvpn/MainActivity.java @@ -1,8 +1,11 @@  package de.blinkt.openvpn; +import java.io.File; +import java.util.ArrayList;  import java.util.List;  import android.content.Intent; +import android.net.Uri;  import android.preference.PreferenceActivity;  public class MainActivity extends PreferenceActivity { @@ -19,6 +22,15 @@ public class MainActivity extends PreferenceActivity {  			translation.summary = translatedby;  			target.add(translation);  		} +		 +		if(SendDumpActivity.getLastestDump(this)!=null) { +			Header sendDump = new Header(); +			sendDump.titleRes = R.string.send_minidump; +			sendDump.summaryRes = R.string.send_minidump_summary; +			sendDump.intent = new Intent(this,SendDumpActivity.class); +			target.add(sendDump); +		} +		  	}  	@Override @@ -29,4 +41,6 @@ public class MainActivity extends PreferenceActivity {  	} + +  } diff --git a/src/de/blinkt/openvpn/NetworkSateReceiver.java b/src/de/blinkt/openvpn/NetworkSateReceiver.java index 6c38a0cb..e20c8e52 100644 --- a/src/de/blinkt/openvpn/NetworkSateReceiver.java +++ b/src/de/blinkt/openvpn/NetworkSateReceiver.java @@ -6,11 +6,7 @@ import android.content.Intent;  import android.content.SharedPreferences;
  import android.net.ConnectivityManager;
  import android.net.NetworkInfo;
 -import android.net.NetworkInfo.DetailedState;
  import android.net.NetworkInfo.State;
 -import android.net.wifi.SupplicantState;
 -import android.net.wifi.WifiInfo;
 -import android.net.wifi.WifiManager;
  import android.preference.PreferenceManager;
  public class NetworkSateReceiver extends BroadcastReceiver {
 diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index 6b65c22e..0ae681bc 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -7,10 +7,10 @@ import android.content.Context;  import android.os.Build;  public class OpenVPN { -	 +  	public static LinkedList<LogItem> logbuffer; -	 +  	private static Vector<LogListener> logListener;  	private static Vector<StateListener> stateListener;  	private static String[] mBconfig; @@ -18,14 +18,14 @@ public class OpenVPN {  	private static String mLaststatemsg;  	private static String mLaststate; -	 +  	static {  		logbuffer  = new LinkedList<LogItem>();  		logListener = new Vector<OpenVPN.LogListener>();  		stateListener = new Vector<OpenVPN.StateListener>();  		logInformation();  	} -	 +  	static class LogItem {  		public static final int ERROR = 1;  		public static final int INFO = 2; @@ -36,20 +36,20 @@ public class OpenVPN {  		private int mRessourceId;  		// Default log priority  		int mLevel = INFO; -		 +  		public LogItem(int ressourceId, Object[] args) { -		 mRessourceId = ressourceId; -		 mArgs = args; +			mRessourceId = ressourceId; +			mArgs = args;  		} -		 +  		public LogItem(int loglevel,int ressourceId, Object[] args) { -			 mRessourceId = ressourceId; -			 mArgs = args; -			 mLevel = loglevel; -			} +			mRessourceId = ressourceId; +			mArgs = args; +			mLevel = loglevel; +		} + -		  		public LogItem(String message) {  			mMessage = message;  		} @@ -70,28 +70,32 @@ public class OpenVPN {  			if(mMessage !=null) {  				return mMessage;  			} else { -				if(mArgs == null) -					return c.getString(mRessourceId); -				else -					return c.getString(mRessourceId,mArgs); +				if(c!=null) { +					if(mArgs == null) +						return c.getString(mRessourceId); +					else +						return c.getString(mRessourceId,mArgs); +				} else { +					return String.format("Log (no context) resid %d", mRessourceId); +				}  			}  		}  	} -	 +  	private static final int MAXLOGENTRIES = 200;  	public static final String MANAGMENT_PREFIX = "M:"; -	 +  	public interface LogListener {  		void newLog(LogItem logItem);  	} -	 +  	public interface StateListener {  		void updateState(String state, String logmessage);  	} @@ -108,7 +112,7 @@ public class OpenVPN {  	}  	private static void logInformation() { -		 +  		logInfo(R.string.mobile_info,Build.MODEL, Build.BOARD,Build.BRAND,Build.VERSION.SDK_INT);  	} @@ -120,7 +124,7 @@ public class OpenVPN {  		logListener.remove(ll);  	} -	 +  	synchronized static void addStateListener(StateListener sl){  		stateListener.add(sl);  		if(mLaststate!=null) @@ -156,14 +160,14 @@ public class OpenVPN {  	public synchronized static void updateStateString(String state, String msg) {  		mLaststate= state;  		mLaststatemsg = msg; -		 +  		for (StateListener sl : stateListener) {  			sl.updateState(state,msg);  		}  	}  	public static void logInfo(String message) { -		 +		newlogItem(new LogItem(LogItem.INFO, message));  	}  	public static void logInfo(int ressourceId, Object... args) { @@ -174,7 +178,7 @@ public class OpenVPN {  		logbuffer.addLast(logItem);  		if(logbuffer.size()>MAXLOGENTRIES)  			logbuffer.removeFirst(); -		 +  		for (LogListener ll : logListener) {  			ll.newLog(logItem);  		} @@ -182,7 +186,7 @@ public class OpenVPN {  	public static void logError(String msg) {  		newlogItem(new LogItem(LogItem.ERROR, msg)); -		 +  	}  	public static void logError(int ressourceId) { @@ -191,6 +195,6 @@ public class OpenVPN {  	public static void logError(int ressourceId, Object... args) {  		newlogItem(new LogItem(LogItem.ERROR, ressourceId,args));  	} -	 -	 + +  } diff --git a/src/de/blinkt/openvpn/OpenVPNThread.java b/src/de/blinkt/openvpn/OpenVPNThread.java index b4ead269..7d58552a 100644 --- a/src/de/blinkt/openvpn/OpenVPNThread.java +++ b/src/de/blinkt/openvpn/OpenVPNThread.java @@ -1,19 +1,24 @@  package de.blinkt.openvpn;
  import java.io.BufferedReader;
 +import java.io.BufferedWriter;
 +import java.io.FileWriter;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.util.LinkedList;
  import android.util.Log;
 +import de.blinkt.openvpn.OpenVPN.LogItem;
  public class OpenVPNThread implements Runnable {
 +	private static final String DUMP_PATH_STRING = "Dump path: ";
  	private static final String TAG = "OpenVPN";
  	private String[] mArgv;
  	private Process mProcess;
  	private String mNativeDir;
  	private OpenVpnService mService;
 +	private String mDumpPath;
  	public OpenVPNThread(OpenVpnService service,String[] argv, String nativelibdir)
  	{
 @@ -39,15 +44,28 @@ public class OpenVPNThread implements Runnable {  		} finally {
  			int exitvalue = 0;
  			try {
 -				 exitvalue = mProcess.exitValue();
 +				 exitvalue = mProcess.waitFor();
  			} catch ( IllegalThreadStateException ite) {
  				OpenVPN.logError("Illegal Thread state: " + ite.getLocalizedMessage());
 +			} catch (InterruptedException ie) {
 +				OpenVPN.logError("InterruptedException: " + ie.getLocalizedMessage());
  			}
  			if( exitvalue != 0)
  				OpenVPN.logError("Process exited with exit value " + exitvalue);
  			OpenVPN.updateStateString("NOPROCESS","No process running.");
 -
 +			if(mDumpPath!=null) {
 +				try {
 +					BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log"));
 +					for(LogItem li :OpenVPN.getlogbuffer()){
 +						logout.write(li.getString(null) + "\n");
 +					}
 +					logout.close();
 +					OpenVPN.logError(R.string.minidump_generated);
 +				} catch (IOException e) {
 +					OpenVPN.logError("Writing minidump log: " +e.getLocalizedMessage());
 +				}
 +			}
  			mService.processDied();
  			Log.i(TAG, "Exiting");
 @@ -84,12 +102,15 @@ public class OpenVPNThread implements Runnable {  			mProcess.getOutputStream().close();
  			InputStream in = mProcess.getInputStream();
  			BufferedReader br = new BufferedReader(new InputStreamReader(in));
 -			
 -			
 +				
  			while(true) {
  				String logline = br.readLine();
 -				if(logline==null)
 +				if (logline.startsWith(DUMP_PATH_STRING))
 +					mDumpPath = logline.substring(DUMP_PATH_STRING.length());
 +					
 +				if(logline==null) {
  					return;
 +				}
  				OpenVPN.logMessage(0, "P:", logline);
  			}
 diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java index 24537732..4e26c44b 100644 --- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -39,7 +39,8 @@ public class OpenVpnManagementThread implements Runnable {  	private long mLastOut=0;
  	private LocalServerSocket mServerSocket;
  	private boolean mReleaseHold=true;
 -	private boolean mWaitingForRelease=false; 
 +	private boolean mWaitingForRelease=false;
 +	private long mLastHoldRelease=0; 
  	private static Vector<OpenVpnManagementThread> active=new Vector<OpenVpnManagementThread>();
 @@ -223,18 +224,24 @@ public class OpenVpnManagementThread implements Runnable {  		}
  	}
  	private void releaseHoldCmd() {
 +		if ((System.currentTimeMillis()- mLastHoldRelease) < 5000) {
 +			try {
 +				Thread.sleep(3000);
 +			} catch (InterruptedException e) {}
 +			
 +		}
  		mWaitingForRelease=false;
 -		mReleaseHold=true;
 +		mLastHoldRelease  = System.currentTimeMillis();
  		managmentCommand("hold release\n");
  		managmentCommand("bytecount " + mBytecountinterval + "\n");
  		managmentCommand("state on\n");
  	}
  	public void releaseHold() {
 +		mReleaseHold=true;
  		if(mWaitingForRelease)
  			releaseHoldCmd();
 -		else	
 -			mReleaseHold=true;
 +			
  	}
  	private void processProxyCMD(String argument) {
 @@ -459,9 +466,9 @@ public class OpenVpnManagementThread implements Runnable {  	}
  	public void signalusr1() {
 +		mReleaseHold=false;
  		if(!mWaitingForRelease)
  			managmentCommand("signal SIGUSR1\n");
 -		mReleaseHold=false;
  	}
  	public void reconnect() {
 @@ -473,11 +480,12 @@ public class OpenVpnManagementThread implements Runnable {  		PrivateKey privkey = mProfile.getKeystoreKey();
  		Exception err =null;
 -		// The Jelly Bean *evil* Hack
  		byte[] data = Base64.decode(b64data, Base64.DEFAULT);
 -		if(Build.VERSION.SDK_INT>=16){
 +		// The Jelly Bean *evil* Hack
 +		// 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider
 +		if(Build.VERSION.SDK_INT==16){
  			processSignJellyBeans(privkey,data);
  			return;
  		}
 diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index ca199cc6..603f86ce 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -19,6 +19,7 @@ package de.blinkt.openvpn;  import java.io.IOException;  import java.lang.reflect.InvocationTargetException;  import java.lang.reflect.Method; +import java.util.Locale;  import java.util.Vector;  import android.app.Notification; @@ -104,22 +105,11 @@ public class OpenVpnService extends VpnService implements StateListener {  		// Try to set the priority available since API 16 (Jellybean) -		if( lowpriority) { -			try { -				Method setpriority = nbuilder.getClass().getMethod("setPriority", int.class); -				// PRIORITY_MIN == -2 -				setpriority.invoke(nbuilder, -2 ); - -				//ignore exception -			} catch (NoSuchMethodException nsm) { -			} catch (IllegalArgumentException e) { -			} catch (IllegalAccessException e) { -			} catch (InvocationTargetException e) { -			} -		} +		jbNotificationExtras(lowpriority, nbuilder);  		if(tickerText!=null)  			nbuilder.setTicker(tickerText); +		@SuppressWarnings("deprecation")  		Notification notification = nbuilder.getNotification(); @@ -127,6 +117,29 @@ public class OpenVpnService extends VpnService implements StateListener {  		startForeground(OPENVPN_STATUS, notification);  	} +	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 ); +				 +/*				PendingIntent cancelconnet=null; +				 +				nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel,  +						getString(R.string.cancel_connection),cancelconnet); */ +			} + +			//ignore exception +		} catch (NoSuchMethodException nsm) { +		} catch (IllegalArgumentException e) { +		} catch (IllegalAccessException e) { +		} catch (InvocationTargetException e) { +		} + +	} +  	PendingIntent getLogPendingIntent() {  		// Let the configure Button show the Log  		Intent intent = new Intent(getBaseContext(),LogWindow.class); @@ -436,11 +449,11 @@ public class OpenVpnService extends VpnService implements StateListener {  			} else {  				mDisplayBytecount = false;  			} -			 +  			// Other notifications are shown,  			// This also mean we are no longer connected, ignore bytecount messages until next  			// CONNECTED -			String ticker = state.toLowerCase(); +			String ticker = state.toLowerCase(Locale.getDefault());  			showNotification(state +" " + logmessage,ticker,false,0);  		} diff --git a/src/de/blinkt/openvpn/ProfileManager.java b/src/de/blinkt/openvpn/ProfileManager.java index d2e08a97..9457b53f 100644 --- a/src/de/blinkt/openvpn/ProfileManager.java +++ b/src/de/blinkt/openvpn/ProfileManager.java @@ -51,7 +51,7 @@ public class ProfileManager {  		}  	} -	public static ProfileManager getInstance(Context context) { +	synchronized public static ProfileManager getInstance(Context context) {  		checkInstance(context);  		return instance;  	} diff --git a/src/de/blinkt/openvpn/SendDumpActivity.java b/src/de/blinkt/openvpn/SendDumpActivity.java new file mode 100644 index 00000000..8a09b535 --- /dev/null +++ b/src/de/blinkt/openvpn/SendDumpActivity.java @@ -0,0 +1,60 @@ +package de.blinkt.openvpn; + +import java.io.File; +import java.util.ArrayList; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +public class SendDumpActivity extends Activity { +	 +	protected void onStart() { +		super.onStart(); +		emailMiniDumps(); +		finish(); +	}; +	 +	public void emailMiniDumps() +	{ +		//need to "send multiple" to get more than one attachment +		final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND_MULTIPLE); +		emailIntent.setType("*/*"); +		emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL,  +				new String[]{"Arne Schwabe <arne@rfc2549.org>"}); +		emailIntent.putExtra(Intent.EXTRA_SUBJECT, "OpenVPN Minidump"); + +		emailIntent.putExtra(Intent.EXTRA_TEXT, "Please describe the issue you have experienced"); + +		ArrayList<Uri> uris = new ArrayList<Uri>(); + +		File ldump = getLastestDump(this); +		if(ldump==null) { +			OpenVPN.logError("No Minidump found!"); +		} +		 +		uris.add(Uri.parse("content://de.blinkt.openvpn.FileProvider/" + ldump.getName())); +		uris.add(Uri.parse("content://de.blinkt.openvpn.FileProvider/" + ldump.getName() + ".log")); + +		emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); +		emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); +		startActivity(emailIntent); +	} + +	static public File getLastestDump(Context c) { +		long newestDumpTime=0; +		File newestDumpFile=null; + +		for(File f:c.getCacheDir().listFiles()) { +			if(!f.getName().endsWith(".dmp")) +				continue; + +			if (newestDumpTime < f.lastModified()) { +				newestDumpTime = f.lastModified(); +				newestDumpFile=f; +			} +		} +		return newestDumpFile; +	} +} diff --git a/src/de/blinkt/openvpn/Settings_Obscure.java b/src/de/blinkt/openvpn/Settings_Obscure.java index f7a63043..160dbe0c 100644 --- a/src/de/blinkt/openvpn/Settings_Obscure.java +++ b/src/de/blinkt/openvpn/Settings_Obscure.java @@ -14,13 +14,15 @@ public class Settings_Obscure extends OpenVpnPreferencesFragment implements OnPr  	private EditTextPreference mCustomConfig;  	private ListPreference mLogverbosity;  	private CheckBoxPreference mPersistent; +	private ListPreference mConnectretrymax; +	private EditTextPreference mConnectretry;  	@Override  	public void onCreate(Bundle savedInstanceState) {  		super.onCreate(savedInstanceState);  		// Load the preferences from an XML resource  		addPreferencesFromResource(R.xml.vpn_obscure); -		 +  		mUseRandomHostName = (CheckBoxPreference) findPreference("useRandomHostname");  		mUseFloat = (CheckBoxPreference) findPreference("useFloat"); @@ -28,10 +30,17 @@ public class Settings_Obscure extends OpenVpnPreferencesFragment implements OnPr  		mCustomConfig = (EditTextPreference) findPreference("customOptions");  		mLogverbosity = (ListPreference) findPreference("verblevel");  		mPersistent = (CheckBoxPreference) findPreference("usePersistTun"); -				 +		mConnectretrymax = (ListPreference) findPreference("connectretrymax"); +		mConnectretry = (EditTextPreference) findPreference("connectretry"); +  		mLogverbosity.setOnPreferenceChangeListener(this);  		mLogverbosity.setSummary("%s"); +		mConnectretrymax.setOnPreferenceChangeListener(this); +		mConnectretrymax.setSummary("%s"); +		 +		mConnectretry.setOnPreferenceChangeListener(this); +		  		loadSettings(); @@ -46,6 +55,12 @@ public class Settings_Obscure extends OpenVpnPreferencesFragment implements OnPr  		mLogverbosity.setValue(mProfile.mVerb);  		onPreferenceChange(mLogverbosity, mProfile.mVerb); +		 +		mConnectretrymax.setValue(mProfile.mConnectRetryMax); +		onPreferenceChange(mConnectretrymax, mProfile.mConnectRetryMax); +				 +		mConnectretry.setText(mProfile.mConnectRetry); +		onPreferenceChange(mConnectretry, mProfile.mConnectRetry);  	} @@ -55,7 +70,9 @@ public class Settings_Obscure extends OpenVpnPreferencesFragment implements OnPr  		mProfile.mUseCustomConfig = mUseCustomConfig.isChecked();  		mProfile.mCustomConfigOptions = mCustomConfig.getText();  		mProfile.mVerb = mLogverbosity.getValue(); +		mProfile.mConnectRetryMax = mConnectretrymax.getValue();  		mProfile.mPersistTun = mPersistent.isChecked(); +		mProfile.mConnectRetry = mConnectretry.getText();  	} @@ -69,7 +86,27 @@ public class Settings_Obscure extends OpenVpnPreferencesFragment implements OnPr  			mLogverbosity.setDefaultValue(newValue);  			//This is idiotic.   			int i =Integer.parseInt((String) newValue); -			mLogverbosity.setSummary(mLogverbosity.getEntries()[i]); +			 +			// verb >= 5 is not supported by the chooser +			if(i < mLogverbosity.getEntries().length ) +				mLogverbosity.setSummary(mLogverbosity.getEntries()[i]); +			else +				mLogverbosity.setSummary(String.format("debug verbosity: %d",i)); +		} else if (preference == mConnectretrymax) { +			if(newValue==null) { +				newValue="5"; +			} +			mConnectretrymax.setDefaultValue(newValue); +			 +			for(int i=0;i<mConnectretrymax.getEntryValues().length;i++){ +				if(mConnectretrymax.getEntryValues().equals(newValue)) +					mConnectretrymax.setSummary(mConnectretrymax.getEntries()[i]); +			} +			 +		} else if (preference == mConnectretry) { +			if(newValue==null || newValue=="") +				newValue="5"; +			mConnectretry.setSummary(String.format("%s s" , newValue));  		}  		return true; diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index bdfdd70a..4c3c05f0 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -101,9 +101,16 @@ public class VpnProfile implements  Serializable{  	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; +	  	static final String MINIVPN = "miniopenvpn"; -	public boolean mPersistTun = false; +	 +	 +  	public void clearDefaults() { @@ -191,11 +198,19 @@ public class VpnProfile implements  Serializable{  		cfg+="verb " + mVerb + "\n"; - - - -		// quit after 5 tries -		cfg+="connect-retry-max 5\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"; | 
