aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2007-06-25 13:26:02 +0000
committerMartin Willi <martin@strongswan.org>2007-06-25 13:26:02 +0000
commit4cb9d7a758751dfe658258bdf39671491ef29cc7 (patch)
tree45ec8cc6d10116bb3b83865bcf8b18d5f46db914 /src
parent3f946e1c90d26811a580d8d81f85fd2a77c3267d (diff)
downloadstrongswan-4cb9d7a758751dfe658258bdf39671491ef29cc7.tar.bz2
strongswan-4cb9d7a758751dfe658258bdf39671491ef29cc7.tar.xz
further fixed for mobike roaming
Diffstat (limited to 'src')
-rw-r--r--src/charon/daemon.c3
-rw-r--r--src/charon/encoding/payloads/notify_payload.c8
-rw-r--r--src/charon/encoding/payloads/notify_payload.h2
-rw-r--r--src/charon/kernel/kernel_interface.c32
-rw-r--r--src/charon/sa/ike_sa.c33
-rw-r--r--src/charon/sa/ike_sa_manager.c1
-rw-r--r--src/charon/sa/task_manager.c63
-rw-r--r--src/charon/sa/tasks/ike_mobike.c51
8 files changed, 153 insertions, 40 deletions
diff --git a/src/charon/daemon.c b/src/charon/daemon.c
index 088bbf63b..37699f83f 100644
--- a/src/charon/daemon.c
+++ b/src/charon/daemon.c
@@ -381,6 +381,9 @@ private_daemon_t *daemon_create(void)
sigaddset(&action.sa_mask, SIGHUP);
sigaction(SIGSEGV, &action, NULL);
sigaction(SIGILL, &action, NULL);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
pthread_sigmask(SIG_SETMASK, &action.sa_mask, 0);
return this;
diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c
index ca92fc1bf..d700965d6 100644
--- a/src/charon/encoding/payloads/notify_payload.c
+++ b/src/charon/encoding/payloads/notify_payload.c
@@ -47,14 +47,16 @@ ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL
"INVALID_KE_PAYLOAD");
ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
"AUTHENTICATION_FAILED");
-ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, INVALID_SELECTORS, AUTHENTICATION_FAILED,
+ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTHENTICATION_FAILED,
"SINGLE_PAIR_REQUIRED",
"NO_ADDITIONAL_SAS",
"INTERNAL_ADDRESS_FAILURE",
"FAILED_CP_REQUIRED",
"TS_UNACCEPTABLE",
- "INVALID_SELECTORS");
-ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, INVALID_SELECTORS,
+ "INVALID_SELECTORS",
+ "UNACCEPTABLE_ADDRESSES",
+ "UNEXPECTED_NAT_DETECTED");
+ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED,
"INITIAL_CONTACT",
"SET_WINDOW_SIZE",
"ADDITIONAL_TS_POSSIBLE",
diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h
index 431932631..ca1fe3a96 100644
--- a/src/charon/encoding/payloads/notify_payload.h
+++ b/src/charon/encoding/payloads/notify_payload.h
@@ -65,6 +65,8 @@ enum notify_type_t {
FAILED_CP_REQUIRED = 37,
TS_UNACCEPTABLE = 38,
INVALID_SELECTORS = 39,
+ UNACCEPTABLE_ADDRESSES = 40,
+ UNEXPECTED_NAT_DETECTED = 41,
/* notify status messages */
INITIAL_CONTACT = 16384,
SET_WINDOW_SIZE = 16385,
diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c
index 9847f30a3..bf5479bfe 100644
--- a/src/charon/kernel/kernel_interface.c
+++ b/src/charon/kernel/kernel_interface.c
@@ -228,6 +228,9 @@ struct addr_entry_t {
/** The ip address */
host_t *ip;
+ /** virtual IP managed by us */
+ bool virtual;
+
/** Number of times this IP is used, if virtual */
u_int refcount;
};
@@ -690,6 +693,7 @@ static void process_addr(private_kernel_interface_t *this,
found = TRUE;
addr = malloc_thing(addr_entry_t);
addr->ip = host->clone(host);
+ addr->virtual = FALSE;
addr->refcount = 1;
iface->addrs->insert_last(iface->addrs, addr);
@@ -1070,6 +1074,10 @@ static status_t init_address_list(private_kernel_interface_t *this)
static hook_result_t addr_hook(private_kernel_interface_t *this,
addr_entry_t *in, host_t **out)
{
+ if (in->virtual)
+ { /* skip virtual interfaces added by us */
+ return HOOK_SKIP;
+ }
*out = in->ip;
return HOOK_NEXT;
}
@@ -1107,6 +1115,11 @@ static iterator_t *create_address_iterator(private_kernel_interface_t *this)
{
iterator_t *iterator;
+ /* This iterator is not only hooked, is is double-hooked. As we have stored
+ * our addresses in iface_entry->addr_entry->ip, we need to iterate the
+ * entries in each interface we iterate. This does the iface_hook. The
+ * addr_hook returns the ip instead of the addr_entry. */
+
iterator = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
iterator->set_iterator_hook(iterator, (iterator_hook_t*)iface_hook, this);
return iterator;
@@ -1368,6 +1381,8 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest)
size_t len;
host_t *source = NULL;
+ DBG2(DBG_KNL, "getting source address to reach %H", dest);
+
memset(&request, 0, sizeof(request));
hdr = (struct nlmsghdr*)request;
@@ -1378,10 +1393,10 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest)
msg = (struct rtmsg*)NLMSG_DATA(hdr);
msg->rtm_family = dest->get_family(dest);
msg->rtm_dst_len = msg->rtm_family == AF_INET ? 32 : 128;
- msg->rtm_table = RT_TABLE_MAIN;
- msg->rtm_protocol = RTPROT_STATIC;
+ msg->rtm_table = RT_TABLE_UNSPEC;
+ msg->rtm_protocol = RTPROT_UNSPEC;
msg->rtm_type = RTN_UNICAST;
- msg->rtm_scope = RT_SCOPE_UNIVERSE;
+ msg->rtm_scope = RT_SCOPE_HOST;
chunk = dest->get_address(dest);
add_attribute(hdr, RTA_DST, chunk, sizeof(request));
@@ -1427,12 +1442,13 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest)
}
break;
}
- if (source == NULL)
+ free(out);
+ if (source)
{
- DBG2(DBG_KNL, "no route found to %H", dest);
+ return source;
}
- free(out);
- return source;
+ DBG2(DBG_KNL, "no route found to %H", dest);
+ return NULL;
}
/**
@@ -1481,6 +1497,7 @@ static status_t add_ip(private_kernel_interface_t *this,
addr = malloc_thing(addr_entry_t);
addr->ip = virtual_ip->clone(virtual_ip);
addr->refcount = 1;
+ addr->virtual = TRUE;
pthread_mutex_lock(&this->mutex);
iface->addrs->insert_last(iface->addrs, addr);
pthread_mutex_unlock(&this->mutex);
@@ -2298,7 +2315,6 @@ kernel_interface_t *kernel_interface_create()
private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t);
struct sockaddr_nl addr;
-
/* public functions */
this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,mode_t,bool))add_sa;
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index 00f95960a..5406cb70e 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -1681,7 +1681,13 @@ static status_t roam(private_ike_sa_t *this)
}
me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
- this->other_host);
+ this->other_host);
+ if (me && me->ip_equals(me, this->my_virtual_ip))
+ { /* do not roam to the virtual IP of this IKE_SA */
+ me->destroy(me);
+ me = NULL;
+ }
+
if (me)
{
set_condition(this, COND_STALE, FALSE);
@@ -1695,12 +1701,8 @@ static status_t roam(private_ike_sa_t *this)
}
me->set_port(me, this->my_host->get_port(this->my_host));
-#ifndef MOBIKE
- set_my_host(this, me);
- return reestablish(this);
-#endif
/* our attachement changed, update if we have mobike */
- if (this->extensions & EXT_MOBIKE)
+ if (supports_extension(this, EXT_MOBIKE))
{
mobike = ike_mobike_create(&this->public, TRUE);
mobike->roam(mobike, me, NULL);
@@ -1713,15 +1715,11 @@ static status_t roam(private_ike_sa_t *this)
}
/* there is nothing we can do without mobike */
- if (!(this->extensions & EXT_MOBIKE))
+ if (!supports_extension(this, EXT_MOBIKE))
{
set_condition(this, COND_STALE, TRUE);
return FAILED;
}
-#ifndef MOBIKE
- set_condition(this, COND_STALE, TRUE);
- return FAILED;
-#endif
/* we are unable to reach the peer. Try an alternative address */
iterator = create_additional_address_iterator(this);
@@ -1729,10 +1727,18 @@ static status_t roam(private_ike_sa_t *this)
{
me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
other);
+ if (me && me->ip_equals(me, this->my_virtual_ip))
+ { /* do not roam to the virtual IP of this IKE_SA */
+ me->destroy(me);
+ me = NULL;
+ }
+
if (me)
{
/* good, we have a new route. Use MOBIKE to update */
iterator->destroy(iterator);
+ me->set_port(me, this->my_host->get_port(this->my_host));
+ other->set_port(other, this->other_host->get_port(this->other_host));
mobike = ike_mobike_create(&this->public, TRUE);
mobike->roam(mobike, me, other);
this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
@@ -1740,7 +1746,10 @@ static status_t roam(private_ike_sa_t *this)
}
}
iterator->destroy(iterator);
- return SUCCESS;
+
+ /* no route found to host, give up (temporary) */
+ set_condition(this, COND_STALE, TRUE);
+ return FAILED;
}
/**
diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
index bc9094023..0a0d5e5cf 100644
--- a/src/charon/sa/ike_sa_manager.c
+++ b/src/charon/sa/ike_sa_manager.c
@@ -701,6 +701,7 @@ static iterator_t *create_iterator(private_ike_sa_manager_t* this)
{
iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
this->ike_sa_list, &this->mutex);
+
/* register hook to iterator over ike_sas, not entries */
iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
return iterator;
diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c
index 84ce1fb54..fc2a13061 100644
--- a/src/charon/sa/task_manager.c
+++ b/src/charon/sa/task_manager.c
@@ -314,6 +314,11 @@ static status_t build_request(private_task_manager_t *this)
exchange = INFORMATIONAL;
break;
}
+ if (activate_task(this, IKE_MOBIKE))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
if (activate_task(this, IKE_DPD))
{
exchange = INFORMATIONAL;
@@ -592,6 +597,7 @@ static status_t process_request(private_task_manager_t *this,
exchange_type_t exchange;
payload_t *payload;
notify_payload_t *notify;
+ delete_payload_t *delete;
exchange = message->get_exchange_type(message);
@@ -669,27 +675,56 @@ static status_t process_request(private_task_manager_t *this,
}
case INFORMATIONAL:
{
- delete_payload_t *delete;
-
- delete = (delete_payload_t*)message->get_payload(message, DELETE);
- if (delete)
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
{
- if (delete->get_protocol_id(delete) == PROTO_IKE)
- {
- task = (task_t*)ike_delete_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
- }
- else
+ switch (payload->get_type(payload))
{
- task = (task_t*)child_delete_create(this->ike_sa, NULL);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ case NOTIFY:
+ {
+ notify = (notify_payload_t*)payload;
+ switch (notify->get_notify_type(notify))
+ {
+ case ADDITIONAL_IP4_ADDRESS:
+ case ADDITIONAL_IP6_ADDRESS:
+ case NO_ADDITIONAL_ADDRESSES:
+ case UPDATE_SA_ADDRESSES:
+ case NO_NATS_ALLOWED:
+ case UNACCEPTABLE_ADDRESSES:
+ case UNEXPECTED_NAT_DETECTED:
+ case COOKIE2:
+ task = (task_t*)ike_mobike_create(this->ike_sa,
+ FALSE);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case DELETE:
+ {
+ delete = (delete_payload_t*)payload;
+ if (delete->get_protocol_id(delete) == PROTO_IKE)
+ {
+ task = (task_t*)ike_delete_create(this->ike_sa, FALSE);
+ }
+ else
+ {
+ task = (task_t*)child_delete_create(this->ike_sa, NULL);
+ }
+ break;
+ }
+ default:
+ break;
}
}
- else
+ iterator->destroy(iterator);
+
+ if (task == NULL)
{
task = (task_t*)ike_dpd_create(FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
}
+ this->passive_tasks->insert_last(this->passive_tasks, task);
break;
}
default:
diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c
index 0b3bd072b..a7f5fb6d6 100644
--- a/src/charon/sa/tasks/ike_mobike.c
+++ b/src/charon/sa/tasks/ike_mobike.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <daemon.h>
+#include <sa/tasks/ike_natd.h>
#include <encoding/payloads/notify_payload.h>
@@ -59,6 +60,16 @@ struct private_ike_mobike_t {
* remote host to roam to
*/
host_t *other;
+
+ /**
+ * cookie2 value to verify new addresses
+ */
+ chunk_t cookie2;
+
+ /**
+ * NAT discovery reusing the IKE_NATD task
+ */
+ ike_natd_t *natd;
};
/**
@@ -119,6 +130,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message)
if (first)
{ /* an ADDITIONAL_*_ADDRESS means replace, so flush once */
flush_additional_addresses(this);
+ first = FALSE;
}
data = notify->get_notification_data(notify);
host = host_create_from_chunk(family, data, 0);
@@ -185,10 +197,26 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_AUTH &&
message->get_payload(message, SECURITY_ASSOCIATION))
- {
+ {
message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty);
build_address_list(this, message);
}
+ else if (this->me || this->other)
+ { /* address change */
+ message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty);
+ build_address_list(this, message);
+ /* TODO: NAT discovery */
+
+ /* set new addresses */
+ if (this->me)
+ {
+ this->ike_sa->set_my_host(this->ike_sa, this->me->clone(this->me));
+ }
+ if (this->other)
+ {
+ this->ike_sa->set_other_host(this->ike_sa, this->other->clone(this->other));
+ }
+ }
return NEED_MORE;
}
@@ -197,8 +225,13 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message)
* Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_mobike_t *this, message_t *message)
-{
- process_payloads(this, message);
+{
+ if ((message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_payload(message, SECURITY_ASSOCIATION)) ||
+ message->get_exchange_type(message) == INFORMATIONAL)
+ {
+ process_payloads(this, message);
+ }
return NEED_MORE;
}
@@ -259,9 +292,14 @@ static void migrate(private_ike_mobike_t *this, ike_sa_t *ike_sa)
{
DESTROY_IF(this->me);
DESTROY_IF(this->other);
+ chunk_free(&this->cookie2);
this->ike_sa = ike_sa;
this->me = NULL;
this->other = NULL;
+ if (this->natd)
+ {
+ this->natd->task.migrate(&this->natd->task, ike_sa);
+ }
}
/**
@@ -271,6 +309,11 @@ static void destroy(private_ike_mobike_t *this)
{
DESTROY_IF(this->me);
DESTROY_IF(this->other);
+ chunk_free(&this->cookie2);
+ if (this->natd)
+ {
+ this->natd->task.destroy(&this->natd->task);
+ }
free(this);
}
@@ -301,6 +344,8 @@ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator)
this->initiator = initiator;
this->me = NULL;
this->other = NULL;
+ this->cookie2 = chunk_empty;
+ this->natd = NULL;
return &this->public;
}