aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2016-12-08 17:33:11 +0100
committerTobias Brunner <tobias@strongswan.org>2016-12-08 17:33:11 +0100
commit7e1c8407532c429121b42569710a55bbe34392fa (patch)
treebf3f8af7fb67d8e0d172063b1fa89e931487e25b
parent8c50bb6c365510b76346b132e5796ae585bb7285 (diff)
parent3e85b5a492aa001d6064ee7d88feb2e36ad14359 (diff)
downloadstrongswan-7e1c8407532c429121b42569710a55bbe34392fa.tar.bz2
strongswan-7e1c8407532c429121b42569710a55bbe34392fa.tar.xz
Merge branch 'android-updates'
Adds a permanent notification while connected (or connecting), which allows running as a foreground service, which in turn should prevent Android from terminating the service when low on memory. Also adds support for ChaCha20/Poly1305 AEAD and Curve25519 DH.
-rw-r--r--src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java148
-rw-r--r--src/frontends/android/app/src/main/java/org/strongswan/android/logic/VpnStateService.java2
-rw-r--r--src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java31
-rw-r--r--src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnStateFragment.java3
-rw-r--r--src/frontends/android/app/src/main/jni/Android.mk2
-rw-r--r--src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_attr.c2
-rw-r--r--src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c21
-rw-r--r--src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification.pngbin0 -> 356 bytes
-rw-r--r--src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification_warning.pngbin0 -> 367 bytes
-rw-r--r--src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification.pngbin0 -> 291 bytes
-rw-r--r--src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification_warning.pngbin0 -> 297 bytes
-rw-r--r--src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification.pngbin0 -> 441 bytes
-rw-r--r--src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification_warning.pngbin0 -> 451 bytes
-rw-r--r--src/frontends/android/build.gradle2
-rw-r--r--src/frontends/android/gradle/wrapper/gradle-wrapper.properties4
-rw-r--r--src/libstrongswan/Android.mk4
16 files changed, 175 insertions, 44 deletions
diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java
index a6b9fc52d..0048a2daf 100644
--- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java
+++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java
@@ -17,29 +17,9 @@
package org.strongswan.android.logic;
-import java.io.File;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.security.PrivateKey;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import org.strongswan.android.data.VpnProfile;
-import org.strongswan.android.data.VpnProfileDataSource;
-import org.strongswan.android.data.VpnType.VpnTypeFeature;
-import org.strongswan.android.logic.VpnStateService.ErrorState;
-import org.strongswan.android.logic.VpnStateService.State;
-import org.strongswan.android.logic.imc.ImcState;
-import org.strongswan.android.logic.imc.RemediationInstruction;
-import org.strongswan.android.ui.MainActivity;
-import org.strongswan.android.utils.SettingsWriter;
-
import android.annotation.TargetApi;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
@@ -53,13 +33,39 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.security.KeyChain;
import android.security.KeyChainException;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.content.ContextCompat;
import android.system.OsConstants;
import android.util.Log;
-public class CharonVpnService extends VpnService implements Runnable
+import org.strongswan.android.R;
+import org.strongswan.android.data.VpnProfile;
+import org.strongswan.android.data.VpnProfileDataSource;
+import org.strongswan.android.data.VpnType.VpnTypeFeature;
+import org.strongswan.android.logic.VpnStateService.ErrorState;
+import org.strongswan.android.logic.VpnStateService.State;
+import org.strongswan.android.logic.imc.ImcState;
+import org.strongswan.android.logic.imc.RemediationInstruction;
+import org.strongswan.android.ui.MainActivity;
+import org.strongswan.android.utils.SettingsWriter;
+
+import java.io.File;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class CharonVpnService extends VpnService implements Runnable, VpnStateService.VpnStateListener
{
private static final String TAG = CharonVpnService.class.getSimpleName();
public static final String LOG_FILE = "charon.log";
+ public static final int VPN_STATE_NOTIFICATION_ID = 1;
private String mLogFile;
private VpnProfileDataSource mDataSource;
@@ -71,6 +77,7 @@ public class CharonVpnService extends VpnService implements Runnable
private volatile boolean mProfileUpdated;
private volatile boolean mTerminate;
private volatile boolean mIsDisconnecting;
+ private volatile boolean mShowNotification;
private VpnStateService mService;
private final Object mServiceLock = new Object();
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@@ -91,6 +98,7 @@ public class CharonVpnService extends VpnService implements Runnable
mService = ((VpnStateService.LocalBinder)service).getService();
}
/* we are now ready to start the handler thread */
+ mService.registerListener(CharonVpnService.this);
mConnectionHandler.start();
}
};
@@ -163,6 +171,7 @@ public class CharonVpnService extends VpnService implements Runnable
}
if (mService != null)
{
+ mService.unregisterListener(this);
unbindService(mServiceConnection);
}
mDataSource.close();
@@ -220,6 +229,7 @@ public class CharonVpnService extends VpnService implements Runnable
startConnection(mCurrentProfile);
mIsDisconnecting = false;
+ addNotification();
BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName(), mCurrentProfile.getSplitTunneling());
if (initializeCharon(builder, mLogFile, mCurrentProfile.getVpnType().has(VpnTypeFeature.BYOD)))
{
@@ -268,11 +278,99 @@ public class CharonVpnService extends VpnService implements Runnable
deinitializeCharon();
Log.i(TAG, "charon stopped");
mCurrentProfile = null;
+ removeNotification();
}
}
}
/**
+ * Add a permanent notification while we are connected to avoid the service getting killed by
+ * the system when low on memory.
+ */
+ private void addNotification()
+ {
+ mShowNotification = true;
+ startForeground(VPN_STATE_NOTIFICATION_ID, buildNotification(false));
+ }
+
+ /**
+ * Remove the permanent notification.
+ */
+ private void removeNotification()
+ {
+ mShowNotification = false;
+ stopForeground(true);
+ }
+
+ /**
+ * Build a notification matching the current state
+ */
+ private Notification buildNotification(boolean publicVersion)
+ {
+ VpnProfile profile = mService.getProfile();
+ State state = mService.getState();
+ ErrorState error = mService.getErrorState();
+ String name = "";
+
+ if (profile != null)
+ {
+ name = profile.getName();
+ }
+ android.support.v4.app.NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
+ .setSmallIcon(R.drawable.ic_notification)
+ .setCategory(NotificationCompat.CATEGORY_SERVICE)
+ .setVisibility(publicVersion ? NotificationCompat.VISIBILITY_PUBLIC
+ : NotificationCompat.VISIBILITY_PRIVATE);
+ int s = R.string.state_disabled;
+ if (error != ErrorState.NO_ERROR)
+ {
+ s = R.string.state_error;
+ builder.setSmallIcon(R.drawable.ic_notification_warning);
+ builder.setColor(ContextCompat.getColor(this, R.color.error_text));
+ }
+ else
+ {
+ switch (state)
+ {
+ case CONNECTING:
+ s = R.string.state_connecting;
+ builder.setSmallIcon(R.drawable.ic_notification_warning);
+ builder.setColor(ContextCompat.getColor(this, R.color.warning_text));
+ break;
+ case CONNECTED:
+ s = R.string.state_connected;
+ builder.setColor(ContextCompat.getColor(this, R.color.success_text));
+ builder.setUsesChronometer(true);
+ break;
+ case DISCONNECTING:
+ s = R.string.state_disconnecting;
+ break;
+ }
+ }
+ builder.setContentTitle(getString(s));
+ if (!publicVersion)
+ {
+ builder.setContentText(name);
+ builder.setPublicVersion(buildNotification(true));
+ }
+
+ Intent intent = new Intent(getApplicationContext(), MainActivity.class);
+ PendingIntent pending = PendingIntent.getActivity(getApplicationContext(), 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ builder.setContentIntent(pending);
+ return builder.build();
+ }
+
+ @Override
+ public void stateChanged() {
+ if (mShowNotification)
+ {
+ NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ manager.notify(VPN_STATE_NOTIFICATION_ID, buildNotification(false));
+ }
+ }
+
+ /**
* Notify the state service about a new connection attempt.
* Called by the handler thread.
*
@@ -444,7 +542,7 @@ public class CharonVpnService extends VpnService implements Runnable
private byte[][] getTrustedCertificates()
{
ArrayList<byte[]> certs = new ArrayList<byte[]>();
- TrustedCertificateManager certman = TrustedCertificateManager.getInstance();
+ TrustedCertificateManager certman = TrustedCertificateManager.getInstance().load();
try
{
String alias = this.mCurrentCertificateAlias;
@@ -521,7 +619,7 @@ public class CharonVpnService extends VpnService implements Runnable
*
* @param builder BuilderAdapter for this connection
* @param logfile absolute path to the logfile
- * @param boyd enable BYOD features
+ * @param byod enable BYOD features
* @return TRUE if initialization was successful
*/
public native boolean initializeCharon(BuilderAdapter builder, String logfile, boolean byod);
diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/VpnStateService.java b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/VpnStateService.java
index 7b40e942f..e35277d8c 100644
--- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/VpnStateService.java
+++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/VpnStateService.java
@@ -315,7 +315,7 @@ public class VpnStateService extends Service
*
* May be called from threads other than the main thread.
*
- * @param error error state
+ * @param state IMC state
*/
public void setImcState(final ImcState state)
{
diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java
index dbbfaefb1..30fb101be 100644
--- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java
+++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java
@@ -496,14 +496,12 @@ public class VpnProfileDetailActivity extends AppCompatActivity
showCertificateAlert();
valid = false;
}
- Integer mtu = getInteger(mMTU);
- if (mtu != null && (mtu < MTU_MIN || mtu > MTU_MAX))
+ if (!validateInteger(mMTU, MTU_MIN, MTU_MAX))
{
mMTUWrap.setError(String.format(getString(R.string.alert_text_out_of_range), MTU_MIN, MTU_MAX));
valid = false;
}
- Integer port = getInteger(mPort);
- if (port != null && (port < 1 || port > 65535))
+ if (!validateInteger(mPort, 1, 65535))
{
mPortWrap.setError(String.format(getString(R.string.alert_text_out_of_range), 1, 65535));
valid = false;
@@ -633,6 +631,31 @@ public class VpnProfileDetailActivity extends AppCompatActivity
}
}
+ /**
+ * Check that the value in the given text box is a valid integer in the given range
+ *
+ * @param view text box (numeric entry assumed)
+ * @param min minimum value (inclusive)
+ * @param max maximum value (inclusive)
+ */
+ private boolean validateInteger(EditText view, Integer min, Integer max)
+ {
+ String value = view.getText().toString().trim();
+ try
+ {
+ if (value.isEmpty())
+ {
+ return true;
+ }
+ Integer val = Integer.valueOf(value);
+ return min <= val && val <= max;
+ }
+ catch (NumberFormatException e)
+ {
+ return false;
+ }
+ }
+
private class SelectUserCertOnClickListener implements OnClickListener, KeyChainAliasCallback
{
@Override
diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnStateFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnStateFragment.java
index 0b093d78f..1ea01515c 100644
--- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnStateFragment.java
+++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnStateFragment.java
@@ -187,12 +187,11 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
State state = mService.getState();
ErrorState error = mService.getErrorState();
ImcState imcState = mService.getImcState();
- String name = "", gateway = "";
+ String name = "";
if (profile != null)
{
name = profile.getName();
- gateway = profile.getGateway();
}
if (reportError(connectionID, name, error, imcState))
diff --git a/src/frontends/android/app/src/main/jni/Android.mk b/src/frontends/android/app/src/main/jni/Android.mk
index 849bdec31..51a61b883 100644
--- a/src/frontends/android/app/src/main/jni/Android.mk
+++ b/src/frontends/android/app/src/main/jni/Android.mk
@@ -6,7 +6,7 @@ include $(CLEAR_VARS)
strongswan_USE_BYOD := true
strongswan_CHARON_PLUGINS := android-log openssl fips-prf random nonce pubkey \
- pkcs1 pkcs8 pem xcbc hmac socket-default \
+ chapoly curve25519 pkcs1 pkcs8 pem xcbc hmac socket-default \
eap-identity eap-mschapv2 eap-md5 eap-gtc eap-tls
ifneq ($(strongswan_USE_BYOD),)
diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_attr.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_attr.c
index 8015b7c38..47933d1f2 100644
--- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_attr.c
+++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_attr.c
@@ -58,7 +58,7 @@ METHOD(attribute_handler_t, handle, bool,
DESTROY_IF(dns);
return FALSE;
}
-
+ DBG1(DBG_IKE, "installing DNS server %H", dns);
builder = charonservice->get_vpnservice_builder(charonservice);
builder->add_dns(builder, dns);
dns->destroy(dns);
diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c
index 2532402bb..33585df32 100644
--- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c
+++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c
@@ -550,6 +550,8 @@ METHOD(listener_t, alert, bool,
private_android_service_t *this, ike_sa_t *ike_sa, alert_t alert,
va_list args)
{
+ bool stay_registered = TRUE;
+
if (this->ike_sa == ike_sa)
{
switch (alert)
@@ -557,11 +559,13 @@ METHOD(listener_t, alert, bool,
case ALERT_PEER_ADDR_FAILED:
charonservice->update_status(charonservice,
CHARONSERVICE_LOOKUP_ERROR);
- break;
+ return FALSE;
+
case ALERT_PEER_AUTH_FAILED:
charonservice->update_status(charonservice,
CHARONSERVICE_PEER_AUTH_ERROR);
- break;
+ return FALSE;
+
case ALERT_KEEP_ON_CHILD_SA_FAILURE:
{
uint32_t *id = malloc_thing(uint32_t);
@@ -593,6 +597,7 @@ METHOD(listener_t, alert, bool,
(job_t*)callback_job_create_with_prio(
(callback_job_cb_t)terminate, id, free,
(callback_job_cancel_t)return_false, JOB_PRIO_HIGH));
+ stay_registered = FALSE;
}
else
{
@@ -609,6 +614,7 @@ METHOD(listener_t, alert, bool,
{
charonservice->update_status(charonservice,
CHARONSERVICE_UNREACHABLE_ERROR);
+ stay_registered = FALSE;
}
}
this->lock->unlock(this->lock);
@@ -617,7 +623,7 @@ METHOD(listener_t, alert, bool,
break;
}
}
- return TRUE;
+ return stay_registered;
}
static void add_auth_cfg_pw(private_android_service_t *this,
@@ -789,17 +795,18 @@ static job_requeue_t initiate(private_android_service_t *this)
/* create ESP proposals with and without DH groups, let responder decide
* if PFS is used */
child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
- "aes128gcm16-aes256gcm16-ecp256"));
+ "aes128gcm16-aes256gcm16-chacha20poly1305-"
+ "curve25519-ecp256-modp3072"));
child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
- "aes128-sha256-ecp256-modp3072"));
+ "aes128-sha256-curve25519-ecp256-modp3072"));
child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
"aes256-sha384-ecp521-modp8192"));
child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
"aes128-aes192-aes256-sha1-sha256-sha384-sha512-"
- "ecp256-ecp384-ecp521-"
+ "curve25519-ecp256-ecp384-ecp521-"
"modp2048-modp3072-modp4096-modp1024"));
child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
- "aes128gcm16-aes256gcm16"));
+ "aes128gcm16-aes256gcm16-chacha20poly1305"));
child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
"aes128-sha256"));
child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
diff --git a/src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification.png b/src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification.png
new file mode 100644
index 000000000..d723ee611
--- /dev/null
+++ b/src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification.png
Binary files differ
diff --git a/src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification_warning.png b/src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification_warning.png
new file mode 100644
index 000000000..05198c810
--- /dev/null
+++ b/src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification_warning.png
Binary files differ
diff --git a/src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification.png b/src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification.png
new file mode 100644
index 000000000..fa5d642c5
--- /dev/null
+++ b/src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification.png
Binary files differ
diff --git a/src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification_warning.png b/src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification_warning.png
new file mode 100644
index 000000000..f6cd212be
--- /dev/null
+++ b/src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification_warning.png
Binary files differ
diff --git a/src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification.png b/src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification.png
new file mode 100644
index 000000000..9961c0ae5
--- /dev/null
+++ b/src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification.png
Binary files differ
diff --git a/src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification_warning.png b/src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification_warning.png
new file mode 100644
index 000000000..1b5be812f
--- /dev/null
+++ b/src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification_warning.png
Binary files differ
diff --git a/src/frontends/android/build.gradle b/src/frontends/android/build.gradle
index 33b908c6d..3d5ba798f 100644
--- a/src/frontends/android/build.gradle
+++ b/src/frontends/android/build.gradle
@@ -3,7 +3,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.1.2'
+ classpath 'com.android.tools.build:gradle:2.2.3'
}
}
diff --git a/src/frontends/android/gradle/wrapper/gradle-wrapper.properties b/src/frontends/android/gradle/wrapper/gradle-wrapper.properties
index 33892269f..a6bd91c6c 100644
--- a/src/frontends/android/gradle/wrapper/gradle-wrapper.properties
+++ b/src/frontends/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Apr 13 11:22:32 CEST 2016
+#Tue Sep 20 17:56:35 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk
index 0e8f7f3c8..b594dabcc 100644
--- a/src/libstrongswan/Android.mk
+++ b/src/libstrongswan/Android.mk
@@ -64,12 +64,16 @@ LOCAL_SRC_FILES := $(libstrongswan_la_SOURCES)
LOCAL_SRC_FILES += $(call add_plugin, aes)
+LOCAL_SRC_FILES += $(call add_plugin, chapoly)
+
LOCAL_SRC_FILES += $(call add_plugin, curl)
ifneq ($(call plugin_enabled, curl),)
LOCAL_C_INCLUDES += $(libcurl_PATH)
LOCAL_SHARED_LIBRARIES += libcurl
endif
+LOCAL_SRC_FILES += $(call add_plugin, curve25519)
+
LOCAL_SRC_FILES += $(call add_plugin, des)
LOCAL_SRC_FILES += $(call add_plugin, fips-prf)