child-delete: Track flags per individual CHILD_SA

This commit is contained in:
Tobias Brunner
2017-05-23 18:46:06 +02:00
parent dc3710e987
commit 9a5f7a30f8
+78 -47
View File
@@ -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);
} }