summaryrefslogtreecommitdiff
path: root/src/de/blinkt/openvpn
diff options
context:
space:
mode:
authorarne <arne@gaia.fritz.box>2012-12-25 23:22:13 +0100
committerarne <arne@gaia.fritz.box>2012-12-25 23:22:13 +0100
commitc9dc454f4ec38f075f951fbf32935054023eed94 (patch)
tree33d36c8bfb68db406e3ae90237b145077efecda5 /src/de/blinkt/openvpn
parente57c7dd4a792d02897140d0c5e2d014bcd1147c0 (diff)
parentb2b8b3da3f501543338fc5065519ab778379c274 (diff)
Merge local changes with repository
Diffstat (limited to 'src/de/blinkt/openvpn')
-rw-r--r--src/de/blinkt/openvpn/ConfigConverter.java54
-rw-r--r--src/de/blinkt/openvpn/ConfigParser.java31
-rw-r--r--src/de/blinkt/openvpn/FaqFragment.java5
-rw-r--r--src/de/blinkt/openvpn/FileProvider.java157
-rw-r--r--src/de/blinkt/openvpn/LogWindow.java5
-rw-r--r--src/de/blinkt/openvpn/MainActivity.java14
-rw-r--r--src/de/blinkt/openvpn/OpenVPN.java60
-rw-r--r--src/de/blinkt/openvpn/OpenVPNThread.java31
-rw-r--r--src/de/blinkt/openvpn/OpenVpnManagementThread.java22
-rw-r--r--src/de/blinkt/openvpn/OpenVpnService.java43
-rw-r--r--src/de/blinkt/openvpn/SendDumpActivity.java60
-rw-r--r--src/de/blinkt/openvpn/Settings_Obscure.java43
-rw-r--r--src/de/blinkt/openvpn/VpnProfile.java26
13 files changed, 463 insertions, 88 deletions
diff --git a/src/de/blinkt/openvpn/ConfigConverter.java b/src/de/blinkt/openvpn/ConfigConverter.java
index d140a1a..40aa24e 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 7501ed1..cdec964 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 7902975..a358dc9 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 0000000..e86b544
--- /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 8d228cf..790e143 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 9b32981..32cf575 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 6b65c22..0ae681b 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 b4ead26..7d58552 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 2453773..4e26c44 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 ca199cc..603f86c 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 0000000..8a09b53
--- /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 f7a6304..160dbe0 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 bdfdd70..98f1504 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";