diff --git a/.gitmodules b/.gitmodules
index 045eccfb..506b6f88 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,7 @@
[submodule "external/openconnect"]
path = external/openconnect
- url = https://github.com/cernekee/openconnect
+ url = https://gitlab.com/openconnect/openconnect
+ branch = master
[submodule "external/stoken"]
path = external/stoken
url = https://github.com/cernekee/stoken
diff --git a/.travis.yml b/.travis.yml
index b9531c20..cbfcbd13 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ android:
- tools
- platform-tools
- build-tools-26.0.2
- - android-19
+ - android-24
notifications:
email:
@@ -13,6 +13,7 @@ notifications:
on_failure: always
before_install:
+ - yes | sdkmanager "platforms;android-24"
# Install NDK + openconnect build deps
- sudo apt-get update -qq
- sudo apt-get install -qq build-essential autoconf automake libtool groff expect ant
diff --git a/README.md b/README.md
index b7f19f69..db088751 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,16 @@
+Multi-protocol version, based on [openconnect v8.03](http://www.infradead.org/openconnect/changelog.html).
+
+APK: [OpenConnect_1.11+multi.apk](https://drive.google.com/file/d/17IRsGNYqUav9Yf2bsInxnc0uGD6g_PZz/view)
+XDA thread: [comment](https://forum.xda-developers.com/showthread.php?p=77318683#post77318683)
+
+![Screenshot](https://lh3.googleusercontent.com/Jf8N3KVu29dw0l_LZ0uYPdCFvCUfc5BAMrmJacecXQXv2p8PiLrAbWCPiLg--9kFB3o18ak-eBvmPMaIkBm3j6vDwY4DZOP_FnYtc3p-YUZkynB7_xdFX_H_mdQM6qxqfu7M58Qdr4HB7ypciYzHivAHY5GSk7vcYZRnfBDOa46yuZz8ElcVH6c51VoRWzvy2u4o47Bhxmqtx55BeUK3Z6jYdTsvbGIcnxPZjAhvkw_hvHif54urKvM7xMR8tI-agEoa0bvOrnQP-hIRVSauCFMuVCODBEI5O7R_dfzYEbErh8zwKiIV-DC6KqwW12lB3neYv064OJotU_4kARlv8vMJJ-CYV5AsyvtNMlYa1PyvQFqe5uQ7MMX4hJ326abcqNl-mFThuuofBaddIlQPdNB3iuzZd2xi6MRgLrJpVXe0ILAi0B56KN8xYsPz2NLzaDZewwOAozGawMiMQbk6pWfA1d7bnIyerFc9tv1c9ItPIIYrQUITt2EiOFE4sBGIPeD53JiGtQ-oaxJPNSES4MruUkHm6ynYkHkgK2qgMK5PPKUtK7_0rArXC2jPMkRd8nrS4bU4wd3-fqMGpA_QY68iaLRK7IOfWFQ3HJ3q=w720-h1280-no)
+
OpenConnect for Android
=======================
+[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
+[![Build Status](https://travis-ci.org/cernekee/ics-openconnect.svg?branch=master)](https://travis-ci.org/cernekee/ics-openconnect)
+
This is a VPN client for Android, based on the Linux build of
[OpenConnect](http://www.infradead.org/openconnect/).
diff --git a/app/build.gradle b/app/build.gradle
index a2ec516a..55fd9465 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,13 +1,13 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 19
+ compileSdkVersion 24
defaultConfig {
applicationId "app.openconnect"
minSdkVersion 14
targetSdkVersion 19
versionCode 1119
- versionName "1.11"
+ versionName "1.11+multi"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
signingConfigs {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 20693dcc..c6e01008 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,7 +13,7 @@
+ android:targetSdkVersion="24" />
@@ -91,6 +91,7 @@
tools:ignore="ExportedActivity" >
+
@@ -120,6 +121,14 @@
-->
+
+
+
+
+
+ Extended to include multi-protocol support, 2018-2019 Daniel Lenski <dlenski@gmail.com>
+ using openconnect v8.03. Quick settings tile added by Terry Yao.
+
Copyright 2013-2014 Kevin Cernekee <cernekee@gmail.com>
This is free software with ABSOLUTELY NO WARRANTY.
For details see the COPYING file in the source distribution.
@@ -25,11 +28,11 @@
Copyright 2012-2013 Arne Schwab
OpenConnect
- Copyright 2008-2012 Intel Corporation.
+ Copyright 2008-2019 Intel Corporation.
Author: David Woodhouse
GnuTLS
- Copyright 2000-2012 Free Software Foundation, Inc.
+ Copyright 2000-2019 Free Software Foundation, Inc.
Author: Nikos Mavrogiannopoulos
GMP
diff --git a/app/src/main/assets/raw/noarch/android_csd.sh b/app/src/main/assets/raw/noarch/android_csd_anyconnect.sh
similarity index 100%
rename from app/src/main/assets/raw/noarch/android_csd.sh
rename to app/src/main/assets/raw/noarch/android_csd_anyconnect.sh
diff --git a/app/src/main/assets/raw/noarch/android_csd_gp.sh b/app/src/main/assets/raw/noarch/android_csd_gp.sh
new file mode 100755
index 00000000..607aad77
--- /dev/null
+++ b/app/src/main/assets/raw/noarch/android_csd_gp.sh
@@ -0,0 +1,57 @@
+#!/system/bin/sh
+
+# These value may need to be extracted from the official HIP report, if made-up values are not accepted.
+PLATFORM_VERSION="4.3"
+PLATFORM_NAME="Android-x86"
+HOSTID="deadbeef-dead-beef-dead-beefdeadbeef"
+
+# Read command line arguments into variables
+COOKIE=
+IP=
+MD5=
+
+while [ "$1" ]; do
+ if [ "$1" = "--cookie" ]; then shift; COOKIE="$1"; fi
+ if [ "$1" = "--client-ip" ]; then shift; IP="$1"; fi
+ if [ "$1" = "--md5" ]; then shift; MD5="$1"; fi
+ shift
+done
+
+if [ -z "$COOKIE" -o -z "$IP" -o -z "$MD5" ]; then
+ echo "Parameters --cookie, --client-ip, and --md5 are required" >&2
+ exit 1
+fi
+
+# Extract username and domain and computer from cookie
+USER=$(echo "$COOKIE" | sed -rn 's/(.+&|^)user=([^&]+)(&.+|$)/\2/p')
+DOMAIN=$(echo "$COOKIE" | sed -rn 's/(.+&|^)domain=([^&]+)(&.+|$)/\2/p')
+COMPUTER=$(echo "$COOKIE" | sed -rn 's/(.+&|^)computer=([^&]+)(&.+|$)/\2/p')
+
+# Timestamp in the format expected by GlobalProtect server
+NOW=$(date +'%m/%d/%Y %H:%M:%S')
+
+log OPENCONNECT GP SCRIPT BEFORE TIMID ECHO
+
+echo ' '
+
+# FIXME: Doesn't work as a here-doc (cat <'
+echo " $MD5"
+echo " $USER"
+echo " $DOMAIN"
+echo " $COMPUTER"
+echo " $HOSTID"
+echo " $IP"
+echo ' '
+echo " $NOW"
+echo ' '
+echo ' '
+echo ' 4.0.2-19'
+echo " $PLATFORM_NAME $PLATFORM_VERSION"
+echo ' Google'
+echo " $DOMAIN.internal"
+echo " $COMPUTER"
+echo " $HOSTID"
+echo ' '
+echo ' '
+echo ''
diff --git a/app/src/main/assets/raw/noarch/android_csd_nc.sh b/app/src/main/assets/raw/noarch/android_csd_nc.sh
new file mode 100755
index 00000000..d7327e1a
--- /dev/null
+++ b/app/src/main/assets/raw/noarch/android_csd_nc.sh
@@ -0,0 +1,4 @@
+#!/system/bin/sh
+
+echo "Juniper 'CSD' script is not yet supported on Android" >&2
+exit 1
diff --git a/app/src/main/java/app/openconnect/QSTileService.java b/app/src/main/java/app/openconnect/QSTileService.java
new file mode 100644
index 00000000..8f5925c4
--- /dev/null
+++ b/app/src/main/java/app/openconnect/QSTileService.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2019.
+ *
+ * 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 app.openconnect;
+
+import android.annotation.TargetApi;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.util.Log;
+import app.openconnect.core.OpenConnectManagementThread;
+import app.openconnect.core.OpenVpnService;
+import app.openconnect.core.VPNConnector;
+
+/**
+ * @author Terry E-mail: yaoxinghuo at qq dot com
+ * @date 2019-6-2 18:33
+ * @description
+ */
+@TargetApi(24)
+public class QSTileService extends TileService {
+
+ private static final String TAG = QSTileService.class.getName();
+
+ private int mConnectionState;
+ private VPNConnector mConn;
+
+ @Override
+ public void onStartListening() {
+ super.onStartListening();
+ mConn = new VPNConnector(this, true) {
+ @Override
+ public void onUpdate(OpenVpnService service) {
+ updateState(service);
+ }
+ };
+ }
+
+ @Override
+ public void onStopListening() {
+ super.onStopListening();
+
+ mConn.stopActiveDialog();
+ mConn.unbind();
+ }
+
+ @Override
+ public void onClick() {
+ super.onClick();
+
+ toggle();
+ }
+
+ private void updateState(OpenVpnService service) {
+ int newState = service.getConnectionState();
+
+ if (mConnectionState != newState) {
+ String tileLabel = null;
+ int tileState;
+ String profileName;
+ switch (newState) {
+ case OpenConnectManagementThread.STATE_CONNECTED:
+ tileState = Tile.STATE_ACTIVE;
+ tileLabel = getString(R.string.disconnect);
+ profileName = service.getReconnectName();
+ if (profileName != null) {
+ tileLabel = tileLabel + " " + profileName;
+ }
+// Toast.makeText(this, getString(R.string.state_connected_to, service.profile.getName()), Toast.LENGTH_SHORT).show();
+ break;
+ case OpenConnectManagementThread.STATE_DISCONNECTED:
+ tileState = Tile.STATE_INACTIVE;
+ profileName = service.getReconnectName();
+ if (profileName != null) {
+ tileLabel = getString(R.string.reconnect_to, profileName);
+ }
+ break;
+ default:
+ tileLabel = service.getConnectionStateName();
+ tileState = Tile.STATE_UNAVAILABLE;
+ break;
+ }
+ mConnectionState = newState;
+
+ if (tileLabel == null) {
+ tileLabel = getString(R.string.app);
+ }
+
+ Tile tile = getQsTile();
+ tile.setState(tileState);
+ tile.setLabel(tileLabel);
+ Log.d(TAG, "set tile state: " + tileState + ", label: " + tileLabel);
+ tile.updateTile();
+ }
+ }
+
+ private void toggle() {
+ if (mConnectionState == OpenConnectManagementThread.STATE_CONNECTED) {
+ mConn.service.stopVPN();
+ } else if (mConnectionState == OpenConnectManagementThread.STATE_DISCONNECTED) {
+ mConn.service.startReconnectActivity(this);
+ }
+ }
+}
diff --git a/app/src/main/java/app/openconnect/core/OpenConnectManagementThread.java b/app/src/main/java/app/openconnect/core/OpenConnectManagementThread.java
index f9b03705..e71e922d 100644
--- a/app/src/main/java/app/openconnect/core/OpenConnectManagementThread.java
+++ b/app/src/main/java/app/openconnect/core/OpenConnectManagementThread.java
@@ -162,6 +162,14 @@ private void acceptCert(String hash, boolean save) {
}
private class AndroidOC extends LibOpenConnect {
+ AndroidOC() {
+ super();
+ }
+
+ AndroidOC(String userAgent) {
+ super(userAgent);
+ }
+
private String getPeerCertSHA1() {
MessageDigest md;
try {
@@ -431,6 +439,15 @@ private String prefToTempFile(String prefName, boolean isExecutable) throws IOEx
private boolean setPreferences() {
String s;
+ int ret = 0;
+
+ s = getStringPref("vpn_protocol");
+ if (s != null && s.length() > 0)
+ ret = mOC.setProtocol(s);
+ if (ret < 0) {
+ log("Error " + ret + " setting VPN protocol to " + s);
+ return false;
+ }
try {
String PATH = System.getenv("PATH");
@@ -439,7 +456,7 @@ private boolean setPreferences() {
PATH = mFilesDir + ":" + PATH;
}
s = prefToTempFile("custom_csd_wrapper", true);
- mOC.setCSDWrapper(s != null ? s : (mFilesDir + File.separator + "android_csd.sh"), mCacheDir, PATH);
+ mOC.setCSDWrapper(s != null ? s : (mFilesDir + File.separator + "android_csd_" + mOC.getProtocol() + ".sh"), mCacheDir, PATH);
s = prefToTempFile("ca_certificate", false);
if (s != null) {
@@ -486,7 +503,6 @@ private boolean setPreferences() {
s = getStringPref("software_token");
String token = getStringPref("token_string");
- int ret = 0;
if (s.equals("securid")) {
ret = mOC.setTokenMode(LibOpenConnect.OC_TOKEN_MODE_STOKEN, token);
@@ -648,7 +664,7 @@ private void setIPInfo(VpnService.Builder b) {
log("DOMAIN: " + domain);
}
- mOpenVPNService.setIPInfo(ip, mOC.getHostname());
+ mOpenVPNService.setIPInfo(ip, mOC.getHostname(), mOC.getIdleTimeout());
}
private void errorAlert(String message) {
@@ -692,9 +708,15 @@ private boolean runVPN() {
mCacheDir = mContext.getCacheDir().getPath();
extractBinaries();
+ String userAgent = getBoolPref("reported_user_agent_override")
+ ? getStringPref("reported_user_agent") : null;
+
setState(STATE_CONNECTING);
synchronized (mMainloopLock) {
- mOC = new AndroidOC();
+ if (userAgent != null)
+ mOC = new AndroidOC(userAgent);
+ else
+ mOC = new AndroidOC();
}
if (setPreferences() == false) {
diff --git a/app/src/main/java/app/openconnect/core/OpenVpnService.java b/app/src/main/java/app/openconnect/core/OpenVpnService.java
index 80881dad..8d4b43bb 100644
--- a/app/src/main/java/app/openconnect/core/OpenVpnService.java
+++ b/app/src/main/java/app/openconnect/core/OpenVpnService.java
@@ -75,6 +75,7 @@ public class OpenVpnService extends VpnService {
private SharedPreferences mPrefs;
private KeepAlive mKeepAlive;
+ private int mIdleTimeout;
private final IBinder mBinder = new LocalBinder();
@@ -193,17 +194,11 @@ private synchronized void registerKeepAlive() {
Log.i(TAG, "server DNS IP is bogus, falling back to " + DNSServer + " for KeepAlive", e);
}
- int idle = 1800;
- try {
- int val = Integer.parseInt(ipInfo.CSTPOptions.get("X-CSTP-Idle-Timeout"));
- if (val >= 60 && val <= 7200) {
- idle = val;
- }
- } catch (Exception e) {
- }
-
- // set to 40% of the idle timeout value, to buy a little margin in case
+ // set to 40% of the server's idle timeout value, to buy a little margin in case
// the first 1-2 attempts fail
+ int idle = this.mIdleTimeout;
+ if (idle < 60 || idle > 7200)
+ idle = 1800;
idle = idle * 4 / 10;
Log.d(TAG, "calculated KeepAlive interval: " + idle + " seconds");
@@ -461,9 +456,10 @@ public synchronized VPNStats getStats() {
return mStats;
}
- public synchronized void setIPInfo(LibOpenConnect.IPInfo ipInfo, String serverName) {
+ public synchronized void setIPInfo(LibOpenConnect.IPInfo ipInfo, String serverName, int idleTimeout) {
this.ipInfo = ipInfo;
this.serverName = serverName;
+ this.mIdleTimeout = idleTimeout;
}
public LogArrayAdapter getArrayAdapter(Context context) {
diff --git a/app/src/main/java/app/openconnect/fragments/ConnectionEditorFragment.java b/app/src/main/java/app/openconnect/fragments/ConnectionEditorFragment.java
index 8c5b40bf..b13e7816 100644
--- a/app/src/main/java/app/openconnect/fragments/ConnectionEditorFragment.java
+++ b/app/src/main/java/app/openconnect/fragments/ConnectionEditorFragment.java
@@ -79,6 +79,9 @@ public void onCreate(Bundle savedInstanceState) {
addPreferencesFromResource(R.xml.pref_openconnect);
setClickListeners();
+ // FIXME: populate the vpn_protocol list dynamically using mOC.getSupportedProtocols()
+ // Preference = (ListPreference)mPrefs.findPreference("vpn_protocol");
+
SharedPreferences sp = mPrefs.getSharedPreferences();
for (Map.Entry entry : sp.getAll().entrySet()) {
updatePref(sp, entry.getKey());
@@ -143,7 +146,15 @@ public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent
}
}
- /* disable token_string item if the profile isn't using a software token */
+ /* disable_xml_post is only applicable to anyconnect */
+ if (key.equals("vpn_protocol")) {
+ pref = findPreference("disable_xml_post");
+ if (pref != null) {
+ pref.setEnabled(value.equals("anyconnect"));
+ }
+ }
+
+ /* disable token_string item if the profile isn't using a software token */
if (key.equals("software_token")) {
pref = findPreference("token_string");
if (pref != null) {
diff --git a/app/src/main/java/app/openconnect/fragments/FaqFragment.java b/app/src/main/java/app/openconnect/fragments/FaqFragment.java
index daff43c1..7f255ea0 100644
--- a/app/src/main/java/app/openconnect/fragments/FaqFragment.java
+++ b/app/src/main/java/app/openconnect/fragments/FaqFragment.java
@@ -45,12 +45,27 @@ public class FaqFragment extends Fragment {
private String htmlEncode(String in) {
in = TextUtils.htmlEncode(in).replace("\n", "
");
- // match markdown-formatted links: [link text](http://foo.bar.com)
- // replace with: link text
StringBuilder out = new StringBuilder();
- Pattern p = Pattern.compile("\\[(.+?)\\]\\((\\S+)\\)");
Matcher m;
+ // match markdown-formatted code: `code`
+ // replace with: code
+ Pattern p = Pattern.compile("`(.+?)`");
+ while (true) {
+ m = p.matcher(in);
+ if (!m.find()) {
+ break;
+ }
+ out.append(in.substring(0, m.start()));
+ out.append("");
+ out.append(m.group(1));
+ out.append("");
+ in = in.substring(m.end());
+ }
+
+ // match markdown-formatted links: [link text](http://foo.bar.com)
+ // replace with: link text
+ p = Pattern.compile("\\[(.+?)\\]\\((\\S+)\\)");
while (true) {
m = p.matcher(in);
if (!m.find()) {
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 8aadbfd9..71bf9186 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -1,6 +1,17 @@
+
+ - Cisco AnyConnect or ocserv
+ - Juniper Network Connect or Pulse Secure
+ - Palo Alto Networks GlobalProtect
+
+
+ - anyconnect
+ - nc
+ - gp
+
+
- Disabled
- RSA SecurID
@@ -74,25 +85,25 @@
- What is this app used for?
- - OpenConnect is used to access virtual private networks (VPNs) which utilize the Cisco AnyConnect SSL VPN protocol. A typical use case might involve logging into your workplace remotely to check email after hours.\n\nIf in doubt, check with your I.T. administrator to see if a suitable service is available.
+ - [OpenConnect](https://en.wikipedia.org/wiki/OpenConnect) was initially created to access [virtual private networks (VPNs)](https://en.wikipedia.org/wiki/Virtual_private_network) which utilize the Cisco AnyConnect SSL VPN protocol. It has since been extended to support the [Juniper](https://en.wikipedia.org/wiki/Juniper_Networks) SSL VPN protocol (now known as Pulse Connect Secure) and the [Palo Alto Networks](https://en.wikipedia.org/wiki/Palo_Alto_Networks) GlobalProtect SSL VPN protocol. A typical use case might involve logging into your workplace remotely to check email after hours.\n\nIf in doubt, check with your I.T. administrator to see if a suitable service is available.
- How do I get started?
- In most cases, you\'ll just need to create a profile and enter the hostname of the VPN gateway. The other fields in the profile are all optional and should be left alone unless there is a specific need to change them.\n\nOnce you\'ve set up the profile, select the VPN entry and OpenConnect will attempt to establish a new session. If this fails, the \"Log\" tab may provide helpful diagnostic information.
- How do I authenticate using an SSL client certificate?
- - Copy your certificate files to Android\'s external storage directory (nominally /sdcard or the Downloads folder), then edit the VPN profile and make the following changes:\n\nP12 or PFX file: select \"User certificate\", pick the file from the list, then touch \"select\". Leave \"Private key\" blank.\n\nSingle PEM/CRT/CER file: same as above.\n\nSeparate PEM/CRT/CER and KEY files: populate \"User certificate\" with the certificate file, and \"Private key\" with the key file.\n\nWhen finished, delete the certificate files from external storage so they cannot be stolen by other apps.\n\nIf you are generating your own keys (e.g. for use with your ocserv gateway), some basic CA setup instructions are posted [here](http://forum.xda-developers.com/showpost.php?p=52119253&postcount=25).
+ - Copy your certificate files to Android\'s external storage directory (nominally `/sdcard` or the Downloads folder), then edit the VPN profile and make the following changes:\n\nP12 or PFX file: select \"User certificate\", pick the file from the list, then touch \"select\". Leave \"Private key\" blank.\n\nSingle PEM/CRT/CER file: same as above.\n\nSeparate PEM/CRT/CER and KEY files: populate \"User certificate\" with the certificate file, and \"Private key\" with the key file.\n\nWhen finished, delete the certificate files from external storage so they cannot be stolen by other apps.\n\nIf you are generating your own keys (e.g. for use with your ocserv gateway), some basic CA setup instructions are posted [here](https://forum.xda-developers.com/showpost.php?p=52119253&postcount=25).
- Will OpenConnect work with non-AnyConnect VPNs?
- - Unfortunately the software design is tied very closely to the AnyConnect requirements and the libopenconnect interfaces. Therefore it only works with Cisco AnyConnect and ocserv gateways.
+ - The Juniper (now Pulse Secure) and PAN GlobalProtect protocols are also supported as of OpenConnect v8.0. When connecting to a Juniper or GlobalProtect VPN, the protocol must be explicitly specified in the VPN profile.
- Will OpenConnect work with Cisco IPsec VPNs running on an ASA?
- - OpenConnect supports SSL VPN (CSTP + DTLS) only.
+ - OpenConnect supports SSL VPN (CSTP + [DTLS](https://en.wikipedia.org/wiki/Datagram_Transport_Layer_Security)) only. It does not support the IPsec/[IKE](https://en.wikipedia.org/wiki/Internet_Key_Exchange)-based VPNs supported by the older [Cisco Systems VPN Client](https://en.wikipedia.org/wiki/Cisco_Systems_VPN_Client).
- - How do I import a SecurID software token?
- - If you have an URL that starts with \"com.rsa.securid.iphone://\" or \"http://127.0.0.1/securid/\" in your email, click on it and tell OpenConnect to add it to the desired VPN profile. If you just have a raw token string then write it to a text file, copy it under /sdcard, click \"Token string\" in the VPN profile editor, then select the filename.\n\nIf you have an \"sdtid\" XML file, copy it to /sdcard and then import it.
+ - How do I import a [SecurID](https://en.wikipedia.org/wiki/RSA_SecurID) software token?
+ - If you have an URL that starts with `com.rsa.securid.iphone://` or `http://127.0.0.1/securid/` in your email, click on it and tell OpenConnect to add it to the desired VPN profile. If you just have a raw token string then write it to a text file, copy it under `/sdcard`, click \"Token string\" in the VPN profile editor, then select the filename.\n\nIf you have an `sdtid` XML file, copy it to `/sdcard` and then import it.
- Is it possible to skip all login prompts when connecting?
- - If you have saved your username, password, or other credentials, or if you are using SecurID or certificate authentication, you can try enabling \"Batch Mode\" in the VPN profile to skip the login dialogs. If you need to change your saved password later or have trouble connecting, just disable batch mode.\n\nThe VPN warning dialog is a security feature built into the Android OS. If your device is rooted, you can bypass it by installing the [Xposed framework](http://forum.xda-developers.com/xposed/xposed-installer-versions-changelog-t2714053), enabling the OpenConnect module, then rebooting.\n\nDue to the user interaction required by these dialogs, it is not always possible to reliably start up the VPN in the background. So a \"start-on-boot\" feature is not currently provided.
+ - If you have saved your username, password, or other credentials, or if you are using SecurID or certificate authentication, you can try enabling \"Batch Mode\" in the VPN profile to skip the login dialogs. If you need to change your saved password later or have trouble connecting, just disable batch mode.\n\nThe VPN warning dialog is a security feature built into the Android OS. If your device is rooted, you can bypass it by installing the [Xposed framework](https://forum.xda-developers.com/xposed/xposed-installer-versions-changelog-t2714053), enabling the OpenConnect module, then rebooting.\n\nDue to the user interaction required by these dialogs, it is not always possible to reliably start up the VPN in the background. So a \"start-on-boot\" feature is not currently provided.
- How do I improve battery life while the VPN is up?
- One option is to select \"Pause when asleep\" under Settings. The downside is that VPN access will be temporarily stopped when the screen is off. Also, ASA gateways sometimes get annoyed with constant reconnections and may prematurely terminate your session after a few days.\n\nAnother option is to contact your server administrator and request that they disable dead peer detection (DPD), increase the idle timeout to >1hr, and increase the keepalive interval to ~5min or so.
@@ -104,7 +115,7 @@
- Apps which perform their own DNS resolution, such as Firefox, may have issues picking up the latest system DNS settings when connecting to the VPN. This can be a problem if your system DNS servers are not accessible over the VPN\'s routes, or if you are trying to look up hostnames that do not have public (internet) DNS entries.
- Under what circumstances will OpenConnect request root?
- - There are two root-only features shown under Settings; both are disabled by default. One setting works around a ROM bug in CM9 which sets incorrect permissions on /dev/tun, preventing VpnService from passing traffic to the tunnel interface; the other setting loads tun.ko on ROMs that neglect to load it by default.\n\nBased on user feedback and testing, future releases may autodetect these conditions.
+ - There are two root-only features shown under Settings; both are disabled by default. One setting works around a ROM bug in CM9 which sets incorrect permissions on `/dev/tun`, preventing `VpnService` from passing traffic to the tunnel interface; the other setting loads `tun.ko` on ROMs that neglect to load it by default.\n\nBased on user feedback and testing, future releases may autodetect these conditions.
- How do I send a problem report?
- Navigate to Log -> (menu) -> Send log file. Please be sure to furnish a complete, accurate description of the issue you are seeing, as the logs do not always show a smoking gun.
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b7c3f71b..1e6f7e5a 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -164,6 +164,10 @@
Unknown
Batch mode
Reported OS
+ Override reported User-Agent
+ Use a custom HTTP User-Agent header, instead of OpenConnect\'s default; some servers are picky about this value.
+ Reported User-Agent
+ Some Cisco servers accept \"Cisco AnyConnect VPN Agent\"; some Juniper servers accept \"ncsvc\".
Custom CSD wrapper
Split tunnel mode
Split tunnel networks
@@ -186,5 +190,6 @@
The certificate from VPN server \"%1$s\" failed verification.\n\nReason: \"%2$s\"\nSHA1: %3$s\n\nConnect anyway?
Just once
Always connect
+ VPN Protocol
diff --git a/app/src/main/res/xml/pref_openconnect.xml b/app/src/main/res/xml/pref_openconnect.xml
index b63e2cd3..8c422eab 100644
--- a/app/src/main/res/xml/pref_openconnect.xml
+++ b/app/src/main/res/xml/pref_openconnect.xml
@@ -8,6 +8,13 @@
android:title="@string/profile_name"
android:inputType="text|textNoSuggestions|textCapSentences"
android:defaultValue="" />
+
+
+