From 614359a7d5bedb5d750bac33fdd4b335dde451e5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Jul 2014 12:38:44 +0200 Subject: bus: Add ike_reestablish_pre hook, called before DNS resolution The old hook is renamed to ike_reestablish_post and is now also called when the initiation of the new IKE_SA failed. --- .../android/jni/libandroidbridge/backend/android_service.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/frontends/android/jni/libandroidbridge/backend/android_service.c') diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c index d73dc4582..a6a24dba9 100644 --- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c @@ -445,10 +445,11 @@ METHOD(listener_t, ike_rekey, bool, return TRUE; } -METHOD(listener_t, ike_reestablish, bool, - private_android_service_t *this, ike_sa_t *old, ike_sa_t *new) +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) + if (this->ike_sa == old && initiated) { this->ike_sa = new; /* re-register hook to detect initiation failures */ @@ -655,7 +656,7 @@ android_service_t *android_service_create(android_creds_t *creds, char *type, .public = { .listener = { .ike_rekey = _ike_rekey, - .ike_reestablish = _ike_reestablish, + .ike_reestablish_post = _ike_reestablish_post, .ike_updown = _ike_updown, .child_updown = _child_updown, .alert = _alert, -- cgit v1.2.3 From cc1712a8f4656f0e2417da44f3b27385e71ffa17 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Jul 2014 13:11:10 +0200 Subject: android: Use DNS proxy when reestablishing IKE_SAs --- .../jni/libandroidbridge/backend/android_service.c | 48 ++++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'src/frontends/android/jni/libandroidbridge/backend/android_service.c') diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c index a6a24dba9..113056532 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 #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, @@ -349,6 +366,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, @@ -368,6 +387,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"); @@ -445,6 +469,20 @@ METHOD(listener_t, ike_rekey, bool, return TRUE; } +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); + } + return TRUE; +} + METHOD(listener_t, ike_reestablish_post, bool, private_android_service_t *this, ike_sa_t *old, ike_sa_t *new, bool initiated) @@ -459,7 +497,6 @@ METHOD(listener_t, ike_reestablish_post, 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; } @@ -631,6 +668,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); @@ -656,6 +694,7 @@ android_service_t *android_service_create(android_creds_t *creds, char *type, .public = { .listener = { .ike_rekey = _ike_rekey, + .ike_reestablish_pre = _ike_reestablish_pre, .ike_reestablish_post = _ike_reestablish_post, .ike_updown = _ike_updown, .child_updown = _child_updown, @@ -664,6 +703,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, -- cgit v1.2.3 From c66f5f844d0e19e5785e223e756d2fd6955e8f24 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Jul 2014 14:01:12 +0200 Subject: android: Recreate the TUN device without DNS when reestablishing IKE_SAs This enables DNS resolution while reestablishing if the VPN gateway pushed DNS servers to the client that are only reachable via VPN. --- .../jni/libandroidbridge/backend/android_service.c | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'src/frontends/android/jni/libandroidbridge/backend/android_service.c') diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c index 113056532..73738c22e 100644 --- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c @@ -349,6 +349,36 @@ static bool setup_tun_device(private_android_service_t *this, return TRUE; } +/** + * 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 */ @@ -479,6 +509,14 @@ METHOD(listener_t, ike_reestablish_pre, bool, 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; } -- cgit v1.2.3 From 945832c67d139a2a7a3006c0b97894b78ee9caf9 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Jul 2014 16:20:00 +0200 Subject: android: Only allow DNS queries for the configured hostname --- src/frontends/android/jni/libandroidbridge/backend/android_service.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/frontends/android/jni/libandroidbridge/backend/android_service.c') diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c index 73738c22e..fb8f93311 100644 --- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c @@ -749,6 +749,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); -- cgit v1.2.3 From 5fd9e5fd009995ce0b6fed738efc00d90a0d1f89 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 17 Jul 2014 15:22:29 +0200 Subject: android: Terminate IKE_SA if initial IKE_SA_INIT fails Since VpnStateService.disconnect() is now not called until the error dialog is dismissed the daemon would continue to try connecting. So while the error dialog is shown the connection might actually be successfully established in the background, which is not intended. This way the IKE_SA is destroyed right after sending the IKE_SA_INIT of the second connection attempt (due to keyingtries=0). --- .../jni/libandroidbridge/backend/android_service.c | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'src/frontends/android/jni/libandroidbridge/backend/android_service.c') diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c index fb8f93311..5a85d3026 100644 --- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c @@ -407,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) @@ -476,9 +487,20 @@ 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)); } this->lock->unlock(this->lock); break; -- cgit v1.2.3 From ffff7219ef6af21c9497af8db49bfb3c1c9a3036 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 17 Jul 2014 15:39:29 +0200 Subject: android: For keyingtries > 0 notify the GUI if the limit is reached when reestablishing The IKE_SA is destroyed anyway, so letting the GUI remain in "connecting" state would be incorrect. We still use keyingtries=0 for now, though. And we still abort after the first failed attempt initially, in case there is a configuration error. --- .../jni/libandroidbridge/backend/android_service.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/frontends/android/jni/libandroidbridge/backend/android_service.c') diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c index 5a85d3026..e60c491c1 100644 --- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c @@ -502,6 +502,23 @@ METHOD(listener_t, alert, bool, (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; default: -- cgit v1.2.3