implemented routeability checks for mobike (experimental)

This commit is contained in:
Martin Willi 2007-09-03 12:37:25 +00:00
parent f5da63e937
commit 5474dc6500
5 changed files with 194 additions and 54 deletions

View File

@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/xfrm.h>
@ -67,6 +68,9 @@
#define PRIO_LOW 3000
#define PRIO_HIGH 2000
/** delay before firing roam jobs (ms) */
#define ROAM_DELAY 100
#define BUFFER_SIZE 1024
/**
@ -344,6 +348,11 @@ struct private_kernel_interface_t {
* Netlink rt socket to receive address change events
*/
int socket_rt_events;
/**
* time of the last roam_job
*/
struct timeval last_roam;
};
/**
@ -527,6 +536,31 @@ static void process_expire(private_kernel_interface_t *this, struct nlmsghdr *hd
charon->processor->queue_job(charon->processor, job);
}
/**
* start a roaming job. We delay it for a second and fire only one job
* for multiple events. Otherwise we would create two many jobs.
*/
static void fire_roam_job(private_kernel_interface_t *this, bool address)
{
struct timeval now;
if (gettimeofday(&now, NULL) == 0)
{
if (timercmp(&now, &this->last_roam, >))
{
now.tv_usec += ROAM_DELAY * 1000;
while (now.tv_usec > 1000000)
{
now.tv_sec++;
now.tv_usec -= 1000000;
}
this->last_roam = now;
charon->scheduler->schedule_job(charon->scheduler,
(job_t*)roam_job_create(address), ROAM_DELAY);
}
}
}
/**
* process RTM_NEWLINK/RTM_DELLINK from kernel
*/
@ -623,8 +657,7 @@ static void process_link(private_kernel_interface_t *this,
/* send an update to all IKE_SAs */
if (update && event)
{
charon->processor->queue_job(charon->processor,
(job_t*)roam_job_create(TRUE));
fire_roam_job(this, TRUE);
}
}
@ -731,8 +764,7 @@ static void process_addr(private_kernel_interface_t *this,
/* send an update to all IKE_SAs */
if (update && event && changed)
{
charon->processor->queue_job(charon->processor,
(job_t*)roam_job_create(TRUE));
fire_roam_job(this, TRUE);
}
}
@ -828,8 +860,7 @@ static job_requeue_t receive_events(private_kernel_interface_t *this)
break;
case RTM_NEWROUTE:
case RTM_DELROUTE:
charon->processor->queue_job(charon->processor,
(job_t*)roam_job_create(FALSE));
fire_roam_job(this, FALSE);
break;
default:
break;
@ -2517,6 +2548,7 @@ kernel_interface_t *kernel_interface_create()
this->hiter = NULL;
this->seq = 200;
pthread_mutex_init(&this->mutex,NULL);
timerclear(&this->last_roam);
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;

View File

@ -812,8 +812,6 @@ static status_t generate_message(private_ike_sa_t *this, message_t *message,
{
this->time.outbound = time(NULL);
message->set_ike_sa_id(message, this->ike_sa_id);
message->set_destination(message, this->other_host->clone(this->other_host));
message->set_source(message, this->my_host->clone(this->my_host));
return message->generate(message, this->crypter_out, this->signer_out, packet);
}
@ -859,7 +857,6 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
if (this->state == IKE_CREATED)
{
if (this->other_host->is_anyaddr(this->other_host))
{
child_cfg->destroy(child_cfg);
@ -1802,30 +1799,19 @@ static status_t roam(private_ike_sa_t *this, bool address)
other = this->other_host;
me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
other);
/* TODO: find a better path using additional addresses of peer */
if (!me)
{
/* no route found to host, set to stale, wait for a new route */
set_condition(this, COND_STALE, TRUE);
return FAILED;
}
set_condition(this, COND_STALE, FALSE);
if (me->ip_equals(me, this->my_host) &&
other->ip_equals(other, this->other_host))
if (me)
{
DBG2(DBG_IKE, "%H still reached through %H, no update needed",
this->other_host, me);
if (me->ip_equals(me, this->my_host) &&
other->ip_equals(other, this->other_host))
{
DBG2(DBG_IKE, "keeping connection path %H - %H", this->other_host, me);
me->destroy(me);
return SUCCESS;
}
me->destroy(me);
return SUCCESS;
}
me->set_port(me, this->my_host->get_port(this->my_host));
other = other->clone(other);
other->set_port(other, this->other_host->get_port(this->other_host));
set_my_host(this, me);
set_other_host(this, other);
/* update addresses with mobike, if supported ... */
if (supports_extension(this, EXT_MOBIKE))

View File

@ -217,6 +217,9 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
{
u_int32_t timeout;
job_t *job;
iterator_t *iterator;
packet_t *packet;
task_t *task;
if (this->initiating.retransmitted <= RETRANSMIT_TRIES)
{
@ -237,8 +240,22 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
}
this->initiating.retransmitted++;
charon->sender->send(charon->sender,
this->initiating.packet->clone(this->initiating.packet));
packet = this->initiating.packet->clone(this->initiating.packet);
/* mobike needs to now when we retransmit, so we call it here */
iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
while (iterator->iterate(iterator, (void*)&task))
{
if (task->get_type(task) == IKE_MOBIKE)
{
ike_mobike_t *mobike = (ike_mobike_t*)task;
mobike->transmit(mobike, packet);
break;
}
}
iterator->destroy(iterator);
charon->sender->send(charon->sender, packet);
job = (job_t*)retransmit_job_create(this->initiating.mid,
this->ike_sa->get_id(this->ike_sa));
charon->scheduler->schedule_job(charon->scheduler, job, timeout);
@ -255,6 +272,7 @@ static status_t build_request(private_task_manager_t *this)
iterator_t *iterator;
task_t *task;
message_t *message;
host_t *me, *other;
status_t status;
exchange_type_t exchange = 0;
@ -372,8 +390,13 @@ static status_t build_request(private_task_manager_t *this)
return SUCCESS;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
message = message_create();
message->set_message_id(message, this->initiating.mid);
message->set_source(message, me->clone(me));
message->set_destination(message, other->clone(other));
message->set_exchange_type(message, exchange);
this->initiating.type = exchange;
this->initiating.retransmitted = 0;
@ -412,7 +435,7 @@ static status_t build_request(private_task_manager_t *this)
* close the SA */
flush(this);
return DESTROY_ME;
}
}
return retransmit(this, this->initiating.mid);
}
@ -523,17 +546,23 @@ static void handle_collisions(private_task_manager_t *this, task_t *task)
/**
* build a response depending on the "passive" task list
*/
static status_t build_response(private_task_manager_t *this,
exchange_type_t exchange)
static status_t build_response(private_task_manager_t *this, message_t *request)
{
iterator_t *iterator;
task_t *task;
message_t *message;
host_t *me, *other;
bool delete = FALSE;
status_t status;
me = request->get_destination(request);
other = request->get_source(request);
message = message_create();
message->set_exchange_type(message, exchange);
message->set_exchange_type(message, request->get_exchange_type(request));
/* send response along the path the request came in */
message->set_source(message, me->clone(me));
message->set_destination(message, other->clone(other));
message->set_message_id(message, this->responding.mid);
message->set_request(message, FALSE);
@ -563,7 +592,7 @@ static status_t build_response(private_task_manager_t *this,
iterator->destroy(iterator);
/* remove resonder SPI if IKE_SA_INIT failed */
if (delete && exchange == IKE_SA_INIT)
if (delete && request->get_exchange_type(request) == IKE_SA_INIT)
{
ike_sa_id_t *id = this->ike_sa->get_id(this->ike_sa);
id->set_responder_spi(id, 0);
@ -596,15 +625,12 @@ static status_t process_request(private_task_manager_t *this,
{
iterator_t *iterator;
task_t *task = NULL;
exchange_type_t exchange;
payload_t *payload;
notify_payload_t *notify;
delete_payload_t *delete;
exchange = message->get_exchange_type(message);
/* create tasks depending on request type */
switch (exchange)
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
{
@ -760,7 +786,7 @@ static status_t process_request(private_task_manager_t *this,
}
iterator->destroy(iterator);
return build_response(this, exchange);
return build_response(this, message);
}
/**

View File

@ -64,7 +64,12 @@ struct private_ike_mobike_t {
/**
* use task to update addresses
*/
bool roam;
bool update;
/**
* do routability check
*/
bool check;
/**
* include address list update
@ -140,7 +145,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message)
}
case UPDATE_SA_ADDRESSES:
{
this->roam = TRUE;
this->update = TRUE;
break;
}
case NO_ADDITIONAL_ADDRESSES:
@ -224,6 +229,54 @@ static void update_children(private_ike_mobike_t *this)
iterator->destroy(iterator);
}
/**
* Implementation of ike_mobike_t.transmit
*/
static void transmit(private_ike_mobike_t *this, packet_t *packet)
{
host_t *me, *other, *me_old, *other_old;
iterator_t *iterator;
packet_t *copy;
if (!this->check)
{
return;
}
me_old = this->ike_sa->get_my_host(this->ike_sa);
other_old = this->ike_sa->get_other_host(this->ike_sa);
me = charon->kernel_interface->get_source_addr(
charon->kernel_interface, other_old);
if (me)
{
me->set_port(me, me->ip_equals(me, me_old) ?
me_old->get_port(me_old) : IKEV2_NATT_PORT);
packet->set_source(packet, me);
}
iterator = this->ike_sa->create_additional_address_iterator(this->ike_sa);
while (iterator->iterate(iterator, (void**)&other))
{
me = charon->kernel_interface->get_source_addr(
charon->kernel_interface, other);
if (me)
{
/* reuse port for an active address, 4500 otherwise */
me->set_port(me, me->ip_equals(me, me_old) ?
me_old->get_port(me_old) : IKEV2_NATT_PORT);
other = other->clone(other);
other->set_port(other, other->ip_equals(other, other_old) ?
other_old->get_port(other_old) : IKEV2_NATT_PORT);
copy = packet->clone(packet);
copy->set_source(copy, me);
copy->set_destination(copy, other);
charon->sender->send(charon->sender, copy);
}
}
iterator->destroy(iterator);
}
/**
* Implementation of task_t.process for initiator
*/
@ -237,20 +290,20 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message)
}
else if (message->get_exchange_type(message) == INFORMATIONAL)
{
if (this->roam)
if (this->update)
{
message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty);
update_children(this);
}
if (this->address)
{
build_address_list(this, message);
}
this->natd = ike_natd_create(this->ike_sa, this->initiator);
this->natd->task.build(&this->natd->task, message);
update_children(this);
if (this->natd)
{
this->natd->task.build(&this->natd->task, message);
}
}
return NEED_MORE;
}
@ -267,7 +320,7 @@ static status_t process_r(private_ike_mobike_t *this, message_t *message)
else if (message->get_exchange_type(message) == INFORMATIONAL)
{
process_payloads(this, message);
if (this->roam)
if (this->update)
{
host_t *me, *other;
@ -306,7 +359,7 @@ static status_t build_r(private_ike_mobike_t *this, message_t *message)
{
this->natd->task.build(&this->natd->task, message);
}
if (this->roam)
if (this->update)
{
update_children(this);
}
@ -324,7 +377,6 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message)
message->get_payload(message, SECURITY_ASSOCIATION))
{
process_payloads(this, message);
return SUCCESS;
}
else if (message->get_exchange_type(message) == INFORMATIONAL)
@ -341,11 +393,39 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message)
{
this->natd->task.process(&this->natd->task, message);
}
if (this->roam)
if (this->update)
{
/* update again, as NAT state may have changed */
update_children(this);
}
if (this->check)
{
host_t *me_new, *me_old, *other_new, *other_old;
me_new = message->get_destination(message);
other_new = message->get_source(message);
me_old = this->ike_sa->get_my_host(this->ike_sa);
other_old = this->ike_sa->get_other_host(this->ike_sa);
if (!me_new->equals(me_new, me_old))
{
this->update = TRUE;
this->ike_sa->set_my_host(this->ike_sa, me_new->clone(me_new));
}
if (!other_new->equals(other_new, other_old))
{
this->update = TRUE;
this->ike_sa->set_other_host(this->ike_sa, other_new->clone(other_new));
}
if (this->update)
{
/* start the update with the same task */
this->check = FALSE;
this->address = FALSE;
this->ike_sa->set_pending_updates(this->ike_sa, 1);
return NEED_MORE;
}
}
return SUCCESS;
}
return NEED_MORE;
@ -356,8 +436,9 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message)
*/
static void roam(private_ike_mobike_t *this, bool address)
{
this->roam = TRUE;
this->check = TRUE;
this->address = address;
this->natd = ike_natd_create(this->ike_sa, this->initiator);
this->ike_sa->set_pending_updates(this->ike_sa,
this->ike_sa->get_pending_updates(this->ike_sa) + 1);
}
@ -404,6 +485,7 @@ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator)
private_ike_mobike_t *this = malloc_thing(private_ike_mobike_t);
this->public.roam = (void(*)(ike_mobike_t*,bool))roam;
this->public.transmit = (void(*)(ike_mobike_t*,packet_t*))transmit;
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
@ -421,7 +503,8 @@ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator)
this->ike_sa = ike_sa;
this->initiator = initiator;
this->roam = FALSE;
this->update = FALSE;
this->check = FALSE;
this->address = TRUE;
this->cookie2 = chunk_empty;
this->natd = NULL;

View File

@ -28,6 +28,7 @@ typedef struct ike_mobike_t ike_mobike_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
#include <network/packet.h>
/**
* @brief Task of type ike_mobike, detects and handles MOBIKE extension.
@ -58,6 +59,18 @@ struct ike_mobike_t {
* @param address TRUE to include address list update
*/
void (*roam)(ike_mobike_t *this, bool address);
/**
* @brief Transmision hook, called by task manager.
*
* The task manager calls this hook whenever it transmits a packet. It
* allows the mobike task to send the packet on multiple paths to do path
* probing.
*
* @param this calling object
* @param packet the packet to transmit
*/
void (*transmit)(ike_mobike_t *this, packet_t *packet);
};
/**