android: Bypass/protect previously bypassed sockets if connectivity changes
authorTobias Brunner <tobias@strongswan.org>
Thu, 11 Oct 2012 16:48:17 +0000 (18:48 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 16 Oct 2012 12:16:17 +0000 (14:16 +0200)
src/frontends/android/jni/libandroidbridge/charonservice.c
src/frontends/android/jni/libandroidbridge/charonservice.h
src/frontends/android/jni/libandroidbridge/kernel/android_net.c

index 591ca90..c636052 100644 (file)
@@ -82,6 +82,11 @@ struct private_charonservice_t {
         * CharonVpnService reference
         */
        jobject vpn_service;
+
+       /**
+        * Sockets that were bypassed and we keep track for
+        */
+       linked_list_t *sockets;
 };
 
 /**
@@ -177,8 +182,10 @@ failed:
        return success;
 }
 
-METHOD(charonservice_t, bypass_socket, bool,
-       private_charonservice_t *this, int fd, int family)
+/**
+ * Bypass a single socket
+ */
+static bool bypass_single_socket(intptr_t fd, private_charonservice_t *this)
 {
        JNIEnv *env;
        jmethodID method_id;
@@ -193,7 +200,7 @@ METHOD(charonservice_t, bypass_socket, bool,
        }
        if (!(*env)->CallBooleanMethod(env, this->vpn_service, method_id, fd))
        {
-               DBG1(DBG_CFG, "VpnService.protect() failed");
+               DBG2(DBG_KNL, "VpnService.protect() failed");
                goto failed;
        }
        androidjni_detach_thread();
@@ -205,6 +212,19 @@ failed:
        return FALSE;
 }
 
+METHOD(charonservice_t, bypass_socket, bool,
+       private_charonservice_t *this, int fd, int family)
+{
+       if (fd >= 0)
+       {
+               this->sockets->insert_last(this->sockets, (void*)(intptr_t)fd);
+               return bypass_single_socket((intptr_t)fd, this);
+       }
+       this->sockets->invoke_function(this->sockets, (void*)bypass_single_socket,
+                                                                  this);
+       return TRUE;
+}
+
 /**
  * Converts the given Java array of byte arrays (byte[][]) to a linked list
  * of chunk_t objects.
@@ -415,6 +435,7 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
                .creds = android_creds_create(),
                .builder = vpnservice_builder_create(builder),
                .network_manager = network_manager_create(service),
+               .sockets = linked_list_create(),
                .vpn_service = (*env)->NewGlobalRef(env, service),
        );
        charonservice = &this->public;
@@ -451,6 +472,7 @@ static void charonservice_deinit(JNIEnv *env)
        private_charonservice_t *this = (private_charonservice_t*)charonservice;
 
        this->network_manager->destroy(this->network_manager);
+       this->sockets->destroy(this->sockets);
        this->builder->destroy(this->builder);
        this->creds->destroy(this->creds);
        this->attr->destroy(this->attr);
index 2d5e8f0..4b5839f 100644 (file)
@@ -70,7 +70,9 @@ struct charonservice_t {
 
        /**
         * Install a bypass policy for the given socket using the protect() Method
-        * of the Android VpnService interface
+        * of the Android VpnService interface.
+        *
+        * Use -1 as fd to re-bypass previously bypassed sockets.
         *
         * @param fd                    socket file descriptor
         * @param family                socket protocol family
index ce62294..710bee5 100644 (file)
@@ -53,6 +53,8 @@ struct private_kernel_android_net_t {
  */
 static job_requeue_t roam_event()
 {
+       /* this will fail if no connection is up */
+       charonservice->bypass_socket(charonservice, -1, 0);
        hydra->kernel_interface->roam(hydra->kernel_interface, TRUE);
        return JOB_REQUEUE_NONE;
 }