child-delete: Track flags per individual CHILD_SA
This commit is contained in:
@@ -39,41 +39,51 @@ struct private_child_delete_t {
|
|||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are we the initiator?
|
* Whether we are the initiator of the exchange
|
||||||
*/
|
*/
|
||||||
bool initiator;
|
bool initiator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Protocol of CHILD_SA to delete
|
* Protocol of CHILD_SA to delete (as initiator)
|
||||||
*/
|
*/
|
||||||
protocol_id_t protocol;
|
protocol_id_t protocol;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inbound SPI of CHILD_SA to delete
|
* Inbound SPI of CHILD_SA to delete (as initiator)
|
||||||
*/
|
*/
|
||||||
uint32_t spi;
|
uint32_t spi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* whether to enforce delete action policy
|
* CHILD_SA already expired (as initiator)
|
||||||
*/
|
|
||||||
bool check_delete_action;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* is this delete exchange following a rekey?
|
|
||||||
*/
|
|
||||||
bool rekeyed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CHILD_SA already expired?
|
|
||||||
*/
|
*/
|
||||||
bool expired;
|
bool expired;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CHILD_SAs which get deleted
|
* CHILD_SAs which get deleted, entry_t*
|
||||||
*/
|
*/
|
||||||
linked_list_t *child_sas;
|
linked_list_t *child_sas;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a deleted CHILD_SA
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** Deleted CHILD_SA */
|
||||||
|
child_sa_t *child_sa;
|
||||||
|
/** Whether the CHILD_SA was rekeyed */
|
||||||
|
bool rekeyed;
|
||||||
|
/** Whether to enforce any delete action policy */
|
||||||
|
bool check_delete_action;
|
||||||
|
} entry_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given entry is for the same CHILD_SA
|
||||||
|
*/
|
||||||
|
static bool match_child(entry_t *entry, child_sa_t *child_sa)
|
||||||
|
{
|
||||||
|
return entry->child_sa == child_sa;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* build the delete payloads from the listed child_sas
|
* build the delete payloads from the listed child_sas
|
||||||
*/
|
*/
|
||||||
@@ -81,25 +91,27 @@ static void build_payloads(private_child_delete_t *this, message_t *message)
|
|||||||
{
|
{
|
||||||
delete_payload_t *ah = NULL, *esp = NULL;
|
delete_payload_t *ah = NULL, *esp = NULL;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
child_sa_t *child_sa;
|
entry_t *entry;
|
||||||
|
protocol_id_t protocol;
|
||||||
|
uint32_t spi;
|
||||||
|
|
||||||
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
||||||
while (enumerator->enumerate(enumerator, (void**)&child_sa))
|
while (enumerator->enumerate(enumerator, (void**)&entry))
|
||||||
{
|
{
|
||||||
protocol_id_t protocol = child_sa->get_protocol(child_sa);
|
protocol = entry->child_sa->get_protocol(entry->child_sa);
|
||||||
uint32_t spi = child_sa->get_spi(child_sa, TRUE);
|
spi = entry->child_sa->get_spi(entry->child_sa, TRUE);
|
||||||
|
|
||||||
switch (protocol)
|
switch (protocol)
|
||||||
{
|
{
|
||||||
case PROTO_ESP:
|
case PROTO_ESP:
|
||||||
if (esp == NULL)
|
if (!esp)
|
||||||
{
|
{
|
||||||
esp = delete_payload_create(PLV2_DELETE, PROTO_ESP);
|
esp = delete_payload_create(PLV2_DELETE, PROTO_ESP);
|
||||||
message->add_payload(message, (payload_t*)esp);
|
message->add_payload(message, (payload_t*)esp);
|
||||||
}
|
}
|
||||||
esp->add_spi(esp, spi);
|
esp->add_spi(esp, spi);
|
||||||
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
|
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
|
||||||
protocol_id_names, protocol, ntohl(spi));
|
protocol_id_names, protocol, ntohl(spi));
|
||||||
break;
|
break;
|
||||||
case PROTO_AH:
|
case PROTO_AH:
|
||||||
if (ah == NULL)
|
if (ah == NULL)
|
||||||
@@ -109,12 +121,12 @@ static void build_payloads(private_child_delete_t *this, message_t *message)
|
|||||||
}
|
}
|
||||||
ah->add_spi(ah, spi);
|
ah->add_spi(ah, spi);
|
||||||
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
|
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
|
||||||
protocol_id_names, protocol, ntohl(spi));
|
protocol_id_names, protocol, ntohl(spi));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
child_sa->set_state(child_sa, CHILD_DELETING);
|
entry->child_sa->set_state(entry->child_sa, CHILD_DELETING);
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
}
|
}
|
||||||
@@ -208,6 +220,7 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
|
|||||||
uint32_t spi;
|
uint32_t spi;
|
||||||
protocol_id_t protocol;
|
protocol_id_t protocol;
|
||||||
child_sa_t *child_sa;
|
child_sa_t *child_sa;
|
||||||
|
entry_t *entry;
|
||||||
|
|
||||||
payloads = message->create_payload_enumerator(message);
|
payloads = message->create_payload_enumerator(message);
|
||||||
while (payloads->enumerate(payloads, &payload))
|
while (payloads->enumerate(payloads, &payload))
|
||||||
@@ -225,27 +238,37 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
|
|||||||
{
|
{
|
||||||
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
|
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
|
||||||
spi, FALSE);
|
spi, FALSE);
|
||||||
if (child_sa == NULL)
|
if (!child_sa)
|
||||||
{
|
{
|
||||||
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, "
|
DBG1(DBG_IKE, "received DELETE for unknown %N CHILD_SA with"
|
||||||
"but no such SA", protocol_id_names, protocol, ntohl(spi));
|
" SPI %.8x", protocol_id_names, protocol, ntohl(spi));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
|
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
|
||||||
protocol_id_names, protocol, ntohl(spi));
|
protocol_id_names, protocol, ntohl(spi));
|
||||||
|
|
||||||
|
if (this->child_sas->find_first(this->child_sas,
|
||||||
|
(void*)match_child, NULL, child_sa) == SUCCESS)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
INIT(entry,
|
||||||
|
.child_sa = child_sa
|
||||||
|
);
|
||||||
switch (child_sa->get_state(child_sa))
|
switch (child_sa->get_state(child_sa))
|
||||||
{
|
{
|
||||||
case CHILD_REKEYED:
|
case CHILD_REKEYED:
|
||||||
this->rekeyed = TRUE;
|
entry->rekeyed = TRUE;
|
||||||
break;
|
break;
|
||||||
case CHILD_DELETING:
|
case CHILD_DELETING:
|
||||||
/* we don't send back a delete if we initiated ourself */
|
/* we don't send back a delete if we already initiated
|
||||||
|
* a delete ourself */
|
||||||
if (!this->initiator)
|
if (!this->initiator)
|
||||||
{
|
{
|
||||||
|
free(entry);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* fall through */
|
break;
|
||||||
case CHILD_REKEYING:
|
case CHILD_REKEYING:
|
||||||
/* we reply as usual, rekeying will fail */
|
/* we reply as usual, rekeying will fail */
|
||||||
case CHILD_INSTALLED_INBOUND:
|
case CHILD_INSTALLED_INBOUND:
|
||||||
@@ -254,22 +277,18 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
|
|||||||
{
|
{
|
||||||
if (is_redundant(this, child_sa))
|
if (is_redundant(this, child_sa))
|
||||||
{
|
{
|
||||||
this->rekeyed = TRUE;
|
entry->rekeyed = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->check_delete_action = TRUE;
|
entry->check_delete_action = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (this->child_sas->find_first(this->child_sas, NULL,
|
this->child_sas->insert_last(this->child_sas, entry);
|
||||||
(void**)&child_sa) != SUCCESS)
|
|
||||||
{
|
|
||||||
this->child_sas->insert_last(this->child_sas, child_sa);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
spis->destroy(spis);
|
spis->destroy(spis);
|
||||||
}
|
}
|
||||||
@@ -283,6 +302,7 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
|
|||||||
static status_t destroy_and_reestablish(private_child_delete_t *this)
|
static status_t destroy_and_reestablish(private_child_delete_t *this)
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
|
entry_t *entry;
|
||||||
child_sa_t *child_sa;
|
child_sa_t *child_sa;
|
||||||
child_cfg_t *child_cfg;
|
child_cfg_t *child_cfg;
|
||||||
protocol_id_t protocol;
|
protocol_id_t protocol;
|
||||||
@@ -291,11 +311,12 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
|
|||||||
status_t status = SUCCESS;
|
status_t status = SUCCESS;
|
||||||
|
|
||||||
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
||||||
while (enumerator->enumerate(enumerator, (void**)&child_sa))
|
while (enumerator->enumerate(enumerator, (void**)&entry))
|
||||||
{
|
{
|
||||||
|
child_sa = entry->child_sa;
|
||||||
/* signal child down event if we weren't rekeying */
|
/* signal child down event if we weren't rekeying */
|
||||||
protocol = child_sa->get_protocol(child_sa);
|
protocol = child_sa->get_protocol(child_sa);
|
||||||
if (!this->rekeyed)
|
if (!entry->rekeyed)
|
||||||
{
|
{
|
||||||
charon->bus->child_updown(charon->bus, child_sa, FALSE);
|
charon->bus->child_updown(charon->bus, child_sa, FALSE);
|
||||||
}
|
}
|
||||||
@@ -313,7 +334,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
|
|||||||
child_cfg->get_ref(child_cfg);
|
child_cfg->get_ref(child_cfg);
|
||||||
action = child_sa->get_close_action(child_sa);
|
action = child_sa->get_close_action(child_sa);
|
||||||
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
|
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
|
||||||
if (this->check_delete_action)
|
if (entry->check_delete_action)
|
||||||
{ /* enforce child_cfg policy if deleted passively */
|
{ /* enforce child_cfg policy if deleted passively */
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
@@ -348,12 +369,14 @@ static void log_children(private_child_delete_t *this)
|
|||||||
{
|
{
|
||||||
linked_list_t *my_ts, *other_ts;
|
linked_list_t *my_ts, *other_ts;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
|
entry_t *entry;
|
||||||
child_sa_t *child_sa;
|
child_sa_t *child_sa;
|
||||||
uint64_t bytes_in, bytes_out;
|
uint64_t bytes_in, bytes_out;
|
||||||
|
|
||||||
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
enumerator = this->child_sas->create_enumerator(this->child_sas);
|
||||||
while (enumerator->enumerate(enumerator, (void**)&child_sa))
|
while (enumerator->enumerate(enumerator, (void**)&entry))
|
||||||
{
|
{
|
||||||
|
child_sa = entry->child_sa;
|
||||||
my_ts = linked_list_create_from_enumerator(
|
my_ts = linked_list_create_from_enumerator(
|
||||||
child_sa->create_ts_enumerator(child_sa, TRUE));
|
child_sa->create_ts_enumerator(child_sa, TRUE));
|
||||||
other_ts = linked_list_create_from_enumerator(
|
other_ts = linked_list_create_from_enumerator(
|
||||||
@@ -388,6 +411,7 @@ METHOD(task_t, build_i, status_t,
|
|||||||
private_child_delete_t *this, message_t *message)
|
private_child_delete_t *this, message_t *message)
|
||||||
{
|
{
|
||||||
child_sa_t *child_sa;
|
child_sa_t *child_sa;
|
||||||
|
entry_t *entry;
|
||||||
|
|
||||||
child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
|
child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
|
||||||
this->spi, TRUE);
|
this->spi, TRUE);
|
||||||
@@ -402,15 +426,18 @@ METHOD(task_t, build_i, status_t,
|
|||||||
/* we work only with the inbound SPI */
|
/* we work only with the inbound SPI */
|
||||||
this->spi = child_sa->get_spi(child_sa, TRUE);
|
this->spi = child_sa->get_spi(child_sa, TRUE);
|
||||||
}
|
}
|
||||||
this->child_sas->insert_last(this->child_sas, child_sa);
|
INIT(entry,
|
||||||
|
.child_sa = child_sa,
|
||||||
|
);
|
||||||
|
this->child_sas->insert_last(this->child_sas, entry);
|
||||||
if (child_sa->get_state(child_sa) == CHILD_REKEYED)
|
if (child_sa->get_state(child_sa) == CHILD_REKEYED)
|
||||||
{
|
{
|
||||||
this->rekeyed = TRUE;
|
entry->rekeyed = TRUE;
|
||||||
}
|
}
|
||||||
log_children(this);
|
log_children(this);
|
||||||
build_payloads(this, message);
|
build_payloads(this, message);
|
||||||
|
|
||||||
if (!this->rekeyed && this->expired)
|
if (!entry->rekeyed && this->expired)
|
||||||
{
|
{
|
||||||
child_cfg_t *child_cfg;
|
child_cfg_t *child_cfg;
|
||||||
|
|
||||||
@@ -457,24 +484,28 @@ METHOD(child_delete_t , get_child, child_sa_t*,
|
|||||||
private_child_delete_t *this)
|
private_child_delete_t *this)
|
||||||
{
|
{
|
||||||
child_sa_t *child_sa = NULL;
|
child_sa_t *child_sa = NULL;
|
||||||
this->child_sas->get_first(this->child_sas, (void**)&child_sa);
|
entry_t *entry;
|
||||||
|
|
||||||
|
if (this->child_sas->get_first(this->child_sas, (void**)&entry) == SUCCESS)
|
||||||
|
{
|
||||||
|
child_sa = entry->child_sa;
|
||||||
|
}
|
||||||
return child_sa;
|
return child_sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(task_t, migrate, void,
|
METHOD(task_t, migrate, void,
|
||||||
private_child_delete_t *this, ike_sa_t *ike_sa)
|
private_child_delete_t *this, ike_sa_t *ike_sa)
|
||||||
{
|
{
|
||||||
this->check_delete_action = FALSE;
|
|
||||||
this->ike_sa = ike_sa;
|
this->ike_sa = ike_sa;
|
||||||
|
|
||||||
this->child_sas->destroy(this->child_sas);
|
this->child_sas->destroy_function(this->child_sas, free);
|
||||||
this->child_sas = linked_list_create();
|
this->child_sas = linked_list_create();
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(task_t, destroy, void,
|
METHOD(task_t, destroy, void,
|
||||||
private_child_delete_t *this)
|
private_child_delete_t *this)
|
||||||
{
|
{
|
||||||
this->child_sas->destroy(this->child_sas);
|
this->child_sas->destroy_function(this->child_sas, free);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user