]>
Commit | Line | Data |
---|---|---|
4a208143 | 1 | /* |
664389eb | 2 | * Copyright (C) 2012-2020 Tobias Brunner |
cb887af4 TB |
3 | * Copyright (C) 2012 Giuliano Grassi |
4 | * Copyright (C) 2012 Ralf Sager | |
7b417757 | 5 | * HSR Hochschule fuer Technik Rapperswil |
4a208143 TB |
6 | * |
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>. | |
11 | * | |
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 | |
15 | * for more details. | |
16 | */ | |
17 | ||
a3048743 | 18 | #include <signal.h> |
4a208143 | 19 | #include <string.h> |
6db742e7 | 20 | #include <sys/utsname.h> |
4a208143 | 21 | #include <android/log.h> |
fe05f1f0 | 22 | #include <errno.h> |
4a208143 | 23 | |
6f11e941 | 24 | #include "charonservice.h" |
cb887af4 | 25 | #include "android_jni.h" |
3a05756b | 26 | #include "backend/android_attr.h" |
8430e54d | 27 | #include "backend/android_creds.h" |
7b417757 | 28 | #include "backend/android_fetcher.h" |
406d680e | 29 | #include "backend/android_private_key.h" |
1b4c4123 | 30 | #include "backend/android_scheduler.h" |
c6c39c78 | 31 | #include "backend/android_service.h" |
17508851 | 32 | #include "kernel/android_ipsec.h" |
24447cf4 | 33 | #include "kernel/android_net.h" |
cb887af4 | 34 | |
96658d72 TB |
35 | #ifdef USE_BYOD |
36 | #include "byod/imc_android.h" | |
37 | #endif | |
38 | ||
cb887af4 | 39 | #include <daemon.h> |
06ed785e | 40 | #include <ipsec.h> |
4a208143 | 41 | #include <library.h> |
a3048743 | 42 | #include <threading/thread.h> |
4a208143 | 43 | |
d2007494 | 44 | #define ANDROID_DEBUG_LEVEL 1 |
76e55491 | 45 | #define ANDROID_RETRASNMIT_TRIES 3 |
901f6ac4 | 46 | #define ANDROID_RETRANSMIT_TIMEOUT 2.0 |
76e55491 | 47 | #define ANDROID_RETRANSMIT_BASE 1.4 |
73a6bec3 | 48 | #define ANDROID_KEEPALIVE_INTERVAL 45 |
664389eb | 49 | #define ANDROID_KEEPALIVE_DPD_MARGIN 20 |
d2007494 | 50 | |
6f11e941 TB |
51 | typedef struct private_charonservice_t private_charonservice_t; |
52 | ||
53 | /** | |
54 | * private data of charonservice | |
55 | */ | |
56 | struct private_charonservice_t { | |
57 | ||
58 | /** | |
59 | * public interface | |
60 | */ | |
61 | charonservice_t public; | |
529c8c88 | 62 | |
3a05756b TB |
63 | /** |
64 | * android_attr instance | |
65 | */ | |
66 | android_attr_t *attr; | |
67 | ||
8430e54d TB |
68 | /** |
69 | * android_creds instance | |
70 | */ | |
71 | android_creds_t *creds; | |
72 | ||
c6c39c78 TB |
73 | /** |
74 | * android_service instance | |
75 | */ | |
76 | android_service_t *service; | |
77 | ||
ae4f1ea1 TB |
78 | /** |
79 | * VpnService builder (accessed via JNI) | |
80 | */ | |
81 | vpnservice_builder_t *builder; | |
82 | ||
38bbca58 TB |
83 | /** |
84 | * NetworkManager instance (accessed via JNI) | |
85 | */ | |
86 | network_manager_t *network_manager; | |
87 | ||
529c8c88 TB |
88 | /** |
89 | * CharonVpnService reference | |
90 | */ | |
91 | jobject vpn_service; | |
45885ca6 TB |
92 | |
93 | /** | |
94 | * Sockets that were bypassed and we keep track for | |
95 | */ | |
96 | linked_list_t *sockets; | |
6f11e941 TB |
97 | }; |
98 | ||
99 | /** | |
100 | * Single instance of charonservice_t. | |
101 | */ | |
102 | charonservice_t *charonservice; | |
4a208143 TB |
103 | |
104 | /** | |
105 | * hook in library for debugging messages | |
106 | */ | |
cb887af4 | 107 | extern void (*dbg)(debug_t group, level_t level, char *fmt, ...); |
4a208143 TB |
108 | |
109 | /** | |
110 | * Logging hook for library logs, using android specific logging | |
111 | */ | |
112 | static void dbg_android(debug_t group, level_t level, char *fmt, ...) | |
113 | { | |
114 | va_list args; | |
115 | ||
d2007494 | 116 | if (level <= ANDROID_DEBUG_LEVEL) |
4a208143 TB |
117 | { |
118 | char sgroup[16], buffer[8192]; | |
119 | char *current = buffer, *next; | |
d2007494 | 120 | |
4a208143 TB |
121 | snprintf(sgroup, sizeof(sgroup), "%N", debug_names, group); |
122 | va_start(args, fmt); | |
123 | vsnprintf(buffer, sizeof(buffer), fmt, args); | |
124 | va_end(args); | |
125 | while (current) | |
126 | { /* log each line separately */ | |
127 | next = strchr(current, '\n'); | |
128 | if (next) | |
129 | { | |
130 | *(next++) = '\0'; | |
131 | } | |
132 | __android_log_print(ANDROID_LOG_INFO, "charon", "00[%s] %s\n", | |
133 | sgroup, current); | |
134 | current = next; | |
135 | } | |
136 | } | |
137 | } | |
138 | ||
8c2af60c TB |
139 | METHOD(charonservice_t, update_status, bool, |
140 | private_charonservice_t *this, android_vpn_state_t code) | |
141 | { | |
142 | JNIEnv *env; | |
143 | jmethodID method_id; | |
144 | bool success = FALSE; | |
145 | ||
146 | androidjni_attach_thread(&env); | |
147 | ||
148 | method_id = (*env)->GetMethodID(env, android_charonvpnservice_class, | |
149 | "updateStatus", "(I)V"); | |
150 | if (!method_id) | |
151 | { | |
152 | goto failed; | |
153 | } | |
154 | (*env)->CallVoidMethod(env, this->vpn_service, method_id, (jint)code); | |
155 | success = !androidjni_exception_occurred(env); | |
156 | ||
157 | failed: | |
158 | androidjni_exception_occurred(env); | |
159 | androidjni_detach_thread(); | |
160 | return success; | |
161 | } | |
162 | ||
dc52cfab TB |
163 | METHOD(charonservice_t, update_imc_state, bool, |
164 | private_charonservice_t *this, android_imc_state_t state) | |
165 | { | |
166 | JNIEnv *env; | |
167 | jmethodID method_id; | |
168 | bool success = FALSE; | |
169 | ||
170 | androidjni_attach_thread(&env); | |
171 | ||
172 | method_id = (*env)->GetMethodID(env, android_charonvpnservice_class, | |
173 | "updateImcState", "(I)V"); | |
174 | if (!method_id) | |
175 | { | |
176 | goto failed; | |
177 | } | |
178 | (*env)->CallVoidMethod(env, this->vpn_service, method_id, (jint)state); | |
179 | success = !androidjni_exception_occurred(env); | |
180 | ||
181 | failed: | |
182 | androidjni_exception_occurred(env); | |
183 | androidjni_detach_thread(); | |
184 | return success; | |
185 | } | |
186 | ||
a05acd76 TB |
187 | METHOD(charonservice_t, add_remediation_instr, bool, |
188 | private_charonservice_t *this, char *instr) | |
189 | { | |
190 | JNIEnv *env; | |
191 | jmethodID method_id; | |
192 | jstring jinstr; | |
193 | bool success = FALSE; | |
194 | ||
195 | androidjni_attach_thread(&env); | |
196 | ||
197 | method_id = (*env)->GetMethodID(env, android_charonvpnservice_class, | |
198 | "addRemediationInstruction", | |
199 | "(Ljava/lang/String;)V"); | |
200 | if (!method_id) | |
201 | { | |
202 | goto failed; | |
203 | } | |
204 | jinstr = (*env)->NewStringUTF(env, instr); | |
205 | if (!jinstr) | |
206 | { | |
207 | goto failed; | |
208 | } | |
209 | (*env)->CallVoidMethod(env, this->vpn_service, method_id, jinstr); | |
210 | success = !androidjni_exception_occurred(env); | |
211 | ||
212 | failed: | |
213 | androidjni_exception_occurred(env); | |
214 | androidjni_detach_thread(); | |
215 | return success; | |
216 | } | |
217 | ||
45885ca6 TB |
218 | /** |
219 | * Bypass a single socket | |
220 | */ | |
8a2e4d4a | 221 | static bool bypass_single_socket(private_charonservice_t *this, int fd) |
d4f76751 TB |
222 | { |
223 | JNIEnv *env; | |
224 | jmethodID method_id; | |
225 | ||
226 | androidjni_attach_thread(&env); | |
227 | ||
228 | method_id = (*env)->GetMethodID(env, android_charonvpnservice_class, | |
229 | "protect", "(I)Z"); | |
230 | if (!method_id) | |
231 | { | |
232 | goto failed; | |
233 | } | |
234 | if (!(*env)->CallBooleanMethod(env, this->vpn_service, method_id, fd)) | |
235 | { | |
45885ca6 | 236 | DBG2(DBG_KNL, "VpnService.protect() failed"); |
d4f76751 TB |
237 | goto failed; |
238 | } | |
239 | androidjni_detach_thread(); | |
240 | return TRUE; | |
241 | ||
242 | failed: | |
243 | androidjni_exception_occurred(env); | |
244 | androidjni_detach_thread(); | |
245 | return FALSE; | |
246 | } | |
247 | ||
8a2e4d4a TB |
248 | CALLBACK(bypass_single_socket_cb, void, |
249 | intptr_t fd, va_list args) | |
250 | { | |
251 | private_charonservice_t *this; | |
252 | ||
253 | VA_ARGS_VGET(args, this); | |
254 | bypass_single_socket(this, fd); | |
255 | } | |
256 | ||
45885ca6 TB |
257 | METHOD(charonservice_t, bypass_socket, bool, |
258 | private_charonservice_t *this, int fd, int family) | |
259 | { | |
260 | if (fd >= 0) | |
261 | { | |
262 | this->sockets->insert_last(this->sockets, (void*)(intptr_t)fd); | |
8a2e4d4a | 263 | return bypass_single_socket(this, fd); |
45885ca6 | 264 | } |
8a2e4d4a | 265 | this->sockets->invoke_function(this->sockets, bypass_single_socket_cb, this); |
45885ca6 TB |
266 | return TRUE; |
267 | } | |
268 | ||
3aba3386 TB |
269 | /** |
270 | * Converts the given Java array of byte arrays (byte[][]) to a linked list | |
271 | * of chunk_t objects. | |
272 | */ | |
273 | static linked_list_t *convert_array_of_byte_arrays(JNIEnv *env, | |
274 | jobjectArray jarray) | |
275 | { | |
276 | linked_list_t *list; | |
277 | jsize i; | |
278 | ||
279 | list = linked_list_create(); | |
280 | for (i = 0; i < (*env)->GetArrayLength(env, jarray); ++i) | |
281 | { | |
282 | chunk_t *chunk; | |
283 | jbyteArray jbytearray; | |
284 | ||
285 | chunk = malloc_thing(chunk_t); | |
286 | list->insert_last(list, chunk); | |
287 | ||
288 | jbytearray = (*env)->GetObjectArrayElement(env, jarray, i); | |
289 | *chunk = chunk_alloc((*env)->GetArrayLength(env, jbytearray)); | |
290 | (*env)->GetByteArrayRegion(env, jbytearray, 0, chunk->len, chunk->ptr); | |
291 | (*env)->DeleteLocalRef(env, jbytearray); | |
292 | } | |
293 | return list; | |
294 | } | |
295 | ||
2bec193a TB |
296 | METHOD(charonservice_t, get_trusted_certificates, linked_list_t*, |
297 | private_charonservice_t *this) | |
298 | { | |
299 | JNIEnv *env; | |
300 | jmethodID method_id; | |
301 | jobjectArray jcerts; | |
302 | linked_list_t *list; | |
2bec193a TB |
303 | |
304 | androidjni_attach_thread(&env); | |
305 | ||
306 | method_id = (*env)->GetMethodID(env, | |
307 | android_charonvpnservice_class, | |
9d994ba5 | 308 | "getTrustedCertificates", "()[[B"); |
2bec193a TB |
309 | if (!method_id) |
310 | { | |
311 | goto failed; | |
312 | } | |
9d994ba5 | 313 | jcerts = (*env)->CallObjectMethod(env, this->vpn_service, method_id); |
37d42a76 | 314 | if (!jcerts || androidjni_exception_occurred(env)) |
2bec193a TB |
315 | { |
316 | goto failed; | |
317 | } | |
3aba3386 TB |
318 | list = convert_array_of_byte_arrays(env, jcerts); |
319 | androidjni_detach_thread(); | |
320 | return list; | |
321 | ||
322 | failed: | |
323 | androidjni_exception_occurred(env); | |
324 | androidjni_detach_thread(); | |
325 | return NULL; | |
326 | } | |
327 | ||
328 | METHOD(charonservice_t, get_user_certificate, linked_list_t*, | |
329 | private_charonservice_t *this) | |
330 | { | |
331 | JNIEnv *env; | |
332 | jmethodID method_id; | |
333 | jobjectArray jencodings; | |
334 | linked_list_t *list; | |
2bec193a | 335 | |
3aba3386 | 336 | androidjni_attach_thread(&env); |
2bec193a | 337 | |
3aba3386 TB |
338 | method_id = (*env)->GetMethodID(env, |
339 | android_charonvpnservice_class, | |
340 | "getUserCertificate", "()[[B"); | |
341 | if (!method_id) | |
342 | { | |
343 | goto failed; | |
344 | } | |
406d680e | 345 | jencodings = (*env)->CallObjectMethod(env, this->vpn_service, method_id); |
37d42a76 | 346 | if (!jencodings || androidjni_exception_occurred(env)) |
3aba3386 TB |
347 | { |
348 | goto failed; | |
2bec193a | 349 | } |
3aba3386 | 350 | list = convert_array_of_byte_arrays(env, jencodings); |
2bec193a TB |
351 | androidjni_detach_thread(); |
352 | return list; | |
353 | ||
354 | failed: | |
355 | androidjni_exception_occurred(env); | |
356 | androidjni_detach_thread(); | |
357 | return NULL; | |
358 | } | |
359 | ||
406d680e TB |
360 | METHOD(charonservice_t, get_user_key, private_key_t*, |
361 | private_charonservice_t *this, public_key_t *pubkey) | |
362 | { | |
363 | JNIEnv *env; | |
364 | jmethodID method_id; | |
365 | private_key_t *key; | |
366 | jobject jkey; | |
367 | ||
368 | androidjni_attach_thread(&env); | |
369 | ||
370 | method_id = (*env)->GetMethodID(env, | |
371 | android_charonvpnservice_class, | |
372 | "getUserKey", "()Ljava/security/PrivateKey;"); | |
373 | if (!method_id) | |
374 | { | |
375 | goto failed; | |
376 | } | |
377 | jkey = (*env)->CallObjectMethod(env, this->vpn_service, method_id); | |
37d42a76 | 378 | if (!jkey || androidjni_exception_occurred(env)) |
406d680e TB |
379 | { |
380 | goto failed; | |
381 | } | |
382 | key = android_private_key_create(jkey, pubkey); | |
383 | androidjni_detach_thread(); | |
384 | return key; | |
385 | ||
386 | failed: | |
387 | DESTROY_IF(pubkey); | |
388 | androidjni_exception_occurred(env); | |
389 | androidjni_detach_thread(); | |
390 | return NULL; | |
391 | } | |
392 | ||
ae4f1ea1 TB |
393 | METHOD(charonservice_t, get_vpnservice_builder, vpnservice_builder_t*, |
394 | private_charonservice_t *this) | |
395 | { | |
396 | return this->builder; | |
397 | } | |
398 | ||
38bbca58 TB |
399 | METHOD(charonservice_t, get_network_manager, network_manager_t*, |
400 | private_charonservice_t *this) | |
401 | { | |
402 | return this->network_manager; | |
403 | } | |
404 | ||
c6c39c78 TB |
405 | /** |
406 | * Initiate a new connection | |
407 | * | |
79af70c6 | 408 | * @param settings configuration settings (gets owned) |
c6c39c78 | 409 | */ |
79af70c6 | 410 | static void initiate(settings_t *settings) |
c6c39c78 TB |
411 | { |
412 | private_charonservice_t *this = (private_charonservice_t*)charonservice; | |
413 | ||
6830cb1c TB |
414 | lib->settings->set_str(lib->settings, |
415 | "charon.plugins.tnc-imc.preferred_language", | |
416 | settings->get_str(settings, "global.language", "en")); | |
a7060581 TB |
417 | lib->settings->set_bool(lib->settings, |
418 | "charon.plugins.revocation.enable_crl", | |
419 | settings->get_bool(settings, "global.crl", TRUE)); | |
420 | lib->settings->set_bool(lib->settings, | |
421 | "charon.plugins.revocation.enable_ocsp", | |
422 | settings->get_bool(settings, "global.ocsp", TRUE)); | |
205ec47d TB |
423 | lib->settings->set_bool(lib->settings, |
424 | "charon.rsa_pss", | |
425 | settings->get_bool(settings, "global.rsa_pss", FALSE)); | |
4d02c49e TB |
426 | /* this is actually the size of the complete IKE/IP packet, so if the MTU |
427 | * for the TUN devices has to be reduced to pass traffic the IKE packets | |
428 | * will be a bit smaller than necessary as there is no IPsec overhead like | |
429 | * for the tunneled traffic (but compensating that seems like overkill) */ | |
430 | lib->settings->set_int(lib->settings, | |
431 | "charon.fragment_size", | |
432 | settings->get_int(settings, "global.mtu", | |
433 | ANDROID_DEFAULT_MTU)); | |
db599d6b TB |
434 | /* use configured interval, or an increased default to save battery power */ |
435 | lib->settings->set_int(lib->settings, | |
436 | "charon.keep_alive", | |
437 | settings->get_int(settings, "global.nat_keepalive", | |
438 | ANDROID_KEEPALIVE_INTERVAL)); | |
664389eb TB |
439 | /* send DPDs if above interval is exceeded, use a static value for now */ |
440 | lib->settings->set_int(lib->settings, | |
441 | "charon.keep_alive_dpd_margin", | |
442 | ANDROID_KEEPALIVE_DPD_MARGIN); | |
6830cb1c | 443 | |
a7060581 TB |
444 | /* reload plugins after changing settings */ |
445 | lib->plugins->reload(lib->plugins, NULL); | |
446 | ||
c6c39c78 | 447 | this->creds->clear(this->creds); |
c6c39c78 | 448 | DESTROY_IF(this->service); |
79af70c6 | 449 | this->service = android_service_create(this->creds, settings); |
c6c39c78 TB |
450 | } |
451 | ||
8430e54d TB |
452 | /** |
453 | * Initialize/deinitialize Android backend | |
454 | */ | |
96658d72 | 455 | static bool charonservice_register(plugin_t *plugin, plugin_feature_t *feature, |
8430e54d TB |
456 | bool reg, void *data) |
457 | { | |
458 | private_charonservice_t *this = (private_charonservice_t*)charonservice; | |
459 | if (reg) | |
460 | { | |
461 | lib->credmgr->add_set(lib->credmgr, &this->creds->set); | |
75136327 MW |
462 | charon->attributes->add_handler(charon->attributes, |
463 | &this->attr->handler); | |
8430e54d TB |
464 | } |
465 | else | |
466 | { | |
467 | lib->credmgr->remove_set(lib->credmgr, &this->creds->set); | |
75136327 MW |
468 | charon->attributes->remove_handler(charon->attributes, |
469 | &this->attr->handler); | |
c6c39c78 TB |
470 | if (this->service) |
471 | { | |
472 | this->service->destroy(this->service); | |
473 | this->service = NULL; | |
474 | } | |
8430e54d TB |
475 | } |
476 | return TRUE; | |
477 | } | |
478 | ||
67332b4e TB |
479 | /** |
480 | * Set strongswan.conf options | |
481 | */ | |
482 | static void set_options(char *logfile) | |
483 | { | |
484 | lib->settings->set_int(lib->settings, | |
485 | "charon.plugins.android_log.loglevel", ANDROID_DEBUG_LEVEL); | |
486 | /* setup file logger */ | |
487 | lib->settings->set_str(lib->settings, | |
948c42ab TB |
488 | "charon.filelog.android.path", logfile); |
489 | lib->settings->set_str(lib->settings, | |
490 | "charon.filelog.android.time_format", "%b %e %T"); | |
67332b4e | 491 | lib->settings->set_bool(lib->settings, |
948c42ab | 492 | "charon.filelog.android.append", TRUE); |
67332b4e | 493 | lib->settings->set_bool(lib->settings, |
948c42ab | 494 | "charon.filelog.android.flush_line", TRUE); |
67332b4e | 495 | lib->settings->set_int(lib->settings, |
948c42ab | 496 | "charon.filelog.android.default", ANDROID_DEBUG_LEVEL); |
67332b4e TB |
497 | |
498 | lib->settings->set_int(lib->settings, | |
499 | "charon.retransmit_tries", ANDROID_RETRASNMIT_TRIES); | |
500 | lib->settings->set_double(lib->settings, | |
501 | "charon.retransmit_timeout", ANDROID_RETRANSMIT_TIMEOUT); | |
502 | lib->settings->set_double(lib->settings, | |
503 | "charon.retransmit_base", ANDROID_RETRANSMIT_BASE); | |
9d957bac TB |
504 | lib->settings->set_bool(lib->settings, |
505 | "charon.initiator_only", TRUE); | |
67332b4e TB |
506 | lib->settings->set_bool(lib->settings, |
507 | "charon.close_ike_on_child_failure", TRUE); | |
070cd12d TB |
508 | lib->settings->set_bool(lib->settings, |
509 | "charon.check_current_path", TRUE); | |
67332b4e TB |
510 | /* setting the source address breaks the VpnService.protect() function which |
511 | * uses SO_BINDTODEVICE internally. the addresses provided to the kernel as | |
512 | * auxiliary data have precedence over this option causing a routing loop if | |
513 | * the gateway is contained in the VPN routes. alternatively, providing an | |
514 | * explicit device (in addition or instead of the source address) in the | |
515 | * auxiliary data would also work, but we currently don't have that | |
516 | * information */ | |
517 | lib->settings->set_bool(lib->settings, | |
518 | "charon.plugins.socket-default.set_source", FALSE); | |
0015727e TB |
519 | /* the Linux kernel does currently not support UDP encaspulation for IPv6 |
520 | * so lets disable IPv6 for now to avoid issues with dual-stack gateways */ | |
521 | lib->settings->set_bool(lib->settings, | |
522 | "charon.plugins.socket-default.use_ipv6", FALSE); | |
96658d72 TB |
523 | |
524 | #ifdef USE_BYOD | |
525 | lib->settings->set_str(lib->settings, | |
526 | "charon.plugins.eap-tnc.protocol", "tnccs-2.0"); | |
65ee857a TB |
527 | lib->settings->set_int(lib->settings, |
528 | "charon.plugins.eap-ttls.max_message_count", 0); | |
96658d72 TB |
529 | lib->settings->set_bool(lib->settings, |
530 | "android.imc.send_os_info", TRUE); | |
753035f6 TB |
531 | lib->settings->set_str(lib->settings, |
532 | "libtnccs.tnc_config", ""); | |
96658d72 | 533 | #endif |
67332b4e TB |
534 | } |
535 | ||
6f11e941 TB |
536 | /** |
537 | * Initialize the charonservice object | |
538 | */ | |
2ecda342 | 539 | static void charonservice_init(JNIEnv *env, jobject service, jobject builder, |
3fe9a436 | 540 | char *appdir, jboolean byod) |
6f11e941 TB |
541 | { |
542 | private_charonservice_t *this; | |
24447cf4 | 543 | static plugin_feature_t features[] = { |
17508851 TB |
544 | PLUGIN_CALLBACK(kernel_ipsec_register, kernel_android_ipsec_create), |
545 | PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"), | |
10823724 TB |
546 | PLUGIN_CALLBACK(kernel_net_register, kernel_android_net_create), |
547 | PLUGIN_PROVIDE(CUSTOM, "kernel-net"), | |
96658d72 TB |
548 | PLUGIN_CALLBACK(charonservice_register, NULL), |
549 | PLUGIN_PROVIDE(CUSTOM, "android-backend"), | |
8430e54d | 550 | PLUGIN_DEPENDS(CUSTOM, "libcharon"), |
0bebbae9 | 551 | PLUGIN_DEPENDS(CERT_DECODE, CERT_X509_CRL), |
7b417757 TB |
552 | PLUGIN_REGISTER(FETCHER, android_fetcher_create), |
553 | PLUGIN_PROVIDE(FETCHER, "http://"), | |
554 | PLUGIN_PROVIDE(FETCHER, "https://"), | |
24447cf4 | 555 | }; |
6f11e941 TB |
556 | |
557 | INIT(this, | |
558 | .public = { | |
8c2af60c | 559 | .update_status = _update_status, |
dc52cfab | 560 | .update_imc_state = _update_imc_state, |
a05acd76 | 561 | .add_remediation_instr = _add_remediation_instr, |
d4f76751 | 562 | .bypass_socket = _bypass_socket, |
2bec193a | 563 | .get_trusted_certificates = _get_trusted_certificates, |
3aba3386 | 564 | .get_user_certificate = _get_user_certificate, |
406d680e | 565 | .get_user_key = _get_user_key, |
ae4f1ea1 | 566 | .get_vpnservice_builder = _get_vpnservice_builder, |
38bbca58 | 567 | .get_network_manager = _get_network_manager, |
6f11e941 | 568 | }, |
3a05756b | 569 | .attr = android_attr_create(), |
0bebbae9 | 570 | .creds = android_creds_create(appdir), |
ae4f1ea1 | 571 | .builder = vpnservice_builder_create(builder), |
ef3d1a1b | 572 | .network_manager = network_manager_create(service), |
45885ca6 | 573 | .sockets = linked_list_create(), |
529c8c88 | 574 | .vpn_service = (*env)->NewGlobalRef(env, service), |
6f11e941 TB |
575 | ); |
576 | charonservice = &this->public; | |
d2007494 | 577 | |
24447cf4 | 578 | lib->plugins->add_static_features(lib->plugins, "androidbridge", features, |
5421092b | 579 | countof(features), TRUE, NULL, NULL); |
96658d72 TB |
580 | |
581 | #ifdef USE_BYOD | |
2ecda342 | 582 | if (byod) |
aa4ff3b2 TB |
583 | { |
584 | plugin_feature_t byod_features[] = { | |
585 | PLUGIN_CALLBACK(imc_android_register, this->vpn_service), | |
586 | PLUGIN_PROVIDE(CUSTOM, "android-imc"), | |
587 | PLUGIN_DEPENDS(CUSTOM, "android-backend"), | |
588 | PLUGIN_DEPENDS(CUSTOM, "imc-manager"), | |
589 | }; | |
590 | ||
591 | lib->plugins->add_static_features(lib->plugins, "android-byod", | |
5421092b | 592 | byod_features, countof(byod_features), TRUE, NULL, NULL); |
aa4ff3b2 | 593 | } |
96658d72 | 594 | #endif |
6f11e941 TB |
595 | } |
596 | ||
597 | /** | |
598 | * Deinitialize the charonservice object | |
599 | */ | |
529c8c88 | 600 | static void charonservice_deinit(JNIEnv *env) |
6f11e941 TB |
601 | { |
602 | private_charonservice_t *this = (private_charonservice_t*)charonservice; | |
603 | ||
38bbca58 | 604 | this->network_manager->destroy(this->network_manager); |
45885ca6 | 605 | this->sockets->destroy(this->sockets); |
ae4f1ea1 | 606 | this->builder->destroy(this->builder); |
8430e54d | 607 | this->creds->destroy(this->creds); |
3a05756b | 608 | this->attr->destroy(this->attr); |
529c8c88 | 609 | (*env)->DeleteGlobalRef(env, this->vpn_service); |
6f11e941 TB |
610 | free(this); |
611 | charonservice = NULL; | |
612 | } | |
613 | ||
a3048743 TB |
614 | /** |
615 | * Handle SIGSEGV/SIGILL signals raised by threads | |
616 | */ | |
617 | static void segv_handler(int signal) | |
618 | { | |
619 | dbg_android(DBG_DMN, 1, "thread %u received %d", thread_current_id(), | |
620 | signal); | |
621 | exit(1); | |
622 | } | |
623 | ||
f3695d08 TB |
624 | /** |
625 | * Register this logger as default before we have the bus available | |
626 | */ | |
627 | static void __attribute__ ((constructor))register_logger() | |
628 | { | |
629 | dbg = dbg_android; | |
630 | } | |
631 | ||
4a208143 TB |
632 | /** |
633 | * Initialize charon and the libraries via JNI | |
634 | */ | |
c3ee829e | 635 | JNI_METHOD(CharonVpnService, initializeCharon, jboolean, |
3fe9a436 | 636 | jobject builder, jstring jlogfile, jstring jappdir, jboolean byod) |
4a208143 | 637 | { |
a3048743 | 638 | struct sigaction action; |
6db742e7 | 639 | struct utsname utsname; |
3fe9a436 | 640 | char *logfile, *appdir, *plugins; |
a3048743 | 641 | |
4a208143 | 642 | /* initialize library */ |
34d3bfcf | 643 | if (!library_init(NULL, "charon")) |
4a208143 TB |
644 | { |
645 | library_deinit(); | |
c3ee829e | 646 | return FALSE; |
4a208143 TB |
647 | } |
648 | ||
d67a5b0c TB |
649 | if (android_sdk_version >= ANDROID_MARSHMALLOW) |
650 | { | |
651 | /* use a custom scheduler so the app is woken when jobs have to run */ | |
652 | lib->scheduler = android_scheduler_create(this, lib->scheduler); | |
653 | } | |
654 | ||
67332b4e TB |
655 | /* set options before initializing other libraries that might read them */ |
656 | logfile = androidjni_convert_jstring(env, jlogfile); | |
19c95c9b | 657 | |
67332b4e TB |
658 | set_options(logfile); |
659 | free(logfile); | |
660 | ||
06ed785e TB |
661 | if (!libipsec_init()) |
662 | { | |
663 | libipsec_deinit(); | |
06ed785e | 664 | library_deinit(); |
c3ee829e | 665 | return FALSE; |
06ed785e TB |
666 | } |
667 | ||
1c306c0e | 668 | if (!libcharon_init()) |
6db742e7 TB |
669 | { |
670 | libcharon_deinit(); | |
671 | libipsec_deinit(); | |
6db742e7 | 672 | library_deinit(); |
c3ee829e | 673 | return FALSE; |
6db742e7 TB |
674 | } |
675 | ||
9665686b | 676 | charon->load_loggers(charon); |
6f11e941 | 677 | |
3fe9a436 TB |
678 | appdir = androidjni_convert_jstring(env, jappdir); |
679 | charonservice_init(env, this, builder, appdir, byod); | |
680 | free(appdir); | |
67332b4e | 681 | |
6db742e7 TB |
682 | if (uname(&utsname) != 0) |
683 | { | |
684 | memset(&utsname, 0, sizeof(utsname)); | |
685 | } | |
19c95c9b TB |
686 | DBG1(DBG_DMN, "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"); |
687 | DBG1(DBG_DMN, "Starting IKE service (strongSwan "VERSION", %s, %s, " | |
c5ba3817 | 688 | "%s %s, %s)", android_version_string, android_device_string, |
6db742e7 TB |
689 | utsname.sysname, utsname.release, utsname.machine); |
690 | ||
2ecda342 TB |
691 | #ifdef PLUGINS_BYOD |
692 | if (byod) | |
693 | { | |
694 | plugins = PLUGINS " " PLUGINS_BYOD; | |
695 | } | |
696 | else | |
697 | #endif | |
698 | { | |
699 | plugins = PLUGINS; | |
700 | } | |
701 | ||
702 | if (!charon->initialize(charon, plugins)) | |
4a208143 TB |
703 | { |
704 | libcharon_deinit(); | |
529c8c88 | 705 | charonservice_deinit(env); |
06ed785e | 706 | libipsec_deinit(); |
4a208143 | 707 | library_deinit(); |
c3ee829e | 708 | return FALSE; |
4a208143 | 709 | } |
607f8e99 | 710 | lib->plugins->status(lib->plugins, LEVEL_CTRL); |
4a208143 | 711 | |
a3048743 TB |
712 | /* add handler for SEGV and ILL etc. */ |
713 | action.sa_handler = segv_handler; | |
714 | action.sa_flags = 0; | |
715 | sigemptyset(&action.sa_mask); | |
716 | sigaction(SIGSEGV, &action, NULL); | |
717 | sigaction(SIGILL, &action, NULL); | |
718 | sigaction(SIGBUS, &action, NULL); | |
719 | action.sa_handler = SIG_IGN; | |
720 | sigaction(SIGPIPE, &action, NULL); | |
721 | ||
4a208143 TB |
722 | /* start daemon (i.e. the threads in the thread-pool) */ |
723 | charon->start(charon); | |
c3ee829e | 724 | return TRUE; |
4a208143 TB |
725 | } |
726 | ||
727 | /** | |
6f11e941 | 728 | * Deinitialize charon and all libraries |
4a208143 TB |
729 | */ |
730 | JNI_METHOD(CharonVpnService, deinitializeCharon, void) | |
731 | { | |
6db742e7 | 732 | /* deinitialize charon before we destroy our own objects */ |
4a208143 | 733 | libcharon_deinit(); |
529c8c88 | 734 | charonservice_deinit(env); |
06ed785e | 735 | libipsec_deinit(); |
4a208143 TB |
736 | library_deinit(); |
737 | } | |
738 | ||
c6c39c78 TB |
739 | /** |
740 | * Initiate SA | |
741 | */ | |
742 | JNI_METHOD(CharonVpnService, initiate, void, | |
79af70c6 | 743 | jstring jconfig) |
c6c39c78 | 744 | { |
79af70c6 TB |
745 | settings_t *settings; |
746 | char *config; | |
c6c39c78 | 747 | |
79af70c6 TB |
748 | config = androidjni_convert_jstring(env, jconfig); |
749 | settings = settings_create_string(config); | |
8b6c2334 TB |
750 | free(config); |
751 | ||
79af70c6 | 752 | initiate(settings); |
c6c39c78 | 753 | } |
836a9438 TB |
754 | |
755 | /** | |
756 | * Utility function to verify proposal strings (static, so `this` is the class) | |
757 | */ | |
758 | JNI_METHOD_P(org_strongswan_android_utils, Utils, isProposalValid, jboolean, | |
759 | jboolean ike, jstring proposal) | |
760 | { | |
761 | proposal_t *prop; | |
762 | char *str; | |
763 | bool valid; | |
764 | ||
836a9438 TB |
765 | if (!library_init(NULL, "charon")) |
766 | { | |
767 | library_deinit(); | |
768 | return FALSE; | |
769 | } | |
770 | str = androidjni_convert_jstring(env, proposal); | |
771 | prop = proposal_create_from_string(ike ? PROTO_IKE : PROTO_ESP, str); | |
772 | valid = prop != NULL; | |
773 | DESTROY_IF(prop); | |
774 | free(str); | |
775 | library_deinit(); | |
776 | return valid; | |
777 | } | |
7028e9d3 TB |
778 | |
779 | /** | |
780 | * Utility function to parse an IP address from a string (static, so `this` is the class) | |
781 | */ | |
782 | JNI_METHOD_P(org_strongswan_android_utils, Utils, parseInetAddressBytes, jbyteArray, | |
783 | jstring address) | |
784 | { | |
785 | jbyteArray bytes; | |
786 | host_t *host; | |
787 | char *str; | |
788 | ||
7028e9d3 TB |
789 | if (!library_init(NULL, "charon")) |
790 | { | |
791 | library_deinit(); | |
792 | return NULL; | |
793 | } | |
794 | str = androidjni_convert_jstring(env, address); | |
795 | host = host_create_from_string(str, 0); | |
796 | if (!host) | |
797 | { | |
798 | free(str); | |
799 | return NULL; | |
800 | } | |
801 | bytes = byte_array_from_chunk(env, host->get_address(host)); | |
802 | host->destroy(host); | |
803 | free(str); | |
804 | library_deinit(); | |
805 | return bytes; | |
806 | } |