android: Bypass/protect previously bypassed sockets if connectivity changes

This commit is contained in:
Tobias Brunner
2012-10-16 14:16:17 +02:00
parent 9167ca8b2b
commit 45885ca613
3 changed files with 30 additions and 4 deletions
@@ -82,6 +82,11 @@ struct private_charonservice_t {
* CharonVpnService reference * CharonVpnService reference
*/ */
jobject vpn_service; jobject vpn_service;
/**
* Sockets that were bypassed and we keep track for
*/
linked_list_t *sockets;
}; };
/** /**
@@ -177,8 +182,10 @@ failed:
return success; 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; JNIEnv *env;
jmethodID method_id; jmethodID method_id;
@@ -193,7 +200,7 @@ METHOD(charonservice_t, bypass_socket, bool,
} }
if (!(*env)->CallBooleanMethod(env, this->vpn_service, method_id, fd)) if (!(*env)->CallBooleanMethod(env, this->vpn_service, method_id, fd))
{ {
DBG1(DBG_CFG, "VpnService.protect() failed"); DBG2(DBG_KNL, "VpnService.protect() failed");
goto failed; goto failed;
} }
androidjni_detach_thread(); androidjni_detach_thread();
@@ -205,6 +212,19 @@ failed:
return FALSE; 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 * Converts the given Java array of byte arrays (byte[][]) to a linked list
* of chunk_t objects. * of chunk_t objects.
@@ -415,6 +435,7 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
.creds = android_creds_create(), .creds = android_creds_create(),
.builder = vpnservice_builder_create(builder), .builder = vpnservice_builder_create(builder),
.network_manager = network_manager_create(service), .network_manager = network_manager_create(service),
.sockets = linked_list_create(),
.vpn_service = (*env)->NewGlobalRef(env, service), .vpn_service = (*env)->NewGlobalRef(env, service),
); );
charonservice = &this->public; charonservice = &this->public;
@@ -451,6 +472,7 @@ static void charonservice_deinit(JNIEnv *env)
private_charonservice_t *this = (private_charonservice_t*)charonservice; private_charonservice_t *this = (private_charonservice_t*)charonservice;
this->network_manager->destroy(this->network_manager); this->network_manager->destroy(this->network_manager);
this->sockets->destroy(this->sockets);
this->builder->destroy(this->builder); this->builder->destroy(this->builder);
this->creds->destroy(this->creds); this->creds->destroy(this->creds);
this->attr->destroy(this->attr); this->attr->destroy(this->attr);
@@ -70,7 +70,9 @@ struct charonservice_t {
/** /**
* Install a bypass policy for the given socket using the protect() Method * 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 fd socket file descriptor
* @param family socket protocol family * @param family socket protocol family
@@ -53,6 +53,8 @@ struct private_kernel_android_net_t {
*/ */
static job_requeue_t roam_event() 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); hydra->kernel_interface->roam(hydra->kernel_interface, TRUE);
return JOB_REQUEUE_NONE; return JOB_REQUEUE_NONE;
} }