aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/frontends/android/AndroidManifest.xml1
-rw-r--r--src/frontends/android/jni/Android.mk3
-rw-r--r--src/frontends/android/jni/libandroidbridge/Android.mk1
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_service.c54
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_service.h5
-rw-r--r--src/frontends/android/jni/libandroidbridge/charonservice.c58
-rw-r--r--src/frontends/android/jni/libandroidbridge/charonservice.h11
-rw-r--r--src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c3
-rw-r--r--src/frontends/android/jni/libandroidbridge/kernel/android_net.c77
-rw-r--r--src/frontends/android/jni/libandroidbridge/kernel/network_manager.c244
-rw-r--r--src/frontends/android/jni/libandroidbridge/kernel/network_manager.h91
-rw-r--r--src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java54
-rw-r--r--src/frontends/android/src/org/strongswan/android/logic/NetworkManager.java113
-rw-r--r--src/libcharon/bus/bus.h2
-rw-r--r--src/libcharon/daemon.c3
-rw-r--r--src/libcharon/sa/ike_sa.c2
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c14
-rw-r--r--src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c7
-rw-r--r--src/libipsec/ipsec_processor.c4
-rw-r--r--src/libipsec/ipsec_sa.c16
-rw-r--r--src/libipsec/ipsec_sa.h14
-rw-r--r--src/libipsec/ipsec_sa_mgr.c69
-rw-r--r--src/libipsec/ipsec_sa_mgr.h21
-rw-r--r--src/libstrongswan/Android.mk4
-rw-r--r--src/libstrongswan/Makefile.am6
-rw-r--r--src/libstrongswan/host_resolver.c391
-rw-r--r--src/libstrongswan/host_resolver.h60
-rw-r--r--src/libstrongswan/library.c2
-rw-r--r--src/libstrongswan/library.h6
-rw-r--r--src/libstrongswan/threading/mutex.c8
-rw-r--r--src/libstrongswan/threading/rwlock.c7
-rw-r--r--src/libstrongswan/utils.h16
-rw-r--r--src/libstrongswan/utils/host.c50
33 files changed, 1218 insertions, 199 deletions
diff --git a/src/frontends/android/AndroidManifest.xml b/src/frontends/android/AndroidManifest.xml
index f0ed02ff3..4655cd7fc 100644
--- a/src/frontends/android/AndroidManifest.xml
+++ b/src/frontends/android/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-sdk android:minSdkVersion="14" />
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:icon="@drawable/ic_launcher"
diff --git a/src/frontends/android/jni/Android.mk b/src/frontends/android/jni/Android.mk
index 326565f2b..40a7a06a3 100644
--- a/src/frontends/android/jni/Android.mk
+++ b/src/frontends/android/jni/Android.mk
@@ -16,11 +16,14 @@ openssl_PATH := $(LOCAL_PATH)/openssl/include
# CFLAGS (partially from a configure run using droid-gcc)
strongswan_CFLAGS := \
+ -Wall \
+ -Wextra \
-Wno-format \
-Wno-pointer-sign \
-Wno-pointer-arith \
-Wno-sign-compare \
-Wno-strict-aliasing \
+ -Wno-unused-parameter \
-DHAVE___BOOL \
-DHAVE_STDBOOL_H \
-DHAVE_ALLOCA_H \
diff --git a/src/frontends/android/jni/libandroidbridge/Android.mk b/src/frontends/android/jni/libandroidbridge/Android.mk
index f47e39656..b1fa4d1cb 100644
--- a/src/frontends/android/jni/libandroidbridge/Android.mk
+++ b/src/frontends/android/jni/libandroidbridge/Android.mk
@@ -11,6 +11,7 @@ backend/android_service.c backend/android_service.h \
charonservice.c charonservice.h \
kernel/android_ipsec.c kernel/android_ipsec.h \
kernel/android_net.c kernel/android_net.h \
+kernel/network_manager.c kernel/network_manager.h \
vpnservice_builder.c vpnservice_builder.h
# build libandroidbridge -------------------------------------------------------
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c
index 2a115d2f9..b00567f60 100644
--- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c
@@ -59,11 +59,6 @@ struct private_android_service_t {
char *type;
/**
- * local ipv4 address
- */
- char *local_address;
-
- /**
* gateway
*/
char *gateway;
@@ -362,7 +357,6 @@ METHOD(listener_t, child_updown, bool,
{
/* 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");
@@ -403,19 +397,6 @@ METHOD(listener_t, ike_updown, bool,
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)
@@ -432,6 +413,15 @@ METHOD(listener_t, alert, bool,
charonservice->update_status(charonservice,
CHARONSERVICE_PEER_AUTH_ERROR);
break;
+ 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 */
+ charonservice->update_status(charonservice,
+ CHARONSERVICE_UNREACHABLE_ERROR);
+ }
+ this->lock->unlock(this->lock);
+ break;
default:
break;
}
@@ -455,9 +445,8 @@ METHOD(listener_t, ike_reestablish, bool,
if (this->ike_sa == old)
{
this->ike_sa = new;
- /* re-register hooks to detect initiation failures */
+ /* re-register hook to detect initiation failures */
this->public.listener.ike_updown = _ike_updown;
- this->public.listener.ike_state_change = _ike_state_change;
/* the TUN device will be closed when the new CHILD_SA is established */
}
return TRUE;
@@ -480,13 +469,13 @@ static job_requeue_t initiate(private_android_service_t *this)
}
};
- ike_cfg = ike_cfg_create(TRUE, TRUE, this->local_address, FALSE,
+ ike_cfg = ike_cfg_create(TRUE, TRUE, "0.0.0.0", 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 */
+ UNIQUE_REPLACE, 0, /* keyingtries */
36000, 0, /* rekey 10h, reauth none */
600, 600, /* jitter, over 10min */
TRUE, FALSE, /* mobike, aggressive */
@@ -538,10 +527,14 @@ static job_requeue_t initiate(private_android_service_t *this)
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);
+ ACTION_NONE, ACTION_RESTART, ACTION_RESTART,
+ FALSE, 0, 0, NULL, NULL, 0);
+ /* create an ESP proposal with the algorithms currently supported by
+ * libipsec, no PFS for now */
+ child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
+ "aes128-aes192-aes256-sha1-sha256-sha384-sha512"));
+ 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, TRUE, ts);
ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0",
0, "255.255.255.255", 65535);
@@ -588,7 +581,6 @@ METHOD(android_service_t, destroy, void,
close_tun_device(this);
this->lock->destroy(this->lock);
free(this->type);
- free(this->local_address);
free(this->gateway);
free(this->username);
if (this->password)
@@ -603,8 +595,8 @@ METHOD(android_service_t, destroy, void,
* See header
*/
android_service_t *android_service_create(android_creds_t *creds, char *type,
- char *local_address, char *gateway,
- char *username, char *password)
+ char *gateway, char *username,
+ char *password)
{
private_android_service_t *this;
@@ -614,14 +606,12 @@ android_service_t *android_service_create(android_creds_t *creds, char *type,
.ike_rekey = _ike_rekey,
.ike_reestablish = _ike_reestablish,
.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,
.password = password,
.gateway = gateway,
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.h b/src/frontends/android/jni/libandroidbridge/backend/android_service.h
index 52c3dc5c8..1bfdcf994 100644
--- a/src/frontends/android/jni/libandroidbridge/backend/android_service.h
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.h
@@ -53,13 +53,12 @@ struct android_service_t {
*
* @param creds Android specific credential set
* @param type VPN type (see VpnType.java)
- * @param local_address local ip address
* @param gateway gateway address
* @param username user name (local identity)
* @param password password (if any)
*/
android_service_t *android_service_create(android_creds_t *creds, char *type,
- char *local_address, char *gateway,
- char *username, char *password);
+ char *gateway, char *username,
+ char *password);
#endif /** ANDROID_SERVICE_H_ @}*/
diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.c b/src/frontends/android/jni/libandroidbridge/charonservice.c
index ef4d42edf..1fde9887b 100644
--- a/src/frontends/android/jni/libandroidbridge/charonservice.c
+++ b/src/frontends/android/jni/libandroidbridge/charonservice.c
@@ -38,7 +38,7 @@
#define ANDROID_DEBUG_LEVEL 1
#define ANDROID_RETRASNMIT_TRIES 3
-#define ANDROID_RETRANSMIT_TIMEOUT 3.0
+#define ANDROID_RETRANSMIT_TIMEOUT 2.0
#define ANDROID_RETRANSMIT_BASE 1.4
typedef struct private_charonservice_t private_charonservice_t;
@@ -74,9 +74,19 @@ struct private_charonservice_t {
vpnservice_builder_t *builder;
/**
+ * NetworkManager instance (accessed via JNI)
+ */
+ network_manager_t *network_manager;
+
+ /**
* CharonVpnService reference
*/
jobject vpn_service;
+
+ /**
+ * Sockets that were bypassed and we keep track for
+ */
+ linked_list_t *sockets;
};
/**
@@ -172,8 +182,10 @@ failed:
return success;
}
-METHOD(charonservice_t, bypass_socket, bool,
- private_charonservice_t *this, int fd, int family)
+/**
+ * Bypass a single socket
+ */
+static bool bypass_single_socket(intptr_t fd, private_charonservice_t *this)
{
JNIEnv *env;
jmethodID method_id;
@@ -188,7 +200,7 @@ METHOD(charonservice_t, bypass_socket, bool,
}
if (!(*env)->CallBooleanMethod(env, this->vpn_service, method_id, fd))
{
- DBG1(DBG_CFG, "VpnService.protect() failed");
+ DBG2(DBG_KNL, "VpnService.protect() failed");
goto failed;
}
androidjni_detach_thread();
@@ -200,6 +212,19 @@ failed:
return FALSE;
}
+METHOD(charonservice_t, bypass_socket, bool,
+ private_charonservice_t *this, int fd, int family)
+{
+ if (fd >= 0)
+ {
+ this->sockets->insert_last(this->sockets, (void*)(intptr_t)fd);
+ return bypass_single_socket((intptr_t)fd, this);
+ }
+ this->sockets->invoke_function(this->sockets, (void*)bypass_single_socket,
+ this);
+ return TRUE;
+}
+
/**
* Converts the given Java array of byte arrays (byte[][]) to a linked list
* of chunk_t objects.
@@ -330,22 +355,26 @@ METHOD(charonservice_t, get_vpnservice_builder, vpnservice_builder_t*,
return this->builder;
}
+METHOD(charonservice_t, get_network_manager, network_manager_t*,
+ private_charonservice_t *this)
+{
+ return this->network_manager;
+}
+
/**
* Initiate a new connection
*
- * @param local local ip address (gets owned)
* @param gateway gateway address (gets owned)
* @param username username (gets owned)
* @param password password (gets owned)
*/
-static void initiate(char *type, char *local, char *gateway,
- char *username, char *password)
+static void initiate(char *type, char *gateway, char *username, char *password)
{
private_charonservice_t *this = (private_charonservice_t*)charonservice;
this->creds->clear(this->creds);
DESTROY_IF(this->service);
- this->service = android_service_create(this->creds, type, local, gateway,
+ this->service = android_service_create(this->creds, type, gateway,
username, password);
}
@@ -400,10 +429,13 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
.get_user_certificate = _get_user_certificate,
.get_user_key = _get_user_key,
.get_vpnservice_builder = _get_vpnservice_builder,
+ .get_network_manager = _get_network_manager,
},
.attr = android_attr_create(),
.creds = android_creds_create(),
.builder = vpnservice_builder_create(builder),
+ .network_manager = network_manager_create(service),
+ .sockets = linked_list_create(),
.vpn_service = (*env)->NewGlobalRef(env, service),
);
charonservice = &this->public;
@@ -439,6 +471,8 @@ static void charonservice_deinit(JNIEnv *env)
{
private_charonservice_t *this = (private_charonservice_t*)charonservice;
+ this->network_manager->destroy(this->network_manager);
+ this->sockets->destroy(this->sockets);
this->builder->destroy(this->builder);
this->creds->destroy(this->creds);
this->attr->destroy(this->attr);
@@ -555,16 +589,14 @@ JNI_METHOD(CharonVpnService, deinitializeCharon, void)
* Initiate SA
*/
JNI_METHOD(CharonVpnService, initiate, void,
- jstring jtype, jstring jlocal_address, jstring jgateway, jstring jusername,
- jstring jpassword)
+ jstring jtype, jstring jgateway, jstring jusername, jstring jpassword)
{
- char *type, *local_address, *gateway, *username, *password;
+ char *type, *gateway, *username, *password;
type = androidjni_convert_jstring(env, jtype);
- local_address = androidjni_convert_jstring(env, jlocal_address);
gateway = androidjni_convert_jstring(env, jgateway);
username = androidjni_convert_jstring(env, jusername);
password = androidjni_convert_jstring(env, jpassword);
- initiate(type, local_address, gateway, username, password);
+ initiate(type, gateway, username, password);
}
diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.h b/src/frontends/android/jni/libandroidbridge/charonservice.h
index 376f55014..4b5839f5e 100644
--- a/src/frontends/android/jni/libandroidbridge/charonservice.h
+++ b/src/frontends/android/jni/libandroidbridge/charonservice.h
@@ -32,6 +32,7 @@
#define CHARONSERVICE_H_
#include "vpnservice_builder.h"
+#include "kernel/network_manager.h"
#include <library.h>
#include <utils/linked_list.h>
@@ -69,7 +70,9 @@ struct charonservice_t {
/**
* Install a bypass policy for the given socket using the protect() Method
- * of the Android VpnService interface
+ * of the Android VpnService interface.
+ *
+ * Use -1 as fd to re-bypass previously bypassed sockets.
*
* @param fd socket file descriptor
* @param family socket protocol family
@@ -111,6 +114,12 @@ struct charonservice_t {
*/
vpnservice_builder_t *(*get_vpnservice_builder)(charonservice_t *this);
+ /**
+ * Get the current network_manager_t object
+ *
+ * @return NetworkManager instance
+ */
+ network_manager_t *(*get_network_manager)(charonservice_t *this);
};
/**
diff --git a/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c b/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c
index 08cc61610..85fe5d4c1 100644
--- a/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c
+++ b/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c
@@ -79,7 +79,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
bool encap, bool new_encap, mark_t mark)
{
- return NOT_SUPPORTED;
+ return ipsec->sas->update_sa(ipsec->sas, spi, protocol, cpi, src, dst,
+ new_src, new_dst, encap, new_encap, mark);
}
METHOD(kernel_ipsec_t, query_sa, status_t,
diff --git a/src/frontends/android/jni/libandroidbridge/kernel/android_net.c b/src/frontends/android/jni/libandroidbridge/kernel/android_net.c
index e29f95510..430c95bc8 100644
--- a/src/frontends/android/jni/libandroidbridge/kernel/android_net.c
+++ b/src/frontends/android/jni/libandroidbridge/kernel/android_net.c
@@ -14,6 +14,15 @@
#include "android_net.h"
+#include "../charonservice.h"
+#include <hydra.h>
+#include <debug.h>
+#include <processing/jobs/callback_job.h>
+#include <threading/mutex.h>
+
+/** delay before firing roam events (ms) */
+#define ROAM_DELAY 100
+
typedef struct private_kernel_android_net_t private_kernel_android_net_t;
struct private_kernel_android_net_t {
@@ -22,8 +31,66 @@ struct private_kernel_android_net_t {
* Public kernel interface
*/
kernel_android_net_t public;
+
+ /**
+ * Reference to NetworkManager object
+ */
+ network_manager_t *network_manager;
+
+ /**
+ * earliest time of the next roam event
+ */
+ timeval_t next_roam;
+
+ /**
+ * mutex to check and update roam event time
+ */
+ mutex_t *mutex;
};
+/**
+ * callback function that raises the delayed roam event
+ */
+static job_requeue_t roam_event()
+{
+ /* this will fail if no connection is up */
+ charonservice->bypass_socket(charonservice, -1, 0);
+ hydra->kernel_interface->roam(hydra->kernel_interface, TRUE);
+ return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Listen for connectivity change events and queue a roam event
+ */
+static void connectivity_cb(private_kernel_android_net_t *this,
+ bool disconnected)
+{
+ timeval_t now;
+ job_t *job;
+
+ time_monotonic(&now);
+ this->mutex->lock(this->mutex);
+ if (!timercmp(&now, &this->next_roam, >))
+ {
+ this->mutex->unlock(this->mutex);
+ return;
+ }
+ timeval_add_ms(&now, ROAM_DELAY);
+ this->next_roam = now;
+ this->mutex->unlock(this->mutex);
+
+ job = (job_t*)callback_job_create((callback_job_cb_t)roam_event, NULL,
+ NULL, NULL);
+ lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
+}
+
+METHOD(kernel_net_t, get_source_addr, host_t*,
+ private_kernel_android_net_t *this, host_t *dest, host_t *src)
+{
+ return this->network_manager->get_local_address(this->network_manager,
+ dest->get_family(dest) == AF_INET);
+}
+
METHOD(kernel_net_t, add_ip, status_t,
private_kernel_android_net_t *this, host_t *virtual_ip, host_t *iface_ip)
{
@@ -34,6 +101,9 @@ METHOD(kernel_net_t, add_ip, status_t,
METHOD(kernel_net_t, destroy, void,
private_kernel_android_net_t *this)
{
+ this->network_manager->remove_connectivity_cb(this->network_manager,
+ (void*)connectivity_cb);
+ this->mutex->destroy(this->mutex);
free(this);
}
@@ -47,7 +117,7 @@ kernel_android_net_t *kernel_android_net_create()
INIT(this,
.public = {
.interface = {
- .get_source_addr = (void*)return_null,
+ .get_source_addr = _get_source_addr,
.get_nexthop = (void*)return_null,
.get_interface = (void*)return_null,
.create_address_enumerator = (void*)enumerator_create_empty,
@@ -58,7 +128,12 @@ kernel_android_net_t *kernel_android_net_create()
.destroy = _destroy,
},
},
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .network_manager = charonservice->get_network_manager(charonservice),
);
+ timerclear(&this->next_roam);
+ this->network_manager->add_connectivity_cb(this->network_manager,
+ (void*)connectivity_cb, this);
return &this->public;
};
diff --git a/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c
new file mode 100644
index 000000000..9c97fbb14
--- /dev/null
+++ b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c
@@ -0,0 +1,244 @@
+/*
+ * 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 "network_manager.h"
+
+#include "../android_jni.h"
+#include "../charonservice.h"
+#include <debug.h>
+#include <threading/mutex.h>
+
+typedef struct private_network_manager_t private_network_manager_t;
+
+struct private_network_manager_t {
+
+ /**
+ * Public interface
+ */
+ network_manager_t public;
+
+ /**
+ * Reference to NetworkManager object
+ */
+ jobject obj;
+
+ /**
+ * Java class for NetworkManager
+ */
+ jclass cls;
+
+ /**
+ * Registered callback
+ */
+ struct {
+ connectivity_cb_t cb;
+ void *data;
+ } connectivity_cb;
+
+ /**
+ * Mutex to access callback
+ */
+ mutex_t *mutex;
+};
+
+METHOD(network_manager_t, get_local_address, host_t*,
+ private_network_manager_t *this, bool ipv4)
+{
+ JNIEnv *env;
+ jmethodID method_id;
+ jstring jaddr;
+ char *addr;
+ host_t *host;
+
+ androidjni_attach_thread(&env);
+ method_id = (*env)->GetMethodID(env, this->cls, "getLocalAddress",
+ "(Z)Ljava/lang/String;");
+ if (!method_id)
+ {
+ goto failed;
+ }
+ jaddr = (*env)->CallObjectMethod(env, this->obj, method_id, ipv4);
+ if (!jaddr)
+ {
+ goto failed;
+ }
+ addr = androidjni_convert_jstring(env, jaddr);
+ androidjni_detach_thread();
+ host = host_create_from_string(addr, 0);
+ free(addr);
+ return host;
+
+failed:
+ androidjni_exception_occurred(env);
+ androidjni_detach_thread();
+ return NULL;
+}
+
+JNI_METHOD(NetworkManager, networkChanged, void,
+ bool disconnected)
+{
+ private_network_manager_t *nm;
+
+ nm = (private_network_manager_t*)charonservice->get_network_manager(
+ charonservice);
+ nm->mutex->lock(nm->mutex);
+ if (nm->connectivity_cb.cb)
+ {
+ nm->connectivity_cb.cb(nm->connectivity_cb.data, disconnected);
+ }
+ nm->mutex->unlock(nm->mutex);
+}
+
+METHOD(network_manager_t, add_connectivity_cb, void,
+ private_network_manager_t *this, connectivity_cb_t cb, void *data)
+{
+ this->mutex->lock(this->mutex);
+ if (!this->connectivity_cb.cb)
+ {
+ JNIEnv *env;
+ jmethodID method_id;
+
+ androidjni_attach_thread(&env);
+ method_id = (*env)->GetMethodID(env, this->cls, "Register", "()V");
+ if (!method_id)
+ {
+ androidjni_exception_occurred(env);
+ }
+ else
+ {
+ (*env)->CallVoidMethod(env, this->obj, method_id);
+ if (!androidjni_exception_occurred(env))
+ {
+ this->connectivity_cb.cb = cb;
+ this->connectivity_cb.data = data;
+ }
+ androidjni_detach_thread();
+ }
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Unregister the NetworkManager via JNI.
+ *
+ * this->mutex has to be locked
+ */
+static void unregister_network_manager(private_network_manager_t *this)
+{
+ JNIEnv *env;
+ jmethodID method_id;
+
+ androidjni_attach_thread(&env);
+ method_id = (*env)->GetMethodID(env, this->cls, "Unregister", "()V");
+ if (!method_id)
+ {
+ androidjni_exception_occurred(env);
+ }
+ else
+ {
+ (*env)->CallVoidMethod(env, this->obj, method_id);
+ androidjni_exception_occurred(env);
+ }
+ androidjni_detach_thread();
+}
+
+METHOD(network_manager_t, remove_connectivity_cb, void,
+ private_network_manager_t *this, connectivity_cb_t cb)
+{
+ this->mutex->lock(this->mutex);
+ if (this->connectivity_cb.cb == cb)
+ {
+ this->connectivity_cb.cb = NULL;
+ unregister_network_manager(this);
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(network_manager_t, destroy, void,
+ private_network_manager_t *this)
+{
+ JNIEnv *env;
+
+ this->mutex->lock(this->mutex);
+ if (this->connectivity_cb.cb)
+ {
+ this->connectivity_cb.cb = NULL;
+ unregister_network_manager(this);
+ }
+ this->mutex->unlock(this->mutex);
+
+ androidjni_attach_thread(&env);
+ if (this->obj)
+ {
+ (*env)->DeleteGlobalRef(env, this->obj);
+ }
+ if (this->cls)
+ {
+ (*env)->DeleteGlobalRef(env, this->cls);
+ }
+ androidjni_detach_thread();
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+network_manager_t *network_manager_create(jobject context)
+{
+ private_network_manager_t *this;
+ JNIEnv *env;
+ jmethodID method_id;
+ jobject obj;
+ jclass cls;
+
+ INIT(this,
+ .public = {
+ .get_local_address = _get_local_address,
+ .add_connectivity_cb = _add_connectivity_cb,
+ .remove_connectivity_cb = _remove_connectivity_cb,
+ .destroy = _destroy,
+ },
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ androidjni_attach_thread(&env);
+ cls = (*env)->FindClass(env, JNI_PACKAGE_STRING "/NetworkManager");
+ if (!cls)
+ {
+ goto failed;
+ }
+ this->cls = (*env)->NewGlobalRef(env, cls);
+ method_id = (*env)->GetMethodID(env, cls, "<init>",
+ "(Landroid/content/Context;)V");
+ if (!method_id)
+ {
+ goto failed;
+ }
+ obj = (*env)->NewObject(env, cls, method_id, context);
+ if (!obj)
+ {
+ goto failed;
+ }
+ this->obj = (*env)->NewGlobalRef(env, obj);
+ androidjni_detach_thread();
+ return &this->public;
+
+failed:
+ DBG1(DBG_KNL, "failed to build NetworkManager object");
+ androidjni_exception_occurred(env);
+ androidjni_detach_thread();
+ destroy(this);
+ return NULL;
+};
diff --git a/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h
new file mode 100644
index 000000000..634816405
--- /dev/null
+++ b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h
@@ -0,0 +1,91 @@
+/*
+ * 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 network_manager network_manager
+ * @{ @ingroup kernel_android
+ */
+
+#ifndef NETWORK_MANAGER_H_
+#define NETWORK_MANAGER_H_
+
+#include <jni.h>
+
+#include <library.h>
+#include <utils/host.h>
+
+typedef struct network_manager_t network_manager_t;
+
+/**
+ * Callback called if connectivity changes somehow.
+ *
+ * Implementation should be quick as the call is made by the Java apps main
+ * thread.
+ *
+ * @param data data supplied during registration
+ * @param disconnected TRUE if currently disconnected
+ */
+typedef void (*connectivity_cb_t)(void *data, bool disconnected);
+
+/**
+ * NetworkManager, used to listen for network changes and retrieve local IP
+ * addresses.
+ *
+ * Communicates with NetworkManager via JNI
+ */
+struct network_manager_t {
+
+ /**
+ * Get a local address
+ *
+ * @param ipv4 TRUE to get an IPv4 address
+ * @return the address or NULL if none available
+ */
+ host_t *(*get_local_address)(network_manager_t *this, bool ipv4);
+
+ /**
+ * Register a callback that is called if connectivity changes
+ *
+ * @note Only the first registered callback is currently used
+ *
+ * @param cb callback to register
+ * @param data data provided to callback
+ */
+ void (*add_connectivity_cb)(network_manager_t *this, connectivity_cb_t cb,
+ void *data);
+
+ /**
+ * Unregister a previously registered callback for connectivity changes
+ *
+ * @param cb previously registered callback
+ */
+ void (*remove_connectivity_cb)(network_manager_t *this,
+ connectivity_cb_t cb);
+
+ /**
+ * Destroy a network_manager_t instance
+ */
+ void (*destroy)(network_manager_t *this);
+};
+
+/**
+ * Create a network_manager_t instance
+ *
+ * @param context Context object
+ * @return network_manager_t instance
+ */
+network_manager_t *network_manager_create(jobject context);
+
+#endif /** NETWORK_MANAGER_H_ @}*/
diff --git a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java
index 924781948..02db8c494 100644
--- a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java
+++ b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java
@@ -18,14 +18,10 @@
package org.strongswan.android.logic;
import java.io.File;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
import java.security.PrivateKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
-import java.util.Enumeration;
import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.data.VpnProfileDataSource;
@@ -218,9 +214,7 @@ public class CharonVpnService extends VpnService implements Runnable
initializeCharon(builder, mLogFile);
Log.i(TAG, "charon started");
- String local_address = getLocalIPv4Address();
initiate(mCurrentProfile.getVpnType().getIdentifier(),
- local_address != null ? local_address : "0.0.0.0",
mCurrentProfile.getGateway(), mCurrentProfile.getUsername(),
mCurrentProfile.getPassword());
}
@@ -335,15 +329,7 @@ public class CharonVpnService extends VpnService implements Runnable
switch (status)
{
case STATE_CHILD_SA_DOWN:
- synchronized (mServiceLock)
- {
- /* if we are not actively disconnecting we assume the remote terminated
- * the connection and call disconnect() to deinitialize charon properly */
- if (mService != null && !mIsDisconnecting)
- {
- mService.disconnect();
- }
- }
+ /* we ignore this as we use closeaction=restart */
break;
case STATE_CHILD_SA_UP:
setState(State.CONNECTED);
@@ -486,41 +472,7 @@ public class CharonVpnService extends VpnService implements Runnable
/**
* Initiate VPN, provided by libandroidbridge.so
*/
- public native void initiate(String type, String local_address, String gateway,
- String username, String password);
-
- /**
- * Helper function that retrieves a local IPv4 address.
- *
- * @return string representation of an IPv4 address, or null if none found
- */
- private static String getLocalIPv4Address()
- {
- try
- {
- Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
- while (en.hasMoreElements())
- {
- NetworkInterface intf = en.nextElement();
-
- Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();
- while (enumIpAddr.hasMoreElements())
- {
- InetAddress inetAddress = enumIpAddr.nextElement();
- if (!inetAddress.isLoopbackAddress() && inetAddress.getAddress().length == 4)
- {
- return inetAddress.getHostAddress().toString();
- }
- }
- }
- }
- catch (SocketException ex)
- {
- ex.printStackTrace();
- return null;
- }
- return null;
- }
+ public native void initiate(String type, String gateway, String username, String password);
/**
* Adapter for VpnService.Builder which is used to access it safely via JNI.
@@ -547,7 +499,7 @@ public class CharonVpnService extends VpnService implements Runnable
Context context = getApplicationContext();
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pending = PendingIntent.getActivity(context, 0, intent,
- Intent.FLAG_ACTIVITY_NEW_TASK);
+ PendingIntent.FLAG_UPDATE_CURRENT);
builder.setConfigureIntent(pending);
return builder;
}
diff --git a/src/frontends/android/src/org/strongswan/android/logic/NetworkManager.java b/src/frontends/android/src/org/strongswan/android/logic/NetworkManager.java
new file mode 100644
index 000000000..160865fb7
--- /dev/null
+++ b/src/frontends/android/src/org/strongswan/android/logic/NetworkManager.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+package org.strongswan.android.logic;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+
+public class NetworkManager extends BroadcastReceiver
+{
+ private final Context mContext;
+ private boolean mRegistered;
+
+ public NetworkManager(Context context)
+ {
+ mContext = context;
+ }
+
+ public void Register()
+ {
+ mContext.registerReceiver(this, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+ }
+
+ public void Unregister()
+ {
+ mContext.unregisterReceiver(this);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent)
+ {
+ ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo info = cm.getActiveNetworkInfo();
+ networkChanged(info == null || !info.isConnected());
+ }
+
+ /**
+ * Notify the native parts about a network change
+ *
+ * @param disconnected true if no connection is available at the moment
+ */
+ public native void networkChanged(boolean disconnected);
+
+ /**
+ * Function that retrieves a local address of the given family.
+ *
+ * @param ipv4 true to return an IPv4 address, false for IPv6
+ * @return string representation of an IPv4 address, or null if none found
+ */
+ public String getLocalAddress(boolean ipv4)
+ {
+ try
+ {
+ Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
+ if (en == null)
+ { /* no interfaces at all */
+ return null;
+ }
+ while (en.hasMoreElements())
+ {
+ NetworkInterface intf = en.nextElement();
+ if (intf.isLoopback() || !intf.isUp() ||
+ intf.getName().startsWith("tun"))
+ {
+ continue;
+ }
+ Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();
+ while (enumIpAddr.hasMoreElements())
+ {
+ InetAddress inetAddress = enumIpAddr.nextElement();
+ if (inetAddress.isLoopbackAddress())
+ {
+ continue;
+ }
+ if ((ipv4 && inetAddress instanceof Inet4Address) ||
+ (!ipv4 && inetAddress instanceof Inet6Address))
+ {
+ return inetAddress.getHostAddress();
+ }
+ }
+ }
+ }
+ catch (SocketException ex)
+ {
+ ex.printStackTrace();
+ return null;
+ }
+ return null;
+ }
+}
diff --git a/src/libcharon/bus/bus.h b/src/libcharon/bus/bus.h
index aba8acdbd..4bde2434b 100644
--- a/src/libcharon/bus/bus.h
+++ b/src/libcharon/bus/bus.h
@@ -90,6 +90,8 @@ enum alert_t {
ALERT_PEER_AUTH_FAILED,
/** failed to resolve peer address, no arguments */
ALERT_PEER_ADDR_FAILED,
+ /** peer did not respond to initial message, current try (int, 0-based) */
+ ALERT_PEER_INIT_UNREACHABLE,
};
/**
diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c
index 6e977efc4..9ae56a91d 100644
--- a/src/libcharon/daemon.c
+++ b/src/libcharon/daemon.c
@@ -84,7 +84,8 @@ static void destroy(private_daemon_t *this)
{
/* terminate all idle threads */
lib->processor->set_threads(lib->processor, 0);
-
+ /* make sure nobody waits for a DNS query */
+ lib->hosts->flush(lib->hosts);
/* close all IKE_SAs */
if (this->public.ike_sa_manager)
{
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index 1d49acb52..d9118fc49 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -1690,6 +1690,8 @@ METHOD(ike_sa_t, retransmit, status_t,
{
/* retry IKE_SA_INIT/Main Mode if we have multiple keyingtries */
u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
+ charon->bus->alert(charon->bus, ALERT_PEER_INIT_UNREACHABLE,
+ this->keyingtry);
this->keyingtry++;
if (tries == 0 || tries > this->keyingtry)
{
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
index 3f63a8496..e5f070e13 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
@@ -543,12 +543,7 @@ static void queue_route_reinstall(private_kernel_netlink_net_t *this,
time_monotonic(&now);
if (timercmp(&now, &this->last_route_reinstall, >))
{
- now.tv_usec += ROUTE_DELAY * 1000;
- while (now.tv_usec > 1000000)
- {
- now.tv_sec++;
- now.tv_usec -= 1000000;
- }
+ timeval_add_ms(&now, ROUTE_DELAY);
this->last_route_reinstall = now;
job = (job_t*)callback_job_create((callback_job_cb_t)reinstall_routes,
@@ -704,12 +699,7 @@ static void fire_roam_event(private_kernel_netlink_net_t *this, bool address)
this->roam_lock->unlock(this->roam_lock);
return;
}
- now.tv_usec += ROAM_DELAY * 1000;
- while (now.tv_usec > 1000000)
- {
- now.tv_sec++;
- now.tv_usec -= 1000000;
- }
+ timeval_add_ms(&now, ROAM_DELAY);
this->next_roam = now;
this->roam_lock->unlock(this->roam_lock);
diff --git a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
index 16a46bb56..47a8829f7 100644
--- a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
+++ b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
@@ -285,12 +285,7 @@ static void fire_roam_event(private_kernel_pfroute_net_t *this, bool address)
time_monotonic(&now);
if (timercmp(&now, &this->last_roam, >))
{
- now.tv_usec += ROAM_DELAY * 1000;
- while (now.tv_usec > 1000000)
- {
- now.tv_sec++;
- now.tv_usec -= 1000000;
- }
+ timeval_add_ms(&now, ROAM_DELAY);
this->last_roam = now;
job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
diff --git a/src/libipsec/ipsec_processor.c b/src/libipsec/ipsec_processor.c
index a91d9e074..353f0e7e0 100644
--- a/src/libipsec/ipsec_processor.c
+++ b/src/libipsec/ipsec_processor.c
@@ -146,7 +146,9 @@ static job_requeue_t process_inbound(private_ipsec_processor_t *this)
policy->destroy(policy);
break;
}
- DBG1(DBG_ESP, "discarding inbound IP packet due to policy");
+ DBG1(DBG_ESP, "discarding inbound IP packet %H == %H due to "
+ "policy", ip_packet->get_source(ip_packet),
+ ip_packet->get_destination(ip_packet));
/* no matching policy found, fall-through */
}
case IPPROTO_NONE:
diff --git a/src/libipsec/ipsec_sa.c b/src/libipsec/ipsec_sa.c
index cccd16404..66852259c 100644
--- a/src/libipsec/ipsec_sa.c
+++ b/src/libipsec/ipsec_sa.c
@@ -95,6 +95,20 @@ METHOD(ipsec_sa_t, get_destination, host_t*,
return this->dst;
}
+METHOD(ipsec_sa_t, set_source, void,
+ private_ipsec_sa_t *this, host_t *addr)
+{
+ this->src->destroy(this->src);
+ this->src = addr->clone(addr);
+}
+
+METHOD(ipsec_sa_t, set_destination, void,
+ private_ipsec_sa_t *this, host_t *addr)
+{
+ this->dst->destroy(this->dst);
+ this->dst = addr->clone(addr);
+}
+
METHOD(ipsec_sa_t, get_spi, u_int32_t,
private_ipsec_sa_t *this)
{
@@ -202,6 +216,8 @@ ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst,
.destroy = _destroy,
.get_source = _get_source,
.get_destination = _get_destination,
+ .set_source = _set_source,
+ .set_destination = _set_destination,
.get_spi = _get_spi,
.get_reqid = _get_reqid,
.get_protocol = _get_protocol,
diff --git a/src/libipsec/ipsec_sa.h b/src/libipsec/ipsec_sa.h
index 5fd03b6e4..271e0129f 100644
--- a/src/libipsec/ipsec_sa.h
+++ b/src/libipsec/ipsec_sa.h
@@ -52,6 +52,20 @@ struct ipsec_sa_t {
host_t *(*get_destination)(ipsec_sa_t *this);
/**
+ * Set the source address for this SA
+ *
+ * @param addr source address of this SA (gets cloned)
+ */
+ void (*set_source)(ipsec_sa_t *this, host_t *addr);
+
+ /**
+ * Set the destination address for this SA
+ *
+ * @param addr destination address of this SA (gets cloned)
+ */
+ void (*set_destination)(ipsec_sa_t *this, host_t *addr);
+
+ /**
* Get the SPI for this SA
*
* @return SPI of this SA
diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c
index e42c77aa5..35ad6c171 100644
--- a/src/libipsec/ipsec_sa_mgr.c
+++ b/src/libipsec/ipsec_sa_mgr.c
@@ -237,29 +237,29 @@ static bool match_entry_by_sa_ptr(ipsec_sa_entry_t *item, ipsec_sa_t *sa)
return item->sa == sa;
}
-static bool match_entry_by_spi_inbound(ipsec_sa_entry_t *item, u_int32_t spi,
- bool inbound)
+static bool match_entry_by_spi_inbound(ipsec_sa_entry_t *item, u_int32_t *spi,
+ bool *inbound)
{
- return item->sa->get_spi(item->sa) == spi &&
- item->sa->is_inbound(item->sa) == inbound;
+ return item->sa->get_spi(item->sa) == *spi &&
+ item->sa->is_inbound(item->sa) == *inbound;
}
-static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, u_int32_t spi,
+static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, u_int32_t *spi,
host_t *src, host_t *dst)
{
- return item->sa->match_by_spi_src_dst(item->sa, spi, src, dst);
+ return item->sa->match_by_spi_src_dst(item->sa, *spi, src, dst);
}
static bool match_entry_by_reqid_inbound(ipsec_sa_entry_t *item,
- u_int32_t reqid, bool inbound)
+ u_int32_t *reqid, bool *inbound)
{
- return item->sa->match_by_reqid(item->sa, reqid, inbound);
+ return item->sa->match_by_reqid(item->sa, *reqid, *inbound);
}
-static bool match_entry_by_spi_dst(ipsec_sa_entry_t *item, u_int32_t spi,
+static bool match_entry_by_spi_dst(ipsec_sa_entry_t *item, u_int32_t *spi,
host_t *dst)
{
- return item->sa->match_by_spi_dst(item->sa, spi, dst);
+ return item->sa->match_by_spi_dst(item->sa, *spi, dst);
}
/**
@@ -381,7 +381,7 @@ static bool allocate_spi(private_ipsec_sa_mgr_t *this, u_int32_t spi)
if (this->allocated_spis->get(this->allocated_spis, &spi) ||
this->sas->find_first(this->sas, (void*)match_entry_by_spi_inbound,
- NULL, spi, TRUE) == SUCCESS)
+ NULL, &spi, TRUE) == SUCCESS)
{
return FALSE;
}
@@ -471,7 +471,7 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t,
}
if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst,
- NULL, spi, src, dst) == SUCCESS)
+ NULL, &spi, src, dst) == SUCCESS)
{
this->mutex->unlock(this->mutex);
DBG1(DBG_ESP, "failed to install SAD entry: already installed");
@@ -487,6 +487,44 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t,
return SUCCESS;
}
+METHOD(ipsec_sa_mgr_t, update_sa, status_t,
+ private_ipsec_sa_mgr_t *this, u_int32_t spi, u_int8_t protocol,
+ u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
+ bool encap, bool new_encap, mark_t mark)
+{
+ ipsec_sa_entry_t *entry = NULL;
+
+ DBG2(DBG_ESP, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
+ ntohl(spi), src, dst, new_src, new_dst);
+
+ if (!new_encap)
+ {
+ DBG1(DBG_ESP, "failed to update SAD entry: can't deactivate UDP "
+ "encapsulation");
+ return NOT_SUPPORTED;
+ }
+
+ this->mutex->lock(this->mutex);
+ if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst,
+ (void**)&entry, &spi, src, dst) == SUCCESS &&
+ wait_for_entry(this, entry))
+ {
+ entry->sa->set_source(entry->sa, new_src);
+ entry->sa->set_destination(entry->sa, new_dst);
+ /* checkin the entry */
+ entry->locked = FALSE;
+ entry->condvar->signal(entry->condvar);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (!entry)
+ {
+ DBG1(DBG_ESP, "failed to update SAD entry: not found");
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
METHOD(ipsec_sa_mgr_t, del_sa, status_t,
private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi,
u_int8_t protocol, u_int16_t cpi, mark_t mark)
@@ -498,7 +536,7 @@ METHOD(ipsec_sa_mgr_t, del_sa, status_t,
enumerator = this->sas->create_enumerator(this->sas);
while (enumerator->enumerate(enumerator, (void**)&current))
{
- if (match_entry_by_spi_src_dst(current, spi, src, dst))
+ if (match_entry_by_spi_src_dst(current, &spi, src, dst))
{
if (wait_remove_entry(this, current))
{
@@ -529,7 +567,7 @@ METHOD(ipsec_sa_mgr_t, checkout_by_reqid, ipsec_sa_t*,
this->mutex->lock(this->mutex);
if (this->sas->find_first(this->sas, (void*)match_entry_by_reqid_inbound,
- (void**)&entry, reqid, inbound) == SUCCESS &&
+ (void**)&entry, &reqid, &inbound) == SUCCESS &&
wait_for_entry(this, entry))
{
sa = entry->sa;
@@ -546,7 +584,7 @@ METHOD(ipsec_sa_mgr_t, checkout_by_spi, ipsec_sa_t*,
this->mutex->lock(this->mutex);
if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_dst,
- (void**)&entry, spi, dst) == SUCCESS &&
+ (void**)&entry, &spi, dst) == SUCCESS &&
wait_for_entry(this, entry))
{
sa = entry->sa;
@@ -609,6 +647,7 @@ ipsec_sa_mgr_t *ipsec_sa_mgr_create()
.public = {
.get_spi = _get_spi,
.add_sa = _add_sa,
+ .update_sa = _update_sa,
.del_sa = _del_sa,
.checkout_by_spi = _checkout_by_spi,
.checkout_by_reqid = _checkout_by_reqid,
diff --git a/src/libipsec/ipsec_sa_mgr.h b/src/libipsec/ipsec_sa_mgr.h
index 303b36f0e..db30a86bb 100644
--- a/src/libipsec/ipsec_sa_mgr.h
+++ b/src/libipsec/ipsec_sa_mgr.h
@@ -86,6 +86,27 @@ struct ipsec_sa_mgr_t {
traffic_selector_t *src_ts, traffic_selector_t *dst_ts);
/**
+ * Update the hosts on an installed SA.
+ *
+ * @param spi SPI of the SA
+ * @param protocol protocol for this SA (ESP/AH)
+ * @param cpi CPI for IPComp, 0 if no IPComp is used
+ * @param src current source address
+ * @param dst current destination address
+ * @param new_src new source address
+ * @param new_dst new destination address
+ * @param encap current use of UDP encapsulation
+ * @param new_encap new use of UDP encapsulation
+ * @param mark optional mark for this SA
+ * @return SUCCESS if operation completed
+ */
+ status_t (*update_sa)(ipsec_sa_mgr_t *this,
+ u_int32_t spi, u_int8_t protocol, u_int16_t cpi,
+ host_t *src, host_t *dst,
+ host_t *new_src, host_t *new_dst,
+ bool encap, bool new_encap, mark_t mark);
+
+ /**
* Delete a previously added SA
*
* @param spi SPI of the SA
diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk
index 4912576df..9c7ef1d0a 100644
--- a/src/libstrongswan/Android.mk
+++ b/src/libstrongswan/Android.mk
@@ -3,8 +3,8 @@ include $(CLEAR_VARS)
# copy-n-paste from Makefile.am
LOCAL_SRC_FILES := \
-library.c chunk.c debug.c enum.c settings.c printf_hook.c asn1/asn1.c \
-asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
+library.c chunk.c debug.c enum.c host_resolver.c settings.c printf_hook.c \
+asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
crypto/crypters/crypter.c crypto/hashers/hasher.c crypto/pkcs7.c crypto/pkcs9.c \
crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
crypto/prfs/prf.c crypto/prfs/mac_prf.c \
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index 463d57d95..4017bfcc2 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -1,8 +1,8 @@
ipseclib_LTLIBRARIES = libstrongswan.la
libstrongswan_la_SOURCES = \
-library.c chunk.c debug.c enum.c settings.c printf_hook.c asn1/asn1.c \
-asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
+library.c chunk.c debug.c enum.c host_resolver.c settings.c printf_hook.c \
+asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
crypto/crypters/crypter.c crypto/hashers/hasher.c crypto/pkcs7.c crypto/pkcs9.c \
crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
crypto/prfs/prf.c crypto/prfs/mac_prf.c \
@@ -31,7 +31,7 @@ utils/optionsfrom.c utils/capabilities.c utils/backtrace.c utils/tun_device.c
if USE_DEV_HEADERS
strongswan_includedir = ${dev_headers}
nobase_strongswan_include_HEADERS = \
-library.h chunk.h debug.h enum.h settings.h printf_hook.h \
+library.h chunk.h debug.h enum.h host_resolver.h settings.h printf_hook.h \
asn1/asn1.h asn1/asn1_parser.h asn1/oid.h bio/bio_reader.h bio/bio_writer.h \
crypto/crypters/crypter.h crypto/hashers/hasher.h crypto/mac.h \
crypto/pkcs7.h crypto/pkcs9.h crypto/proposal/proposal_keywords.h \
diff --git a/src/libstrongswan/host_resolver.c b/src/libstrongswan/host_resolver.c
new file mode 100644
index 000000000..55b07d318
--- /dev/null
+++ b/src/libstrongswan/host_resolver.c
@@ -0,0 +1,391 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "host_resolver.h"
+
+#include <debug.h>
+#include <library.h>
+#include <threading/condvar.h>
+#include <threading/mutex.h>
+#include <threading/thread.h>
+#include <utils/hashtable.h>
+#include <utils/linked_list.h>
+
+/**
+ * Default minimum and maximum number of threads
+ */
+#define MIN_THREADS_DEFAULT 0
+#define MAX_THREADS_DEFAULT 3
+
+/**
+ * Timeout in seconds to wait for new queries until a thread may be stopped
+ */
+#define NEW_QUERY_WAIT_TIMEOUT 30
+
+typedef struct private_host_resolver_t private_host_resolver_t;
+
+/**
+ * Private data of host_resolver_t
+ */
+struct private_host_resolver_t {
+
+ /**
+ * Public interface
+ */
+ host_resolver_t public;
+
+ /**
+ * Hashtable to check for queued queries, query_t*
+ */
+ hashtable_t *queries;
+
+ /**
+ * Queue for queries, query_t*
+ */
+ linked_list_t *queue;
+
+ /**
+ * Mutex to safely access private data
+ */
+ mutex_t *mutex;
+
+ /**
+ * Condvar to signal arrival of new queries
+ */
+ condvar_t *new_query;
+
+ /**
+ * Minimum number of resolver threads
+ */
+ u_int min_threads;
+
+ /**
+ * Maximum number of resolver threads
+ */
+ u_int max_threads;
+
+ /**
+ * Current number of threads
+ */
+ u_int threads;
+
+ /**
+ * Current number of busy threads
+ */
+ u_int busy_threads;
+
+ /**
+ * Pool of threads, thread_t*
+ */
+ linked_list_t *pool;
+
+ /**
+ * TRUE if no new queries are accepted
+ */
+ bool disabled;
+
+};
+
+typedef struct {
+ /** DNS name we are looking for */
+ char *name;
+ /** address family we request */
+ int family;
+ /** Condvar to signal completion of a query */
+ condvar_t *done;
+ /** refcount */
+ refcount_t refcount;
+ /** the result if successful */
+ host_t *result;
+} query_t;
+
+/**
+ * Destroy the given query_t object if refcount is zero
+ */
+static void query_destroy(query_t *this)
+{
+ if (ref_put(&this->refcount))
+ {
+ DESTROY_IF(this->result);
+ this->done->destroy(this->done);
+ free(this->name);
+ free(this);
+ }
+}
+
+/**
+ * Signals all waiting threads and destroys the query
+ */
+static void query_signal_and_destroy(query_t *this)
+{
+ this->done->broadcast(this->done);
+ query_destroy(this);
+}
+
+/**
+ * Hash a queued query
+ */
+static u_int query_hash(query_t *this)
+{
+ return chunk_hash_inc(chunk_create(this->name, strlen(this->name)),
+ chunk_hash(chunk_from_thing(this->family)));
+}
+
+/**
+ * Compare two queued queries
+ */
+static bool query_equals(query_t *this, query_t *other)
+{
+ return this->family == other->family && streq(this->name, other->name);
+}
+
+/**
+ * Main function of resolver threads
+ */
+static void *resolve_hosts(private_host_resolver_t *this)
+{
+ struct addrinfo hints, *result;
+ query_t *query;
+ int error;
+ bool old, timed_out;
+
+ while (TRUE)
+ {
+ this->mutex->lock(this->mutex);
+ thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
+ while (this->queue->remove_first(this->queue,
+ (void**)&query) != SUCCESS)
+ {
+ old = thread_cancelability(TRUE);
+ timed_out = this->new_query->timed_wait(this->new_query,
+ this->mutex, NEW_QUERY_WAIT_TIMEOUT * 1000);
+ thread_cancelability(old);
+ if (this->disabled)
+ {
+ thread_cleanup_pop(TRUE);
+ return NULL;
+ }
+ else if (timed_out && (this->threads > this->min_threads))
+ { /* terminate this thread by detaching it */
+ thread_t *thread = thread_current();
+
+ this->threads--;
+ this->pool->remove(this->pool, thread, NULL);
+ thread_cleanup_pop(TRUE);
+ thread->detach(thread);
+ return NULL;
+ }
+ }
+ this->busy_threads++;
+ thread_cleanup_pop(TRUE);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = query->family;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ thread_cleanup_push((thread_cleanup_t)query_signal_and_destroy, query);
+ old = thread_cancelability(TRUE);
+ error = getaddrinfo(query->name, NULL, &hints, &result);
+ thread_cancelability(old);
+ thread_cleanup_pop(FALSE);
+
+ this->mutex->lock(this->mutex);
+ this->busy_threads--;
+ if (error != 0)
+ {
+ DBG1(DBG_LIB, "resolving '%s' failed: %s", query->name,
+ gai_strerror(error));
+ }
+ else
+ { /* result is a linked list, but we use only the first address */
+ query->result = host_create_from_sockaddr(result->ai_addr);
+ freeaddrinfo(result);
+ }
+ this->queries->remove(this->queries, query);
+ query->done->broadcast(query->done);
+ this->mutex->unlock(this->mutex);
+ query_destroy(query);
+ }
+ return NULL;
+}
+
+/**
+ * Try to convert IP addresses directly
+ */
+static host_t *try_numeric_lookup(char *name, int family)
+{
+ struct addrinfo hints, *result;
+ int error;
+ host_t *host;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ error = getaddrinfo(name, NULL, &hints, &result);
+ if (error != 0)
+ { /* not an IP address */
+ return NULL;
+ }
+ else
+ { /* result is a linked list, but we use only the first address */
+ host = host_create_from_sockaddr(result->ai_addr);
+ freeaddrinfo(result);
+ }
+ return host;
+}
+
+METHOD(host_resolver_t, resolve, host_t*,
+ private_host_resolver_t *this, char *name, int family)
+{
+ query_t *query, lookup = {
+ .name = name,
+ .family = family,
+ };
+ host_t *result;
+
+ if (streq(name, "%any") || streq(name, "0.0.0.0"))
+ {
+ return host_create_any(family ? family : AF_INET);
+ }
+ if (streq(name, "%any6") || streq(name, "::"))
+ {
+ return host_create_any(family ? family : AF_INET6);
+ }
+ if (family == AF_INET && strchr(name, ':'))
+ { /* do not try to convert v6 addresses for v4 family */
+ return NULL;
+ }
+ result = try_numeric_lookup(name, family);
+ if (result)
+ { /* shortcut for numeric IP addresses */
+ return result;
+ }
+ this->mutex->lock(this->mutex);
+ if (this->disabled)
+ {
+ this->mutex->unlock(this->mutex);
+ return NULL;
+ }
+ query = this->queries->get(this->queries, &lookup);
+ if (!query)
+ {
+ INIT(query,
+ .name = strdup(name),
+ .family = family,
+ .done = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .refcount = 1,
+ );
+ this->queries->put(this->queries, query, query);
+ this->queue->insert_last(this->queue, query);
+ this->new_query->signal(this->new_query);
+ }
+ ref_get(&query->refcount);
+ if (this->busy_threads == this->threads &&
+ this->threads < this->max_threads)
+ {
+ thread_t *thread;
+
+ thread = thread_create((thread_main_t)resolve_hosts, this);
+ if (thread)
+ {
+ this->threads++;
+ this->pool->insert_last(this->pool, thread);
+ }
+ }
+ query->done->wait(query->done, this->mutex);
+ this->mutex->unlock(this->mutex);
+
+ result = query->result ? query->result->clone(query->result) : NULL;
+ query_destroy(query);
+ return result;
+}
+
+METHOD(host_resolver_t, flush, void,
+ private_host_resolver_t *this)
+{
+ enumerator_t *enumerator;
+ query_t *query;
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->queries->create_enumerator(this->queries);
+ while (enumerator->enumerate(enumerator, &query, NULL))
+ { /* use the hashtable here as we also want to signal dequeued queries */
+ this->queries->remove_at(this->queries, enumerator);
+ query->done->broadcast(query->done);
+ }
+ enumerator->destroy(enumerator);
+ this->queue->destroy_function(this->queue, (void*)query_destroy);
+ this->queue = linked_list_create();
+ this->disabled = TRUE;
+ /* this will already terminate most idle threads */
+ this->new_query->broadcast(this->new_query);
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(host_resolver_t, destroy, void,
+ private_host_resolver_t *this)
+{
+ thread_t *thread;
+
+ flush(this);
+ this->pool->invoke_offset(this->pool, offsetof(thread_t, cancel));
+ while (this->pool->remove_first(this->pool, (void**)&thread) == SUCCESS)
+ {
+ thread->join(thread);
+ }
+ this->pool->destroy(this->pool);
+ this->queue->destroy(this->queue);
+ this->queries->destroy(this->queries);
+ this->new_query->destroy(this->new_query);
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+host_resolver_t *host_resolver_create()
+{
+ private_host_resolver_t *this;
+
+ INIT(this,
+ .public = {
+ .resolve = _resolve,
+ .flush = _flush,
+ .destroy = _destroy,
+ },
+ .queries = hashtable_create((hashtable_hash_t)query_hash,
+ (hashtable_equals_t)query_equals, 8),
+ .queue = linked_list_create(),
+ .pool = linked_list_create(),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .new_query = condvar_create(CONDVAR_TYPE_DEFAULT),
+ );
+
+ this->min_threads = max(0, lib->settings->get_int(lib->settings,
+ "libstrongswan.host_resolver.min_threads",
+ MIN_THREADS_DEFAULT));
+ this->max_threads = max(this->min_threads ?: 1,
+ lib->settings->get_int(lib->settings,
+ "libstrongswan.host_resolver.max_threads",
+ MAX_THREADS_DEFAULT));
+ return &this->public;
+}
diff --git a/src/libstrongswan/host_resolver.h b/src/libstrongswan/host_resolver.h
new file mode 100644
index 000000000..f7b8c7e9f
--- /dev/null
+++ b/src/libstrongswan/host_resolver.h
@@ -0,0 +1,60 @@
+/*
+ * 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 host_resolver host_resolver
+ * @{ @ingroup libstrongswan
+ */
+
+#ifndef HOST_RESOLVER_H_
+#define HOST_RESOLVER_H_
+
+#include "utils/host.h"
+
+typedef struct host_resolver_t host_resolver_t;
+
+/**
+ * Resolve hosts by DNS name but do so in a separate thread (calling
+ * getaddrinfo(3) directly might block indefinitely, or at least a very long
+ * time if no DNS servers are reachable).
+ */
+struct host_resolver_t {
+
+ /**
+ * Resolve host from the given DNS name.
+ *
+ * @param name name to lookup
+ * @param family requested address family
+ * @return resolved host or NULL if failed or canceled
+ */
+ host_t *(*resolve)(host_resolver_t *this, char *name, int family);
+
+ /**
+ * Flush the queue of queries. No new queries will be accepted afterwards.
+ */
+ void (*flush)(host_resolver_t *this);
+
+ /**
+ * Destroy a host_resolver_t.
+ */
+ void (*destroy)(host_resolver_t *this);
+};
+
+/**
+ * Create a host_resolver_t instance.
+ */
+host_resolver_t *host_resolver_create();
+
+#endif /** HOST_RESOLVER_H_ @}*/
diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c
index 1179b468c..a42d68cbc 100644
--- a/src/libstrongswan/library.c
+++ b/src/libstrongswan/library.c
@@ -68,6 +68,7 @@ void library_deinit()
this->public.scheduler->destroy(this->public.scheduler);
this->public.processor->destroy(this->public.processor);
this->public.plugins->destroy(this->public.plugins);
+ this->public.hosts->destroy(this->public.hosts);
this->public.settings->destroy(this->public.settings);
this->public.credmgr->destroy(this->public.credmgr);
this->public.creds->destroy(this->public.creds);
@@ -183,6 +184,7 @@ bool library_init(char *settings)
this->objects = hashtable_create((hashtable_hash_t)hash,
(hashtable_equals_t)equals, 4);
this->public.settings = settings_create(settings);
+ this->public.hosts = host_resolver_create();
this->public.proposal = proposal_keywords_create();
this->public.crypto = crypto_factory_create();
this->public.creds = credential_factory_create();
diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h
index b79bd91be..5bd0d67eb 100644
--- a/src/libstrongswan/library.h
+++ b/src/libstrongswan/library.h
@@ -77,6 +77,7 @@
#include "printf_hook.h"
#include "utils.h"
#include "chunk.h"
+#include "host_resolver.h"
#include "settings.h"
#include "integrity_checker.h"
#include "processing/processor.h"
@@ -171,6 +172,11 @@ struct library_t {
scheduler_t *scheduler;
/**
+ * resolve hosts by DNS name
+ */
+ host_resolver_t *hosts;
+
+ /**
* various settings loaded from settings file
*/
settings_t *settings;
diff --git a/src/libstrongswan/threading/mutex.c b/src/libstrongswan/threading/mutex.c
index 2ef918a28..df0cd27bf 100644
--- a/src/libstrongswan/threading/mutex.c
+++ b/src/libstrongswan/threading/mutex.c
@@ -282,13 +282,7 @@ METHOD(condvar_t, timed_wait, bool,
ms = timeout % 1000;
tv.tv_sec += s;
- tv.tv_usec += ms * 1000;
-
- if (tv.tv_usec > 1000000 /* 1s */)
- {
- tv.tv_usec -= 1000000;
- tv.tv_sec++;
- }
+ timeval_add_ms(&tv, ms);
return timed_wait_abs(this, mutex, tv);
}
diff --git a/src/libstrongswan/threading/rwlock.c b/src/libstrongswan/threading/rwlock.c
index 7097a8e8c..9ce9c6a71 100644
--- a/src/libstrongswan/threading/rwlock.c
+++ b/src/libstrongswan/threading/rwlock.c
@@ -433,13 +433,8 @@ METHOD(rwlock_condvar_t, timed_wait, bool,
ms = timeout % 1000;
tv.tv_sec += s;
- tv.tv_usec += ms * 1000;
+ timeval_add_ms(&tv, ms);
- if (tv.tv_usec > 1000000 /* 1s */)
- {
- tv.tv_usec -= 1000000;
- tv.tv_sec++;
- }
return timed_wait_abs(this, lock, tv);
}
diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h
index f47c65ac1..4e2065f63 100644
--- a/src/libstrongswan/utils.h
+++ b/src/libstrongswan/utils.h
@@ -455,6 +455,22 @@ void closefrom(int lowfd);
time_t time_monotonic(timeval_t *tv);
/**
+ * Add the given number of milliseconds to the given timeval struct
+ *
+ * @param tv timeval struct to modify
+ * @param ms number of milliseconds
+ */
+static inline void timeval_add_ms(timeval_t *tv, u_int ms)
+{
+ tv->tv_usec += ms * 1000;
+ while (tv->tv_usec > 1000000 /* 1s */)
+ {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+}
+
+/**
* returns null
*/
void *return_null();
diff --git a/src/libstrongswan/utils/host.c b/src/libstrongswan/utils/host.c
index e17b6ad02..1d0614001 100644
--- a/src/libstrongswan/utils/host.c
+++ b/src/libstrongswan/utils/host.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2009 Tobias Brunner
+ * Copyright (C) 2006-2012 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -16,14 +16,10 @@
* for more details.
*/
-#define _GNU_SOURCE
-#include <sys/socket.h>
-#include <netdb.h>
-#include <string.h>
-
#include "host.h"
#include <debug.h>
+#include <library.h>
#define IPV4_LEN 4
#define IPV6_LEN 16
@@ -450,48 +446,14 @@ host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
*/
host_t *host_create_from_dns(char *string, int af, u_int16_t port)
{
- private_host_t *this;
- struct addrinfo hints, *result;
- int error;
-
- if (streq(string, "%any"))
- {
- return host_create_any_port(af ? af : AF_INET, port);
- }
- if (streq(string, "%any6"))
- {
- return host_create_any_port(af ? af : AF_INET6, port);
- }
- if (af == AF_INET && strchr(string, ':'))
- { /* do not try to convert v6 addresses for v4 family */
- return NULL;
- }
+ host_t *this;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = af;
- error = getaddrinfo(string, NULL, &hints, &result);
- if (error != 0)
- {
- DBG1(DBG_LIB, "resolving '%s' failed: %s", string, gai_strerror(error));
- return NULL;
- }
- /* result is a linked list, but we use only the first address */
- this = (private_host_t*)host_create_from_sockaddr(result->ai_addr);
- freeaddrinfo(result);
+ this = lib->hosts->resolve(lib->hosts, string, af);
if (this)
{
- switch (this->address.sa_family)
- {
- case AF_INET:
- this->address4.sin_port = htons(port);
- break;
- case AF_INET6:
- this->address6.sin6_port = htons(port);
- break;
- }
- return &this->public;
+ this->set_port(this, port);
}
- return NULL;
+ return this;
}
/*