aboutsummaryrefslogtreecommitdiffstats
path: root/src/frontends/android/jni/libandroidbridge/backend/android_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontends/android/jni/libandroidbridge/backend/android_service.c')
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_service.c134
1 files changed, 127 insertions, 7 deletions
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c
index d73dc4582..e60c491c1 100644
--- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2013 Tobias Brunner
+ * Copyright (C) 2010-2014 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil
@@ -19,6 +19,7 @@
#include <unistd.h>
#include "android_service.h"
+#include "android_dns_proxy.h"
#include "../charonservice.h"
#include "../vpnservice_builder.h"
@@ -83,6 +84,15 @@ struct private_android_service_t {
*/
int tunfd;
+ /**
+ * DNS proxy
+ */
+ android_dns_proxy_t *dns_proxy;
+
+ /**
+ * Whether to use the DNS proxy or not
+ */
+ bool use_dns_proxy;
};
/**
@@ -143,7 +153,7 @@ static job_requeue_t handle_plain(private_android_service_t *this)
fd_set set;
ssize_t len;
int tunfd;
- bool old;
+ bool old, dns_proxy;
timeval_t tv = {
/* check every second if tunfd is still valid */
.tv_sec = 1,
@@ -159,6 +169,8 @@ static job_requeue_t handle_plain(private_android_service_t *this)
}
tunfd = this->tunfd;
FD_SET(tunfd, &set);
+ /* cache this while we have the lock */
+ dns_proxy = this->use_dns_proxy;
this->lock->unlock(this->lock);
old = thread_cancelability(TRUE);
@@ -192,7 +204,10 @@ static job_requeue_t handle_plain(private_android_service_t *this)
packet = ip_packet_create(raw);
if (packet)
{
- ipsec->processor->queue_outbound(ipsec->processor, packet);
+ if (!dns_proxy || !this->dns_proxy->handle(this->dns_proxy, packet))
+ {
+ ipsec->processor->queue_outbound(ipsec->processor, packet);
+ }
}
else
{
@@ -324,6 +339,8 @@ static bool setup_tun_device(private_android_service_t *this,
(ipsec_inbound_cb_t)deliver_plain, this);
ipsec->processor->register_outbound(ipsec->processor,
(ipsec_outbound_cb_t)send_esp, NULL);
+ this->dns_proxy->register_cb(this->dns_proxy,
+ (dns_proxy_response_cb_t)deliver_plain, this);
lib->processor->queue_job(lib->processor,
(job_t*)callback_job_create((callback_job_cb_t)handle_plain, this,
@@ -333,6 +350,36 @@ static bool setup_tun_device(private_android_service_t *this,
}
/**
+ * Setup a new TUN device based on the existing one, but without DNS server.
+ */
+static bool setup_tun_device_without_dns(private_android_service_t *this)
+{
+ vpnservice_builder_t *builder;
+ int tunfd;
+
+ DBG1(DBG_DMN, "setting up TUN device without DNS");
+
+ builder = charonservice->get_vpnservice_builder(charonservice);
+
+ tunfd = builder->establish_no_dns(builder);
+ if (tunfd == -1)
+ {
+ return FALSE;
+ }
+
+ this->lock->write_lock(this->lock);
+ if (this->tunfd > 0)
+ { /* close previously opened TUN device, this should always be the case */
+ close(this->tunfd);
+ }
+ this->tunfd = tunfd;
+ this->lock->unlock(this->lock);
+
+ DBG1(DBG_DMN, "successfully created TUN device without DNS");
+ return TRUE;
+}
+
+/**
* Close the current tun device
*/
static void close_tun_device(private_android_service_t *this)
@@ -349,6 +396,8 @@ static void close_tun_device(private_android_service_t *this)
this->tunfd = -1;
this->lock->unlock(this->lock);
+ this->dns_proxy->unregister_cb(this->dns_proxy,
+ (dns_proxy_response_cb_t)deliver_plain);
ipsec->processor->unregister_outbound(ipsec->processor,
(ipsec_outbound_cb_t)send_esp);
ipsec->processor->unregister_inbound(ipsec->processor,
@@ -358,6 +407,17 @@ static void close_tun_device(private_android_service_t *this)
close(tunfd);
}
+/**
+ * Terminate the IKE_SA with the given unique ID
+ */
+CALLBACK(terminate, job_requeue_t,
+ u_int32_t *id)
+{
+ charon->controller->terminate_ike(charon->controller, *id,
+ controller_cb_empty, NULL, 0);
+ return JOB_REQUEUE_NONE;
+}
+
METHOD(listener_t, child_updown, bool,
private_android_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
bool up)
@@ -368,6 +428,11 @@ METHOD(listener_t, child_updown, bool,
{
/* disable the hooks registered to catch initiation failures */
this->public.listener.ike_updown = NULL;
+ /* CHILD_SA is up so we can disable the DNS proxy we enabled to
+ * reestablish the SA */
+ this->lock->write_lock(this->lock);
+ this->use_dns_proxy = FALSE;
+ this->lock->unlock(this->lock);
if (!setup_tun_device(this, ike_sa, child_sa))
{
DBG1(DBG_DMN, "failed to setup TUN device");
@@ -422,9 +487,37 @@ METHOD(listener_t, alert, bool,
case ALERT_PEER_INIT_UNREACHABLE:
this->lock->read_lock(this->lock);
if (this->tunfd < 0)
- { /* only handle this if we are not reestablishing the SA */
+ {
+ u_int32_t *id = malloc_thing(u_int32_t);
+
+ /* always fail if we are not able to initiate the IKE_SA
+ * initially */
charonservice->update_status(charonservice,
CHARONSERVICE_UNREACHABLE_ERROR);
+ /* terminate the IKE_SA so no further keying tries are
+ * attempted */
+ *id = ike_sa->get_unique_id(ike_sa);
+ lib->processor->queue_job(lib->processor,
+ (job_t*)callback_job_create_with_prio(
+ (callback_job_cb_t)terminate, id, free,
+ (callback_job_cancel_t)return_false, JOB_PRIO_HIGH));
+ }
+ else
+ {
+ peer_cfg_t *peer_cfg;
+ u_int32_t tries, try;
+
+ /* when reestablishing and if keyingtries is not %forever
+ * the IKE_SA is destroyed after the set number of tries,
+ * so notify the GUI */
+ peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+ tries = peer_cfg->get_keyingtries(peer_cfg);
+ try = va_arg(args, u_int32_t);
+ if (tries != 0 && try == tries-1)
+ {
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_UNREACHABLE_ERROR);
+ }
}
this->lock->unlock(this->lock);
break;
@@ -445,11 +538,34 @@ METHOD(listener_t, ike_rekey, bool,
return TRUE;
}
-METHOD(listener_t, ike_reestablish, bool,
+METHOD(listener_t, ike_reestablish_pre, bool,
private_android_service_t *this, ike_sa_t *old, ike_sa_t *new)
{
if (this->ike_sa == old)
{
+ /* enable DNS proxy so hosts are properly resolved while the TUN device
+ * is still active */
+ this->lock->write_lock(this->lock);
+ this->use_dns_proxy = TRUE;
+ this->lock->unlock(this->lock);
+ /* if DNS servers are installed that are only reachable through the VPN
+ * the DNS proxy doesn't help, so uninstall DNS servers */
+ if (!setup_tun_device_without_dns(this))
+ {
+ DBG1(DBG_DMN, "failed to setup TUN device without DNS");
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_GENERIC_ERROR);
+ }
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, ike_reestablish_post, bool,
+ private_android_service_t *this, ike_sa_t *old, ike_sa_t *new,
+ bool initiated)
+{
+ if (this->ike_sa == old && initiated)
+ {
this->ike_sa = new;
/* re-register hook to detect initiation failures */
this->public.listener.ike_updown = _ike_updown;
@@ -458,7 +574,6 @@ METHOD(listener_t, ike_reestablish, bool,
* get ignored and thus we trigger the event here */
charonservice->update_status(charonservice,
CHARONSERVICE_CHILD_STATE_DOWN);
- /* the TUN device will be closed when the new CHILD_SA is established */
}
return TRUE;
}
@@ -630,6 +745,7 @@ METHOD(android_service_t, destroy, void,
charon->bus->remove_listener(charon->bus, &this->public.listener);
/* make sure the tun device is actually closed */
close_tun_device(this);
+ this->dns_proxy->destroy(this->dns_proxy);
this->lock->destroy(this->lock);
free(this->type);
free(this->gateway);
@@ -655,7 +771,8 @@ android_service_t *android_service_create(android_creds_t *creds, char *type,
.public = {
.listener = {
.ike_rekey = _ike_rekey,
- .ike_reestablish = _ike_reestablish,
+ .ike_reestablish_pre = _ike_reestablish_pre,
+ .ike_reestablish_post = _ike_reestablish_post,
.ike_updown = _ike_updown,
.child_updown = _child_updown,
.alert = _alert,
@@ -663,6 +780,7 @@ android_service_t *android_service_create(android_creds_t *creds, char *type,
.destroy = _destroy,
},
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .dns_proxy = android_dns_proxy_create(),
.username = username,
.password = password,
.gateway = gateway,
@@ -670,6 +788,8 @@ android_service_t *android_service_create(android_creds_t *creds, char *type,
.type = type,
.tunfd = -1,
);
+ /* only allow queries for the VPN gateway */
+ this->dns_proxy->add_hostname(this->dns_proxy, gateway);
charon->bus->add_listener(charon->bus, &this->public.listener);