added policy cache to kernel interface

allows refcounting of multiple installed policies
	finally brings us stable simultaneous rekeying
This commit is contained in:
Martin Willi
2006-07-12 11:42:36 +00:00
parent 269f7f448b
commit aeeb4f4f97
7 changed files with 564 additions and 579 deletions
+34 -125
View File
@@ -113,11 +113,6 @@ struct private_child_sa_t {
* transaction which is rekeying this CHILD_SA
*/
void *rekeying_transaction;
/**
* has this child SA been rekeyed/is rekeying?
*/
bool is_rekeying;
/**
* Specifies if NAT traversal is used
@@ -446,21 +441,21 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
policy->me.net, policy->other.net,
policy->me.net_mask, policy->other.net_mask,
XFRM_POLICY_OUT, policy->upper_proto,
this->protocol, this->reqid);
this->protocol, this->reqid, FALSE);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_IN, policy->upper_proto,
this->protocol, this->reqid);
this->protocol, this->reqid, FALSE);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_FWD, policy->upper_proto,
this->protocol, this->reqid);
this->protocol, this->reqid, FALSE);
if (status != SUCCESS)
{
@@ -487,7 +482,6 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
static void set_rekeying_transaction(private_child_sa_t *this, void *transaction)
{
this->rekeying_transaction = transaction;
this->is_rekeying = TRUE;
}
/**
@@ -498,100 +492,28 @@ static void* get_rekeying_transaction(private_child_sa_t *this)
return this->rekeying_transaction;
}
/**
* Implementation of child_sa_t.is_rekeying.
*/
static bool is_rekeying(private_child_sa_t *this)
{
return this->is_rekeying;
}
/**
* Implementation of child_sa_t.get_use_time
*/
static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use_time)
{
iterator_t *iterator;
sa_policy_t *policy;
struct protoent *proto;
char proto_buf[8] = "";
char *proto_name = proto_buf;
status_t status;
*use_time = UNDEFINED_TIME;
iterator = this->policies->create_iterator(this->policies, TRUE);
while (iterator->iterate(iterator, (void**)&policy))
if (inbound)
{
time_t ut;
if (policy->upper_proto)
{
proto = getprotobynumber(policy->upper_proto);
if (proto)
{
proto_name = proto->p_name;
}
else
{
snprintf(proto_buf, sizeof(proto_buf), "<%d>", policy->upper_proto);
}
}
this->logger->log(this->logger, CONTROL|LEVEL1,
"querying policy: %s/%d==%s==%s/%d",
policy->me.net->get_address(policy->me.net), policy->me.net_mask,
proto_name,
policy->other.net->get_address(policy->other.net), policy->other.net_mask);
if (inbound)
{
status = charon->kernel_interface->query_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_IN, policy->upper_proto,
&ut);
/* also check forward policy in tunnel mode */
if (status == SUCCESS /*&& mode == TUNNEL XXX */)
{
time_t fwd;
status = charon->kernel_interface->query_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_FWD, policy->upper_proto,
&fwd);
if (status == SUCCESS)
{
ut = max(ut, fwd);
}
}
}
else
{
status = charon->kernel_interface->query_policy(charon->kernel_interface,
this->me.addr, this->other.addr,
policy->me.net, policy->other.net,
policy->me.net_mask, policy->other.net_mask,
XFRM_POLICY_OUT, policy->upper_proto,
&ut);
}
if (status != SUCCESS)
{
iterator->destroy(iterator);
return FAILED;
}
*use_time = max(*use_time, ut);
status = charon->kernel_interface->query_sa(charon->kernel_interface,
this->me.addr, this->me.spi,
this->protocol, use_time);
}
iterator->destroy(iterator);
return SUCCESS;
else
{
status = charon->kernel_interface->query_sa(charon->kernel_interface,
this->other.addr, this->other.spi,
this->protocol, use_time);
}
return status;
}
/**
@@ -759,18 +681,13 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho
iterator = this->policies->create_iterator(this->policies, TRUE);
while (iterator->iterate(iterator, (void**)&policy))
{
this->logger->log(this->logger, CONTROL|LEVEL1,
"updating policy: %s/%d====%s/%d",
policy->me.net->get_address(policy->me.net), policy->me.net_mask,
policy->other.net->get_address(policy->other.net), policy->other.net_mask);
status = charon->kernel_interface->add_policy(
charon->kernel_interface,
new_me, new_other,
policy->me.net, policy->other.net,
policy->me.net_mask, policy->other.net_mask,
XFRM_POLICY_OUT, policy->upper_proto,
this->protocol, this->reqid);
this->protocol, this->reqid, TRUE);
status |= charon->kernel_interface->add_policy(
charon->kernel_interface,
@@ -778,7 +695,7 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_IN, policy->upper_proto,
this->protocol, this->reqid);
this->protocol, this->reqid, TRUE);
status |= charon->kernel_interface->add_policy(
charon->kernel_interface,
@@ -786,8 +703,8 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_FWD, policy->upper_proto,
this->protocol, this->reqid);
this->protocol, this->reqid, TRUE);
if (status != SUCCESS)
{
iterator->destroy(iterator);
@@ -879,27 +796,21 @@ static void destroy(private_child_sa_t *this)
/* delete all policies in the kernel */
while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
{
if (!this->is_rekeying)
{
/* let rekeyed policies, as they are used by another child_sa */
charon->kernel_interface->del_policy(charon->kernel_interface,
this->me.addr, this->other.addr,
policy->me.net, policy->other.net,
policy->me.net_mask, policy->other.net_mask,
XFRM_POLICY_OUT, policy->upper_proto);
charon->kernel_interface->del_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_IN, policy->upper_proto);
charon->kernel_interface->del_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_FWD, policy->upper_proto);
}
/* let rekeyed policies, as they are used by another child_sa */
charon->kernel_interface->del_policy(charon->kernel_interface,
policy->me.net, policy->other.net,
policy->me.net_mask, policy->other.net_mask,
XFRM_POLICY_OUT, policy->upper_proto);
charon->kernel_interface->del_policy(charon->kernel_interface,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_IN, policy->upper_proto);
charon->kernel_interface->del_policy(charon->kernel_interface,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_FWD, policy->upper_proto);
policy->me.net->destroy(policy->me.net);
policy->other.net->destroy(policy->other.net);
free(policy);
@@ -933,7 +844,6 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
this->public.set_rekeying_transaction = (void (*)(child_sa_t*,void*))set_rekeying_transaction;
this->public.get_rekeying_transaction = (void* (*)(child_sa_t*))get_rekeying_transaction;
this->public.is_rekeying = (bool (*)(child_sa_t*))is_rekeying;
this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status;
this->public.destroy = (void(*)(child_sa_t*))destroy;
@@ -953,7 +863,6 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
this->policies = linked_list_create();
this->protocol = PROTO_NONE;
this->rekeying_transaction = NULL;
this->is_rekeying = FALSE;
return &this->public;
}
+5 -12
View File
@@ -174,6 +174,9 @@ struct child_sa_t {
* such situations to handle them cleanly. A rekeying transaction
* registers itself to the CHILD_SA, and checks later if another
* transaction is in progress of a rekey.
*
* @todo Fix include problematics to allow inclusion of
* the create_child_sa_t transaction.
*
* @param this calling object
*/
@@ -182,22 +185,12 @@ struct child_sa_t {
/**
* @brief Get the transaction which rekeys this CHILD_SA.
*
* See set_rekeying_transactoin
* @see set_rekeying_transactoin().
*
* @param this calling object
*/
void* (*get_rekeying_transaction) (child_sa_t *this);
/**
* @brief Is the CHILD SA rekeying/in progress of rekeying?
*
* This is a readonly parameter. It is set whenever the
* set_rekeying_transaction() method is called.
*
* @param this calling object
*/
bool (*is_rekeying) (child_sa_t *this);
/**
* @brief Log the status of a child_sa to a logger.
*
@@ -223,7 +216,7 @@ struct child_sa_t {
/**
* @brief Constructor to create a new child_sa_t.
*
*
* @param rekey_reqid reqid of old CHILD_SA when rekeying, 0 otherwise
* @param me own address
* @param other remote address
+6 -17
View File
@@ -172,8 +172,8 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result)
host_t *me, *other;
/* check if we are not already rekeying */
if (this->rekeyed_sa &&
this->rekeyed_sa->is_rekeying(this->rekeyed_sa))
if (this->rekeyed_sa &&
this->rekeyed_sa->get_rekeying_transaction(this->rekeyed_sa))
{
this->logger->log(this->logger, ERROR,
"rekeying a CHILD_SA which is already rekeying, aborted");
@@ -628,20 +628,11 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request
response->add_payload(response, (payload_t*)ts_response);
}
/* CHILD_SA successfully created. We set us as the rekeying transaction of
* this SA. If we already initiated rekeying of the same SA, we will detect
* the rekeyed SA. If we already initiated rekeying of the same SA, we will detect
* this later in the conclude() call. */
if (this->rekeyed_sa)
{
if (this->rekeyed_sa->is_rekeying(this->rekeyed_sa))
{
/* rekeying already in progress, register us, too */
this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, &this->public);
}
else
{
/* no rekeying in progress. mark SA as rekeyed, but not conflicted */
this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, NULL);
}
this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, &this->public);
}
return SUCCESS;
}
@@ -779,14 +770,14 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response,
other = (private_create_child_sa_t*)
this->rekeyed_sa->get_rekeying_transaction(this->rekeyed_sa);
/* we are not rekeying anymore, unregister us */
/* rekeying finished, update SA status */
this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, NULL);
if (other != this)
{ /* simlutaneous rekeying is going on, not so good */
chunk_t this_lowest, other_lowest;
/* check if this has a lower nonce the other */
/* check if this has a lower nonce than other */
if (memcmp(this->nonce_i.ptr, this->nonce_r.ptr,
min(this->nonce_i.len, this->nonce_r.len)) < 0)
{
@@ -822,7 +813,6 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response,
/* delete the old SA if we have won the rekeying nonce compare*/
if (!this->lost)
{
other->rekeyed_sa->set_rekeying_transaction(other->rekeyed_sa, NULL);
delete_child_sa = delete_child_sa_create(this->ike_sa, this->message_id + 1);
delete_child_sa->set_child_sa(delete_child_sa, this->rekeyed_sa);
*next = (transaction_t*)delete_child_sa;
@@ -832,7 +822,6 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response,
{
/* we have lost simlutaneous rekeying, delete the CHILD_SA we just have created */
delete_child_sa = delete_child_sa_create(this->ike_sa, this->message_id + 1);
new_child->set_rekeying_transaction(new_child, NULL);
delete_child_sa->set_child_sa(delete_child_sa, new_child);
*next = (transaction_t*)delete_child_sa;
}
+5 -2
View File
@@ -192,8 +192,11 @@ static status_t process_delete(private_delete_child_sa_t *this, delete_payload_t
* this means we have lost the nonce comparison, and the rekeying
* will fail. We set a flag in the transaction for this special case.
*/
this->logger->log(this->logger, CONTROL,
"DELETE received while rekeying, rekeying cancelled");
if (!response)
{ /* only whine as initiator */
this->logger->log(this->logger, CONTROL,
"DELETE received while rekeying, rekeying cancelled");
}
rekey->cancel(rekey);
}
/* delete it, with inbound spi */