using dpd actions to enforce connection state
dpd actions a per child-, not peer ike-sa
This commit is contained in:
+135
-147
@@ -599,7 +599,7 @@ static status_t send_dpd(private_ike_sa_t *this)
|
||||
send_dpd_job_t *job;
|
||||
time_t diff, delay;
|
||||
|
||||
delay = this->peer_cfg->get_dpd_delay(this->peer_cfg);
|
||||
delay = this->peer_cfg->get_dpd(this->peer_cfg);
|
||||
|
||||
if (delay == 0)
|
||||
{
|
||||
@@ -1434,147 +1434,6 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.retransmit.
|
||||
*/
|
||||
static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
|
||||
{ /* FIXME: IKE-ME */
|
||||
this->time.outbound = time(NULL);
|
||||
if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
|
||||
{
|
||||
child_cfg_t *child_cfg;
|
||||
child_sa_t* child_sa;
|
||||
linked_list_t *to_route, *to_restart;
|
||||
iterator_t *iterator;
|
||||
|
||||
/* send a proper signal to brief interested bus listeners */
|
||||
switch (this->state)
|
||||
{
|
||||
case IKE_CONNECTING:
|
||||
{
|
||||
/* retry IKE_SA_INIT if we have multiple keyingtries */
|
||||
u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
|
||||
this->keyingtry++;
|
||||
if (tries == 0 || tries > this->keyingtry)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "peer not responding, trying again "
|
||||
"(%d/%d) in background ", this->keyingtry + 1, tries);
|
||||
reset(this);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
|
||||
break;
|
||||
}
|
||||
case IKE_REKEYING:
|
||||
SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
|
||||
break;
|
||||
case IKE_DELETING:
|
||||
SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* summarize how we have to handle each child */
|
||||
to_route = linked_list_create();
|
||||
to_restart = linked_list_create();
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&child_sa))
|
||||
{
|
||||
child_cfg = child_sa->get_config(child_sa);
|
||||
|
||||
if (child_sa->get_state(child_sa) == CHILD_ROUTED)
|
||||
{
|
||||
/* reroute routed CHILD_SAs */
|
||||
to_route->insert_last(to_route, child_cfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* use DPD action for established CHILD_SAs */
|
||||
switch (this->peer_cfg->get_dpd_action(this->peer_cfg))
|
||||
{
|
||||
case DPD_ROUTE:
|
||||
to_route->insert_last(to_route, child_cfg);
|
||||
break;
|
||||
case DPD_RESTART:
|
||||
to_restart->insert_last(to_restart, child_cfg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
/* create a new IKE_SA if we have to route or to restart */
|
||||
if (to_route->get_count(to_route) || to_restart->get_count(to_restart))
|
||||
{
|
||||
private_ike_sa_t *new;
|
||||
task_t *task;
|
||||
|
||||
new = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
|
||||
charon->ike_sa_manager, TRUE);
|
||||
|
||||
set_peer_cfg(new, this->peer_cfg);
|
||||
/* use actual used host, not the wildcarded one in config */
|
||||
new->other_host->destroy(new->other_host);
|
||||
new->other_host = this->other_host->clone(this->other_host);
|
||||
/* reset port to 500, but only if peer is not NATed */
|
||||
if (!has_condition(this, COND_NAT_THERE))
|
||||
{
|
||||
new->other_host->set_port(new->other_host, IKEV2_UDP_PORT);
|
||||
}
|
||||
/* take over virtual ip, as we need it for a proper route */
|
||||
if (this->my_virtual_ip)
|
||||
{
|
||||
set_virtual_ip(new, TRUE, this->my_virtual_ip);
|
||||
}
|
||||
|
||||
/* install routes */
|
||||
while (to_route->remove_last(to_route, (void**)&child_cfg) == SUCCESS)
|
||||
{
|
||||
route(new, child_cfg);
|
||||
}
|
||||
|
||||
/* restart children */
|
||||
if (to_restart->get_count(to_restart))
|
||||
{
|
||||
task = (task_t*)ike_init_create(&new->public, TRUE, NULL);
|
||||
new->task_manager->queue_task(new->task_manager, task);
|
||||
task = (task_t*)ike_natd_create(&new->public, TRUE);
|
||||
new->task_manager->queue_task(new->task_manager, task);
|
||||
task = (task_t*)ike_cert_pre_create(&new->public, TRUE);
|
||||
new->task_manager->queue_task(new->task_manager, task);
|
||||
task = (task_t*)ike_config_create(&new->public, TRUE);
|
||||
new->task_manager->queue_task(new->task_manager, task);
|
||||
task = (task_t*)ike_auth_create(&new->public, TRUE);
|
||||
new->task_manager->queue_task(new->task_manager, task);
|
||||
task = (task_t*)ike_cert_post_create(&new->public, TRUE);
|
||||
new->task_manager->queue_task(new->task_manager, task);
|
||||
|
||||
while (to_restart->remove_last(to_restart, (void**)&child_cfg) == SUCCESS)
|
||||
{
|
||||
task = (task_t*)child_create_create(&new->public, child_cfg);
|
||||
new->task_manager->queue_task(new->task_manager, task);
|
||||
}
|
||||
task = (task_t*)ike_auth_lifetime_create(&new->public, TRUE);
|
||||
new->task_manager->queue_task(new->task_manager, task);
|
||||
if (this->peer_cfg->use_mobike(this->peer_cfg))
|
||||
{
|
||||
task = (task_t*)ike_mobike_create(&new->public, TRUE);
|
||||
new->task_manager->queue_task(new->task_manager, task);
|
||||
}
|
||||
new->task_manager->initiate(new->task_manager);
|
||||
}
|
||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, &new->public);
|
||||
}
|
||||
to_route->destroy(to_route);
|
||||
to_restart->destroy(to_restart);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_prf.
|
||||
*/
|
||||
@@ -1978,9 +1837,9 @@ static status_t rekey(private_ike_sa_t *this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.reestablish
|
||||
* Implementation of ike_sa_t.reauth
|
||||
*/
|
||||
static status_t reestablish(private_ike_sa_t *this)
|
||||
static status_t reauth(private_ike_sa_t *this)
|
||||
{
|
||||
task_t *task;
|
||||
|
||||
@@ -2014,6 +1873,134 @@ static status_t reestablish(private_ike_sa_t *this)
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.reestablish
|
||||
*/
|
||||
static status_t reestablish(private_ike_sa_t *this)
|
||||
{
|
||||
ike_sa_t *new;
|
||||
host_t *host;
|
||||
iterator_t *iterator;
|
||||
child_sa_t *child_sa;
|
||||
child_cfg_t *child_cfg;
|
||||
action_t action;
|
||||
bool required = FALSE;
|
||||
status_t status = FAILED;
|
||||
|
||||
if (!this->ike_initiator &&
|
||||
(this->other_virtual_ip != NULL ||
|
||||
has_condition(this, COND_EAP_AUTHENTICATED)
|
||||
#ifdef ME
|
||||
|| this->is_mediation_server
|
||||
#endif /* ME */
|
||||
))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE);
|
||||
new->set_peer_cfg(new, this->peer_cfg);
|
||||
host = this->other_host;
|
||||
new->set_other_host(new, host->clone(host));
|
||||
host = this->my_host;
|
||||
new->set_my_host(new, host->clone(host));
|
||||
/* if we already have a virtual IP, we reuse it */
|
||||
host = this->my_virtual_ip;
|
||||
if (host)
|
||||
{
|
||||
new->set_virtual_ip(new, TRUE, host);
|
||||
}
|
||||
|
||||
#ifdef ME
|
||||
/* we initiate the new IKE_SA of the mediation connection without CHILD_SA */
|
||||
if (this->peer_cfg->is_mediation(this->peer_cfg))
|
||||
{
|
||||
required = TRUE;
|
||||
}
|
||||
#endif /* ME */
|
||||
|
||||
iterator = create_child_sa_iterator(this);
|
||||
while (iterator->iterate(iterator, (void**)&child_sa))
|
||||
{
|
||||
child_cfg = child_sa->get_config(child_sa);
|
||||
action = child_cfg->get_action(child_cfg);
|
||||
|
||||
if (action == ACTION_RESTART || action == ACTION_ROUTE)
|
||||
{
|
||||
required = TRUE;
|
||||
if (action == ACTION_RESTART)
|
||||
{
|
||||
DBG1(DBG_IKE, "restarting CHILD_SA %s",
|
||||
child_cfg->get_name(child_cfg));
|
||||
child_cfg->get_ref(child_cfg);
|
||||
status = new->initiate(new, child_cfg);
|
||||
if (status == DESTROY_ME)
|
||||
{
|
||||
required = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new->route(new, child_cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
if (required)
|
||||
{
|
||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, new);
|
||||
}
|
||||
else
|
||||
{
|
||||
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new);
|
||||
DBG1(DBG_IKE, "unable to reestablish IKE_SA, no CHILD_SA to recreate");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.retransmit.
|
||||
*/
|
||||
static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
|
||||
{
|
||||
this->time.outbound = time(NULL);
|
||||
if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
|
||||
{
|
||||
/* send a proper signal to brief interested bus listeners */
|
||||
switch (this->state)
|
||||
{
|
||||
case IKE_CONNECTING:
|
||||
{
|
||||
/* retry IKE_SA_INIT if we have multiple keyingtries */
|
||||
u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
|
||||
this->keyingtry++;
|
||||
if (tries == 0 || tries > this->keyingtry)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "peer not responding, trying again "
|
||||
"(%d/%d) in background ", this->keyingtry + 1, tries);
|
||||
reset(this);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
|
||||
break;
|
||||
}
|
||||
case IKE_REKEYING:
|
||||
SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
|
||||
break;
|
||||
case IKE_DELETING:
|
||||
SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
reestablish(this);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.set_auth_lifetime.
|
||||
*/
|
||||
@@ -2087,9 +2074,9 @@ static status_t roam(private_ike_sa_t *this, bool address)
|
||||
this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
|
||||
return this->task_manager->initiate(this->task_manager);
|
||||
}
|
||||
DBG1(DBG_IKE, "reestablishing IKE_SA due address change");
|
||||
/* ... reestablish if not */
|
||||
return reestablish(this);
|
||||
DBG1(DBG_IKE, "reauthenticating IKE_SA due address change");
|
||||
/* ... reauth if not */
|
||||
return reauth(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2436,6 +2423,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
this->public.delete_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
|
||||
this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
|
||||
this->public.rekey = (status_t (*)(ike_sa_t*))rekey;
|
||||
this->public.reauth = (status_t (*)(ike_sa_t*))reauth;
|
||||
this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish;
|
||||
this->public.set_auth_lifetime = (void(*)(ike_sa_t*, u_int32_t lifetime))set_auth_lifetime;
|
||||
this->public.roam = (status_t(*)(ike_sa_t*,bool))roam;
|
||||
|
||||
+11
-2
@@ -115,7 +115,7 @@ enum ike_condition_t {
|
||||
/**
|
||||
* received a certificate request from the peer
|
||||
*/
|
||||
COND_CERTREQ_SEEN = (1<<4),
|
||||
COND_CERTREQ_SEEN = (1<<5),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -803,13 +803,22 @@ struct ike_sa_t {
|
||||
status_t (*rekey) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* Restablish the IKE_SA.
|
||||
* Reauthenticate the IKE_SA.
|
||||
*
|
||||
* Create a completely new IKE_SA with authentication, recreates all children
|
||||
* within the IKE_SA, closes this IKE_SA.
|
||||
*
|
||||
* @return DESTROY_ME to destroy the IKE_SA
|
||||
*/
|
||||
status_t (*reauth) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* Restablish the IKE_SA.
|
||||
*
|
||||
* Reestablish an IKE_SA after it has been closed.
|
||||
*
|
||||
* @return DESTROY_ME to destroy the IKE_SA
|
||||
*/
|
||||
status_t (*reestablish) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
|
||||
@@ -152,23 +152,48 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy the children listed in this->child_sas
|
||||
* destroy the children listed in this->child_sas, reestablish by policy
|
||||
*/
|
||||
static void destroy_children(private_child_delete_t *this)
|
||||
static status_t destroy_and_reestablish(private_child_delete_t *this)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
child_sa_t *child_sa;
|
||||
child_cfg_t *child_cfg;
|
||||
protocol_id_t protocol;
|
||||
u_int32_t spi;
|
||||
status_t status = SUCCESS;
|
||||
|
||||
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);
|
||||
protocol = child_sa->get_protocol(child_sa);
|
||||
child_cfg = child_sa->get_config(child_sa);
|
||||
child_cfg->get_ref(child_cfg);
|
||||
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
|
||||
if (!this->initiator)
|
||||
{ /* enforce child_cfg policy if deleted passively */
|
||||
switch (child_cfg->get_action(child_cfg))
|
||||
{
|
||||
case ACTION_RESTART:
|
||||
child_cfg->get_ref(child_cfg);
|
||||
status = this->ike_sa->initiate(this->ike_sa, child_cfg);
|
||||
break;
|
||||
case ACTION_ROUTE:
|
||||
status = this->ike_sa->route(this->ike_sa, child_cfg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
child_cfg->destroy(child_cfg);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,9 +234,8 @@ static status_t process_i(private_child_delete_t *this, message_t *message)
|
||||
this->child_sas = linked_list_create();
|
||||
|
||||
process_payloads(this, message);
|
||||
destroy_children(this);
|
||||
SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
|
||||
return SUCCESS;
|
||||
return destroy_and_reestablish(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,9 +258,8 @@ static status_t build_r(private_child_delete_t *this, message_t *message)
|
||||
{
|
||||
build_payloads(this, message);
|
||||
}
|
||||
destroy_children(this);
|
||||
SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
|
||||
return SUCCESS;
|
||||
return destroy_and_reestablish(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,6 +87,7 @@ static status_t process_r(private_ike_delete_t *this, message_t *message)
|
||||
break;
|
||||
case IKE_ESTABLISHED:
|
||||
DBG1(DBG_IKE, "deleting IKE_SA on request");
|
||||
this->ike_sa->reestablish(this->ike_sa);
|
||||
break;
|
||||
case IKE_REKEYING:
|
||||
break;
|
||||
|
||||
@@ -68,7 +68,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
|
||||
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
|
||||
/* reestablish only if we have children */
|
||||
/* reauthenticate only if we have children */
|
||||
iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
|
||||
if (iterator->get_count(iterator) == 0
|
||||
#ifdef ME
|
||||
@@ -77,7 +77,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
|
||||
#endif /* ME */
|
||||
)
|
||||
{
|
||||
DBG1(DBG_IKE, "unable to reestablish IKE_SA, no CHILD_SA to recreate");
|
||||
DBG1(DBG_IKE, "unable to reauthenticate IKE_SA, no CHILD_SA to recreate");
|
||||
iterator->destroy(iterator);
|
||||
return FAILED;
|
||||
}
|
||||
@@ -104,7 +104,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
|
||||
{
|
||||
charon->ike_sa_manager->checkin_and_destroy(
|
||||
charon->ike_sa_manager, new);
|
||||
DBG1(DBG_IKE, "reestablishing IKE_SA failed");
|
||||
DBG1(DBG_IKE, "reauthenticating IKE_SA failed");
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
|
||||
iterator->destroy(iterator);
|
||||
charon->ike_sa_manager->checkin_and_destroy(
|
||||
charon->ike_sa_manager, new);
|
||||
DBG1(DBG_IKE, "reestablishing IKE_SA failed");
|
||||
DBG1(DBG_IKE, "reauthenticating IKE_SA failed");
|
||||
return FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user