diff options
Diffstat (limited to 'src/de/blinkt')
-rw-r--r-- | src/de/blinkt/openvpn/ConfigConverter.java | 54 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/ConfigParser.java | 31 | ||||
-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/LogWindow.java | 5 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/MainActivity.java | 14 | ||||
-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/SendDumpActivity.java | 60 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/Settings_Obscure.java | 43 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/VpnProfile.java | 26 |
13 files changed, 463 insertions, 88 deletions
diff --git a/src/de/blinkt/openvpn/ConfigConverter.java b/src/de/blinkt/openvpn/ConfigConverter.java index d140a1a4..40aa24e0 100644 --- a/src/de/blinkt/openvpn/ConfigConverter.java +++ b/src/de/blinkt/openvpn/ConfigConverter.java @@ -144,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; @@ -175,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; @@ -229,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; @@ -275,7 +284,6 @@ public class ConfigConverter extends ListActivity { } } - log(R.string.import_could_not_open,filename); return null; } @@ -325,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); diff --git a/src/de/blinkt/openvpn/ConfigParser.java b/src/de/blinkt/openvpn/ConfigParser.java index 7501ed17..cdec964e 100644 --- a/src/de/blinkt/openvpn/ConfigParser.java +++ b/src/de/blinkt/openvpn/ConfigParser.java @@ -2,8 +2,11 @@ package de.blinkt.openvpn; 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 @@ -83,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'; } @@ -228,10 +231,13 @@ public class ConfigParser { "route-metric", "route-method", "status", + "script-security", "show-net-up", "suppress-timestamps", "tmp-dir", + "tun-ipv6", "topology", + "win-sys", }; @@ -350,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)); @@ -436,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){ @@ -511,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/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/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/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..98f15044 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -101,9 +101,15 @@ 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"; + static final String MINIVPN = "miniopenvpn"; - public boolean mPersistTun = false; + + + public void clearDefaults() { @@ -191,11 +197,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"; |