aboutsummaryrefslogtreecommitdiffstats
path: root/src/frontends/android/jni/libandroidbridge/backend
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2012-08-13 12:07:52 +0200
committerTobias Brunner <tobias@strongswan.org>2012-08-13 12:07:52 +0200
commit09ae3d79ca0f1143736a0de45678915a3ebe5a3f (patch)
treed304e8e618450d0e4867dfc72e14ed575a442c20 /src/frontends/android/jni/libandroidbridge/backend
parente4ef4c9877d5ccb773ace0edf655351428c39572 (diff)
parentefbb5e8c57330ec730825aa31ac5153f1d1c5913 (diff)
downloadstrongswan-09ae3d79ca0f1143736a0de45678915a3ebe5a3f.tar.bz2
strongswan-09ae3d79ca0f1143736a0de45678915a3ebe5a3f.tar.xz
Merge branch 'android-app'
This branch introduces a userland IPsec implementation (libipsec) and an Android App which targets the VpnService API that is provided by Android 4+. The implementation is based on the bachelor thesis 'Userland IPsec for Android 4' by Giuliano Grassi and Ralf Sager.
Diffstat (limited to 'src/frontends/android/jni/libandroidbridge/backend')
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_attr.c120
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_attr.h52
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_creds.c176
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_creds.h67
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_service.c533
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_service.h61
6 files changed, 1009 insertions, 0 deletions
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_attr.c b/src/frontends/android/jni/libandroidbridge/backend/android_attr.c
new file mode 100644
index 000000000..e8c506950
--- /dev/null
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_attr.c
@@ -0,0 +1,120 @@
+/*
+ * 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 "android_attr.h"
+#include "../charonservice.h"
+
+#include <hydra.h>
+#include <debug.h>
+#include <library.h>
+
+typedef struct private_android_attr_t private_android_attr_t;
+
+/**
+ * Private data of an android_attr_t object.
+ */
+struct private_android_attr_t {
+
+ /**
+ * Public interface.
+ */
+ android_attr_t public;
+};
+
+METHOD(attribute_handler_t, handle, bool,
+ private_android_attr_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ vpnservice_builder_t *builder;
+ host_t *dns;
+
+ switch (type)
+ {
+ case INTERNAL_IP4_DNS:
+ dns = host_create_from_chunk(AF_INET, data, 0);
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!dns || dns->is_anyaddr(dns))
+ {
+ DESTROY_IF(dns);
+ return FALSE;
+ }
+
+ builder = charonservice->get_vpnservice_builder(charonservice);
+ builder->add_dns(builder, dns);
+ dns->destroy(dns);
+ return TRUE;
+}
+
+METHOD(attribute_handler_t, release, void,
+ private_android_attr_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ /* DNS servers cannot be removed from an existing TUN device */
+}
+
+METHOD(enumerator_t, enumerate_dns, bool,
+ enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data)
+{
+ *type = INTERNAL_IP4_DNS;
+ *data = chunk_empty;
+ this->enumerate = (void*)return_false;
+ return TRUE;
+}
+
+METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
+ private_android_attr_t *this, identification_t *server, host_t *vip)
+{
+ enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .enumerate = (void*)_enumerate_dns,
+ .destroy = (void*)free,
+ );
+ return enumerator;
+}
+
+METHOD(android_attr_t, destroy, void,
+ private_android_attr_t *this)
+{
+ free(this);
+}
+
+/**
+ * Described in header
+ */
+android_attr_t *android_attr_create()
+{
+ private_android_attr_t *this;
+
+ INIT(this,
+ .public = {
+ .handler = {
+ .handle = _handle,
+ .release = _release,
+ .create_attribute_enumerator = _create_attribute_enumerator,
+ },
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->public;
+}
+
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_attr.h b/src/frontends/android/jni/libandroidbridge/backend/android_attr.h
new file mode 100644
index 000000000..56b02e1ce
--- /dev/null
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_attr.h
@@ -0,0 +1,52 @@
+/*
+ * 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 android_attr android_attr
+ * @{ @ingroup android_backend
+ */
+
+#ifndef ANDROID_ATTR_H_
+#define ANDROID_ATTR_H_
+
+#include <library.h>
+#include <attributes/attribute_handler.h>
+
+typedef struct android_attr_t android_attr_t;
+
+/**
+ * Handler for DNS configuration
+ */
+struct android_attr_t {
+
+ /**
+ * implements the attribute_handler_t interface
+ */
+ attribute_handler_t handler;
+
+ /**
+ * Destroy a android_attr_t
+ */
+ void (*destroy)(android_attr_t *this);
+};
+
+/**
+ * Create a android_attr_t instance.
+ */
+android_attr_t *android_attr_create(void);
+
+#endif /** ANDROID_ATTR_H_ @}*/
+
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_creds.c b/src/frontends/android/jni/libandroidbridge/backend/android_creds.c
new file mode 100644
index 000000000..27023d721
--- /dev/null
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_creds.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * 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 "android_creds.h"
+#include "../charonservice.h"
+
+#include <daemon.h>
+#include <library.h>
+#include <credentials/sets/mem_cred.h>
+#include <threading/rwlock.h>
+
+typedef struct private_android_creds_t private_android_creds_t;
+
+/**
+ * Private data of an android_creds_t object
+ */
+struct private_android_creds_t {
+
+ /**
+ * Public interface
+ */
+ android_creds_t public;
+
+ /**
+ * Credential set storing trusted certificates and user credentials
+ */
+ mem_cred_t *creds;
+
+ /**
+ * read/write lock to make sure certificates are only loaded once
+ */
+ rwlock_t *lock;
+
+ /**
+ * TRUE if certificates have been loaded via JNI
+ */
+ bool loaded;
+};
+
+/**
+ * Load trusted certificates via charonservice (JNI).
+ */
+static void load_trusted_certificates(private_android_creds_t *this)
+{
+ linked_list_t *certs;
+ certificate_t *cert;
+ chunk_t *current;
+
+ certs = charonservice->get_trusted_certificates(charonservice);
+ if (certs)
+ {
+ while (certs->remove_first(certs, (void**)&current) == SUCCESS)
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_BLOB_ASN1_DER, *current, BUILD_END);
+ if (cert)
+ {
+ DBG2(DBG_CFG, "loaded CA certificate '%Y'",
+ cert->get_subject(cert));
+ this->creds->add_cert(this->creds, TRUE, cert);
+ }
+ chunk_free(current);
+ free(current);
+ }
+ certs->destroy(certs);
+ }
+}
+
+METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
+ private_android_creds_t *this, certificate_type_t cert, key_type_t key,
+ identification_t *id, bool trusted)
+{
+ enumerator_t *enumerator;
+
+ if (!trusted || (cert != CERT_ANY && cert != CERT_X509))
+ {
+ return NULL;
+ }
+ this->lock->read_lock(this->lock);
+ if (!this->loaded)
+ {
+ this->lock->unlock(this->lock);
+ this->lock->write_lock(this->lock);
+ /* check again after acquiring the write lock */
+ if (!this->loaded)
+ {
+ load_trusted_certificates(this);
+ this->loaded = TRUE;
+ }
+ this->lock->unlock(this->lock);
+ this->lock->read_lock(this->lock);
+ }
+ enumerator = this->creds->set.create_cert_enumerator(&this->creds->set,
+ cert, key, id, trusted);
+ return enumerator_create_cleaner(enumerator, (void*)this->lock->unlock,
+ this->lock);
+}
+
+METHOD(android_creds_t, add_username_password, void,
+ private_android_creds_t *this, char *username, char *password)
+{
+ shared_key_t *shared_key;
+ identification_t *id;
+ chunk_t secret;
+
+ secret = chunk_create(password, strlen(password));
+ shared_key = shared_key_create(SHARED_EAP, chunk_clone(secret));
+ id = identification_create_from_string(username);
+
+ this->creds->add_shared(this->creds, shared_key, id, NULL);
+}
+
+METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
+ private_android_creds_t *this, shared_key_type_t type,
+ identification_t *me, identification_t *other)
+{
+ return this->creds->set.create_shared_enumerator(&this->creds->set,
+ type, me, other);
+}
+
+METHOD(android_creds_t, clear, void,
+ private_android_creds_t *this)
+{
+ this->lock->write_lock(this->lock);
+ this->creds->clear(this->creds);
+ this->loaded = FALSE;
+ this->lock->unlock(this->lock);
+}
+
+METHOD(android_creds_t, destroy, void,
+ private_android_creds_t *this)
+{
+ clear(this);
+ this->creds->destroy(this->creds);
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+android_creds_t *android_creds_create()
+{
+ private_android_creds_t *this;
+
+ INIT(this,
+ .public = {
+ .set = {
+ .create_cert_enumerator = _create_cert_enumerator,
+ .create_shared_enumerator = _create_shared_enumerator,
+ .create_private_enumerator = (void*)return_null,
+ .create_cdp_enumerator = (void*)return_null,
+ .cache_cert = (void*)nop,
+ },
+ .add_username_password = _add_username_password,
+ .clear = _clear,
+ .destroy = _destroy,
+ },
+ .creds = mem_cred_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_creds.h b/src/frontends/android/jni/libandroidbridge/backend/android_creds.h
new file mode 100644
index 000000000..33de838c1
--- /dev/null
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_creds.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * 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 android_creds android_creds
+ * @{ @ingroup android_backend
+ */
+
+#ifndef ANDROID_CREDS_H_
+#define ANDROID_CREDS_H_
+
+#include <library.h>
+#include <credentials/credential_set.h>
+
+typedef struct android_creds_t android_creds_t;
+
+/**
+ * Android credential set that provides CA certificates via JNI and supplied
+ * user credentials.
+ */
+struct android_creds_t {
+
+ /**
+ * Implements credential_set_t
+ */
+ credential_set_t set;
+
+ /**
+ * Add user name and password for EAP authentication
+ *
+ * @param username user name
+ * @param password password
+ */
+ void (*add_username_password)(android_creds_t *this, char *username,
+ char *password);
+
+ /**
+ * Clear the cached certificates and stored credentials.
+ */
+ void (*clear)(android_creds_t *this);
+
+ /**
+ * Destroy a android_creds instance.
+ */
+ void (*destroy)(android_creds_t *this);
+
+};
+
+/**
+ * Create an android_creds instance.
+ */
+android_creds_t *android_creds_create();
+
+#endif /** ANDROID_CREDS_H_ @}*/
+
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c
new file mode 100644
index 000000000..dfc0d2342
--- /dev/null
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2010-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 <errno.h>
+#include <unistd.h>
+
+#include "android_service.h"
+#include "../charonservice.h"
+#include "../vpnservice_builder.h"
+
+#include <daemon.h>
+#include <library.h>
+#include <ipsec.h>
+#include <processing/jobs/callback_job.h>
+#include <threading/rwlock.h>
+#include <threading/thread.h>
+
+typedef struct private_android_service_t private_android_service_t;
+
+#define TUN_DEFAULT_MTU 1400
+
+/**
+ * private data of Android service
+ */
+struct private_android_service_t {
+
+ /**
+ * public interface
+ */
+ android_service_t public;
+
+ /**
+ * current IKE_SA
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * local ipv4 address
+ */
+ char *local_address;
+
+ /**
+ * gateway
+ */
+ char *gateway;
+
+ /**
+ * username
+ */
+ char *username;
+
+ /**
+ * lock to safely access the TUN device fd
+ */
+ rwlock_t *lock;
+
+ /**
+ * TUN device file descriptor
+ */
+ int tunfd;
+
+};
+
+/**
+ * Outbound callback
+ */
+static void send_esp(void *data, esp_packet_t *packet)
+{
+ charon->sender->send_no_marker(charon->sender, (packet_t*)packet);
+}
+
+/**
+ * Inbound callback
+ */
+static void deliver_plain(private_android_service_t *this,
+ ip_packet_t *packet)
+{
+ chunk_t encoding;
+ ssize_t len;
+
+ encoding = packet->get_encoding(packet);
+
+ this->lock->read_lock(this->lock);
+ if (this->tunfd < 0)
+ { /* the TUN device is already closed */
+ this->lock->unlock(this->lock);
+ packet->destroy(packet);
+ return;
+ }
+ len = write(this->tunfd, encoding.ptr, encoding.len);
+ this->lock->unlock(this->lock);
+
+ if (len < 0 || len != encoding.len)
+ {
+ DBG1(DBG_DMN, "failed to write packet to TUN device: %s",
+ strerror(errno));
+ }
+ packet->destroy(packet);
+}
+
+/**
+ * Receiver callback
+ */
+static void receiver_esp_cb(void *data, packet_t *packet)
+{
+ esp_packet_t *esp_packet;
+
+ esp_packet = esp_packet_create_from_packet(packet);
+ ipsec->processor->queue_inbound(ipsec->processor, esp_packet);
+}
+
+/**
+ * Job handling outbound plaintext packets
+ */
+static job_requeue_t handle_plain(private_android_service_t *this)
+{
+ ip_packet_t *packet;
+ chunk_t raw;
+ fd_set set;
+ ssize_t len;
+ int tunfd;
+ bool old;
+
+ FD_ZERO(&set);
+
+ this->lock->read_lock(this->lock);
+ if (this->tunfd < 0)
+ { /* the TUN device is already closed */
+ this->lock->unlock(this->lock);
+ return JOB_REQUEUE_NONE;
+ }
+ tunfd = this->tunfd;
+ FD_SET(tunfd, &set);
+ this->lock->unlock(this->lock);
+
+ old = thread_cancelability(TRUE);
+ len = select(tunfd + 1, &set, NULL, NULL, NULL);
+ thread_cancelability(old);
+
+ if (len < 0)
+ {
+ DBG1(DBG_DMN, "select on TUN device failed: %s", strerror(errno));
+ return JOB_REQUEUE_NONE;
+ }
+
+ raw = chunk_alloc(TUN_DEFAULT_MTU);
+ len = read(tunfd, raw.ptr, raw.len);
+ if (len < 0)
+ {
+ DBG1(DBG_DMN, "reading from TUN device failed: %s", strerror(errno));
+ chunk_free(&raw);
+ return JOB_REQUEUE_FAIR;
+ }
+ raw.len = len;
+
+ packet = ip_packet_create(raw);
+ if (packet)
+ {
+ ipsec->processor->queue_outbound(ipsec->processor, packet);
+ }
+ else
+ {
+ DBG1(DBG_DMN, "invalid IP packet read from TUN device");
+ }
+ return JOB_REQUEUE_DIRECT;
+}
+
+/**
+ * Add a route to the TUN device builder
+ */
+static bool add_route(vpnservice_builder_t *builder, host_t *net,
+ u_int8_t prefix)
+{
+ /* if route is 0.0.0.0/0, split it into two routes 0.0.0.0/1 and
+ * 128.0.0.0/1 because otherwise it would conflict with the current default
+ * route */
+ if (net->is_anyaddr(net) && prefix == 0)
+ {
+ bool success;
+
+ success = add_route(builder, net, 1);
+ net = host_create_from_string("128.0.0.0", 0);
+ success = success && add_route(builder, net, 1);
+ net->destroy(net);
+ return success;
+ }
+ return builder->add_route(builder, net, prefix);
+}
+
+/**
+ * Generate and set routes from installed IPsec policies
+ */
+static bool add_routes(vpnservice_builder_t *builder, child_sa_t *child_sa)
+{
+ traffic_selector_t *src_ts, *dst_ts;
+ enumerator_t *enumerator;
+ bool success = TRUE;
+
+ enumerator = child_sa->create_policy_enumerator(child_sa);
+ while (success && enumerator->enumerate(enumerator, &src_ts, &dst_ts))
+ {
+ host_t *net;
+ u_int8_t prefix;
+
+ dst_ts->to_subnet(dst_ts, &net, &prefix);
+ success = add_route(builder, net, prefix);
+ net->destroy(net);
+ }
+ enumerator->destroy(enumerator);
+ return success;
+}
+
+/**
+ * Setup a new TUN device for the supplied SAs, also queues a job that
+ * reads packets from this device.
+ * Additional information such as DNS servers are gathered in appropriate
+ * listeners asynchronously. To be sure every required bit of information is
+ * available this should be called after the CHILD_SA has been established.
+ */
+static bool setup_tun_device(private_android_service_t *this,
+ ike_sa_t *ike_sa, child_sa_t *child_sa)
+{
+ vpnservice_builder_t *builder;
+ host_t *vip;
+ int tunfd;
+
+ DBG1(DBG_DMN, "setting up TUN device for CHILD_SA %s{%u}",
+ child_sa->get_name(child_sa), child_sa->get_reqid(child_sa));
+ vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
+ if (!vip || vip->is_anyaddr(vip))
+ {
+ DBG1(DBG_DMN, "setting up TUN device failed, no virtual IP found");
+ return FALSE;
+ }
+
+ builder = charonservice->get_vpnservice_builder(charonservice);
+ if (!builder->add_address(builder, vip) ||
+ !add_routes(builder, child_sa) ||
+ !builder->set_mtu(builder, TUN_DEFAULT_MTU))
+ {
+ return FALSE;
+ }
+
+ tunfd = builder->establish(builder);
+ if (tunfd == -1)
+ {
+ return FALSE;
+ }
+
+ this->lock->write_lock(this->lock);
+ this->tunfd = tunfd;
+ this->lock->unlock(this->lock);
+
+ DBG1(DBG_DMN, "successfully created TUN device");
+
+ charon->receiver->add_esp_cb(charon->receiver,
+ (receiver_esp_cb_t)receiver_esp_cb, NULL);
+ ipsec->processor->register_inbound(ipsec->processor,
+ (ipsec_inbound_cb_t)deliver_plain, this);
+ ipsec->processor->register_outbound(ipsec->processor,
+ (ipsec_outbound_cb_t)send_esp, NULL);
+
+ lib->processor->queue_job(lib->processor,
+ (job_t*)callback_job_create((callback_job_cb_t)handle_plain, this,
+ NULL, (callback_job_cancel_t)return_false));
+ return TRUE;
+}
+
+/**
+ * Close the current tun device
+ */
+static void close_tun_device(private_android_service_t *this)
+{
+ int tunfd;
+
+ this->lock->write_lock(this->lock);
+ if (this->tunfd < 0)
+ { /* already closed (or never created) */
+ this->lock->unlock(this->lock);
+ return;
+ }
+ tunfd = this->tunfd;
+ this->tunfd = -1;
+ this->lock->unlock(this->lock);
+
+ ipsec->processor->unregister_outbound(ipsec->processor,
+ (ipsec_outbound_cb_t)send_esp);
+ ipsec->processor->unregister_inbound(ipsec->processor,
+ (ipsec_inbound_cb_t)deliver_plain);
+ charon->receiver->del_esp_cb(charon->receiver,
+ (receiver_esp_cb_t)receiver_esp_cb);
+ close(tunfd);
+}
+
+METHOD(listener_t, child_updown, bool,
+ private_android_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+ bool up)
+{
+ if (this->ike_sa == ike_sa)
+ {
+ if (up)
+ {
+ /* disable the hooks registered to catch initiation failures */
+ this->public.listener.ike_updown = NULL;
+ this->public.listener.ike_state_change = NULL;
+ if (!setup_tun_device(this, ike_sa, child_sa))
+ {
+ DBG1(DBG_DMN, "failed to setup TUN device");
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_GENERIC_ERROR);
+ return FALSE;
+
+ }
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_CHILD_STATE_UP);
+ }
+ else
+ {
+ close_tun_device(this);
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_CHILD_STATE_DOWN);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, ike_updown, bool,
+ private_android_service_t *this, ike_sa_t *ike_sa, bool up)
+{
+ /* this callback is only registered during initiation, so if the IKE_SA
+ * goes down we assume an authentication error */
+ if (this->ike_sa == ike_sa && !up)
+ {
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_AUTH_ERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, ike_state_change, bool,
+ private_android_service_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
+{
+ /* this call back is only registered during initiation */
+ if (this->ike_sa == ike_sa && state == IKE_DESTROYING)
+ {
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_UNREACHABLE_ERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, alert, bool,
+ private_android_service_t *this, ike_sa_t *ike_sa, alert_t alert,
+ va_list args)
+{
+ if (this->ike_sa == ike_sa)
+ {
+ switch (alert)
+ {
+ case ALERT_PEER_ADDR_FAILED:
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_LOOKUP_ERROR);
+ break;
+ case ALERT_PEER_AUTH_FAILED:
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_PEER_AUTH_ERROR);
+ break;
+ default:
+ break;
+ }
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, ike_rekey, bool,
+ private_android_service_t *this, ike_sa_t *old, ike_sa_t *new)
+{
+ if (this->ike_sa == old)
+ {
+ this->ike_sa = new;
+ }
+ return TRUE;
+}
+
+static job_requeue_t initiate(private_android_service_t *this)
+{
+ identification_t *gateway, *user;
+ ike_cfg_t *ike_cfg;
+ peer_cfg_t *peer_cfg;
+ child_cfg_t *child_cfg;
+ traffic_selector_t *ts;
+ ike_sa_t *ike_sa;
+ auth_cfg_t *auth;
+ lifetime_cfg_t lifetime = {
+ .time = {
+ .life = 10800, /* 3h */
+ .rekey = 10200, /* 2h50min */
+ .jitter = 300 /* 5min */
+ }
+ };
+
+ ike_cfg = ike_cfg_create(TRUE, TRUE, this->local_address, FALSE,
+ charon->socket->get_port(charon->socket, FALSE),
+ this->gateway, FALSE, IKEV2_UDP_PORT);
+ ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
+
+ peer_cfg = peer_cfg_create("android", IKEV2, ike_cfg, CERT_SEND_IF_ASKED,
+ UNIQUE_REPLACE, 1, /* keyingtries */
+ 36000, 0, /* rekey 10h, reauth none */
+ 600, 600, /* jitter, over 10min */
+ TRUE, FALSE, /* mobike, aggressive */
+ 0, 0, /* DPD delay, timeout */
+ host_create_from_string("0.0.0.0", 0) /* virt */,
+ NULL, FALSE, NULL, NULL); /* pool, mediation */
+
+
+ auth = auth_cfg_create();
+ auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
+ user = identification_create_from_string(this->username);
+ auth->add(auth, AUTH_RULE_IDENTITY, user);
+ peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
+ auth = auth_cfg_create();
+ auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
+ gateway = identification_create_from_string(this->gateway);
+ auth->add(auth, AUTH_RULE_IDENTITY, gateway);
+ peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
+
+ child_cfg = child_cfg_create("android", &lifetime, NULL, TRUE, MODE_TUNNEL,
+ ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE,
+ 0, 0, NULL, NULL, 0);
+ child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
+ ts = traffic_selector_create_dynamic(0, 0, 65535);
+ child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
+ ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0",
+ 0, "255.255.255.255", 65535);
+ child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
+ peer_cfg->add_child_cfg(peer_cfg, child_cfg);
+
+ /* get us an IKE_SA */
+ ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
+ peer_cfg);
+ if (!ike_sa)
+ {
+ peer_cfg->destroy(peer_cfg);
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_GENERIC_ERROR);
+ return JOB_REQUEUE_NONE;
+ }
+ if (!ike_sa->get_peer_cfg(ike_sa))
+ {
+ ike_sa->set_peer_cfg(ike_sa, peer_cfg);
+ }
+ peer_cfg->destroy(peer_cfg);
+
+ /* store the IKE_SA so we can track its progress */
+ this->ike_sa = ike_sa;
+
+ /* get an additional reference because initiate consumes one */
+ child_cfg->get_ref(child_cfg);
+ if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
+ {
+ DBG1(DBG_CFG, "failed to initiate tunnel");
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ ike_sa);
+ return JOB_REQUEUE_NONE;
+ }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return JOB_REQUEUE_NONE;
+}
+
+METHOD(android_service_t, destroy, void,
+ private_android_service_t *this)
+{
+ charon->bus->remove_listener(charon->bus, &this->public.listener);
+ /* make sure the tun device is actually closed */
+ close_tun_device(this);
+ this->lock->destroy(this->lock);
+ free(this->local_address);
+ free(this->username);
+ free(this->gateway);
+ free(this);
+}
+
+/**
+ * See header
+ */
+android_service_t *android_service_create(char *local_address, char *gateway,
+ char *username)
+{
+ private_android_service_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .ike_rekey = _ike_rekey,
+ .ike_updown = _ike_updown,
+ .ike_state_change = _ike_state_change,
+ .child_updown = _child_updown,
+ .alert = _alert,
+ },
+ .destroy = _destroy,
+ },
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .local_address = local_address,
+ .username = username,
+ .gateway = gateway,
+ .tunfd = -1,
+ );
+
+ charon->bus->add_listener(charon->bus, &this->public.listener);
+
+ lib->processor->queue_job(lib->processor,
+ (job_t*)callback_job_create((callback_job_cb_t)initiate, this,
+ NULL, NULL));
+ return &this->public;
+}
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.h b/src/frontends/android/jni/libandroidbridge/backend/android_service.h
new file mode 100644
index 000000000..a7bd8b059
--- /dev/null
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010-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 android_service android_service
+ * @{ @ingroup android_backend
+ */
+
+#ifndef ANDROID_SERVICE_H_
+#define ANDROID_SERVICE_H_
+
+#include "android_creds.h"
+
+#include <library.h>
+#include <bus/listeners/listener.h>
+
+typedef struct android_service_t android_service_t;
+
+/**
+ * Service that sets up an IKE_SA/CHILD_SA and handles events
+ */
+struct android_service_t {
+
+ /**
+ * Implements listener_t.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a android_service_t.
+ */
+ void (*destroy)(android_service_t *this);
+
+};
+
+/**
+ * Create an Android service instance. Queues a job that starts initiation of a
+ * new IKE SA.
+ *
+ * @param local_address local ip address
+ * @param gateway gateway address
+ * @param username user name (local identity)
+ */
+android_service_t *android_service_create(char *local_address, char *gateway,
+ char *username);
+
+#endif /** ANDROID_SERVICE_H_ @}*/