diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/config/child_cfg.c | 31 | ||||
-rw-r--r-- | src/charon/config/child_cfg.h | 31 | ||||
-rw-r--r-- | src/charon/config/peer_cfg.c | 42 | ||||
-rw-r--r-- | src/charon/config/peer_cfg.h | 37 | ||||
-rw-r--r-- | src/charon/plugins/sql/sql_config.c | 4 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_config.c | 17 | ||||
-rw-r--r-- | src/charon/processing/jobs/rekey_ike_sa_job.c | 2 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 282 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.h | 13 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_delete.c | 35 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_delete.c | 1 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_reauth.c | 8 |
12 files changed, 264 insertions, 239 deletions
diff --git a/src/charon/config/child_cfg.c b/src/charon/config/child_cfg.c index 9a22dcf4f..510d9a67f 100644 --- a/src/charon/config/child_cfg.c +++ b/src/charon/config/child_cfg.c @@ -28,6 +28,12 @@ ENUM(mode_names, MODE_TRANSPORT, MODE_BEET, "BEET", ); +ENUM(action_names, ACTION_NONE, ACTION_RESTART, + "ACTION_NONE", + "ACTION_ROUTE", + "ACTION_RESTART", +); + typedef struct private_child_cfg_t private_child_cfg_t; /** @@ -81,6 +87,11 @@ struct private_child_cfg_t { mode_t mode; /** + * action to take on DPD/passive close + */ + action_t action; + + /** * Time before an SA gets invalid */ u_int32_t lifetime; @@ -338,7 +349,7 @@ static u_int32_t get_lifetime(private_child_cfg_t *this, bool rekey) } /** - * Implementation of child_cfg_t.get_name + * Implementation of child_cfg_t.get_mode */ static mode_t get_mode(private_child_cfg_t *this) { @@ -346,6 +357,14 @@ static mode_t get_mode(private_child_cfg_t *this) } /** + * Implementation of child_cfg_t.get_action + */ +static action_t get_action(private_child_cfg_t *this) +{ + return this->action; +} + +/** * Implementation of child_cfg_t.get_dh_group. */ static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this) @@ -398,11 +417,11 @@ static void destroy(private_child_cfg_t *this) */ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, u_int32_t rekeytime, u_int32_t jitter, - char *updown, bool hostaccess, mode_t mode) + char *updown, bool hostaccess, mode_t mode, + action_t action) { private_child_cfg_t *this = malloc_thing(private_child_cfg_t); - /* public functions */ this->public.get_name = (char* (*) (child_cfg_t*))get_name; this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector; this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors; @@ -412,12 +431,12 @@ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, this->public.get_updown = (char* (*) (child_cfg_t*))get_updown; this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess; this->public.get_mode = (mode_t (*) (child_cfg_t *))get_mode; + this->public.get_action = (action_t (*) (child_cfg_t *))get_action; this->public.get_lifetime = (u_int32_t (*) (child_cfg_t *,bool))get_lifetime; this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group; this->public.get_ref = (void (*) (child_cfg_t*))get_ref; this->public.destroy = (void (*) (child_cfg_t*))destroy; - /* apply init values */ this->name = strdup(name); this->lifetime = lifetime; this->rekeytime = rekeytime; @@ -425,8 +444,7 @@ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, this->updown = updown ? strdup(updown) : NULL; this->hostaccess = hostaccess; this->mode = mode; - - /* initialize private members*/ + this->action = action; this->refcount = 1; this->proposals = linked_list_create(); this->my_ts = linked_list_create(); @@ -434,3 +452,4 @@ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, return &this->public; } + diff --git a/src/charon/config/child_cfg.h b/src/charon/config/child_cfg.h index c7401d623..7c65e0a95 100644 --- a/src/charon/config/child_cfg.h +++ b/src/charon/config/child_cfg.h @@ -25,6 +25,7 @@ #define CHILD_CFG_H_ typedef enum mode_t mode_t; +typedef enum action_t action_t; typedef struct child_cfg_t child_cfg_t; #include <library.h> @@ -51,6 +52,23 @@ enum mode_t { extern enum_name_t *mode_names; /** + * Action to take when DPD detected/connection gets closed by peer. + */ +enum action_t { + /** No action */ + ACTION_NONE, + /** Route config to reestablish on demand */ + ACTION_ROUTE, + /** Restart config immediately */ + ACTION_RESTART, +}; + +/** + * enum names for action_t. + */ +extern enum_name_t *action_names; + +/** * A child_cfg_t defines the config template for a CHILD_SA. * * After creation, proposals and traffic selectors may be added to the config. @@ -170,11 +188,18 @@ struct child_cfg_t { * The mode is either tunnel, transport or BEET. The peer must agree * on the method, fallback is tunnel mode. * - * @return lifetime in seconds + * @return ipsec mode */ mode_t (*get_mode) (child_cfg_t *this); /** + * Action to take on DPD/passive close + * + * @return DPD/passive close action + */ + action_t (*get_action) (child_cfg_t *this); + + /** * Get the DH group to use for CHILD_SA setup. * * @return dh group to use @@ -218,10 +243,12 @@ struct child_cfg_t { * @param updown updown script to execute on up/down event * @param hostaccess TRUE to allow access to the local host * @param mode mode to propose for CHILD_SA, transport, tunnel or BEET + * @param action DPD/passive close action * @return child_cfg_t object */ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, u_int32_t rekeytime, u_int32_t jitter, - char *updown, bool hostaccess, mode_t mode); + char *updown, bool hostaccess, mode_t mode, + action_t action); #endif /* CHILD_CFG_H_ @} */ diff --git a/src/charon/config/peer_cfg.c b/src/charon/config/peer_cfg.c index f0804d93f..85fa22a1a 100644 --- a/src/charon/config/peer_cfg.c +++ b/src/charon/config/peer_cfg.c @@ -31,13 +31,6 @@ ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND, "CERT_NEVER_SEND" ); -ENUM(dpd_action_names, DPD_NONE, DPD_RESTART, - "DPD_NONE", - "DPD_CLEAR", - "DPD_ROUTE", - "DPD_RESTART" -); - typedef struct private_peer_cfg_t private_peer_cfg_t; /** @@ -141,14 +134,9 @@ struct private_peer_cfg_t { u_int32_t over_time; /** - * What to do with an SA when other peer seams to be dead? - */ - bool dpd_delay; - - /** - * What to do with CHILDren when other peer seams to be dead? + * DPD check intervall */ - bool dpd_action; + u_int32_t dpd; /** * virtual IP to use locally @@ -380,19 +368,11 @@ static bool use_mobike(private_peer_cfg_t *this) } /** - * Implements peer_cfg_t.get_dpd_delay - */ -static u_int32_t get_dpd_delay(private_peer_cfg_t *this) -{ - return this->dpd_delay; -} - -/** - * Implements peer_cfg_t.get_dpd_action + * Implements peer_cfg_t.get_dpd */ -static dpd_action_t get_dpd_action(private_peer_cfg_t *this) +static u_int32_t get_dpd(private_peer_cfg_t *this) { - return this->dpd_action; + return this->dpd; } /** @@ -473,8 +453,7 @@ static bool equals(private_peer_cfg_t *this, private_peer_cfg_t *other) this->reauth_time == other->reauth_time && this->jitter_time == other->jitter_time && this->over_time == other->over_time && - this->dpd_delay == other->dpd_delay && - this->dpd_action == other->dpd_action && + this->dpd == other->dpd && (this->virtual_ip == other->virtual_ip || (this->virtual_ip && other->virtual_ip && this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) && @@ -531,8 +510,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, u_int32_t eap_vendor, u_int32_t keyingtries, u_int32_t rekey_time, u_int32_t reauth_time, u_int32_t jitter_time, - u_int32_t over_time, bool mobike, - u_int32_t dpd_delay, dpd_action_t dpd_action, + u_int32_t over_time, bool mobike, u_int32_t dpd, host_t *virtual_ip, char *pool, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id) @@ -557,8 +535,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->public.get_reauth_time = (u_int32_t(*)(peer_cfg_t*))get_reauth_time; this->public.get_over_time = (u_int32_t(*)(peer_cfg_t*))get_over_time; this->public.use_mobike = (bool (*) (peer_cfg_t *))use_mobike; - this->public.get_dpd_delay = (u_int32_t (*) (peer_cfg_t *))get_dpd_delay; - this->public.get_dpd_action = (dpd_action_t (*) (peer_cfg_t *))get_dpd_action; + this->public.get_dpd = (u_int32_t (*) (peer_cfg_t *))get_dpd; this->public.get_virtual_ip = (host_t* (*) (peer_cfg_t *))get_virtual_ip; this->public.get_pool = (char*(*)(peer_cfg_t*))get_pool; this->public.get_auth = (auth_info_t*(*)(peer_cfg_t*))get_auth; @@ -597,8 +574,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->jitter_time = jitter_time; this->over_time = over_time; this->use_mobike = mobike; - this->dpd_delay = dpd_delay; - this->dpd_action = dpd_action; + this->dpd = dpd; this->virtual_ip = virtual_ip; this->pool = pool ? strdup(pool) : NULL; this->auth = auth_info_create(); diff --git a/src/charon/config/peer_cfg.h b/src/charon/config/peer_cfg.h index dedabf07d..29de4afa8 100644 --- a/src/charon/config/peer_cfg.h +++ b/src/charon/config/peer_cfg.h @@ -25,7 +25,6 @@ #ifndef PEER_CFG_H_ #define PEER_CFG_H_ -typedef enum dpd_action_t dpd_action_t; typedef enum cert_policy_t cert_policy_t; typedef struct peer_cfg_t peer_cfg_t; @@ -64,27 +63,6 @@ enum cert_policy_t { extern enum_name_t *cert_policy_names; /** - * Actions to take when a peer does not respond (dead peer detected). - * - * These values are the same as in pluto/starter, so do not modify them! - */ -enum dpd_action_t { - /** DPD disabled */ - DPD_NONE, - /** remove CHILD_SAs without replacement */ - DPD_CLEAR, - /** route the CHILD_SAs to resetup when needed */ - DPD_ROUTE, - /** restart CHILD_SAs in a new IKE_SA, immediately */ - DPD_RESTART, -}; - -/** - * enum names for dpd_action_t. - */ -extern enum_name_t *dpd_action_names; - -/** * Configuration of a peer, specified by IDs. * * The peer config defines a connection between two given IDs. It contains @@ -259,14 +237,7 @@ struct peer_cfg_t { * * @return dpd_delay in seconds */ - u_int32_t (*get_dpd_delay) (peer_cfg_t *this); - - /** - * What should be done with a CHILD_SA, when other peer does not respond. - * - * @return dpd action - */ - dpd_action_t (*get_dpd_action) (peer_cfg_t *this); + u_int32_t (*get_dpd) (peer_cfg_t *this); /** * Get a virtual IP for the local peer. @@ -371,8 +342,7 @@ struct peer_cfg_t { * @param over_time maximum overtime before closing a rekeying/reauth SA * @param reauth sould be done reauthentication instead of rekeying? * @param mobike use MOBIKE (RFC4555) if peer supports it - * @param dpd_delay after how many seconds of inactivity to check DPD - * @param dpd_action what to do with CHILD_SAs when detected a dead peer + * @param dpd DPD check interval, 0 to disable * @param virtual_ip virtual IP for local host, or NULL * @param pool pool name to get configuration attributes from, or NULL * @param mediation TRUE if this is a mediation connection @@ -387,8 +357,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg, u_int32_t eap_vendor, u_int32_t keyingtries, u_int32_t rekey_time, u_int32_t reauth_time, u_int32_t jitter_time, - u_int32_t over_time, bool mobike, - u_int32_t dpd_delay, dpd_action_t dpd_action, + u_int32_t over_time, bool mobike, u_int32_t dpd, host_t *virtual_ip, char *pool, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id); diff --git a/src/charon/plugins/sql/sql_config.c b/src/charon/plugins/sql/sql_config.c index 38c16b280..e13bc314d 100644 --- a/src/charon/plugins/sql/sql_config.c +++ b/src/charon/plugins/sql/sql_config.c @@ -133,7 +133,7 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e) &updown, &hostaccess, &mode)) { child_cfg = child_cfg_create(name, lifetime, rekeytime, jitter, - updown, hostaccess, mode); + updown, hostaccess, mode, ACTION_NONE); /* TODO: read proposal from db */ child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); add_traffic_selectors(this, child_cfg, id); @@ -311,7 +311,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, name, 2, ike, local_id, remote_id, cert_policy, auth_method, eap_type, eap_vendor, keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, - dpd_delay, dpd_action, NULL, NULL, + dpd_delay, NULL, NULL, mediation, mediated_cfg, peer_id); add_child_cfgs(this, peer_cfg, id); return peer_cfg; diff --git a/src/charon/plugins/stroke/stroke_config.c b/src/charon/plugins/stroke/stroke_config.c index f4f3dbc99..a7a723258 100644 --- a/src/charon/plugins/stroke/stroke_config.c +++ b/src/charon/plugins/stroke/stroke_config.c @@ -491,7 +491,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, msg->add_conn.me.sendcert, msg->add_conn.auth_method, msg->add_conn.eap_type, msg->add_conn.eap_vendor, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, - msg->add_conn.mobike, msg->add_conn.dpd.delay, msg->add_conn.dpd.action, + msg->add_conn.mobike, msg->add_conn.dpd.delay, vip, msg->add_conn.other.sourceip ? msg->add_conn.name : NULL, msg->add_conn.ikeme.mediation, mediated_by, peer_id); } @@ -626,13 +626,26 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this, { child_cfg_t *child_cfg; traffic_selector_t *ts; + action_t action; + switch (msg->add_conn.dpd.action) + { /* map startes magic values to our action type */ + case 2: /* =hold */ + action = ACTION_ROUTE; + break; + case 3: /* =restart */ + action = ACTION_RESTART; + break; + default: + action = ACTION_NONE; + break; + } child_cfg = child_cfg_create( msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime, msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, msg->add_conn.me.updown, msg->add_conn.me.hostaccess, - msg->add_conn.mode); + msg->add_conn.mode, action); ts = build_ts(this, &msg->add_conn.me); if (!ts) diff --git a/src/charon/processing/jobs/rekey_ike_sa_job.c b/src/charon/processing/jobs/rekey_ike_sa_job.c index 0960f5166..3b038c8ab 100644 --- a/src/charon/processing/jobs/rekey_ike_sa_job.c +++ b/src/charon/processing/jobs/rekey_ike_sa_job.c @@ -68,7 +68,7 @@ static void execute(private_rekey_ike_sa_job_t *this) { if (this->reauth) { - status = ike_sa->reestablish(ike_sa); + status = ike_sa->reauth(ike_sa); } else { diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 911270a59..281a091da 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -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) { @@ -1435,147 +1435,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. */ static prf_t *get_prf(private_ike_sa_t *this) @@ -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; @@ -2015,6 +1874,134 @@ static status_t reestablish(private_ike_sa_t *this) } /** + * 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. */ static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t 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; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index af25f27c3..1f0595c35 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -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); /** diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c index 2c1db2ad0..4de4113a5 100644 --- a/src/charon/sa/tasks/child_delete.c +++ b/src/charon/sa/tasks/child_delete.c @@ -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); } /** diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c index 6e1ee8b10..02d8c168c 100644 --- a/src/charon/sa/tasks/ike_delete.c +++ b/src/charon/sa/tasks/ike_delete.c @@ -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; diff --git a/src/charon/sa/tasks/ike_reauth.c b/src/charon/sa/tasks/ike_reauth.c index 47d5c2822..849e42ea9 100644 --- a/src/charon/sa/tasks/ike_reauth.c +++ b/src/charon/sa/tasks/ike_reauth.c @@ -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; |