2 * Copyright (C) 2012 Giuliano Grassi
3 * Copyright (C) 2012 Ralf Sager
4 * Copyright (C) 2012 Tobias Brunner
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 #include <android/log.h>
22 #include "charonservice.h"
23 #include "android_jni.h"
24 #include "kernel/android_ipsec.h"
25 #include "kernel/android_net.h"
31 #include <threading/thread.h>
33 #define ANDROID_DEBUG_LEVEL 1
35 typedef struct private_charonservice_t private_charonservice_t
;
38 * private data of charonservice
40 struct private_charonservice_t
{
45 charonservice_t
public;
48 * CharonVpnService reference
54 * Single instance of charonservice_t.
56 charonservice_t
*charonservice
;
59 * hook in library for debugging messages
61 extern void (*dbg
)(debug_t group
, level_t level
, char *fmt
, ...);
64 * Logging hook for library logs, using android specific logging
66 static void dbg_android(debug_t group
, level_t level
, char *fmt
, ...)
70 if (level
<= ANDROID_DEBUG_LEVEL
)
72 char sgroup
[16], buffer
[8192];
73 char *current
= buffer
, *next
;
75 snprintf(sgroup
, sizeof(sgroup
), "%N", debug_names
, group
);
77 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
80 { /* log each line separately */
81 next
= strchr(current
, '\n');
86 __android_log_print(ANDROID_LOG_INFO
, "charon", "00[%s] %s\n",
93 METHOD(charonservice_t
, update_status
, bool,
94 private_charonservice_t
*this, android_vpn_state_t code
)
100 androidjni_attach_thread(&env
);
102 method_id
= (*env
)->GetMethodID(env
, android_charonvpnservice_class
,
103 "updateStatus", "(I)V");
108 (*env
)->CallVoidMethod(env
, this->vpn_service
, method_id
, (jint
)code
);
109 success
= !androidjni_exception_occurred(env
);
112 androidjni_exception_occurred(env
);
113 androidjni_detach_thread();
117 METHOD(charonservice_t
, bypass_socket
, bool,
118 private_charonservice_t
*this, int fd
, int family
)
123 androidjni_attach_thread(&env
);
125 method_id
= (*env
)->GetMethodID(env
, android_charonvpnservice_class
,
131 if (!(*env
)->CallBooleanMethod(env
, this->vpn_service
, method_id
, fd
))
133 DBG1(DBG_CFG
, "VpnService.protect() failed");
136 androidjni_detach_thread();
140 androidjni_exception_occurred(env
);
141 androidjni_detach_thread();
145 METHOD(charonservice_t
, get_trusted_certificates
, linked_list_t
*,
146 private_charonservice_t
*this)
154 androidjni_attach_thread(&env
);
156 method_id
= (*env
)->GetMethodID(env
,
157 android_charonvpnservice_class
,
158 "getTrustedCertificates", "(Ljava/lang/String;)[[B");
163 jcerts
= (*env
)->CallObjectMethod(env
, this->vpn_service
, method_id
, NULL
);
168 list
= linked_list_create();
169 for (i
= 0; i
< (*env
)->GetArrayLength(env
, jcerts
); ++i
)
174 ca_cert
= malloc_thing(chunk_t
);
175 list
->insert_last(list
, ca_cert
);
177 jcert
= (*env
)->GetObjectArrayElement(env
, jcerts
, i
);
178 *ca_cert
= chunk_alloc((*env
)->GetArrayLength(env
, jcert
));
179 (*env
)->GetByteArrayRegion(env
, jcert
, 0, ca_cert
->len
, ca_cert
->ptr
);
180 (*env
)->DeleteLocalRef(env
, jcert
);
182 (*env
)->DeleteLocalRef(env
, jcerts
);
183 androidjni_detach_thread();
187 androidjni_exception_occurred(env
);
188 androidjni_detach_thread();
193 * Initialize the charonservice object
195 static void charonservice_init(JNIEnv
*env
, jobject service
)
197 private_charonservice_t
*this;
198 static plugin_feature_t features
[] = {
199 PLUGIN_CALLBACK(kernel_net_register
, kernel_android_net_create
),
200 PLUGIN_PROVIDE(CUSTOM
, "kernel-net"),
201 PLUGIN_CALLBACK(kernel_ipsec_register
, kernel_android_ipsec_create
),
202 PLUGIN_PROVIDE(CUSTOM
, "kernel-ipsec"),
207 .update_status
= _update_status
,
208 .bypass_socket
= _bypass_socket
,
209 .get_trusted_certificates
= _get_trusted_certificates
,
211 .vpn_service
= (*env
)->NewGlobalRef(env
, service
),
213 charonservice
= &this->public;
215 lib
->plugins
->add_static_features(lib
->plugins
, "androidbridge", features
,
216 countof(features
), TRUE
);
218 lib
->settings
->set_int(lib
->settings
,
219 "charon.plugins.android_log.loglevel", ANDROID_DEBUG_LEVEL
);
223 * Deinitialize the charonservice object
225 static void charonservice_deinit(JNIEnv
*env
)
227 private_charonservice_t
*this = (private_charonservice_t
*)charonservice
;
229 (*env
)->DeleteGlobalRef(env
, this->vpn_service
);
231 charonservice
= NULL
;
235 * Handle SIGSEGV/SIGILL signals raised by threads
237 static void segv_handler(int signal
)
239 dbg_android(DBG_DMN
, 1, "thread %u received %d", thread_current_id(),
245 * Initialize charon and the libraries via JNI
247 JNI_METHOD(CharonVpnService
, initializeCharon
, void)
249 struct sigaction action
;
251 /* logging for library during initialization, as we have no bus yet */
254 /* initialize library */
255 if (!library_init(NULL
))
261 if (!libhydra_init("charon"))
268 if (!libipsec_init())
276 charonservice_init(env
, this);
278 if (!libcharon_init("charon") ||
279 !charon
->initialize(charon
, PLUGINS
))
282 charonservice_deinit(env
);
289 /* add handler for SEGV and ILL etc. */
290 action
.sa_handler
= segv_handler
;
292 sigemptyset(&action
.sa_mask
);
293 sigaction(SIGSEGV
, &action
, NULL
);
294 sigaction(SIGILL
, &action
, NULL
);
295 sigaction(SIGBUS
, &action
, NULL
);
296 action
.sa_handler
= SIG_IGN
;
297 sigaction(SIGPIPE
, &action
, NULL
);
299 /* start daemon (i.e. the threads in the thread-pool) */
300 charon
->start(charon
);
304 * Deinitialize charon and all libraries
306 JNI_METHOD(CharonVpnService
, deinitializeCharon
, void)
309 charonservice_deinit(env
);