Native counterpart of VpnService.Builder added, exposed by charonservice

This commit is contained in:
Tobias Brunner 2012-08-08 13:48:54 +02:00
parent 5215d512bf
commit ae4f1ea180
8 changed files with 409 additions and 6 deletions

View File

@ -8,7 +8,8 @@ backend/android_creds.c backend/android_creds.h \
backend/android_service.c backend/android_service.h \
charonservice.c charonservice.h \
kernel/android_ipsec.c kernel/android_ipsec.h \
kernel/android_net.c kernel/android_net.h
kernel/android_net.c kernel/android_net.h \
vpnservice_builder.c vpnservice_builder.h
# build libandroidbridge -------------------------------------------------------

View File

@ -26,6 +26,7 @@
static JavaVM *android_jvm;
jclass *android_charonvpnservice_class;
jclass *android_charonvpnservice_builder_class;
/**
* Thread-local variable. Only used because of the destructor
@ -88,6 +89,9 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved)
android_charonvpnservice_class =
(*env)->NewGlobalRef(env, (*env)->FindClass(env,
JNI_PACKAGE_STRING "/CharonVpnService"));
android_charonvpnservice_builder_class =
(*env)->NewGlobalRef(env, (*env)->FindClass(env,
JNI_PACKAGE_STRING "/CharonVpnService$BuilderAdapter"));
return JNI_VERSION_1_6;
}

View File

@ -43,6 +43,7 @@
* Initialized in JNI_OnLoad()
*/
extern jclass *android_charonvpnservice_class;
extern jclass *android_charonvpnservice_builder_class;
/**
* Attach the current thread to the JVM

View File

@ -56,6 +56,11 @@ struct private_charonservice_t {
*/
android_service_t *service;
/**
* VpnService builder (accessed via JNI)
*/
vpnservice_builder_t *builder;
/**
* CharonVpnService reference
*/
@ -201,6 +206,12 @@ failed:
return NULL;
}
METHOD(charonservice_t, get_vpnservice_builder, vpnservice_builder_t*,
private_charonservice_t *this)
{
return this->builder;
}
/**
* Initiate a new connection
*
@ -248,7 +259,7 @@ static bool charonservice_register(void *plugin, plugin_feature_t *feature,
/**
* Initialize the charonservice object
*/
static void charonservice_init(JNIEnv *env, jobject service)
static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
{
private_charonservice_t *this;
static plugin_feature_t features[] = {
@ -266,8 +277,10 @@ static void charonservice_init(JNIEnv *env, jobject service)
.update_status = _update_status,
.bypass_socket = _bypass_socket,
.get_trusted_certificates = _get_trusted_certificates,
.get_vpnservice_builder = _get_vpnservice_builder,
},
.creds = android_creds_create(),
.builder = vpnservice_builder_create(builder),
.vpn_service = (*env)->NewGlobalRef(env, service),
);
charonservice = &this->public;
@ -286,6 +299,7 @@ static void charonservice_deinit(JNIEnv *env)
{
private_charonservice_t *this = (private_charonservice_t*)charonservice;
this->builder->destroy(this->builder);
this->creds->destroy(this->creds);
(*env)->DeleteGlobalRef(env, this->vpn_service);
free(this);
@ -305,7 +319,8 @@ static void segv_handler(int signal)
/**
* Initialize charon and the libraries via JNI
*/
JNI_METHOD(CharonVpnService, initializeCharon, void)
JNI_METHOD(CharonVpnService, initializeCharon, void,
jobject builder)
{
struct sigaction action;
@ -334,7 +349,7 @@ JNI_METHOD(CharonVpnService, initializeCharon, void)
return;
}
charonservice_init(env, this);
charonservice_init(env, this, builder);
if (!libcharon_init("charon") ||
!charon->initialize(charon, PLUGINS))

View File

@ -31,6 +31,8 @@
#ifndef CHARONSERVICE_H_
#define CHARONSERVICE_H_
#include "vpnservice_builder.h"
#include <library.h>
#include <utils/linked_list.h>
@ -83,6 +85,13 @@ struct charonservice_t {
*/
linked_list_t *(*get_trusted_certificates)(charonservice_t *this);
/**
* Get the current vpnservice_builder_t object
*
* @return VpnService.Builder instance
*/
vpnservice_builder_t *(*get_vpnservice_builder)(charonservice_t *this);
};
/**

View File

@ -0,0 +1,274 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* 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 "vpnservice_builder.h"
#include "android_jni.h"
#include <debug.h>
#include <library.h>
typedef struct private_vpnservice_builder_t private_vpnservice_builder_t;
/**
* private data of vpnservice_builder
*/
struct private_vpnservice_builder_t {
/**
* public interface
*/
vpnservice_builder_t public;
/**
* Java object
*/
jobject builder;
};
METHOD(vpnservice_builder_t, add_address, bool,
private_vpnservice_builder_t *this, host_t *addr)
{
JNIEnv *env;
jmethodID method_id;
jstring str;
char buf[INET_ADDRSTRLEN];
androidjni_attach_thread(&env);
DBG2(DBG_LIB, "builder: adding interface address %H", addr);
if (addr->get_family(addr) != AF_INET)
{
goto failed;
}
if (snprintf(buf, sizeof(buf), "%H", addr) >= sizeof(buf))
{
goto failed;
}
method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
"addAddress", "(Ljava/lang/String;I)Z");
if (!method_id)
{
goto failed;
}
str = (*env)->NewStringUTF(env, buf);
if (!str)
{
goto failed;
}
if (!(*env)->CallBooleanMethod(env, this->builder, method_id, str, 32))
{
goto failed;
}
androidjni_detach_thread();
return TRUE;
failed:
DBG1(DBG_LIB, "builder: failed to add address");
androidjni_exception_occurred(env);
androidjni_detach_thread();
return FALSE;
}
METHOD(vpnservice_builder_t, set_mtu, bool,
private_vpnservice_builder_t *this, int mtu)
{
JNIEnv *env;
jmethodID method_id;
androidjni_attach_thread(&env);
DBG2(DBG_LIB, "builder: setting MTU to %d", mtu);
method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
"setMtu", "(I)Z");
if (!method_id)
{
goto failed;
}
if (!(*env)->CallBooleanMethod(env, this->builder, method_id, mtu))
{
goto failed;
}
androidjni_detach_thread();
return TRUE;
failed:
DBG1(DBG_LIB, "builder: failed to set MTU");
androidjni_exception_occurred(env);
androidjni_detach_thread();
return FALSE;
}
METHOD(vpnservice_builder_t, add_route, bool,
private_vpnservice_builder_t *this, host_t *net, int prefix)
{
JNIEnv *env;
jmethodID method_id;
jstring str;
char buf[INET_ADDRSTRLEN];
androidjni_attach_thread(&env);
DBG2(DBG_LIB, "builder: adding route %+H/%d", net, prefix);
if (net->get_family(net) != AF_INET)
{
goto failed;
}
if (snprintf(buf, sizeof(buf), "%+H", net) >= sizeof(buf))
{
goto failed;
}
method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
"addRoute", "(Ljava/lang/String;I)Z");
if (!method_id)
{
goto failed;
}
str = (*env)->NewStringUTF(env, buf);
if (!str)
{
goto failed;
}
if (!(*env)->CallBooleanMethod(env, this->builder, method_id, str, prefix))
{
goto failed;
}
androidjni_detach_thread();
return TRUE;
failed:
DBG1(DBG_LIB, "builder: failed to add route");
androidjni_exception_occurred(env);
androidjni_detach_thread();
return FALSE;
}
METHOD(vpnservice_builder_t, add_dns, bool,
private_vpnservice_builder_t *this, host_t *dns)
{
JNIEnv *env;
jmethodID method_id;
jstring str;
char buf[INET_ADDRSTRLEN];
androidjni_attach_thread(&env);
DBG2(DBG_LIB, "builder: adding DNS server %H", dns);
if (dns->get_family(dns) != AF_INET)
{
goto failed;
}
if (snprintf(buf, sizeof(buf), "%H", dns) >= sizeof(buf))
{
goto failed;
}
method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
"addDnsServer", "(Ljava/lang/String;)Z");
if (!method_id)
{
goto failed;
}
str = (*env)->NewStringUTF(env, buf);
if (!str)
{
goto failed;
}
if (!(*env)->CallBooleanMethod(env, this->builder, method_id, str))
{
goto failed;
}
androidjni_detach_thread();
return TRUE;
failed:
DBG1(DBG_LIB, "builder: failed to add DNS server");
androidjni_exception_occurred(env);
androidjni_detach_thread();
return FALSE;
}
METHOD(vpnservice_builder_t, establish, int,
private_vpnservice_builder_t *this)
{
JNIEnv *env;
jmethodID method_id;
int fd;
androidjni_attach_thread(&env);
DBG2(DBG_LIB, "builder: building TUN device");
method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
"establish", "()I");
if (!method_id)
{
goto failed;
}
fd = (*env)->CallIntMethod(env, this->builder, method_id);
if (fd == -1)
{
goto failed;
}
androidjni_detach_thread();
return fd;
failed:
DBG1(DBG_LIB, "builder: failed to build TUN device");
androidjni_exception_occurred(env);
androidjni_detach_thread();
return -1;
}
METHOD(vpnservice_builder_t, destroy, void,
private_vpnservice_builder_t *this)
{
JNIEnv *env;
androidjni_attach_thread(&env);
(*env)->DeleteGlobalRef(env, this->builder);
androidjni_detach_thread();
free(this);
}
vpnservice_builder_t *vpnservice_builder_create(jobject builder)
{
JNIEnv *env;
private_vpnservice_builder_t *this;
INIT(this,
.public = {
.add_address = _add_address,
.add_route = _add_route,
.add_dns = _add_dns,
.set_mtu = _set_mtu,
.establish = _establish,
.destroy = _destroy,
},
);
androidjni_attach_thread(&env);
this->builder = (*env)->NewGlobalRef(env, builder);
androidjni_detach_thread();
return &this->public;
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* 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.
*/
/**
* @defgroup vpnservice_builder vpnservice_builder
* @{ @ingroup libandroidbridge
*/
#ifndef VPNSERVICE_BUILDER_H_
#define VPNSERVICE_BUILDER_H_
#include <jni.h>
#include <library.h>
#include <utils/host.h>
typedef struct vpnservice_builder_t vpnservice_builder_t;
/**
* VpnService.Builder, used to build a TUN device.
*
* Communicates with CharonVpnService.BuilderAdapter via JNI
*/
struct vpnservice_builder_t {
/**
* Add an interface address
*
* @param addr the desired interface address
* @return TRUE on success
*/
bool (*add_address)(vpnservice_builder_t *this, host_t *addr);
/**
* Add a route
*
* @param net the network address
* @param prefix_length the prefix length
* @return TRUE on success
*/
bool (*add_route)(vpnservice_builder_t *this, host_t *net, int prefix);
/**
* Add a DNS server
*
* @param dns the address of the DNS server
* @return TRUE on success
*/
bool (*add_dns)(vpnservice_builder_t *this, host_t *dns);
/**
* Set the MTU for the TUN device
*
* @param mtu the MTU to set
* @return TRUE on success
*/
bool (*set_mtu)(vpnservice_builder_t *this, int mtu);
/**
* Build the TUN device
*
* @return the TUN file descriptor, -1 if failed
*/
int (*establish)(vpnservice_builder_t *this);
/**
* Destroy a vpnservice_builder
*/
void (*destroy)(vpnservice_builder_t *this);
};
/**
* Create a vpnservice_builder instance
*
* @param builder CharonVpnService.BuilderAdapter object
* @return vpnservice_builder_t instance
*/
vpnservice_builder_t *vpnservice_builder_create(jobject builder);
#endif /** VPNSERVICE_BUILDER_H_ @}*/

View File

@ -193,7 +193,8 @@ public class CharonVpnService extends VpnService implements Runnable
setError(ErrorState.NO_ERROR);
setState(State.CONNECTING);
initializeCharon();
BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName());
initializeCharon(builder);
Log.i(TAG, "charon started");
String local_address = getLocalIPv4Address();
@ -401,8 +402,10 @@ public class CharonVpnService extends VpnService implements Runnable
/**
* Initialization of charon, provided by libandroidbridge.so
*
* @param builder BuilderAdapter for this connection
*/
public native void initializeCharon();
public native void initializeCharon(BuilderAdapter builder);
/**
* Deinitialize charon, provided by libandroidbridge.so
@ -450,6 +453,7 @@ public class CharonVpnService extends VpnService implements Runnable
/**
* Adapter for VpnService.Builder which is used to access it safely via JNI.
* There is a corresponding C object to access it from native code.
*/
public class BuilderAdapter
{