merged tasking branch into trunk
This commit is contained in:
@@ -0,0 +1,718 @@
|
||||
/**
|
||||
* @file child_create.c
|
||||
*
|
||||
* @brief Implementation of the child_create task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 "child_create.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/ts_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
|
||||
|
||||
typedef struct private_child_create_t private_child_create_t;
|
||||
|
||||
/**
|
||||
* Private members of a child_create_t task.
|
||||
*/
|
||||
struct private_child_create_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
child_create_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* nonce chosen by us
|
||||
*/
|
||||
chunk_t my_nonce;
|
||||
|
||||
/**
|
||||
* nonce chosen by peer
|
||||
*/
|
||||
chunk_t other_nonce;
|
||||
|
||||
/**
|
||||
* policy to create the CHILD_SA from
|
||||
*/
|
||||
policy_t *policy;
|
||||
|
||||
/**
|
||||
* list of proposal candidates
|
||||
*/
|
||||
linked_list_t *proposals;
|
||||
|
||||
/**
|
||||
* selected proposal to use for CHILD_SA
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* traffic selectors for initiators side
|
||||
*/
|
||||
linked_list_t *tsi;
|
||||
|
||||
/**
|
||||
* traffic selectors for responders side
|
||||
*/
|
||||
linked_list_t *tsr;
|
||||
|
||||
/**
|
||||
* mode the new CHILD_SA uses (transport/tunnel/beet)
|
||||
*/
|
||||
mode_t mode;
|
||||
|
||||
/**
|
||||
* reqid to use if we are rekeying
|
||||
*/
|
||||
u_int32_t reqid;
|
||||
|
||||
/**
|
||||
* CHILD_SA which gets established
|
||||
*/
|
||||
child_sa_t *child_sa;
|
||||
};
|
||||
|
||||
/**
|
||||
* get the nonce from a message
|
||||
*/
|
||||
static status_t get_nonce(message_t *message, chunk_t *nonce)
|
||||
{
|
||||
nonce_payload_t *payload;
|
||||
|
||||
payload = (nonce_payload_t*)message->get_payload(message, NONCE);
|
||||
if (payload == NULL)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
*nonce = payload->get_nonce(payload);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* generate a new nonce to include in a CREATE_CHILD_SA message
|
||||
*/
|
||||
static status_t generate_nonce(chunk_t *nonce)
|
||||
{
|
||||
status_t status;
|
||||
randomizer_t *randomizer = randomizer_create();
|
||||
|
||||
status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
|
||||
nonce);
|
||||
randomizer->destroy(randomizer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "error generating random nonce value");
|
||||
return FAILED;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a list of traffic selectors if any selector belongs to host
|
||||
*/
|
||||
static bool ts_list_is_host(linked_list_t *list, host_t *host)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
bool is_host = TRUE;
|
||||
iterator_t *iterator = list->create_iterator(list, TRUE);
|
||||
|
||||
while (is_host && iterator->iterate(iterator, (void**)&ts))
|
||||
{
|
||||
is_host = is_host && ts->is_host(ts, host);
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
return is_host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a CHILD_SA for usage
|
||||
*/
|
||||
static status_t select_and_install(private_child_create_t *this)
|
||||
{
|
||||
prf_plus_t *prf_plus;
|
||||
status_t status;
|
||||
chunk_t nonce_i, nonce_r, seed;
|
||||
linked_list_t *my_ts, *other_ts;
|
||||
host_t *me, *other, *other_vip, *my_vip;
|
||||
|
||||
if (this->proposals == NULL || this->tsi == NULL || this->tsr == NULL)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "SA/TS payloads missing in message");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
nonce_i = this->my_nonce;
|
||||
nonce_r = this->other_nonce;
|
||||
my_ts = this->tsi;
|
||||
other_ts = this->tsr;
|
||||
}
|
||||
else
|
||||
{
|
||||
nonce_r = this->my_nonce;
|
||||
nonce_i = this->other_nonce;
|
||||
my_ts = this->tsr;
|
||||
other_ts = this->tsi;
|
||||
}
|
||||
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
|
||||
other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
|
||||
|
||||
this->proposal = this->policy->select_proposal(this->policy, this->proposals);
|
||||
|
||||
if (this->initiator && my_vip)
|
||||
{ /* if we have a virtual IP, shorten our TS to the minimum */
|
||||
my_ts = this->policy->select_my_traffic_selectors(this->policy, my_ts,
|
||||
my_vip);
|
||||
}
|
||||
else
|
||||
{ /* shorten in the host2host case only */
|
||||
my_ts = this->policy->select_my_traffic_selectors(this->policy,
|
||||
my_ts, me);
|
||||
}
|
||||
if (other_vip)
|
||||
{ /* if other has a virtual IP, shorten it's traffic selectors to it */
|
||||
other_ts = this->policy->select_other_traffic_selectors(this->policy,
|
||||
other_ts, other_vip);
|
||||
}
|
||||
else
|
||||
{ /* use his host for the host2host case */
|
||||
other_ts = this->policy->select_other_traffic_selectors(this->policy,
|
||||
other_ts, other);
|
||||
}
|
||||
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
|
||||
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
|
||||
if (this->initiator)
|
||||
{
|
||||
this->tsi = my_ts;
|
||||
this->tsr = other_ts;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->tsr = my_ts;
|
||||
this->tsi = other_ts;
|
||||
}
|
||||
|
||||
if (this->proposal == NULL ||
|
||||
this->tsi->get_count(this->tsi) == 0 ||
|
||||
this->tsr->get_count(this->tsr) == 0)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "no acceptable proposal found");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (!this->initiator)
|
||||
{
|
||||
/* check if requested mode is acceptable, downgrade if required */
|
||||
switch (this->mode)
|
||||
{
|
||||
case MODE_TRANSPORT:
|
||||
if (!ts_list_is_host(this->tsi, other) ||
|
||||
!ts_list_is_host(this->tsr, me))
|
||||
{
|
||||
this->mode = MODE_TUNNEL;
|
||||
DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
|
||||
}
|
||||
else if (this->ike_sa->is_natt_enabled(this->ike_sa))
|
||||
{
|
||||
this->mode = MODE_TUNNEL;
|
||||
DBG1(DBG_IKE, "not using tranport mode, connection NATed");
|
||||
}
|
||||
break;
|
||||
case MODE_BEET:
|
||||
if (!ts_list_is_host(this->tsi, NULL) ||
|
||||
!ts_list_is_host(this->tsr, NULL))
|
||||
{
|
||||
this->mode = MODE_TUNNEL;
|
||||
DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
seed = chunk_cata("cc", nonce_i, nonce_r);
|
||||
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
status = this->child_sa->update(this->child_sa, this->proposal,
|
||||
this->mode, prf_plus);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = this->child_sa->add(this->child_sa, this->proposal,
|
||||
this->mode, prf_plus);
|
||||
}
|
||||
prf_plus->destroy(prf_plus);
|
||||
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
|
||||
this->mode);
|
||||
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel");
|
||||
return status;
|
||||
}
|
||||
/* add to IKE_SA, and remove from task */
|
||||
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
|
||||
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
|
||||
this->child_sa = NULL;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* build the payloads for the message
|
||||
*/
|
||||
static void build_payloads(private_child_create_t *this, message_t *message)
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
ts_payload_t *ts_payload;
|
||||
nonce_payload_t *nonce_payload;
|
||||
|
||||
/* add SA payload */
|
||||
if (this->initiator)
|
||||
{
|
||||
sa_payload = sa_payload_create_from_proposal_list(this->proposals);
|
||||
}
|
||||
else
|
||||
{
|
||||
sa_payload = sa_payload_create_from_proposal(this->proposal);
|
||||
}
|
||||
message->add_payload(message, (payload_t*)sa_payload);
|
||||
|
||||
/* add TSi/TSr payloads */
|
||||
ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
|
||||
message->add_payload(message, (payload_t*)ts_payload);
|
||||
ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
|
||||
message->add_payload(message, (payload_t*)ts_payload);
|
||||
|
||||
/* add nonce payload if not in IKE_AUTH */
|
||||
if (message->get_exchange_type(message) == CREATE_CHILD_SA)
|
||||
{
|
||||
nonce_payload = nonce_payload_create();
|
||||
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
|
||||
message->add_payload(message, (payload_t*)nonce_payload);
|
||||
}
|
||||
|
||||
/* add a notify if we are not in tunnel mode */
|
||||
switch (this->mode)
|
||||
{
|
||||
case MODE_TRANSPORT:
|
||||
message->add_notify(message, FALSE, USE_TRANSPORT_MODE, chunk_empty);
|
||||
break;
|
||||
case MODE_BEET:
|
||||
message->add_notify(message, FALSE, USE_BEET_MODE, chunk_empty);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read payloads from message
|
||||
*/
|
||||
static void process_payloads(private_child_create_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
sa_payload_t *sa_payload;
|
||||
ts_payload_t *ts_payload;
|
||||
notify_payload_t *notify_payload;
|
||||
|
||||
/* defaults to TUNNEL mode */
|
||||
this->mode = MODE_TUNNEL;
|
||||
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case SECURITY_ASSOCIATION:
|
||||
sa_payload = (sa_payload_t*)payload;
|
||||
this->proposals = sa_payload->get_proposals(sa_payload);
|
||||
break;
|
||||
case TRAFFIC_SELECTOR_INITIATOR:
|
||||
ts_payload = (ts_payload_t*)payload;
|
||||
this->tsi = ts_payload->get_traffic_selectors(ts_payload);
|
||||
break;
|
||||
case TRAFFIC_SELECTOR_RESPONDER:
|
||||
ts_payload = (ts_payload_t*)payload;
|
||||
this->tsr = ts_payload->get_traffic_selectors(ts_payload);
|
||||
break;
|
||||
case NOTIFY:
|
||||
notify_payload = (notify_payload_t*)payload;
|
||||
switch (notify_payload ->get_notify_type(notify_payload ))
|
||||
{
|
||||
case USE_TRANSPORT_MODE:
|
||||
this->mode = MODE_TRANSPORT;
|
||||
break;
|
||||
case USE_BEET_MODE:
|
||||
this->mode = MODE_BEET;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for initiator
|
||||
*/
|
||||
static status_t build_i(private_child_create_t *this, message_t *message)
|
||||
{
|
||||
host_t *me, *other, *vip;
|
||||
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case IKE_SA_INIT:
|
||||
return get_nonce(message, &this->my_nonce);
|
||||
case CREATE_CHILD_SA:
|
||||
if (generate_nonce(&this->my_nonce) != SUCCESS)
|
||||
{
|
||||
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
return SUCCESS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SIG(CHILD_UP_START, "establishing CHILD_SA");
|
||||
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
vip = this->policy->get_virtual_ip(this->policy, NULL);
|
||||
|
||||
if (vip)
|
||||
{ /* propose a 0.0.0.0/0 subnet when we use virtual ip */
|
||||
this->tsi = this->policy->get_my_traffic_selectors(this->policy, NULL);
|
||||
vip->destroy(vip);
|
||||
}
|
||||
else
|
||||
{ /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
|
||||
this->tsi = this->policy->get_my_traffic_selectors(this->policy, me);
|
||||
}
|
||||
this->tsr = this->policy->get_other_traffic_selectors(this->policy, other);
|
||||
this->proposals = this->policy->get_proposals(this->policy);
|
||||
this->mode = this->policy->get_mode(this->policy);
|
||||
|
||||
this->child_sa = child_sa_create(me, other,
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa),
|
||||
this->policy, this->reqid,
|
||||
this->ike_sa->is_natt_enabled(this->ike_sa));
|
||||
|
||||
if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "unable to allocate SPIs from kernel");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
build_payloads(this, message);
|
||||
|
||||
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
|
||||
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
|
||||
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
|
||||
this->tsi = NULL;
|
||||
this->tsr = NULL;
|
||||
this->proposals = NULL;
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_r(private_child_create_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case IKE_SA_INIT:
|
||||
return get_nonce(message, &this->other_nonce);
|
||||
case CREATE_CHILD_SA:
|
||||
get_nonce(message, &this->other_nonce);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
process_payloads(this, message);
|
||||
|
||||
if (this->tsi == NULL || this->tsr == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "TS payload missing in message");
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
this->policy = charon->policies->get_policy(charon->policies,
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa),
|
||||
this->tsr, this->tsi,
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa));
|
||||
|
||||
if (this->policy && this->ike_sa->get_policy(this->ike_sa) == NULL)
|
||||
{
|
||||
this->ike_sa->set_policy(this->ike_sa, this->policy);
|
||||
}
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_child_create_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case IKE_SA_INIT:
|
||||
return get_nonce(message, &this->my_nonce);
|
||||
case CREATE_CHILD_SA:
|
||||
if (generate_nonce(&this->my_nonce) != SUCCESS)
|
||||
{
|
||||
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
return SUCCESS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->policy == NULL)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "received traffic selectors inacceptable");
|
||||
message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa),
|
||||
this->policy, this->reqid,
|
||||
this->ike_sa->is_natt_enabled(this->ike_sa));
|
||||
|
||||
if (select_and_install(this) != SUCCESS)
|
||||
{
|
||||
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
build_payloads(this, message);
|
||||
|
||||
SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_child_create_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
status_t status;
|
||||
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case IKE_SA_INIT:
|
||||
return get_nonce(message, &this->other_nonce);
|
||||
case CREATE_CHILD_SA:
|
||||
get_nonce(message, &this->other_nonce);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* check for erronous notifies */
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
if (payload->get_type(payload) == NOTIFY)
|
||||
{
|
||||
notify_payload_t *notify = (notify_payload_t*)payload;
|
||||
notify_type_t type = notify->get_notify_type(notify);
|
||||
|
||||
if (type < 16383)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "received %N notify error",
|
||||
notify_type_names, type);
|
||||
iterator->destroy(iterator);
|
||||
/* an error in CHILD_SA creation is not critical */
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
process_payloads(this, message);
|
||||
|
||||
status = select_and_install(this);
|
||||
|
||||
SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_child_create_t *this)
|
||||
{
|
||||
return CHILD_CREATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_create_t.use_reqid
|
||||
*/
|
||||
static void use_reqid(private_child_create_t *this, u_int32_t reqid)
|
||||
{
|
||||
this->reqid = reqid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
chunk_free(&this->my_nonce);
|
||||
chunk_free(&this->other_nonce);
|
||||
if (this->tsi)
|
||||
{
|
||||
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
if (this->tsr)
|
||||
{
|
||||
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
DESTROY_IF(this->child_sa);
|
||||
DESTROY_IF(this->proposal);
|
||||
if (this->proposals)
|
||||
{
|
||||
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->proposals = NULL;
|
||||
this->tsi = NULL;
|
||||
this->tsr = NULL;
|
||||
this->child_sa = NULL;
|
||||
this->mode = MODE_TUNNEL;
|
||||
this->reqid = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_child_create_t *this)
|
||||
{
|
||||
chunk_free(&this->my_nonce);
|
||||
chunk_free(&this->other_nonce);
|
||||
if (this->tsi)
|
||||
{
|
||||
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
if (this->tsr)
|
||||
{
|
||||
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
|
||||
}
|
||||
DESTROY_IF(this->child_sa);
|
||||
DESTROY_IF(this->proposal);
|
||||
if (this->proposals)
|
||||
{
|
||||
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
|
||||
}
|
||||
|
||||
DESTROY_IF(this->policy);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
|
||||
{
|
||||
private_child_create_t *this = malloc_thing(private_child_create_t);
|
||||
|
||||
this->public.use_reqid = (void(*)(child_create_t*,u_int32_t))use_reqid;
|
||||
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;
|
||||
if (policy)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
this->initiator = TRUE;
|
||||
policy->get_ref(policy);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
this->initiator = FALSE;
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->policy = policy;
|
||||
this->my_nonce = chunk_empty;
|
||||
this->other_nonce = chunk_empty;
|
||||
this->proposals = NULL;
|
||||
this->proposal = NULL;
|
||||
this->tsi = NULL;
|
||||
this->tsr = NULL;
|
||||
this->child_sa = NULL;
|
||||
this->mode = MODE_TUNNEL;
|
||||
this->reqid = 0;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file child_create.h
|
||||
*
|
||||
* @brief Interface child_create_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CHILD_CREATE_H_
|
||||
#define CHILD_CREATE_H_
|
||||
|
||||
typedef struct child_create_t child_create_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <config/policies/policy.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type CHILD_CREATE, established a new CHILD_SA.
|
||||
*
|
||||
* This task may be included in the IKE_AUTH message or in a separate
|
||||
* CREATE_CHILD_SA exchange.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - child_create_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct child_create_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
|
||||
/**
|
||||
* @brief Use a specific reqid for the CHILD_SA.
|
||||
*
|
||||
* When this task is used for rekeying, the same reqid is used
|
||||
* for the new CHILD_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param reqid reqid to use
|
||||
*/
|
||||
void (*use_reqid) (child_create_t *this, u_int32_t reqid);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new child_create task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param policy policy if task initiator, NULL if responder
|
||||
* @return child_create task to handle by the task_manager
|
||||
*/
|
||||
child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy);
|
||||
|
||||
#endif /* CHILD_CREATE_H_ */
|
||||
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* @file child_delete.c
|
||||
*
|
||||
* @brief Implementation of the child_delete task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2007 Martin Willi
|
||||
* 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 "child_delete.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
|
||||
|
||||
typedef struct private_child_delete_t private_child_delete_t;
|
||||
|
||||
/**
|
||||
* Private members of a child_delete_t task.
|
||||
*/
|
||||
struct private_child_delete_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
child_delete_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* CHILD_SAs which get deleted
|
||||
*/
|
||||
linked_list_t *child_sas;
|
||||
};
|
||||
|
||||
/**
|
||||
* build the delete payloads from the listed child_sas
|
||||
*/
|
||||
static void build_payloads(private_child_delete_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
delete_payload_t *ah = NULL, *esp = NULL;
|
||||
u_int32_t spi;
|
||||
child_sa_t *child_sa;
|
||||
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&child_sa))
|
||||
{
|
||||
spi = child_sa->get_spi(child_sa, TRUE);
|
||||
switch (child_sa->get_protocol(child_sa))
|
||||
{
|
||||
case PROTO_ESP:
|
||||
if (esp == NULL)
|
||||
{
|
||||
esp = delete_payload_create(PROTO_ESP);
|
||||
message->add_payload(message, (payload_t*)esp);
|
||||
}
|
||||
esp->add_spi(esp, spi);
|
||||
break;
|
||||
case PROTO_AH:
|
||||
if (ah == NULL)
|
||||
{
|
||||
ah = delete_payload_create(PROTO_AH);
|
||||
message->add_payload(message, (payload_t*)ah);
|
||||
}
|
||||
ah->add_spi(ah, spi);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
child_sa->set_state(child_sa, CHILD_DELETING);
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* read in payloads and find the children to delete
|
||||
*/
|
||||
static void process_payloads(private_child_delete_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *payloads, *spis;
|
||||
payload_t *payload;
|
||||
delete_payload_t *delete_payload;
|
||||
u_int32_t spi;
|
||||
protocol_id_t protocol;
|
||||
child_sa_t *child_sa;
|
||||
|
||||
payloads = message->get_payload_iterator(message);
|
||||
while (payloads->iterate(payloads, (void**)&payload))
|
||||
{
|
||||
if (payload->get_type(payload) == DELETE)
|
||||
{
|
||||
delete_payload = (delete_payload_t*)payload;
|
||||
protocol = delete_payload->get_protocol_id(delete_payload);
|
||||
if (protocol != PROTO_ESP && protocol != PROTO_AH)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
spis = delete_payload->create_spi_iterator(delete_payload);
|
||||
while (spis->iterate(spis, (void**)&spi))
|
||||
{
|
||||
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
|
||||
spi, FALSE);
|
||||
if (child_sa == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, "
|
||||
"but no such SA", protocol_id_names, protocol, ntohl(spi));
|
||||
break;
|
||||
}
|
||||
|
||||
if (child_sa->get_state(child_sa) == CHILD_REKEYING)
|
||||
{
|
||||
/* TODO: handle rekeying */
|
||||
}
|
||||
|
||||
this->child_sas->insert_last(this->child_sas, child_sa);
|
||||
}
|
||||
spis->destroy(spis);
|
||||
}
|
||||
}
|
||||
payloads->destroy(payloads);
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy the children listed in this->child_sas
|
||||
*/
|
||||
static void destroy_children(private_child_delete_t *this)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
child_sa_t *child_sa;
|
||||
protocol_id_t protocol;
|
||||
u_int32_t spi;
|
||||
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&child_sa))
|
||||
{
|
||||
/* TODO: can we do this more cleanly? */
|
||||
spi = child_sa->get_spi(child_sa, TRUE);
|
||||
protocol = child_sa->get_protocol(child_sa);
|
||||
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for initiator
|
||||
*/
|
||||
static status_t build_i(private_child_delete_t *this, message_t *message)
|
||||
{
|
||||
build_payloads(this, message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_child_delete_t *this, message_t *message)
|
||||
{
|
||||
/* flush the list before adding new SAs */
|
||||
this->child_sas->destroy(this->child_sas);
|
||||
this->child_sas = linked_list_create();
|
||||
|
||||
process_payloads(this, message);
|
||||
destroy_children(this);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_r(private_child_delete_t *this, message_t *message)
|
||||
{
|
||||
process_payloads(this, message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_child_delete_t *this, message_t *message)
|
||||
{
|
||||
build_payloads(this, message);
|
||||
destroy_children(this);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_child_delete_t *this)
|
||||
{
|
||||
return CHILD_DELETE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
|
||||
this->child_sas->destroy(this->child_sas);
|
||||
this->child_sas = linked_list_create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_child_delete_t *this)
|
||||
{
|
||||
this->child_sas->destroy(this->child_sas);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
|
||||
{
|
||||
private_child_delete_t *this = malloc_thing(private_child_delete_t);
|
||||
|
||||
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;
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->child_sas = linked_list_create();
|
||||
|
||||
if (child_sa != NULL)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
this->initiator = TRUE;
|
||||
this->child_sas->insert_last(this->child_sas, child_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
this->initiator = FALSE;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file child_delete.h
|
||||
*
|
||||
* @brief Interface child_delete_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CHILD_DELETE_H_
|
||||
#define CHILD_DELETE_H_
|
||||
|
||||
typedef struct child_delete_t child_delete_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <sa/child_sa.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type child_delete, delete a CHILD_SA.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - child_delete_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct child_delete_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new child_delete task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param child_sa CHILD_SA to delete, or NULL as responder
|
||||
* @return child_delete task to handle by the task_manager
|
||||
*/
|
||||
child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
|
||||
|
||||
#endif /* CHILD_DELETE_H_ */
|
||||
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* @file child_rekey.c
|
||||
*
|
||||
* @brief Implementation of the child_rekey task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 "child_rekey.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <sa/tasks/child_create.h>
|
||||
|
||||
|
||||
typedef struct private_child_rekey_t private_child_rekey_t;
|
||||
|
||||
/**
|
||||
* Private members of a child_rekey_t task.
|
||||
*/
|
||||
struct private_child_rekey_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
child_rekey_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* the CHILD_CREATE task which is reused to simplify rekeying
|
||||
*/
|
||||
child_create_t *child_create;
|
||||
|
||||
/**
|
||||
* CHILD_SA which gets rekeyed
|
||||
*/
|
||||
child_sa_t *child_sa;
|
||||
|
||||
/**
|
||||
* redundandt CHILD_SA created simultaneously
|
||||
*/
|
||||
child_sa_t *simultaneous;
|
||||
|
||||
/**
|
||||
* the lowest nonce compared so far
|
||||
*/
|
||||
chunk_t nonce;
|
||||
|
||||
/**
|
||||
* TRUE if we have the lower nonce
|
||||
*/
|
||||
bool winner;
|
||||
};
|
||||
|
||||
/**
|
||||
* get the nonce from a message, return TRUE if it was lower than this->nonce
|
||||
*/
|
||||
static bool get_nonce(private_child_rekey_t *this, message_t *message)
|
||||
{
|
||||
nonce_payload_t *payload;
|
||||
chunk_t nonce;
|
||||
|
||||
payload = (nonce_payload_t*)message->get_payload(message, NONCE);
|
||||
if (payload == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
nonce = payload->get_nonce(payload);
|
||||
|
||||
if (this->nonce.ptr && memcmp(nonce.ptr, this->nonce.ptr,
|
||||
min(nonce.len, this->nonce.len)) > 0)
|
||||
{
|
||||
chunk_free(&nonce);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
chunk_free(&this->nonce);
|
||||
this->nonce = nonce;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* find a child using the REKEY_SA notify
|
||||
*/
|
||||
static void find_child(private_child_rekey_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
u_int32_t spi;
|
||||
protocol_id_t protocol;
|
||||
|
||||
if (payload->get_type(payload) != NOTIFY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
notify = (notify_payload_t*)payload;
|
||||
protocol = notify->get_protocol_id(notify);
|
||||
spi = notify->get_spi(notify);
|
||||
|
||||
if (protocol != PROTO_ESP && protocol != PROTO_AH)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
|
||||
spi, FALSE);
|
||||
break;
|
||||
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* handle a detected simultaneous rekeying situation as responder
|
||||
*/
|
||||
static void simultaneous_r(private_child_rekey_t *this, message_t *message)
|
||||
{
|
||||
private_child_rekey_t *other = NULL;
|
||||
task_t *task;
|
||||
iterator_t *iterator;
|
||||
|
||||
this->ike_sa->create_task_iterator(this->ike_sa);
|
||||
while (iterator->iterate(iterator, (void**)&task))
|
||||
{
|
||||
if (task->get_type(task) == CHILD_REKEY)
|
||||
{
|
||||
other = (private_child_rekey_t*)task;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
if (other)
|
||||
{
|
||||
other->simultaneous = this->child_create->get_child(this->child_create);
|
||||
|
||||
if (!get_nonce(other, message))
|
||||
{
|
||||
/* this wins the race, other lost */
|
||||
other->winner = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* was there a simultaneous rekeying, did we win the nonce compare?
|
||||
*/
|
||||
static bool simultaneous_i(private_child_rekey_t *this, message_t *message)
|
||||
{
|
||||
if (this->winner || get_nonce(this, message))
|
||||
{
|
||||
/* we have the lower nonce and win */
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for initiator
|
||||
*/
|
||||
static status_t build_i(private_child_rekey_t *this, message_t *message)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
protocol_id_t protocol;
|
||||
u_int32_t spi, reqid;
|
||||
|
||||
/* our CHILD_CREATE task does the hard work for us... */
|
||||
reqid = this->child_sa->get_reqid(this->child_sa);
|
||||
this->child_create->use_reqid(this->child_create, reqid);
|
||||
this->child_create->task.build(&this->child_create->task, message);
|
||||
get_nonce(this, message);
|
||||
|
||||
/* ... we just need the rekey notify */
|
||||
protocol = this->child_sa->get_protocol(this->child_sa);
|
||||
spi = this->child_sa->get_spi(this->child_sa, TRUE);
|
||||
notify = notify_payload_create_from_protocol_and_type(protocol, REKEY_SA);
|
||||
notify->set_spi(notify, spi);
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
|
||||
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_r(private_child_rekey_t *this, message_t *message)
|
||||
{
|
||||
/* let the CHILD_CREATE task process the message */
|
||||
this->child_create->task.process(&this->child_create->task, message);
|
||||
get_nonce(this, message);
|
||||
|
||||
find_child(this, message);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_child_rekey_t *this, message_t *message)
|
||||
{
|
||||
u_int32_t reqid;
|
||||
|
||||
if (this->child_sa == NULL ||
|
||||
this->child_sa->get_state(this->child_sa) == CHILD_DELETING)
|
||||
{
|
||||
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* let the CHILD_CREATE task build the response */
|
||||
reqid = this->child_sa->get_reqid(this->child_sa);
|
||||
this->child_create->use_reqid(this->child_create, reqid);
|
||||
this->child_create->task.build(&this->child_create->task, message);
|
||||
get_nonce(this, message);
|
||||
|
||||
if (this->child_sa->get_state(this->child_sa) == CHILD_REKEYING)
|
||||
{
|
||||
/* simultaneous_detected(this); */
|
||||
}
|
||||
|
||||
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_child_rekey_t *this, message_t *message)
|
||||
{
|
||||
protocol_id_t protocol;
|
||||
u_int32_t spi;
|
||||
|
||||
this->child_create->task.process(&this->child_create->task, message);
|
||||
|
||||
/*if (!simultaneous_won(this, message))
|
||||
{
|
||||
* delete the redundant CHILD_SA, instead of the rekeyed *
|
||||
this->child_sa = this->create_child->get_child(this->create_child);
|
||||
}*/
|
||||
spi = this->child_sa->get_spi(this->child_sa, TRUE);
|
||||
protocol = this->child_sa->get_protocol(this->child_sa);
|
||||
|
||||
/* TODO: don't delete when rekeying failed */
|
||||
if (this->ike_sa->delete_child_sa(this->ike_sa, protocol, spi) != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_child_rekey_t *this)
|
||||
{
|
||||
return CHILD_REKEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_child_rekey_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->child_create->task.migrate(&this->child_create->task, ike_sa);
|
||||
chunk_free(&this->nonce);
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->winner = TRUE;
|
||||
this->simultaneous = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_child_rekey_t *this)
|
||||
{
|
||||
this->child_create->task.destroy(&this->child_create->task);
|
||||
chunk_free(&this->nonce);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
|
||||
{
|
||||
private_child_rekey_t *this = malloc_thing(private_child_rekey_t);
|
||||
policy_t *policy;
|
||||
|
||||
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;
|
||||
if (child_sa != NULL)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
this->initiator = TRUE;
|
||||
policy = child_sa->get_policy(child_sa);
|
||||
this->child_create = child_create_create(ike_sa, policy);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
this->initiator = FALSE;
|
||||
this->child_create = child_create_create(ike_sa, NULL);
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->child_sa = child_sa;
|
||||
this->nonce = chunk_empty;
|
||||
this->winner = TRUE;
|
||||
this->simultaneous = NULL;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file child_rekey.h
|
||||
*
|
||||
* @brief Interface child_rekey_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CHILD_REKEY_H_
|
||||
#define CHILD_REKEY_H_
|
||||
|
||||
typedef struct child_rekey_t child_rekey_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type CHILD_REKEY, rekey an established CHILD_SA.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - child_rekey_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct child_rekey_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new CHILD_REKEY task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param child_sa child_sa to rekey, NULL if responder
|
||||
* @return child_rekey task to handle by the task_manager
|
||||
*/
|
||||
child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
|
||||
|
||||
#endif /* CHILD_REKEY_H_ */
|
||||
@@ -0,0 +1,513 @@
|
||||
/**
|
||||
* @file ike_auth.c
|
||||
*
|
||||
* @brief Implementation of the ike_auth task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 "ike_auth.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <encoding/payloads/id_payload.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
|
||||
|
||||
typedef struct private_ike_auth_t private_ike_auth_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_auth_t task.
|
||||
*/
|
||||
struct private_ike_auth_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
ike_auth_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Nonce chosen by us in ike_init
|
||||
*/
|
||||
chunk_t my_nonce;
|
||||
|
||||
/**
|
||||
* Nonce chosen by peer in ike_init
|
||||
*/
|
||||
chunk_t other_nonce;
|
||||
|
||||
/**
|
||||
* IKE_SA_INIT message sent by us
|
||||
*/
|
||||
packet_t *my_packet;
|
||||
|
||||
/**
|
||||
* IKE_SA_INIT message sent by peer
|
||||
*/
|
||||
packet_t *other_packet;
|
||||
|
||||
/**
|
||||
* authenticator to authenticate us
|
||||
*/
|
||||
authenticator_t *my_auth;
|
||||
|
||||
/**
|
||||
* authenticator to authenticate peer
|
||||
*/
|
||||
authenticator_t *other_auth;
|
||||
|
||||
/**
|
||||
* has the peer been authenticated successfully?
|
||||
*/
|
||||
bool peer_authenticated;
|
||||
};
|
||||
|
||||
/**
|
||||
* build the payloads for the message
|
||||
*/
|
||||
static status_t build_payloads(private_ike_auth_t *this, message_t *message)
|
||||
{
|
||||
authenticator_t *auth;
|
||||
auth_payload_t *auth_payload;
|
||||
id_payload_t *id_payload;
|
||||
chunk_t ike_sa_init;
|
||||
identification_t *me, *other;
|
||||
policy_t *policy;
|
||||
auth_method_t method = AUTH_RSA;
|
||||
status_t status;
|
||||
|
||||
/* add own ID payload */
|
||||
me = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other = this->ike_sa->get_other_id(this->ike_sa);
|
||||
|
||||
id_payload = id_payload_create_from_identification(this->initiator, me);
|
||||
message->add_payload(message, (payload_t*)id_payload);
|
||||
|
||||
/* as initiator, include other ID if it does not contain wildcards */
|
||||
if (this->initiator && !other->contains_wildcards(other))
|
||||
{
|
||||
id_payload = id_payload_create_from_identification(FALSE, other);
|
||||
message->add_payload(message, (payload_t*)id_payload);
|
||||
}
|
||||
|
||||
/* create own authenticator and add auth payload */
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
if (policy)
|
||||
{
|
||||
method = policy->get_auth_method(policy);
|
||||
}
|
||||
auth = authenticator_create(this->ike_sa, method);
|
||||
if (auth == NULL)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "configured authentication method %N not supported",
|
||||
auth_method_names, method);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
ike_sa_init = this->my_packet->get_data(this->my_packet);
|
||||
status = auth->build(auth, ike_sa_init, this->other_nonce, &auth_payload);
|
||||
auth->destroy(auth);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "generating authentication data failed");
|
||||
return FAILED;
|
||||
}
|
||||
message->add_payload(message, (payload_t*)auth_payload);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* process payloads from message
|
||||
*/
|
||||
static void process_payloads(private_ike_auth_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
payload_type_t type;
|
||||
identification_t *idi = NULL, *idr = NULL;
|
||||
auth_payload_t *auth_payload = NULL;
|
||||
authenticator_t *auth;
|
||||
auth_method_t auth_method;
|
||||
status_t status;
|
||||
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
type = payload->get_type(payload);
|
||||
switch (type)
|
||||
{
|
||||
case ID_INITIATOR:
|
||||
{
|
||||
id_payload_t *id_payload = (id_payload_t*)payload;
|
||||
idi = id_payload->get_identification(id_payload);
|
||||
break;
|
||||
}
|
||||
case ID_RESPONDER:
|
||||
{
|
||||
id_payload_t *id_payload = (id_payload_t*)payload;
|
||||
idr = id_payload->get_identification(id_payload);
|
||||
break;
|
||||
}
|
||||
case AUTHENTICATION:
|
||||
{
|
||||
auth_payload = (auth_payload_t*)payload;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
/* apply IDs */
|
||||
if ((this->initiator && idr == NULL) || (!this->initiator && idi == NULL))
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "ID payload missing in message");
|
||||
DESTROY_IF(idr); DESTROY_IF(idi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
if (!idr->matches(idr, other_id, NULL))
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "received inacceptable id %D, %D required", idr,
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
DESTROY_IF(idi); DESTROY_IF(idr);
|
||||
return;
|
||||
}
|
||||
this->ike_sa->set_other_id(this->ike_sa, idr);
|
||||
}
|
||||
else
|
||||
{
|
||||
identification_t *my_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
if (idr)
|
||||
{
|
||||
if (!idr->matches(idr, my_id, NULL))
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "received inacceptable id %D, %D required",
|
||||
idr, this->ike_sa->get_other_id(this->ike_sa));
|
||||
DESTROY_IF(idi); DESTROY_IF(idr);
|
||||
return;
|
||||
}
|
||||
this->ike_sa->set_my_id(this->ike_sa, idr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (my_id->contains_wildcards(my_id))
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "own ID (%D) not defined after exchange",
|
||||
my_id);
|
||||
DESTROY_IF(idi);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->ike_sa->set_other_id(this->ike_sa, idi);
|
||||
}
|
||||
|
||||
/* verify auth payload */
|
||||
if (auth_payload == NULL)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "AUTH payload missing in message");
|
||||
return;
|
||||
}
|
||||
|
||||
auth_method = auth_payload->get_auth_method(auth_payload);
|
||||
auth = authenticator_create(this->ike_sa, auth_method);
|
||||
if (auth == NULL)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "authentication method %N used by %D not "
|
||||
"supported", auth_method_names, auth_method,
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
return;
|
||||
}
|
||||
status = auth->verify(auth, this->other_packet->get_data(this->other_packet),
|
||||
this->my_nonce, auth_payload);
|
||||
auth->destroy(auth);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
|
||||
this->ike_sa->get_other_id(this->ike_sa),
|
||||
auth_method_names, auth_method);
|
||||
return;
|
||||
}
|
||||
this->peer_authenticated = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* collect the needed information in the IKE_SA_INIT exchange from our message
|
||||
*/
|
||||
static status_t collect_my_init_data(private_ike_auth_t *this, message_t *message)
|
||||
{
|
||||
nonce_payload_t *nonce;
|
||||
|
||||
/* get the nonce that was generated in ike_init */
|
||||
nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
|
||||
if (nonce == NULL)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
this->my_nonce = nonce->get_nonce(nonce);
|
||||
|
||||
/* pre-generate the message, so we can store it for us */
|
||||
if (this->ike_sa->generate_message(this->ike_sa, message,
|
||||
&this->my_packet) != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* collect the needed information in the IKE_SA_INIT exchange from others message
|
||||
*/
|
||||
static status_t collect_other_init_data(private_ike_auth_t *this, message_t *message)
|
||||
{
|
||||
/* we collect the needed information in the IKE_SA_INIT exchange */
|
||||
nonce_payload_t *nonce;
|
||||
|
||||
/* get the nonce that was generated in ike_init */
|
||||
nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
|
||||
if (nonce == NULL)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
this->other_nonce = nonce->get_nonce(nonce);
|
||||
|
||||
/* pre-generate the message, so we can store it for us */
|
||||
this->other_packet = message->get_packet(message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for initiator
|
||||
*/
|
||||
static status_t build_i(private_ike_auth_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) == IKE_SA_INIT)
|
||||
{
|
||||
return collect_my_init_data(this, message);
|
||||
}
|
||||
|
||||
if (build_payloads(this, message) == SUCCESS)
|
||||
{
|
||||
return NEED_MORE;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_r(private_ike_auth_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) == IKE_SA_INIT)
|
||||
{
|
||||
return collect_other_init_data(this, message);
|
||||
}
|
||||
|
||||
process_payloads(this, message);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_ike_auth_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) == IKE_SA_INIT)
|
||||
{
|
||||
return collect_my_init_data(this, message);
|
||||
}
|
||||
|
||||
if (!this->peer_authenticated)
|
||||
{
|
||||
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (build_payloads(this, message) == SUCCESS)
|
||||
{
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_ike_auth_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
|
||||
if (message->get_exchange_type(message) == IKE_SA_INIT)
|
||||
{
|
||||
return collect_other_init_data(this, message);
|
||||
}
|
||||
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
if (payload->get_type(payload) == NOTIFY)
|
||||
{
|
||||
notify_payload_t *notify = (notify_payload_t*)payload;
|
||||
notify_type_t type = notify->get_notify_type(notify);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case NO_PROPOSAL_CHOSEN:
|
||||
case SINGLE_PAIR_REQUIRED:
|
||||
case NO_ADDITIONAL_SAS:
|
||||
case INTERNAL_ADDRESS_FAILURE:
|
||||
case FAILED_CP_REQUIRED:
|
||||
case TS_UNACCEPTABLE:
|
||||
case INVALID_SELECTORS:
|
||||
/* these are errors, but are not critical as only the
|
||||
* CHILD_SA won't get build, but IKE_SA establishes anyway */
|
||||
DBG1(DBG_IKE, "received %N notify, no CHILD_SA built",
|
||||
notify_type_names, type);
|
||||
iterator->destroy(iterator);
|
||||
return SUCCESS;
|
||||
default:
|
||||
{
|
||||
if (type < 16383)
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N notify error",
|
||||
notify_type_names, type);
|
||||
iterator->destroy(iterator);
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
process_payloads(this, message);
|
||||
|
||||
if (this->peer_authenticated)
|
||||
{
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_ike_auth_t *this)
|
||||
{
|
||||
return IKE_AUTHENTICATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_ike_auth_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
chunk_free(&this->my_nonce);
|
||||
chunk_free(&this->other_nonce);
|
||||
DESTROY_IF(this->my_packet);
|
||||
DESTROY_IF(this->other_packet);
|
||||
DESTROY_IF(this->my_auth);
|
||||
DESTROY_IF(this->other_auth);
|
||||
this->my_packet = NULL;
|
||||
this->other_packet = NULL;
|
||||
this->my_auth = NULL;
|
||||
this->other_auth = NULL;
|
||||
this->peer_authenticated = FALSE;
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_ike_auth_t *this)
|
||||
{
|
||||
chunk_free(&this->my_nonce);
|
||||
chunk_free(&this->other_nonce);
|
||||
DESTROY_IF(this->my_packet);
|
||||
DESTROY_IF(this->other_packet);
|
||||
DESTROY_IF(this->my_auth);
|
||||
DESTROY_IF(this->other_auth);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_ike_auth_t *this = malloc_thing(private_ike_auth_t);
|
||||
|
||||
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;
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->initiator = initiator;
|
||||
this->my_nonce = chunk_empty;
|
||||
this->other_nonce = chunk_empty;
|
||||
this->my_packet = NULL;
|
||||
this->other_packet = NULL;
|
||||
this->my_auth = NULL;
|
||||
this->other_auth = NULL;
|
||||
this->peer_authenticated = FALSE;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file ike_auth.h
|
||||
*
|
||||
* @brief Interface ike_auth_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IKE_AUTH_H_
|
||||
#define IKE_AUTH_H_
|
||||
|
||||
typedef struct ike_auth_t ike_auth_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type ike_auth, authenticates an IKE_SA authenticators.
|
||||
*
|
||||
* The ike_auth task authenticates the IKE_SA using the IKE_AUTH
|
||||
* exchange.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_auth_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct ike_auth_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new task of type IKE_AUTHENTICATE.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if thask is the initator of an exchange
|
||||
* @return ike_auth task to handle by the task_manager
|
||||
*/
|
||||
ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /* IKE_AUTH_H_ */
|
||||
@@ -0,0 +1,361 @@
|
||||
/**
|
||||
* @file ike_cert.c
|
||||
*
|
||||
* @brief Implementation of the ike_cert task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2007 Martin Willi
|
||||
* 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 "ike_cert.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/certreq_payload.h>
|
||||
|
||||
|
||||
typedef struct private_ike_cert_t private_ike_cert_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_cert_t task.
|
||||
*/
|
||||
struct private_ike_cert_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
ike_cert_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* list of CA cert hashes requested, items point to 20 byte chunk
|
||||
*/
|
||||
linked_list_t *cas;
|
||||
};
|
||||
|
||||
/**
|
||||
* read certificate requests
|
||||
*/
|
||||
static void process_certreqs(private_ike_cert_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
if (payload->get_type(payload) == CERTIFICATE_REQUEST)
|
||||
{
|
||||
certreq_payload_t *certreq = (certreq_payload_t*)payload;
|
||||
cert_encoding_t encoding;
|
||||
chunk_t keyids, keyid;
|
||||
|
||||
encoding = certreq->get_cert_encoding(certreq);
|
||||
if (encoding != CERT_X509_SIGNATURE)
|
||||
{
|
||||
DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
|
||||
cert_encoding_names, encoding);
|
||||
continue;
|
||||
}
|
||||
|
||||
keyids = certreq->get_data(certreq);
|
||||
|
||||
while (keyids.len >= HASH_SIZE_SHA1)
|
||||
{
|
||||
keyid = chunk_create(keyids.ptr, HASH_SIZE_SHA1);
|
||||
keyid = chunk_clone(keyid);
|
||||
this->cas->insert_last(this->cas, keyid.ptr);
|
||||
keyids = chunk_skip(keyids, HASH_SIZE_SHA1);
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* import certificates
|
||||
*/
|
||||
static void process_certs(private_ike_cert_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
if (payload->get_type(payload) == CERTIFICATE)
|
||||
{
|
||||
cert_encoding_t encoding;
|
||||
x509_t *cert;
|
||||
chunk_t cert_data;
|
||||
bool found;
|
||||
cert_payload_t *cert_payload = (cert_payload_t*)payload;
|
||||
|
||||
encoding = cert_payload->get_cert_encoding(cert_payload);
|
||||
if (encoding != CERT_X509_SIGNATURE)
|
||||
{
|
||||
DBG1(DBG_IKE, "certificate payload %N not supported, ignored",
|
||||
cert_encoding_names, encoding);
|
||||
continue;
|
||||
}
|
||||
|
||||
cert_data = cert_payload->get_data_clone(cert_payload);
|
||||
cert = x509_create_from_chunk(cert_data);
|
||||
if (cert)
|
||||
{
|
||||
if (charon->credentials->verify(charon->credentials,
|
||||
cert, &found))
|
||||
{
|
||||
DBG2(DBG_IKE, "received end entity certificate is trusted, "
|
||||
"added to store");
|
||||
if (!found)
|
||||
{
|
||||
charon->credentials->add_end_certificate(
|
||||
charon->credentials, cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
cert->destroy(cert);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received end entity certificate is not "
|
||||
"trusted, discarded");
|
||||
cert->destroy(cert);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "parsing of received certificate failed, discarded");
|
||||
chunk_free(&cert_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* build certificate requests
|
||||
*/
|
||||
static void build_certreqs(private_ike_cert_t *this, message_t *message)
|
||||
{
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
identification_t *ca;
|
||||
certreq_payload_t *certreq;
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
|
||||
if (connection->get_certreq_policy(connection) != CERT_NEVER_SEND)
|
||||
{
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
|
||||
if (policy)
|
||||
{
|
||||
ca = policy->get_other_ca(policy);
|
||||
|
||||
if (ca && ca->get_type(ca) != ID_ANY)
|
||||
{
|
||||
certreq = certreq_payload_create_from_cacert(ca);
|
||||
}
|
||||
else
|
||||
{
|
||||
certreq = certreq_payload_create_from_cacerts();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
certreq = certreq_payload_create_from_cacerts();
|
||||
}
|
||||
|
||||
if (certreq)
|
||||
{
|
||||
message->add_payload(message, (payload_t*)certreq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add certificates to message
|
||||
*/
|
||||
static void build_certs(private_ike_cert_t *this, message_t *message)
|
||||
{
|
||||
policy_t *policy;
|
||||
connection_t *connection;
|
||||
x509_t *cert;
|
||||
cert_payload_t *payload;
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
|
||||
if (policy && policy->get_auth_method(policy) == AUTH_RSA)
|
||||
{
|
||||
switch (connection->get_cert_policy(connection))
|
||||
{
|
||||
case CERT_NEVER_SEND:
|
||||
break;
|
||||
case CERT_SEND_IF_ASKED:
|
||||
if (this->cas->get_count(this->cas) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* FALL */
|
||||
case CERT_ALWAYS_SEND:
|
||||
{
|
||||
/* TODO: respect CA cert request */
|
||||
cert = charon->credentials->get_certificate(charon->credentials,
|
||||
policy->get_my_id(policy));
|
||||
if (cert)
|
||||
{
|
||||
payload = cert_payload_create_from_x509(cert);
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t build_i(private_ike_cert_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) == IKE_SA_INIT)
|
||||
{
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
build_certreqs(this, message);
|
||||
build_certs(this, message);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for responder
|
||||
*/
|
||||
static status_t process_r(private_ike_cert_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) == IKE_SA_INIT)
|
||||
{
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
process_certreqs(this, message);
|
||||
process_certs(this, message);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_ike_cert_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) == IKE_SA_INIT)
|
||||
{
|
||||
build_certreqs(this, message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
build_certs(this, message);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_ike_cert_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) == IKE_SA_INIT)
|
||||
{
|
||||
process_certreqs(this, message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
process_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_ike_cert_t *this)
|
||||
{
|
||||
return IKE_CERT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_ike_cert_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
|
||||
this->cas->destroy_function(this->cas, free);
|
||||
this->cas = linked_list_create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_ike_cert_t *this)
|
||||
{
|
||||
this->cas->destroy_function(this->cas, free);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_ike_cert_t *this = malloc_thing(private_ike_cert_t);
|
||||
|
||||
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;
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->initiator = initiator;
|
||||
this->cas = linked_list_create();
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file ike_cert.h
|
||||
*
|
||||
* @brief Interface ike_cert_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IKE_CERT_H_
|
||||
#define IKE_CERT_H_
|
||||
|
||||
typedef struct ike_cert_t ike_cert_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type ike_cert, exchanges certificates and
|
||||
* certificate requests.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_cert_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct ike_cert_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new ike_cert task.
|
||||
*
|
||||
* The initiator parameter means the original initiator, not the initiator
|
||||
* of the certificate request.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if thask is the original initator
|
||||
* @return ike_cert task to handle by the task_manager
|
||||
*/
|
||||
ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /* IKE_CERT_H_ */
|
||||
@@ -0,0 +1,421 @@
|
||||
/**
|
||||
* @file ike_config.c
|
||||
*
|
||||
* @brief Implementation of the ike_config task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
|
||||
* 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 "ike_config.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/cp_payload.h>
|
||||
|
||||
typedef struct private_ike_config_t private_ike_config_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_config_t task.
|
||||
*/
|
||||
struct private_ike_config_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
ike_config_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* associated policy with virtual IP configuration
|
||||
*/
|
||||
policy_t *policy;
|
||||
|
||||
/**
|
||||
* virtual ip
|
||||
*/
|
||||
host_t *virtual_ip;
|
||||
|
||||
/**
|
||||
* list of DNS servers
|
||||
*/
|
||||
linked_list_t *dns;
|
||||
};
|
||||
|
||||
/**
|
||||
* build configuration payloads and attributes
|
||||
*/
|
||||
static void build_payloads(private_ike_config_t *this, message_t *message,
|
||||
config_type_t type)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
configuration_attribute_t *ca;
|
||||
chunk_t chunk, prefix;
|
||||
|
||||
if (!this->virtual_ip)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cp = cp_payload_create();
|
||||
cp->set_config_type(cp, type);
|
||||
|
||||
ca = configuration_attribute_create();
|
||||
|
||||
if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
|
||||
{
|
||||
ca->set_type(ca, INTERNAL_IP4_ADDRESS);
|
||||
if (this->virtual_ip->is_anyaddr(this->virtual_ip))
|
||||
{
|
||||
chunk = chunk_empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk = this->virtual_ip->get_address(this->virtual_ip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ca->set_type(ca, INTERNAL_IP6_ADDRESS);
|
||||
if (this->virtual_ip->is_anyaddr(this->virtual_ip))
|
||||
{
|
||||
chunk = chunk_empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = chunk_alloca(1);
|
||||
*prefix.ptr = 64;
|
||||
chunk = this->virtual_ip->get_address(this->virtual_ip);
|
||||
chunk = chunk_cata("cc", chunk, prefix);
|
||||
}
|
||||
}
|
||||
ca->set_value(ca, chunk);
|
||||
cp->add_configuration_attribute(cp, ca);
|
||||
|
||||
/* we currently always add a DNS request if we request an IP */
|
||||
if (this->initiator)
|
||||
{
|
||||
ca = configuration_attribute_create();
|
||||
if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
|
||||
{
|
||||
ca->set_type(ca, INTERNAL_IP4_DNS);
|
||||
}
|
||||
else
|
||||
{
|
||||
ca->set_type(ca, INTERNAL_IP6_DNS);
|
||||
}
|
||||
cp->add_configuration_attribute(cp, ca);
|
||||
}
|
||||
else
|
||||
{
|
||||
host_t *ip;
|
||||
iterator_t *iterator = this->dns->create_iterator(this->dns, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&ip))
|
||||
{
|
||||
ca = configuration_attribute_create();
|
||||
if (ip->get_family(ip) == AF_INET)
|
||||
{
|
||||
ca->set_type(ca, INTERNAL_IP4_DNS);
|
||||
}
|
||||
else
|
||||
{
|
||||
ca->set_type(ca, INTERNAL_IP6_DNS);
|
||||
}
|
||||
chunk = ip->get_address(ip);
|
||||
ca->set_value(ca, chunk);
|
||||
cp->add_configuration_attribute(cp, ca);
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
message->add_payload(message, (payload_t*)cp);
|
||||
}
|
||||
|
||||
/**
|
||||
* process a single configuration attribute
|
||||
*/
|
||||
static void process_attribute(private_ike_config_t *this,
|
||||
configuration_attribute_t *ca)
|
||||
{
|
||||
host_t *ip;
|
||||
chunk_t addr;
|
||||
int family = AF_INET6;
|
||||
|
||||
switch (ca->get_type(ca))
|
||||
{
|
||||
case INTERNAL_IP4_ADDRESS:
|
||||
family = AF_INET;
|
||||
/* fall */
|
||||
case INTERNAL_IP6_ADDRESS:
|
||||
{
|
||||
addr = ca->get_value(ca);
|
||||
if (addr.len == 0)
|
||||
{
|
||||
ip = host_create_any(family);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* skip prefix byte in IPv6 payload*/
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
addr.len--;
|
||||
}
|
||||
ip = host_create_from_chunk(family, addr, 0);
|
||||
}
|
||||
if (ip && !this->virtual_ip)
|
||||
{
|
||||
this->virtual_ip = ip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INTERNAL_IP4_DNS:
|
||||
family = AF_INET;
|
||||
/* fall */
|
||||
case INTERNAL_IP6_DNS:
|
||||
{
|
||||
addr = ca->get_value(ca);
|
||||
if (addr.len == 0)
|
||||
{
|
||||
ip = host_create_any(family);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip = host_create_from_chunk(family, addr, 0);
|
||||
}
|
||||
if (ip)
|
||||
{
|
||||
this->dns->insert_last(this->dns, ip);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INTERNAL_IP4_NBNS:
|
||||
case INTERNAL_IP6_NBNS:
|
||||
/* TODO */
|
||||
default:
|
||||
DBG1(DBG_IKE, "ignoring %N config attribute",
|
||||
configuration_attribute_type_names,
|
||||
ca->get_type(ca));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for configuration payloads and attributes
|
||||
*/
|
||||
static void process_payloads(private_ike_config_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator, *attributes;
|
||||
payload_t *payload;
|
||||
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
if (payload->get_type(payload) == CONFIGURATION)
|
||||
{
|
||||
cp_payload_t *cp = (cp_payload_t*)payload;
|
||||
configuration_attribute_t *ca;
|
||||
switch (cp->get_config_type(cp))
|
||||
{
|
||||
case CFG_REQUEST:
|
||||
case CFG_REPLY:
|
||||
{
|
||||
attributes = cp->create_attribute_iterator(cp);
|
||||
while (attributes->iterate(attributes, (void**)&ca))
|
||||
{
|
||||
process_attribute(this, ca);
|
||||
}
|
||||
attributes->destroy(attributes);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG1(DBG_IKE, "ignoring %N config payload",
|
||||
config_type_names, cp->get_config_type(cp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t build_i(private_ike_config_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) != IKE_SA_INIT)
|
||||
{
|
||||
this->virtual_ip = this->policy->get_virtual_ip(this->policy, NULL);
|
||||
|
||||
build_payloads(this, message, CFG_REQUEST);
|
||||
}
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for responder
|
||||
*/
|
||||
static status_t process_r(private_ike_config_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) != IKE_SA_INIT)
|
||||
{
|
||||
process_payloads(this, message);
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_ike_config_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) != IKE_SA_INIT)
|
||||
{
|
||||
this->policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
|
||||
if (this->policy && this->virtual_ip)
|
||||
{
|
||||
host_t *ip;
|
||||
|
||||
DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
|
||||
ip = this->policy->get_virtual_ip(this->policy, this->virtual_ip);
|
||||
if (ip == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "not assigning a virtual IP to peer");
|
||||
return SUCCESS;
|
||||
}
|
||||
DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip);
|
||||
this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, ip);
|
||||
|
||||
this->virtual_ip->destroy(this->virtual_ip);
|
||||
this->virtual_ip = ip;
|
||||
|
||||
/* DNS is for testing only */
|
||||
if (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
|
||||
{
|
||||
ip->destroy(ip);
|
||||
ip = host_create_from_string("10.3.0.1", 0);
|
||||
this->dns->insert_last(this->dns, ip);
|
||||
ip = host_create_from_string("10.3.0.2", 0);
|
||||
this->dns->insert_last(this->dns, ip);
|
||||
}
|
||||
|
||||
build_payloads(this, message, CFG_REPLY);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_ike_config_t *this, message_t *message)
|
||||
{
|
||||
if (message->get_exchange_type(message) != IKE_SA_INIT)
|
||||
{
|
||||
host_t *ip;
|
||||
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
this->virtual_ip = NULL;
|
||||
|
||||
process_payloads(this, message);
|
||||
|
||||
if (this->virtual_ip)
|
||||
{
|
||||
this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
|
||||
|
||||
while (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
|
||||
{
|
||||
this->ike_sa->add_dns_server(this->ike_sa, ip);
|
||||
ip->destroy(ip);
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_ike_config_t *this)
|
||||
{
|
||||
return IKE_CONFIG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->virtual_ip = NULL;
|
||||
this->dns = linked_list_create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_ike_config_t *this)
|
||||
{
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy)
|
||||
{
|
||||
private_ike_config_t *this = malloc_thing(private_ike_config_t);
|
||||
|
||||
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;
|
||||
|
||||
if (policy)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
this->initiator = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
this->initiator = FALSE;
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->policy = policy;
|
||||
this->virtual_ip = NULL;
|
||||
this->dns = linked_list_create();
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file ike_config.h
|
||||
*
|
||||
* @brief Interface ike_config_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IKE_CONFIG_H_
|
||||
#define IKE_CONFIG_H_
|
||||
|
||||
typedef struct ike_config_t ike_config_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <config/policies/policy.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type IKE_CONFIG, sets up a virtual IP and other
|
||||
* configurations for an IKE_SA.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_config_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct ike_config_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new ike_config task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param policy policy for the initiator, NULL for the responder
|
||||
* @return ike_config task to handle by the task_manager
|
||||
*/
|
||||
ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy);
|
||||
|
||||
#endif /* IKE_CONFIG_H_ */
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* @file ike_delete.c
|
||||
*
|
||||
* @brief Implementation of the ike_delete task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2007 Martin Willi
|
||||
* 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 "ike_delete.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
|
||||
|
||||
typedef struct private_ike_delete_t private_ike_delete_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_delete_t task.
|
||||
*/
|
||||
struct private_ike_delete_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
ike_delete_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* are we responding to a delete, but have initated our own?
|
||||
*/
|
||||
bool simultaneous;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for initiator
|
||||
*/
|
||||
static status_t build_i(private_ike_delete_t *this, message_t *message)
|
||||
{
|
||||
delete_payload_t *delete_payload;
|
||||
|
||||
delete_payload = delete_payload_create(PROTO_IKE);
|
||||
message->add_payload(message, (payload_t*)delete_payload);
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_ike_delete_t *this, message_t *message)
|
||||
{
|
||||
/* completed, delete IKE_SA by returning FAILED */
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_r(private_ike_delete_t *this, message_t *message)
|
||||
{
|
||||
/* we don't even scan the payloads, as the message wouldn't have
|
||||
* come so far without being correct */
|
||||
switch (this->ike_sa->get_state(this->ike_sa))
|
||||
{
|
||||
case IKE_DELETING:
|
||||
this->simultaneous = TRUE;
|
||||
break;
|
||||
case IKE_ESTABLISHED:
|
||||
DBG1(DBG_IKE, "deleting IKE_SA on request");
|
||||
/* warn only if we are established */
|
||||
default:
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
|
||||
break;
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_ike_delete_t *this, message_t *message)
|
||||
{
|
||||
if (this->simultaneous)
|
||||
{
|
||||
/* wait for peers response for our delete request */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* completed, delete IKE_SA by returning FAILED */
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_ike_delete_t *this)
|
||||
{
|
||||
return IKE_DELETE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_ike_delete_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
this->simultaneous = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_ike_delete_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_ike_delete_t *this = malloc_thing(private_ike_delete_t);
|
||||
|
||||
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;
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->initiator = initiator;
|
||||
this->simultaneous = FALSE;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file ike_delete.h
|
||||
*
|
||||
* @brief Interface ike_delete_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IKE_DELETE_H_
|
||||
#define IKE_DELETE_H_
|
||||
|
||||
typedef struct ike_delete_t ike_delete_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type ike_delete, delete an IKE_SA.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_delete_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct ike_delete_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new ike_delete task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if we initiate the delete
|
||||
* @return ike_delete task to handle by the task_manager
|
||||
*/
|
||||
ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /* IKE_DELETE_H_ */
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file ike_dpd.c
|
||||
*
|
||||
* @brief Implementation of the ike_dpd task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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 "ike_dpd.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
|
||||
typedef struct private_ike_dpd_t private_ike_dpd_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_dpd_t task.
|
||||
*/
|
||||
struct private_ike_dpd_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
ike_dpd_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for initiator
|
||||
* Implementation of task_t.process for responder
|
||||
*/
|
||||
static status_t return_need_more(private_ike_dpd_t *this, message_t *message)
|
||||
{
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t return_success(private_ike_dpd_t *this, message_t *message)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_ike_dpd_t *this)
|
||||
{
|
||||
return IKE_DEADPEER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_ike_dpd_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_ike_dpd_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_dpd_t *ike_dpd_create(bool initiator)
|
||||
{
|
||||
private_ike_dpd_t *this = malloc_thing(private_ike_dpd_t);
|
||||
|
||||
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;
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))return_need_more;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))return_success;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))return_success;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))return_need_more;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file ike_dpd.h
|
||||
*
|
||||
* @brief Interface ike_dpd_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IKE_DPD_H_
|
||||
#define IKE_DPD_H_
|
||||
|
||||
typedef struct ike_dpd_t ike_dpd_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type ike_dpd, detects dead peers.
|
||||
*
|
||||
* The DPD task actually does nothing, as a DPD has no associated payloads.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_dpd_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct ike_dpd_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new ike_dpd task.
|
||||
*
|
||||
* @param initiator TRUE if thask is the original initator
|
||||
* @return ike_dpd task to handle by the task_manager
|
||||
*/
|
||||
ike_dpd_t *ike_dpd_create(bool initiator);
|
||||
|
||||
#endif /* IKE_DPD_H_ */
|
||||
@@ -0,0 +1,536 @@
|
||||
/**
|
||||
* @file ike_init.c
|
||||
*
|
||||
* @brief Implementation of the ike_init task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 "ike_init.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/ke_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
|
||||
|
||||
typedef struct private_ike_init_t private_ike_init_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_init_t task.
|
||||
*/
|
||||
struct private_ike_init_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
ike_init_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Connection established by this IKE_SA
|
||||
*/
|
||||
connection_t *connection;
|
||||
|
||||
/**
|
||||
* diffie hellman group to use
|
||||
*/
|
||||
diffie_hellman_group_t dh_group;
|
||||
|
||||
/**
|
||||
* Diffie hellman object used to generate public DH value.
|
||||
*/
|
||||
diffie_hellman_t *diffie_hellman;
|
||||
|
||||
/**
|
||||
* nonce chosen by us
|
||||
*/
|
||||
chunk_t my_nonce;
|
||||
|
||||
/**
|
||||
* nonce chosen by peer
|
||||
*/
|
||||
chunk_t other_nonce;
|
||||
|
||||
/**
|
||||
* Negotiated proposal used for IKE_SA
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* Old IKE_SA which gets rekeyed
|
||||
*/
|
||||
ike_sa_t *old_sa;
|
||||
};
|
||||
|
||||
/**
|
||||
* build the payloads for the message
|
||||
*/
|
||||
static void build_payloads(private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
ke_payload_t *ke_payload;
|
||||
nonce_payload_t *nonce_payload;
|
||||
linked_list_t *proposal_list;
|
||||
ike_sa_id_t *id;
|
||||
proposal_t *proposal;
|
||||
iterator_t *iterator;
|
||||
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
|
||||
this->connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
proposal_list = this->connection->get_proposals(this->connection);
|
||||
if (this->old_sa)
|
||||
{
|
||||
/* include SPI of new IKE_SA when we are rekeying */
|
||||
iterator = proposal_list->create_iterator(proposal_list, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&proposal))
|
||||
{
|
||||
proposal->set_spi(proposal, id->get_initiator_spi(id));
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
sa_payload = sa_payload_create_from_proposal_list(proposal_list);
|
||||
proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->old_sa)
|
||||
{
|
||||
/* include SPI of new IKE_SA when we are rekeying */
|
||||
this->proposal->set_spi(this->proposal, id->get_responder_spi(id));
|
||||
}
|
||||
sa_payload = sa_payload_create_from_proposal(this->proposal);
|
||||
}
|
||||
message->add_payload(message, (payload_t*)sa_payload);
|
||||
|
||||
ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
|
||||
message->add_payload(message, (payload_t*)ke_payload);
|
||||
|
||||
nonce_payload = nonce_payload_create();
|
||||
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
|
||||
|
||||
message->add_payload(message, (payload_t*)nonce_payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read payloads from message
|
||||
*/
|
||||
static void process_payloads(private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case SECURITY_ASSOCIATION:
|
||||
{
|
||||
sa_payload_t *sa_payload = (sa_payload_t*)payload;
|
||||
linked_list_t *proposal_list;
|
||||
|
||||
proposal_list = sa_payload->get_proposals(sa_payload);
|
||||
this->proposal = this->connection->select_proposal(
|
||||
this->connection, proposal_list);
|
||||
proposal_list->destroy_offset(proposal_list,
|
||||
offsetof(proposal_t, destroy));
|
||||
break;
|
||||
}
|
||||
case KEY_EXCHANGE:
|
||||
{
|
||||
ke_payload_t *ke_payload = (ke_payload_t*)payload;
|
||||
diffie_hellman_group_t dh_group;
|
||||
chunk_t key_data;
|
||||
|
||||
dh_group = ke_payload->get_dh_group_number(ke_payload);
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
if (dh_group != this->dh_group)
|
||||
{
|
||||
DBG1(DBG_IKE, "received a DH group not requested (%N)",
|
||||
diffie_hellman_group_names, dh_group);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->dh_group = dh_group;
|
||||
if (!this->connection->check_dh_group(this->connection,
|
||||
dh_group))
|
||||
{
|
||||
break;
|
||||
}
|
||||
this->diffie_hellman = diffie_hellman_create(dh_group);
|
||||
}
|
||||
if (this->diffie_hellman)
|
||||
{
|
||||
key_data = ke_payload->get_key_exchange_data(ke_payload);
|
||||
this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NONCE:
|
||||
{
|
||||
nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
|
||||
this->other_nonce = nonce_payload->get_nonce(nonce_payload);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t build_i(private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
randomizer_t *randomizer;
|
||||
status_t status;
|
||||
|
||||
this->connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
SIG(IKE_UP_START, "initiating IKE_SA to %H",
|
||||
this->connection->get_other_host(this->connection));
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
|
||||
|
||||
/* if the DH group is set via use_dh_group(), we already have a DH object */
|
||||
if (!this->diffie_hellman)
|
||||
{
|
||||
this->dh_group = this->connection->get_dh_group(this->connection);
|
||||
this->diffie_hellman = diffie_hellman_create(this->dh_group);
|
||||
if (this->diffie_hellman == NULL)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "configured DH group %N not supported",
|
||||
diffie_hellman_group_names, this->dh_group);
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
randomizer = randomizer_create();
|
||||
status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
|
||||
&this->my_nonce);
|
||||
randomizer->destroy(randomizer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "error generating random nonce value");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
build_payloads(this, message);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_r(private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
randomizer_t *randomizer;
|
||||
|
||||
this->connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA",
|
||||
message->get_source(message));
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
|
||||
|
||||
randomizer = randomizer_create();
|
||||
if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
|
||||
&this->my_nonce) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "error generating random nonce value");
|
||||
}
|
||||
randomizer->destroy(randomizer);
|
||||
|
||||
process_payloads(this, message);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
chunk_t secret;
|
||||
status_t status;
|
||||
|
||||
/* check if we have everything we need */
|
||||
if (this->proposal == NULL ||
|
||||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "received proposals inacceptable");
|
||||
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (this->diffie_hellman == NULL ||
|
||||
this->diffie_hellman->get_shared_secret(this->diffie_hellman,
|
||||
&secret) != SUCCESS)
|
||||
{
|
||||
chunk_t chunk;
|
||||
u_int16_t dh_enc;
|
||||
|
||||
SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)",
|
||||
diffie_hellman_group_names, this->dh_group);
|
||||
this->dh_group = this->connection->get_dh_group(this->connection);
|
||||
dh_enc = htons(this->dh_group);
|
||||
chunk.ptr = (u_int8_t*)&dh_enc;
|
||||
chunk.len = sizeof(dh_enc);
|
||||
message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk);
|
||||
DBG1(DBG_IKE, "requesting DH group %N",
|
||||
diffie_hellman_group_names, this->dh_group);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
|
||||
if (this->old_sa)
|
||||
{
|
||||
ike_sa_id_t *id;
|
||||
prf_t *prf, *child_prf;
|
||||
|
||||
/* Apply SPI if we are rekeying */
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
|
||||
|
||||
/* setup crypto keys for the rekeyed SA */
|
||||
prf = this->old_sa->get_prf(this->old_sa);
|
||||
child_prf = this->old_sa->get_child_prf(this->old_sa);
|
||||
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
|
||||
this->other_nonce, this->my_nonce,
|
||||
FALSE, child_prf, prf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* setup crypto keys */
|
||||
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
|
||||
this->other_nonce, this->my_nonce,
|
||||
FALSE, NULL, NULL);
|
||||
}
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "key derivation failed");
|
||||
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
build_payloads(this, message);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
chunk_t secret;
|
||||
status_t status;
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
|
||||
/* check for erronous notifies */
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
if (payload->get_type(payload) == NOTIFY)
|
||||
{
|
||||
notify_payload_t *notify = (notify_payload_t*)payload;
|
||||
notify_type_t type = notify->get_notify_type(notify);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case INVALID_KE_PAYLOAD:
|
||||
{
|
||||
chunk_t data;
|
||||
diffie_hellman_group_t old_dh_group;
|
||||
|
||||
old_dh_group = this->dh_group;
|
||||
data = notify->get_notification_data(notify);
|
||||
this->dh_group = ntohs(*((u_int16_t*)data.ptr));
|
||||
|
||||
DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested"
|
||||
" %N", diffie_hellman_group_names, old_dh_group,
|
||||
diffie_hellman_group_names, this->dh_group);
|
||||
if (!this->connection->check_dh_group(this->connection,
|
||||
this->dh_group))
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "requested DH group %N not "
|
||||
"acceptable, giving up", diffie_hellman_group_names,
|
||||
this->dh_group);
|
||||
iterator->destroy(iterator);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
this->ike_sa->reset(this->ike_sa);
|
||||
|
||||
iterator->destroy(iterator);
|
||||
return NEED_MORE;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (type < 16383)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "received %N notify error",
|
||||
notify_type_names, type);
|
||||
iterator->destroy(iterator);
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
process_payloads(this, message);
|
||||
|
||||
/* check if we have everything */
|
||||
if (this->proposal == NULL ||
|
||||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "peers proposal selection invalid");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (this->diffie_hellman == NULL ||
|
||||
this->diffie_hellman->get_shared_secret(this->diffie_hellman,
|
||||
&secret) != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "peers DH group selection invalid");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* Apply SPI if we are rekeying */
|
||||
if (this->old_sa)
|
||||
{
|
||||
ike_sa_id_t *id;
|
||||
prf_t *prf, *child_prf;
|
||||
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
|
||||
|
||||
/* setup crypto keys for the rekeyed SA */
|
||||
prf = this->old_sa->get_prf(this->old_sa);
|
||||
child_prf = this->old_sa->get_child_prf(this->old_sa);
|
||||
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
|
||||
this->my_nonce, this->other_nonce,
|
||||
TRUE, child_prf, prf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* setup crypto keys for a new SA */
|
||||
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
|
||||
this->my_nonce, this->other_nonce,
|
||||
TRUE, NULL, NULL);
|
||||
}
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "key derivation failed");
|
||||
return FAILED;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_ike_init_t *this)
|
||||
{
|
||||
return IKE_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
DESTROY_IF(this->proposal);
|
||||
DESTROY_IF(this->diffie_hellman);
|
||||
chunk_free(&this->my_nonce);
|
||||
chunk_free(&this->other_nonce);
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->proposal = NULL;
|
||||
this->diffie_hellman = diffie_hellman_create(this->dh_group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_ike_init_t *this)
|
||||
{
|
||||
DESTROY_IF(this->proposal);
|
||||
DESTROY_IF(this->diffie_hellman);
|
||||
chunk_free(&this->my_nonce);
|
||||
chunk_free(&this->other_nonce);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
|
||||
{
|
||||
private_ike_init_t *this = malloc_thing(private_ike_init_t);
|
||||
|
||||
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;
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->initiator = initiator;
|
||||
this->dh_group = MODP_NONE;
|
||||
this->diffie_hellman = NULL;
|
||||
this->my_nonce = chunk_empty;
|
||||
this->other_nonce = chunk_empty;
|
||||
this->proposal = NULL;
|
||||
this->connection = NULL;
|
||||
this->old_sa = old_sa;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file ike_init.h
|
||||
*
|
||||
* @brief Interface ike_init_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IKE_INIT_H_
|
||||
#define IKE_INIT_H_
|
||||
|
||||
typedef struct ike_init_t ike_init_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type IKE_INIT, creates an IKE_SA without authentication.
|
||||
*
|
||||
* The authentication of is handle in the ike_auth and/or ike_auth_eap task.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_init_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct ike_init_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new IKE_INIT task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for (new one when rekeying)
|
||||
* @param initiator TRUE if thask is the original initator
|
||||
* @param old_sa old IKE_SA when we are rekeying
|
||||
* @return ike_init task to handle by the task_manager
|
||||
*/
|
||||
ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa);
|
||||
|
||||
#endif /* IKE_INIT_H_ */
|
||||
@@ -0,0 +1,378 @@
|
||||
/**
|
||||
* @file ike_natd.c
|
||||
*
|
||||
* @brief Implementation of the ike_natd task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2007 Martin Willi
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* 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 "ike_natd.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
|
||||
|
||||
typedef struct private_ike_natd_t private_ike_natd_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_natd_t task.
|
||||
*/
|
||||
struct private_ike_natd_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
ike_natd_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Hasher used to build NAT detection hashes
|
||||
*/
|
||||
hasher_t *hasher;
|
||||
|
||||
/**
|
||||
* Did we process any NAT detection notifys for a source address?
|
||||
*/
|
||||
bool src_seen;
|
||||
|
||||
/**
|
||||
* Did we process any NAT detection notifys for a destination address?
|
||||
*/
|
||||
bool dst_seen;
|
||||
|
||||
/**
|
||||
* Have we found a matching source address NAT hash?
|
||||
*/
|
||||
bool src_matched;
|
||||
|
||||
/**
|
||||
* Have we found a matching destination address NAT hash?
|
||||
*/
|
||||
bool dst_matched;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Build NAT detection hash for a host
|
||||
*/
|
||||
static chunk_t generate_natd_hash(private_ike_natd_t *this,
|
||||
ike_sa_id_t *ike_sa_id, host_t *host)
|
||||
{
|
||||
chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk;
|
||||
chunk_t natd_hash;
|
||||
u_int64_t spi_i, spi_r;
|
||||
u_int16_t port;
|
||||
|
||||
/* prepare all requred chunks */
|
||||
spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
|
||||
spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
|
||||
spi_i_chunk.ptr = (void*)&spi_i;
|
||||
spi_i_chunk.len = sizeof(spi_i);
|
||||
spi_r_chunk.ptr = (void*)&spi_r;
|
||||
spi_r_chunk.len = sizeof(spi_r);
|
||||
port = htons(host->get_port(host));
|
||||
port_chunk.ptr = (void*)&port;
|
||||
port_chunk.len = sizeof(port);
|
||||
addr_chunk = host->get_address(host);
|
||||
DBG2(DBG_IKE, "using SPI %J", ike_sa_id);
|
||||
|
||||
/* natd_hash = SHA1( spi_i | spi_r | address | port ) */
|
||||
natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk);
|
||||
this->hasher->allocate_hash(this->hasher, natd_chunk, &natd_hash);
|
||||
DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
|
||||
DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
|
||||
|
||||
chunk_free(&natd_chunk);
|
||||
return natd_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a NAT detection notify payload.
|
||||
*/
|
||||
static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
|
||||
notify_type_t type, host_t *host)
|
||||
{
|
||||
chunk_t hash;
|
||||
notify_payload_t *notify;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
|
||||
ike_sa_id = this->ike_sa->get_id(this->ike_sa);
|
||||
notify = notify_payload_create();
|
||||
notify->set_notify_type(notify, type);
|
||||
hash = generate_natd_hash(this, ike_sa_id, host);
|
||||
notify->set_notification_data(notify, hash);
|
||||
chunk_free(&hash);
|
||||
|
||||
return notify;
|
||||
}
|
||||
|
||||
/**
|
||||
* read notifys from message and evaluate them
|
||||
*/
|
||||
static void process_payloads(private_ike_natd_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
notify_payload_t *notify;
|
||||
chunk_t hash, src_hash, dst_hash;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
host_t *me, *other;
|
||||
|
||||
/* Precompute NAT-D hashes for incoming NAT notify comparison */
|
||||
ike_sa_id = message->get_ike_sa_id(message);
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
dst_hash = generate_natd_hash(this, ike_sa_id, me);
|
||||
src_hash = generate_natd_hash(this, ike_sa_id, other);
|
||||
|
||||
DBG2(DBG_IKE, "precalculated src_hash %B", &src_hash);
|
||||
DBG2(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
|
||||
|
||||
iterator = message->get_payload_iterator(message);
|
||||
while (iterator->iterate(iterator, (void**)&payload))
|
||||
{
|
||||
if (payload->get_type(payload) != NOTIFY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
notify = (notify_payload_t*)payload;
|
||||
switch (notify->get_notify_type(notify))
|
||||
{
|
||||
case NAT_DETECTION_DESTINATION_IP:
|
||||
{
|
||||
this->dst_seen = TRUE;
|
||||
if (!this->dst_matched)
|
||||
{
|
||||
hash = notify->get_notification_data(notify);
|
||||
DBG2(DBG_IKE, "received dst_hash %B", &hash);
|
||||
if (chunk_equals(hash, dst_hash))
|
||||
{
|
||||
this->dst_matched = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NAT_DETECTION_SOURCE_IP:
|
||||
{
|
||||
this->src_seen = TRUE;
|
||||
if (!this->src_matched)
|
||||
{
|
||||
hash = notify->get_notification_data(notify);
|
||||
DBG2(DBG_IKE, "received src_hash %B", &hash);
|
||||
if (chunk_equals(hash, src_hash))
|
||||
{
|
||||
this->src_matched = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
chunk_free(&src_hash);
|
||||
chunk_free(&dst_hash);
|
||||
|
||||
if (this->src_seen && this->dst_seen)
|
||||
{
|
||||
if (!this->dst_matched)
|
||||
{
|
||||
this->ike_sa->enable_natt(this->ike_sa, TRUE);
|
||||
}
|
||||
if (!this->src_matched)
|
||||
{
|
||||
this->ike_sa->enable_natt(this->ike_sa, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_ike_natd_t *this, message_t *message)
|
||||
{
|
||||
process_payloads(this, message);
|
||||
|
||||
if (this->ike_sa->is_natt_enabled(this->ike_sa))
|
||||
{
|
||||
host_t *me, *other;
|
||||
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
me->set_port(me, IKEV2_NATT_PORT);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
other->set_port(other, IKEV2_NATT_PORT);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t build_i(private_ike_natd_t *this, message_t *message)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
linked_list_t *list;
|
||||
host_t *host;
|
||||
|
||||
/* include one notify if our address is defined, all addresses otherwise */
|
||||
host = this->ike_sa->get_my_host(this->ike_sa);
|
||||
if (host->is_anyaddr(host))
|
||||
{
|
||||
/* TODO: we could get the src address from netlink!? */
|
||||
list = charon->socket->create_local_address_list(charon->socket);
|
||||
while (list->remove_first(list, (void**)&host) == SUCCESS)
|
||||
{
|
||||
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
|
||||
host->destroy(host);
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
}
|
||||
list->destroy(list);
|
||||
}
|
||||
else
|
||||
{
|
||||
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
}
|
||||
|
||||
host = this->ike_sa->get_other_host(this->ike_sa);
|
||||
notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_ike_natd_t *this, message_t *message)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
host_t *me, *other;
|
||||
iterator_t *iterator;
|
||||
u_int count;
|
||||
|
||||
/* when only one payload is in the message, an error occured.
|
||||
* TODO: find a better hack */
|
||||
iterator = message->get_payload_iterator(message);
|
||||
count = iterator->get_count(iterator);
|
||||
iterator->destroy(iterator);
|
||||
if (count < 3)
|
||||
{
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
if (this->src_seen && this->dst_seen)
|
||||
{
|
||||
/* initiator seems to support NAT detection, add response */
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for responder
|
||||
*/
|
||||
static status_t process_r(private_ike_natd_t *this, message_t *message)
|
||||
{
|
||||
process_payloads(this, message);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_ike_natd_t *this)
|
||||
{
|
||||
return IKE_NATD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
this->src_seen = FALSE;
|
||||
this->dst_seen = FALSE;
|
||||
this->src_matched = FALSE;
|
||||
this->dst_matched = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_ike_natd_t *this)
|
||||
{
|
||||
this->hasher->destroy(this->hasher);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_ike_natd_t *this = malloc_thing(private_ike_natd_t);
|
||||
|
||||
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;
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->initiator = initiator;
|
||||
this->hasher = hasher_create(HASH_SHA1);
|
||||
this->src_seen = FALSE;
|
||||
this->dst_seen = FALSE;
|
||||
this->src_matched = FALSE;
|
||||
this->dst_matched = FALSE;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file ike_natd.h
|
||||
*
|
||||
* @brief Interface ike_natd_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IKE_NATD_H_
|
||||
#define IKE_NATD_H_
|
||||
|
||||
typedef struct ike_natd_t ike_natd_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_natd_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct ike_natd_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new ike_natd task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if thask is the original initator
|
||||
* @return ike_natd task to handle by the task_manager
|
||||
*/
|
||||
ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /* IKE_NATD_H_ */
|
||||
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* @file ike_rekey.c
|
||||
*
|
||||
* @brief Implementation of the ike_rekey task.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 "ike_rekey.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <sa/tasks/ike_init.h>
|
||||
#include <queues/jobs/delete_ike_sa_job.h>
|
||||
|
||||
|
||||
typedef struct private_ike_rekey_t private_ike_rekey_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_rekey_t task.
|
||||
*/
|
||||
struct private_ike_rekey_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
ike_rekey_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* New IKE_SA which replaces the current one
|
||||
*/
|
||||
ike_sa_t *new_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* the IKE_INIT task which is reused to simplify rekeying
|
||||
*/
|
||||
ike_init_t *ike_init;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for initiator
|
||||
*/
|
||||
static status_t build_i(private_ike_rekey_t *this, message_t *message)
|
||||
{
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
ike_sa_id_t *id;
|
||||
|
||||
id = ike_sa_id_create(0, 0, TRUE);
|
||||
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
|
||||
id->destroy(id);
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
this->new_sa->set_connection(this->new_sa, connection);
|
||||
this->new_sa->set_policy(this->new_sa, policy);
|
||||
|
||||
this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
|
||||
this->ike_init->task.build(&this->ike_init->task, message);
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_r(private_ike_rekey_t *this, message_t *message)
|
||||
{
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
ike_sa_id_t *id;
|
||||
|
||||
id = ike_sa_id_create(0, 0, FALSE);
|
||||
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
|
||||
id->destroy(id);
|
||||
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
this->new_sa->set_connection(this->new_sa, connection);
|
||||
this->new_sa->set_policy(this->new_sa, policy);
|
||||
|
||||
this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa);
|
||||
this->ike_init->task.process(&this->ike_init->task, message);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.build for responder
|
||||
*/
|
||||
static status_t build_r(private_ike_rekey_t *this, message_t *message)
|
||||
{
|
||||
if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
|
||||
this->new_sa->inherit(this->new_sa, this->ike_sa);
|
||||
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
|
||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
|
||||
this->new_sa = NULL;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.process for initiator
|
||||
*/
|
||||
static status_t process_i(private_ike_rekey_t *this, message_t *message)
|
||||
{
|
||||
job_t *job;
|
||||
|
||||
if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
|
||||
this->new_sa->inherit(this->new_sa, this->ike_sa);
|
||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
|
||||
this->new_sa = NULL;
|
||||
|
||||
job = (job_t*)delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa),
|
||||
TRUE);
|
||||
|
||||
charon->job_queue->add(charon->job_queue, job);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.get_type
|
||||
*/
|
||||
static task_type_t get_type(private_ike_rekey_t *this)
|
||||
{
|
||||
return IKE_REKEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.migrate
|
||||
*/
|
||||
static void migrate(private_ike_rekey_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
if (this->ike_init)
|
||||
{
|
||||
this->ike_init->task.destroy(&this->ike_init->task);
|
||||
}
|
||||
if (this->new_sa)
|
||||
{
|
||||
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
|
||||
this->new_sa);
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->new_sa = NULL;
|
||||
this->ike_init = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of task_t.destroy
|
||||
*/
|
||||
static void destroy(private_ike_rekey_t *this)
|
||||
{
|
||||
if (this->ike_init)
|
||||
{
|
||||
this->ike_init->task.destroy(&this->ike_init->task);
|
||||
}
|
||||
if (this->new_sa)
|
||||
{
|
||||
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
|
||||
this->new_sa);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_ike_rekey_t *this = malloc_thing(private_ike_rekey_t);
|
||||
|
||||
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;
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
|
||||
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
|
||||
}
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->new_sa = NULL;
|
||||
this->ike_init = NULL;
|
||||
this->initiator = initiator;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file ike_rekey.h
|
||||
*
|
||||
* @brief Interface ike_rekey_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IKE_REKEY_H_
|
||||
#define IKE_REKEY_H_
|
||||
|
||||
typedef struct ike_rekey_t ike_rekey_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
|
||||
/**
|
||||
* @brief Task of type IKE_REKEY, rekey an established IKE_SA.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - ike_rekey_create()
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct ike_rekey_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new IKE_REKEY task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE for initiator, FALSE for responder
|
||||
* @return IKE_REKEY task to handle by the task_manager
|
||||
*/
|
||||
ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /* IKE_REKEY_H_ */
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file task.c
|
||||
*
|
||||
* @brief Enum values for task types
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* 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 "task.h"
|
||||
|
||||
ENUM(task_type_names, IKE_INIT, CHILD_REKEY,
|
||||
"IKE_INIT",
|
||||
"IKE_NATD",
|
||||
"IKE_AUTHENTICATE",
|
||||
"IKE_CERT",
|
||||
"IKE_CONFIG",
|
||||
"IKE_DPD",
|
||||
"IKE_REKEY",
|
||||
"IKE_DELETE",
|
||||
"IKE_DEADPEER",
|
||||
"CHILD_CREATE",
|
||||
"CHILD_DELETE",
|
||||
"CHILD_REKEY",
|
||||
);
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @file task.h
|
||||
*
|
||||
* @brief Interface task_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef TASK_H_
|
||||
#define TASK_H_
|
||||
|
||||
typedef enum task_type_t task_type_t;
|
||||
typedef struct task_t task_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <encoding/message.h>
|
||||
|
||||
/**
|
||||
* @brief Different kinds of tasks.
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
enum task_type_t {
|
||||
/** establish an unauthenticated IKE_SA */
|
||||
IKE_INIT,
|
||||
/** detect NAT situation */
|
||||
IKE_NATD,
|
||||
/** authenticate the initiated IKE_SA */
|
||||
IKE_AUTHENTICATE,
|
||||
/** exchange certificates and requests */
|
||||
IKE_CERT,
|
||||
/** Configuration payloads, virtual IP and such */
|
||||
IKE_CONFIG,
|
||||
/** DPD detection */
|
||||
IKE_DEADPEER,
|
||||
/** rekey an IKE_SA */
|
||||
IKE_REKEY,
|
||||
/** delete an IKE_SA */
|
||||
IKE_DELETE,
|
||||
/** liveness check */
|
||||
IKE_DPD,
|
||||
/** establish a CHILD_SA within an IKE_SA */
|
||||
CHILD_CREATE,
|
||||
/** delete an established CHILD_SA */
|
||||
CHILD_DELETE,
|
||||
/** rekey an CHILD_SA */
|
||||
CHILD_REKEY,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum names for task_type_t.
|
||||
*/
|
||||
extern enum_name_t *task_type_names;
|
||||
|
||||
/**
|
||||
* @brief Interface for a task, an operation handled within exchanges.
|
||||
*
|
||||
* A task is an elemantary operation. It may be handled by a single or by
|
||||
* multiple exchanges. An exchange may even complete multiple tasks.
|
||||
* A task has a build() and an process() operation. The build() operation
|
||||
* creates payloads and adds it to the message. The process() operation
|
||||
* inspects a message and handles its payloads. An initiator of an exchange
|
||||
* first calls build() to build the request, and processes the response message
|
||||
* with the process() method.
|
||||
* A responder does the opposite; it calls process() first to handle an incoming
|
||||
* request and secondly calls build() to build an appropriate response.
|
||||
* Both methods return either SUCCESS, NEED_MORE or FAILED. A SUCCESS indicates
|
||||
* that the task completed, even when the task completed unsuccesfully. The
|
||||
* manager then removes the task from the list. A NEED_MORE is returned when
|
||||
* the task needs further build()/process() calls to complete, the manager
|
||||
* leaves the taks in the queue. A returned FAILED indicates a critical failure.
|
||||
* The manager closes the IKE_SA whenever a task returns FAILED.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - None, use implementations specific constructors
|
||||
*
|
||||
* @ingroup tasks
|
||||
*/
|
||||
struct task_t {
|
||||
|
||||
/**
|
||||
* @brief Build a request or response message for this task.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message message to add payloads to
|
||||
* @return
|
||||
* - FAILED if a critical error occured
|
||||
* - NEED_MORE if another call to build/process needed
|
||||
* - SUCCESS if task completed
|
||||
*/
|
||||
status_t (*build) (task_t *this, message_t *message);
|
||||
|
||||
/**
|
||||
* @brief Process a request or response message for this task.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message message to read payloads from
|
||||
* @return
|
||||
* - FAILED if a critical error occured
|
||||
* - NEED_MORE if another call to build/process needed
|
||||
* - SUCCESS if task completed
|
||||
*/
|
||||
status_t (*process) (task_t *this, message_t *message);
|
||||
|
||||
/**
|
||||
* @brief Get the type of the task implementation.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
task_type_t (*get_type) (task_t *this);
|
||||
|
||||
/**
|
||||
* @brief Migrate a task to a new IKE_SA.
|
||||
*
|
||||
* After migrating a task, it goes back to a state where it can be
|
||||
* used again to initate an exchange. This is useful when a task
|
||||
* has to get migrated to a new IKE_SA.
|
||||
* A special usage is when a INVALID_KE_PAYLOAD is received. A call
|
||||
* to reset resets the task, but uses another DH group for the next
|
||||
* try.
|
||||
* The ike_sa is the new IKE_SA this task belongs to and operates on.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param ike_sa new IKE_SA this task works for
|
||||
*/
|
||||
void (*migrate) (task_t *this, ike_sa_t *ike_sa);
|
||||
|
||||
/**
|
||||
* @brief Destroys a task_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy) (task_t *this);
|
||||
};
|
||||
|
||||
#endif /* TASK_H_ */
|
||||
Reference in New Issue
Block a user