From: Tobias Brunner Date: Wed, 8 Aug 2012 11:48:54 +0000 (+0200) Subject: Native counterpart of VpnService.Builder added, exposed by charonservice X-Git-Tag: 5.0.1~210^2~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ae4f1ea180af58704932572e970205b3d33f62c9;p=thirdparty%2Fstrongswan.git Native counterpart of VpnService.Builder added, exposed by charonservice --- diff --git a/src/frontends/android/jni/libandroidbridge/Android.mk b/src/frontends/android/jni/libandroidbridge/Android.mk index 9e1e94a8f4..2e484ec5bd 100644 --- a/src/frontends/android/jni/libandroidbridge/Android.mk +++ b/src/frontends/android/jni/libandroidbridge/Android.mk @@ -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 ------------------------------------------------------- diff --git a/src/frontends/android/jni/libandroidbridge/android_jni.c b/src/frontends/android/jni/libandroidbridge/android_jni.c index b5e935a574..e7cb14fb78 100644 --- a/src/frontends/android/jni/libandroidbridge/android_jni.c +++ b/src/frontends/android/jni/libandroidbridge/android_jni.c @@ -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; } diff --git a/src/frontends/android/jni/libandroidbridge/android_jni.h b/src/frontends/android/jni/libandroidbridge/android_jni.h index 427c641b46..39ba56fc1b 100644 --- a/src/frontends/android/jni/libandroidbridge/android_jni.h +++ b/src/frontends/android/jni/libandroidbridge/android_jni.h @@ -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 diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.c b/src/frontends/android/jni/libandroidbridge/charonservice.c index 8d595fe039..772a96f695 100644 --- a/src/frontends/android/jni/libandroidbridge/charonservice.c +++ b/src/frontends/android/jni/libandroidbridge/charonservice.c @@ -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)) diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.h b/src/frontends/android/jni/libandroidbridge/charonservice.h index e538a22c91..706eaa2205 100644 --- a/src/frontends/android/jni/libandroidbridge/charonservice.h +++ b/src/frontends/android/jni/libandroidbridge/charonservice.h @@ -31,6 +31,8 @@ #ifndef CHARONSERVICE_H_ #define CHARONSERVICE_H_ +#include "vpnservice_builder.h" + #include #include @@ -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); + }; /** diff --git a/src/frontends/android/jni/libandroidbridge/vpnservice_builder.c b/src/frontends/android/jni/libandroidbridge/vpnservice_builder.c new file mode 100644 index 0000000000..6ff7325208 --- /dev/null +++ b/src/frontends/android/jni/libandroidbridge/vpnservice_builder.c @@ -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 . + * + * 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 +#include + +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; +} diff --git a/src/frontends/android/jni/libandroidbridge/vpnservice_builder.h b/src/frontends/android/jni/libandroidbridge/vpnservice_builder.h new file mode 100644 index 0000000000..82efd05f73 --- /dev/null +++ b/src/frontends/android/jni/libandroidbridge/vpnservice_builder.h @@ -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 . + * + * 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 + +#include +#include + +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_ @}*/ diff --git a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java index 2514642d16..1d9881cb8a 100644 --- a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java @@ -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 {