Added android.net.VpnService wrapper around charon (loaded via JNI).
authorTobias Brunner <tobias@strongswan.org>
Fri, 17 Feb 2012 16:16:07 +0000 (17:16 +0100)
committerTobias Brunner <tobias@strongswan.org>
Wed, 8 Aug 2012 13:09:31 +0000 (15:09 +0200)
src/frontends/android/AndroidManifest.xml
src/frontends/android/jni/Android.mk
src/frontends/android/jni/libandroidbridge/Android.mk [new file with mode: 0644]
src/frontends/android/jni/libandroidbridge/charonservice.c [new file with mode: 0644]
src/frontends/android/src/org/strongswan/android/CharonVpnService.java [new file with mode: 0644]
src/frontends/android/src/org/strongswan/android/strongSwanActivity.java

index 702a15d..63464e7 100644 (file)
@@ -5,6 +5,7 @@
     android:versionName="1.0" >
 
     <uses-sdk android:minSdkVersion="15" />
+    <uses-permission android:name="android.permission.INTERNET" />
 
     <application
         android:icon="@drawable/ic_launcher"
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <service android:name=".CharonVpnService" android:permission="android.permission.BIND_VPN_SERVICE">
+            <intent-filter>
+                <action android:name="android.net.VpnService"/>
+            </intent-filter>
+        </service>
     </application>
 
 </manifest>
\ No newline at end of file
index 74c6c6a..e5659a4 100644 (file)
@@ -56,6 +56,7 @@ strongswan_CFLAGS += \
 include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
                vstr \
                openssl \
+               libandroidbridge \
                strongswan/src/libcharon \
                strongswan/src/libhydra \
                strongswan/src/libstrongswan \
diff --git a/src/frontends/android/jni/libandroidbridge/Android.mk b/src/frontends/android/jni/libandroidbridge/Android.mk
new file mode 100644 (file)
index 0000000..7f25a54
--- /dev/null
@@ -0,0 +1,33 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# copy-n-paste from Makefile.am
+LOCAL_SRC_FILES := \
+charonservice.c
+
+# build libandroidbridge -------------------------------------------------------
+
+LOCAL_C_INCLUDES += \
+       $(libvstr_PATH) \
+       $(strongswan_PATH)/src/libhydra \
+       $(strongswan_PATH)/src/libcharon \
+       $(strongswan_PATH)/src/libstrongswan
+
+LOCAL_CFLAGS := $(strongswan_CFLAGS) \
+       -DPLUGINS='"$(strongswan_CHARON_PLUGINS)"'
+
+LOCAL_MODULE := libandroidbridge
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_LDLIBS := -llog
+
+LOCAL_SHARED_LIBRARIES := libstrongswan libhydra libcharon
+
+include $(BUILD_SHARED_LIBRARY)
+
+
diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.c b/src/frontends/android/jni/libandroidbridge/charonservice.c
new file mode 100644 (file)
index 0000000..ecc2434
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+#include <android/log.h>
+#include <jni.h>
+
+#include <hydra.h>
+#include <daemon.h>
+#include <library.h>
+
+#define JNI_PACKAGE org_strongswan_android
+
+#define JNI_METHOD_PP(pack, klass, name, ret, ...) \
+       ret Java_##pack##_##klass##_##name(JNIEnv *env, jobject this, ##__VA_ARGS__)
+
+#define JNI_METHOD_P(pack, klass, name, ret, ...) \
+       JNI_METHOD_PP(pack, klass, name, ret, ##__VA_ARGS__)
+
+#define JNI_METHOD(klass, name, ret, ...) \
+       JNI_METHOD_P(JNI_PACKAGE, klass, name, ret, ##__VA_ARGS__)
+
+/**
+ * hook in library for debugging messages
+ */
+extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
+
+/**
+ * Logging hook for library logs, using android specific logging
+ */
+static void dbg_android(debug_t group, level_t level, char *fmt, ...)
+{
+       va_list args;
+
+       if (level <= 4)
+       {
+               char sgroup[16], buffer[8192];
+               char *current = buffer, *next;
+               snprintf(sgroup, sizeof(sgroup), "%N", debug_names, group);
+               va_start(args, fmt);
+               vsnprintf(buffer, sizeof(buffer), fmt, args);
+               va_end(args);
+               while (current)
+               {       /* log each line separately */
+                       next = strchr(current, '\n');
+                       if (next)
+                       {
+                               *(next++) = '\0';
+                       }
+                       __android_log_print(ANDROID_LOG_INFO, "charon", "00[%s] %s\n",
+                                                               sgroup, current);
+                       current = next;
+               }
+       }
+}
+
+/**
+ * Initialize charon and the libraries via JNI
+ */
+JNI_METHOD(CharonVpnService, initializeCharon, void)
+{
+       /* logging for library during initialization, as we have no bus yet */
+       dbg = dbg_android;
+
+       /* initialize library */
+       if (!library_init(NULL))
+       {
+               library_deinit();
+               return;
+       }
+
+       if (!libhydra_init("charon"))
+       {
+               libhydra_deinit();
+               library_deinit();
+               return;
+       }
+
+       if (!libcharon_init("charon") ||
+               !charon->initialize(charon, PLUGINS))
+       {
+               libcharon_deinit();
+               libhydra_deinit();
+               library_deinit();
+               return;
+       }
+
+       /* start daemon (i.e. the threads in the thread-pool) */
+       charon->start(charon);
+}
+
+/**
+ * Initialize charon and the libraries via JNI
+ */
+JNI_METHOD(CharonVpnService, deinitializeCharon, void)
+{
+       libcharon_deinit();
+       libhydra_deinit();
+       library_deinit();
+}
+
diff --git a/src/frontends/android/src/org/strongswan/android/CharonVpnService.java b/src/frontends/android/src/org/strongswan/android/CharonVpnService.java
new file mode 100644 (file)
index 0000000..596372f
--- /dev/null
@@ -0,0 +1,50 @@
+package org.strongswan.android;
+
+import android.content.Intent;
+import android.net.VpnService;
+
+public class CharonVpnService extends VpnService {
+
+       @Override
+       public int onStartCommand(Intent intent, int flags, int startId) {
+               // called whenever the service is started with startService
+               // create our own thread because we are running in the calling processes main thread
+               return super.onStartCommand(intent, flags, startId);
+       }
+
+       @Override
+       public void onCreate() {
+               // onCreate is only called once
+               initializeCharon();
+               super.onCreate();
+       }
+
+       @Override
+       public void onDestroy() {
+               // called once the service is to be destroyed
+               deinitializeCharon();
+               super.onDestroy();
+       }
+
+       /**
+        * Initialization of charon, provided by libandroidbridge.so
+        */
+       public native void initializeCharon();
+
+       /**
+        * Deinitialize charon, provided by libandroidbridge.so
+        */
+       public native void deinitializeCharon();
+
+       /*
+        * The libraries are extracted to /data/data/org.strongswan.android/...
+        * during installation.
+        */
+       static {
+               System.loadLibrary("crypto");
+               System.loadLibrary("strongswan");
+               System.loadLibrary("hydra");
+               System.loadLibrary("charon");
+               System.loadLibrary("androidbridge");
+       }
+}
index 16d4a09..b4fb6f3 100644 (file)
@@ -1,13 +1,32 @@
 package org.strongswan.android;
 
 import android.app.Activity;
+import android.content.Intent;
+import android.net.VpnService;
 import android.os.Bundle;
 
 public class strongSwanActivity extends Activity {
-    /** Called when the activity is first created. */
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-    }
+       @Override
+       public void onCreate(Bundle savedInstanceState) {
+               super.onCreate(savedInstanceState);
+               setContentView(R.layout.main);
+               startVpnService();
+       }
+
+       private void startVpnService() {
+               Intent intent = VpnService.prepare(this);
+               if (intent != null) {
+                       startActivityForResult(intent, 0);
+               } else {
+                       onActivityResult(0, RESULT_OK, null);
+               }
+       }
+
+       @Override
+       protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+               if (resultCode == RESULT_OK) {
+                       Intent intent = new Intent(this, CharonVpnService.class);
+                       startService(intent);
+               }
+       }
 }
\ No newline at end of file