diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-07-05 00:05:56 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-07-05 00:05:56 +0000 |
commit | 5db544cc26db378616a46dfa22138f0008cf2930 (patch) | |
tree | ff9254d87967bb6f703a5ab5e63edcde2e8a6c17 /src/charon/sa | |
parent | 3d44c2edf1a3663c7d4acc4434bc8a3abace1ebf (diff) | |
download | vyos-strongswan-5db544cc26db378616a46dfa22138f0008cf2930.tar.gz vyos-strongswan-5db544cc26db378616a46dfa22138f0008cf2930.zip |
- Updated to new upstream release.
Diffstat (limited to 'src/charon/sa')
-rw-r--r-- | src/charon/sa/child_sa.c | 251 | ||||
-rw-r--r-- | src/charon/sa/child_sa.h | 28 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 621 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.h | 172 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.c | 19 | ||||
-rw-r--r-- | src/charon/sa/task_manager.c | 103 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_create.c | 77 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_rekey.c | 2 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_auth.c | 7 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_dpd.c | 2 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_mobike.c | 431 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_mobike.h | 73 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_natd.c | 78 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_reauth.c | 175 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_reauth.h | 59 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_rekey.c | 9 | ||||
-rw-r--r-- | src/charon/sa/tasks/task.c | 6 | ||||
-rw-r--r-- | src/charon/sa/tasks/task.h | 6 |
18 files changed, 1597 insertions, 522 deletions
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 1e7b6cb2c..118af3b30 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -60,7 +60,7 @@ struct sa_policy_t { typedef struct private_child_sa_t private_child_sa_t; /** - * Private data of a child_sa_t bject. + * Private data of a child_sa_t object. */ struct private_child_sa_t { /** @@ -138,9 +138,9 @@ struct private_child_sa_t { child_sa_state_t state; /** - * Specifies if NAT traversal is used + * Specifies if UDP encapsulation is enabled (NAT traversal) */ - bool use_natt; + bool encap; /** * mode this SA uses, tunnel/transport @@ -156,6 +156,11 @@ struct private_child_sa_t { * config used to create this child */ child_cfg_t *config; + + /** + * cached interface name for iptables + */ + char *iface; }; /** @@ -276,11 +281,10 @@ static void updown(private_child_sa_t *this, bool up) while (iterator->iterate(iterator, (void**)&policy)) { char command[1024]; - char *ifname = NULL; char *my_client, *other_client, *my_client_mask, *other_client_mask; char *pos, *virtual_ip; FILE *shell; - + /* get subnet/bits from string */ asprintf(&my_client, "%R", policy->my_ts); pos = strchr(my_client, '/'); @@ -301,18 +305,24 @@ static void updown(private_child_sa_t *this, bool up) *pos = '\0'; } - if (this->virtual_ip) - { - asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", - this->virtual_ip); - } - else - { - asprintf(&virtual_ip, ""); - } + if (this->virtual_ip) + { + asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", + this->virtual_ip); + } + else + { + asprintf(&virtual_ip, ""); + } - ifname = charon->kernel_interface->get_interface(charon->kernel_interface, - this->me.addr); + /* we cache the iface name, as it may not be available when + * the SA gets deleted */ + if (up) + { + free(this->iface); + this->iface = charon->kernel_interface->get_interface( + charon->kernel_interface, this->me.addr); + } /* build the command with all env variables. * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing @@ -346,7 +356,7 @@ static void updown(private_child_sa_t *this, bool up) this->me.addr) ? "-host" : "-client", this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6", this->config->get_name(this->config), - ifname ? ifname : "(unknown)", + this->iface ? this->iface : "unknown", this->reqid, this->me.addr, this->me.id, @@ -364,11 +374,11 @@ static void updown(private_child_sa_t *this, bool up) this->config->get_hostaccess(this->config) ? "PLUTO_HOST_ACCESS='1' " : "", script); - free(ifname); free(my_client); free(other_client); free(virtual_ip); + DBG3(DBG_CHD, "running updown script: %s", command); shell = popen(command, "r"); if (shell == NULL) @@ -494,7 +504,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, algorithm_t int_algo_none = {AUTH_UNDEFINED, 0}; host_t *src; host_t *dst; - natt_conf_t *natt; status_t status; this->protocol = proposal->get_protocol(proposal); @@ -561,18 +570,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, int_algo = &int_algo_none; } - /* setup nat-t */ - if (this->use_natt) - { - natt = alloca(sizeof(natt_conf_t)); - natt->sport = src->get_port(src); - natt->dport = dst->get_port(dst); - } - else - { - natt = NULL; - } - soft = this->config->get_lifetime(this->config, TRUE); hard = this->config->get_lifetime(this->config, FALSE); @@ -582,7 +579,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard, enc_algo, int_algo, - prf_plus, natt, mode, mine); + prf_plus, mode, this->encap, mine); this->encryption = *enc_algo; this->integrity = *int_algo; @@ -689,15 +686,15 @@ static status_t add_policies(private_child_sa_t *this, /* install 3 policies: out, in and forward */ status = charon->kernel_interface->add_policy(charon->kernel_interface, this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT, - this->protocol, this->reqid, high_prio, mode, FALSE); + this->protocol, this->reqid, high_prio, mode); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN, - this->protocol, this->reqid, high_prio, mode, FALSE); + this->protocol, this->reqid, high_prio, mode); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD, - this->protocol, this->reqid, high_prio, mode, FALSE); + this->protocol, this->reqid, high_prio, mode); if (status != SUCCESS) { @@ -782,139 +779,89 @@ static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use } /** - * Update the host adress/port of a SA - */ -static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other, - int my_changes, int other_changes, bool mine) -{ - host_t *src, *dst, *new_src, *new_dst; - int src_changes, dst_changes; - status_t status; - u_int32_t spi; - - if (mine) - { - src = this->other.addr; - dst = this->me.addr; - new_src = new_other; - new_dst = new_me; - src_changes = other_changes; - dst_changes = my_changes; - spi = this->other.spi; - } - else - { - src = this->me.addr; - dst = this->other.addr; - new_src = new_me; - new_dst = new_other; - src_changes = my_changes; - dst_changes = other_changes; - spi = this->me.spi; - } - - DBG2(DBG_CHD, "updating %N SA 0x%x, from %#H..#H to %#H..%#H", - protocol_id_names, this->protocol, ntohl(spi), src, dst, new_src, new_dst); - - status = charon->kernel_interface->update_sa(charon->kernel_interface, - dst, spi, this->protocol, - new_src, new_dst, - src_changes, dst_changes); - - if (status != SUCCESS) - { - return FAILED; - } - return SUCCESS; -} - -/** - * Update the host adress/port of a policy - */ -static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other) -{ - iterator_t *iterator; - sa_policy_t *policy; - status_t status; - /* we always use high priorities, as hosts getting updated are INSTALLED */ - - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) - { - status = charon->kernel_interface->add_policy( - charon->kernel_interface, - new_me, new_other, - policy->my_ts, policy->other_ts, - POLICY_OUT, this->protocol, this->reqid, TRUE, this->mode, TRUE); - - status |= charon->kernel_interface->add_policy( - charon->kernel_interface, - new_other, new_me, - policy->other_ts, policy->my_ts, - POLICY_IN, this->protocol, this->reqid, TRUE, this->mode, TRUE); - - status |= charon->kernel_interface->add_policy( - charon->kernel_interface, - new_other, new_me, - policy->other_ts, policy->my_ts, - POLICY_FWD, this->protocol, this->reqid, TRUE, this->mode, TRUE); - - if (status != SUCCESS) - { - iterator->destroy(iterator); - return FAILED; - } - } - iterator->destroy(iterator); - - return SUCCESS; -} - -/** * Implementation of child_sa_t.update_hosts. */ -static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other, - host_diff_t my_changes, host_diff_t other_changes) +static status_t update_hosts(private_child_sa_t *this, + host_t *me, host_t *other, bool encap) { - if (!my_changes && !other_changes) + /* anything changed at all? */ + if (me->equals(me, this->me.addr) && + other->equals(other, this->other.addr) && this->encap == encap) { return SUCCESS; } - + /* run updown script to remove iptables rules */ + updown(this, FALSE); + + this->encap = encap; + /* update our (initator) SAs */ - if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, TRUE) != SUCCESS) - { - return FAILED; - } - + charon->kernel_interface->update_sa(charon->kernel_interface, this->me.spi, + this->protocol, this->other.addr, this->me.addr, other, me, encap); /* update his (responder) SAs */ - if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, FALSE) != SUCCESS) - { - return FAILED; - } + charon->kernel_interface->update_sa(charon->kernel_interface, this->other.spi, + this->protocol, this->me.addr, this->other.addr, me, other, encap); /* update policies */ - if (my_changes & HOST_DIFF_ADDR || other_changes & HOST_DIFF_ADDR) + if (!me->ip_equals(me, this->me.addr) || + !other->ip_equals(other, this->other.addr)) { - if (update_policy_hosts(this, new_me, new_other) != SUCCESS) + iterator_t *iterator; + sa_policy_t *policy; + + /* always use high priorities, as hosts getting updated are INSTALLED */ + iterator = this->policies->create_iterator(this->policies, TRUE); + while (iterator->iterate(iterator, (void**)&policy)) { - return FAILED; + /* remove old policies first */ + charon->kernel_interface->del_policy(charon->kernel_interface, + policy->my_ts, policy->other_ts, POLICY_OUT); + charon->kernel_interface->del_policy(charon->kernel_interface, + policy->other_ts, policy->my_ts, POLICY_IN); + charon->kernel_interface->del_policy(charon->kernel_interface, + policy->other_ts, policy->my_ts, POLICY_FWD); + + /* check wether we have to update a "dynamic" traffic selector */ + if (!me->ip_equals(me, this->me.addr) && + policy->my_ts->is_host(policy->my_ts, this->me.addr)) + { + policy->my_ts->set_address(policy->my_ts, me); + } + if (!other->ip_equals(other, this->other.addr) && + policy->other_ts->is_host(policy->other_ts, this->other.addr)) + { + policy->other_ts->set_address(policy->other_ts, other); + } + + /* reinstall updated policies */ + charon->kernel_interface->add_policy(charon->kernel_interface, + me, other, policy->my_ts, policy->other_ts, POLICY_OUT, + this->protocol, this->reqid, TRUE, this->mode); + charon->kernel_interface->add_policy(charon->kernel_interface, + other, me, policy->other_ts, policy->my_ts, POLICY_IN, + this->protocol, this->reqid, TRUE, this->mode); + charon->kernel_interface->add_policy(charon->kernel_interface, + other, me, policy->other_ts, policy->my_ts, POLICY_FWD, + this->protocol, this->reqid, TRUE, this->mode); } + iterator->destroy(iterator); } - /* update hosts */ - if (my_changes) + /* apply hosts */ + if (!me->equals(me, this->me.addr)) { this->me.addr->destroy(this->me.addr); - this->me.addr = new_me->clone(new_me); + this->me.addr = me->clone(me); } - - if (other_changes) + if (!other->equals(other, this->other.addr)) { this->other.addr->destroy(this->other.addr); - this->other.addr = new_other->clone(new_other); - } - + this->other.addr = other->clone(other); + } + + /* install new iptables rules */ + updown(this, TRUE); + return SUCCESS; } @@ -988,6 +935,7 @@ static void destroy(private_child_sa_t *this) this->me.id->destroy(this->me.id); this->other.id->destroy(this->other.id); this->config->destroy(this->config); + free(this->iface); DESTROY_IF(this->virtual_ip); free(this); } @@ -997,7 +945,7 @@ static void destroy(private_child_sa_t *this) */ child_sa_t * child_sa_create(host_t *me, host_t* other, identification_t *my_id, identification_t *other_id, - child_cfg_t *config, u_int32_t rekey, bool use_natt) + child_cfg_t *config, u_int32_t rekey, bool encap) { static u_int32_t reqid = 0; private_child_sa_t *this = malloc_thing(private_child_sa_t); @@ -1011,7 +959,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; this->public.add = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))add; this->public.update = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))update; - this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts; + this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,bool))update_hosts; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies; this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors; this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; @@ -1030,7 +978,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->other.spi = 0; this->alloc_ah_spi = 0; this->alloc_esp_spi = 0; - this->use_natt = use_natt; + this->encap = encap; this->state = CHILD_CREATED; /* reuse old reqid if we are rekeying an existing CHILD_SA */ this->reqid = rekey ? rekey : ++reqid; @@ -1044,6 +992,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->protocol = PROTO_NONE; this->mode = MODE_TUNNEL; this->virtual_ip = NULL; + this->iface = NULL; this->config = config; config->get_ref(config); diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index cf5f3e7d7..b801dd012 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -35,11 +35,6 @@ typedef struct child_sa_t child_sa_t; #include <config/child_cfg.h> /** - * Where we should start with reqid enumeration - */ -#define REQID_START 2000000000 - -/** * @brief States of a CHILD_SA */ enum child_sa_state_t { @@ -200,19 +195,18 @@ struct child_sa_t { prf_plus_t *prf_plus); /** - * @brief Update the hosts in the kernel SAs and policies + * @brief Update the hosts in the kernel SAs and policies. * - * @warning only call this after update() has been called. + * The CHILD must be INSTALLED to do this update. * - * @param this calling object - * @param new_me the new local host - * @param new_other the new remote host - * @param my_diff differences to apply for me - * @param other_diff differences to apply for other - * @return SUCCESS or FAILED + * @param this calling object + * @param me the new local host + * @param other the new remote host + * @param TRUE to use UDP encapsulation for NAT traversal + * @return SUCCESS or FAILED */ - status_t (*update_hosts)(child_sa_t *this, host_t *new_me, host_t *new_other, - host_diff_t my_diff, host_diff_t other_diff); + status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other, + bool encap); /** * @brief Install the policies using some traffic selectors. @@ -298,13 +292,13 @@ struct child_sa_t { * @param other_id id of remote peer * @param config config to use for this CHILD_SA * @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise - * @param use_natt TRUE if NAT traversal is used + * @param encap TRUE to enable UDP encapsulation (NAT traversal) * @return child_sa_t object * * @ingroup sa */ child_sa_t * child_sa_create(host_t *me, host_t *other, identification_t *my_id, identification_t* other_id, - child_cfg_t *config, u_int32_t reqid, bool use_natt); + child_cfg_t *config, u_int32_t reqid, bool encap); #endif /*CHILD_SA_H_*/ diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 8b4b53e10..0a996329d 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -48,10 +48,12 @@ #include <sa/task_manager.h> #include <sa/tasks/ike_init.h> #include <sa/tasks/ike_natd.h> +#include <sa/tasks/ike_mobike.h> #include <sa/tasks/ike_auth.h> #include <sa/tasks/ike_config.h> #include <sa/tasks/ike_cert.h> #include <sa/tasks/ike_rekey.h> +#include <sa/tasks/ike_reauth.h> #include <sa/tasks/ike_delete.h> #include <sa/tasks/ike_dpd.h> #include <sa/tasks/child_create.h> @@ -142,6 +144,16 @@ struct private_ike_sa_t { * CA that issued the certificate of other */ ca_info_t *other_ca; + + /** + * set of extensions the peer supports + */ + ike_extension_t extensions; + + /** + * set of condition flags currently enabled for this IKE_SA + */ + ike_condition_t conditions; /** * Linked List containing the child sa's of the current IKE_SA. @@ -189,16 +201,6 @@ struct private_ike_sa_t { chunk_t skp_verify; /** - * NAT status of local host. - */ - bool nat_here; - - /** - * NAT status of remote host. - */ - bool nat_there; - - /** * Virtual IP on local host, if any */ host_t *my_virtual_ip; @@ -212,6 +214,16 @@ struct private_ike_sa_t { * List of DNS servers installed by us */ linked_list_t *dns_servers; + + /** + * list of peers additional addresses, transmitted via MOBIKE + */ + linked_list_t *additional_addresses; + + /** + * number pending UPDATE_SA_ADDRESS (MOBIKE) + */ + u_int32_t pending_updates; /** * Timestamps for this IKE_SA @@ -356,33 +368,68 @@ static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg) if (this->my_host->is_anyaddr(this->my_host)) { host_t *me = this->ike_cfg->get_my_host(this->ike_cfg); - set_my_host(this, me->clone(me)); } if (this->other_host->is_anyaddr(this->other_host)) { host_t *other = this->ike_cfg->get_other_host(this->ike_cfg); - set_other_host(this, other->clone(other)); } /* apply IDs if they are not already set */ if (this->my_id->contains_wildcards(this->my_id)) { - identification_t *my_id = this->peer_cfg->get_my_id(this->peer_cfg); - DESTROY_IF(this->my_id); - this->my_id = my_id->clone(my_id); + this->my_id = this->peer_cfg->get_my_id(this->peer_cfg); + this->my_id = this->my_id->clone(this->my_id); } if (this->other_id->contains_wildcards(this->other_id)) { - identification_t *other_id = this->peer_cfg->get_other_id(this->peer_cfg); - DESTROY_IF(this->other_id); - this->other_id = other_id->clone(other_id); + this->other_id = this->peer_cfg->get_other_id(this->peer_cfg); + this->other_id = this->other_id->clone(this->other_id); } } /** + * Implementation of ike_sa_t.send_keepalive + */ +static void send_keepalive(private_ike_sa_t *this) +{ + send_keepalive_job_t *job; + time_t last_out, now, diff; + + if (!(this->conditions & COND_NAT_HERE)) + { /* disable keep alives if we are not NATed anymore */ + return; + } + + last_out = get_use_time(this, FALSE); + now = time(NULL); + + diff = now - last_out; + + if (diff >= KEEPALIVE_INTERVAL) + { + packet_t *packet; + chunk_t data; + + packet = packet_create(); + packet->set_source(packet, this->my_host->clone(this->my_host)); + packet->set_destination(packet, this->other_host->clone(this->other_host)); + data.ptr = malloc(1); + data.ptr[0] = 0xFF; + data.len = 1; + packet->set_data(packet, data); + DBG1(DBG_IKE, "sending keep alive"); + charon->sender->send(charon->sender, packet); + diff = 0; + } + job = send_keepalive_job_create(this->ike_sa_id); + charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, + (KEEPALIVE_INTERVAL - diff) * 1000); +} + +/** * Implementation of ike_sa_t.get_ike_cfg */ static ike_cfg_t *get_ike_cfg(private_ike_sa_t *this) @@ -398,6 +445,80 @@ static void set_ike_cfg(private_ike_sa_t *this, ike_cfg_t *ike_cfg) ike_cfg->get_ref(ike_cfg); this->ike_cfg = ike_cfg; } +/** + * Implementation of ike_sa_t.enable_extension. + */ +static void enable_extension(private_ike_sa_t *this, ike_extension_t extension) +{ + this->extensions |= extension; +} + +/** + * Implementation of ike_sa_t.has_extension. + */ +static bool supports_extension(private_ike_sa_t *this, ike_extension_t extension) +{ + return (this->extensions & extension) != FALSE; +} + +/** + * Implementation of ike_sa_t.has_condition. + */ +static bool has_condition(private_ike_sa_t *this, ike_condition_t condition) +{ + return (this->conditions & condition) != FALSE; +} + +/** + * Implementation of ike_sa_t.enable_condition. + */ +static void set_condition(private_ike_sa_t *this, ike_condition_t condition, + bool enable) +{ + if (has_condition(this, condition) != enable) + { + if (enable) + { + this->conditions |= condition; + switch (condition) + { + case COND_STALE: + DBG1(DBG_IKE, "no route to %H, setting IKE_SA to stale", + this->other_host); + break; + case COND_NAT_HERE: + DBG1(DBG_IKE, "local host is behind NAT, sending keep alives"); + this->conditions |= COND_NAT_ANY; + send_keepalive(this); + break; + case COND_NAT_THERE: + DBG1(DBG_IKE, "remote host is behind NAT"); + this->conditions |= COND_NAT_ANY; + break; + default: + break; + } + } + else + { + this->conditions &= ~condition; + switch (condition) + { + case COND_STALE: + DBG1(DBG_IKE, "new route to %H found", this->other_host); + break; + case COND_NAT_HERE: + case COND_NAT_THERE: + set_condition(this, COND_NAT_ANY, + has_condition(this, COND_NAT_HERE) || + has_condition(this, COND_NAT_THERE)); + break; + default: + break; + } + } + } +} /** * Implementation of ike_sa_t.send_dpd @@ -442,46 +563,12 @@ static status_t send_dpd(private_ike_sa_t *this) } /* recheck in "interval" seconds */ job = send_dpd_job_create(this->ike_sa_id); - charon->event_queue->add_relative(charon->event_queue, (job_t*)job, - (delay - diff) * 1000); + charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, + (delay - diff) * 1000); return SUCCESS; } /** - * Implementation of ike_sa_t.send_keepalive - */ -static void send_keepalive(private_ike_sa_t *this) -{ - send_keepalive_job_t *job; - time_t last_out, now, diff; - - last_out = get_use_time(this, FALSE); - now = time(NULL); - - diff = now - last_out; - - if (diff >= KEEPALIVE_INTERVAL) - { - packet_t *packet; - chunk_t data; - - packet = packet_create(); - packet->set_source(packet, this->my_host->clone(this->my_host)); - packet->set_destination(packet, this->other_host->clone(this->other_host)); - data.ptr = malloc(1); - data.ptr[0] = 0xFF; - data.len = 1; - packet->set_data(packet, data); - charon->sender->send(charon->sender, packet); - DBG1(DBG_IKE, "sending keep alive"); - diff = 0; - } - job = send_keepalive_job_create(this->ike_sa_id); - charon->event_queue->add_relative(charon->event_queue, (job_t*)job, - (KEEPALIVE_INTERVAL - diff) * 1000); -} - -/** * Implementation of ike_sa_t.get_state. */ static ike_sa_state_t get_state(private_ike_sa_t *this) @@ -524,16 +611,16 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) { this->time.rekey = now + soft; job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth); - charon->event_queue->add_relative(charon->event_queue, job, - soft * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, + soft * 1000); } if (hard) { this->time.delete = now + hard; job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->event_queue->add_relative(charon->event_queue, job, - hard * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, + hard * 1000); } } break; @@ -542,8 +629,8 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) { /* delete may fail if a packet gets lost, so set a timeout */ job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->event_queue->add_relative(charon->event_queue, job, - HALF_OPEN_IKE_SA_TIMEOUT); + charon->scheduler->schedule_job(charon->scheduler, job, + HALF_OPEN_IKE_SA_TIMEOUT); break; } default: @@ -570,67 +657,151 @@ static void reset(private_ike_sa_t *this) } /** + * Implementation of ike_sa_t.set_virtual_ip + */ +static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip) +{ + if (local) + { + DBG1(DBG_IKE, "installing new virtual IP %H", ip); + if (this->my_virtual_ip) + { + DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip); + charon->kernel_interface->del_ip(charon->kernel_interface, + this->my_virtual_ip); + this->my_virtual_ip->destroy(this->my_virtual_ip); + } + if (charon->kernel_interface->add_ip(charon->kernel_interface, ip, + this->my_host) == SUCCESS) + { + this->my_virtual_ip = ip->clone(ip); + } + else + { + DBG1(DBG_IKE, "installing virtual IP %H failed", ip); + this->my_virtual_ip = NULL; + } + } + else + { + DESTROY_IF(this->other_virtual_ip); + this->other_virtual_ip = ip->clone(ip); + } +} + +/** + * Implementation of ike_sa_t.get_virtual_ip + */ +static host_t* get_virtual_ip(private_ike_sa_t *this, bool local) +{ + if (local) + { + return this->my_virtual_ip; + } + else + { + return this->other_virtual_ip; + } +} + +/** + * Implementation of ike_sa_t.add_additional_address. + */ +static void add_additional_address(private_ike_sa_t *this, host_t *host) +{ + this->additional_addresses->insert_last(this->additional_addresses, host); +} + +/** + * Implementation of ike_sa_t.create_additional_address_iterator. + */ +static iterator_t* create_additional_address_iterator(private_ike_sa_t *this) +{ + return this->additional_addresses->create_iterator( + this->additional_addresses, TRUE); +} + +/** + * Implementation of ike_sa_t.set_pending_updates. + */ +static void set_pending_updates(private_ike_sa_t *this, u_int32_t updates) +{ + this->pending_updates = updates; +} + +/** + * Implementation of ike_sa_t.get_pending_updates. + */ +static u_int32_t get_pending_updates(private_ike_sa_t *this) +{ + return this->pending_updates; +} + +/** * Update hosts, as addresses may change (NAT) */ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) { - iterator_t *iterator = NULL; - child_sa_t *child_sa = NULL; - host_diff_t my_diff, other_diff; + bool update = FALSE; - if (this->my_host->is_anyaddr(this->my_host) || - this->other_host->is_anyaddr(this->other_host)) - { - /* on first received message */ - this->my_host->destroy(this->my_host); - this->my_host = me->clone(me); - this->other_host->destroy(this->other_host); - this->other_host = other->clone(other); + if (supports_extension(this, EXT_MOBIKE)) + { /* if peer speaks mobike, address updates are explicit only */ return; } - my_diff = me->get_differences(me, this->my_host); - other_diff = other->get_differences(other, this->other_host); - - if (!my_diff && !other_diff) + if (me == NULL) { - return; + me = this->my_host; } - - if (my_diff) + if (other == NULL) { - this->my_host->destroy(this->my_host); - this->my_host = me->clone(me); + other = this->other_host; } - if (!this->nat_here) + /* apply hosts on first received message */ + if (this->my_host->is_anyaddr(this->my_host) || + this->other_host->is_anyaddr(this->other_host)) { - /* update without restrictions if we are not NATted */ - if (other_diff) - { - this->other_host->destroy(this->other_host); - this->other_host = other->clone(other); - } + set_my_host(this, me->clone(me)); + set_other_host(this, other->clone(other)); + update = TRUE; } else { - /* if we are natted, only port may change */ - if (other_diff & HOST_DIFF_ADDR) + /* update our address in any case */ + if (!me->equals(me, this->my_host)) { - return; + set_my_host(this, me->clone(me)); + update = TRUE; } - else if (other_diff & HOST_DIFF_PORT) + + if (!other->equals(other, this->other_host)) { - this->other_host->set_port(this->other_host, other->get_port(other)); + /* update others adress if we are NOT NATed, + * and allow port changes if we are NATed */ + if (!has_condition(this, COND_NAT_HERE) || + other->ip_equals(other, this->other_host)) + { + set_other_host(this, other->clone(other)); + update = TRUE; + } } } - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) + + /* update all associated CHILD_SAs, if required */ + if (update) { - child_sa->update_hosts(child_sa, this->my_host, this->other_host, - my_diff, other_diff); + iterator_t *iterator; + child_sa_t *child_sa; + + iterator = this->child_sas->create_iterator(this->child_sas, TRUE); + while (iterator->iterate(iterator, (void**)&child_sa)) + { + child_sa->update_hosts(child_sa, this->my_host, this->other_host, + has_condition(this, COND_NAT_ANY)); + } + iterator->destroy(iterator); } - iterator->destroy(iterator); } /** @@ -761,12 +932,12 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) } /* add a timeout if peer does not establish it completely */ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); - charon->event_queue->add_relative(charon->event_queue, job, - HALF_OPEN_IKE_SA_TIMEOUT); + charon->scheduler->schedule_job(charon->scheduler, job, + HALF_OPEN_IKE_SA_TIMEOUT); } /* check if message is trustworthy, and update host information */ - if (this->state == IKE_CREATED || + if (this->state == IKE_CREATED || this->state == IKE_CONNECTING || message->get_exchange_type(message) != IKE_SA_INIT) { update_hosts(this, me, other); @@ -788,6 +959,7 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) if (this->other_host->is_anyaddr(this->other_host)) { + child_cfg->destroy(child_cfg); SIG(IKE_UP_START, "initiating IKE_SA"); SIG(IKE_UP_FAILED, "unable to initiate to %%any"); return DESTROY_ME; @@ -803,6 +975,8 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_config_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_mobike_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); } task = (task_t*)child_create_create(&this->public, child_cfg); @@ -863,6 +1037,8 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_config_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_mobike_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); } child_cfg = child_sa->get_config(child_sa); @@ -881,6 +1057,7 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) child_sa_t *child_sa; iterator_t *iterator; linked_list_t *my_ts, *other_ts; + host_t *me, *other; status_t status; SIG(CHILD_ROUTE_START, "routing CHILD_SA"); @@ -916,11 +1093,19 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) /* install kernel policies */ child_sa = child_sa_create(this->my_host, this->other_host, this->my_id, this->other_id, child_cfg, FALSE, 0); + me = this->my_host; + if (this->my_virtual_ip) + { + me = this->my_virtual_ip; + } + other = this->other_host; + if (this->other_virtual_ip) + { + other = this->other_virtual_ip; + } - my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, - this->my_host); - other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, - this->other_host); + my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, me); + other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, other); status = child_sa->add_policies(child_sa, my_ts, other_ts, child_cfg->get_mode(child_cfg)); my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); @@ -1063,6 +1248,16 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) /* 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) @@ -1089,6 +1284,8 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) task = (task_t*)child_create_create(&new->public, child_cfg); new->task_manager->queue_task(new->task_manager, task); } + 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); @@ -1191,55 +1388,6 @@ static void set_other_ca(private_ike_sa_t *this, ca_info_t *other_ca) } /** - * Implementation of ike_sa_t.set_virtual_ip - */ -static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip) -{ - if (local) - { - DBG1(DBG_IKE, "installing new virtual IP %H", ip); - if (this->my_virtual_ip) - { - DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip); - charon->kernel_interface->del_ip(charon->kernel_interface, - this->my_virtual_ip, - this->my_host); - this->my_virtual_ip->destroy(this->my_virtual_ip); - } - if (charon->kernel_interface->add_ip(charon->kernel_interface, ip, - this->my_host) == SUCCESS) - { - this->my_virtual_ip = ip->clone(ip); - } - else - { - DBG1(DBG_IKE, "installing virtual IP %H failed", ip); - this->my_virtual_ip = NULL; - } - } - else - { - DESTROY_IF(this->other_virtual_ip); - this->other_virtual_ip = ip->clone(ip); - } -} - -/** - * Implementation of ike_sa_t.get_virtual_ip - */ -static host_t* get_virtual_ip(private_ike_sa_t *this, bool local) -{ - if (local) - { - return this->my_virtual_ip; - } - else - { - return this->other_virtual_ip; - } -} - -/** * Implementation of ike_sa_t.derive_keys. */ static status_t derive_keys(private_ike_sa_t *this, @@ -1560,72 +1708,78 @@ static status_t rekey(private_ike_sa_t *this) /** * Implementation of ike_sa_t.reestablish */ -static void reestablish(private_ike_sa_t *this) +static status_t reestablish(private_ike_sa_t *this) { - private_ike_sa_t *other; - iterator_t *iterator; - child_sa_t *child_sa; - child_cfg_t *child_cfg; task_t *task; - job_t *job; - - other = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new( - charon->ike_sa_manager, TRUE); - set_peer_cfg(other, this->peer_cfg); - other->other_host->destroy(other->other_host); - other->other_host = this->other_host->clone(this->other_host); - if (this->my_virtual_ip) - { - /* if we already have a virtual IP, we reuse it */ - set_virtual_ip(other, TRUE, this->my_virtual_ip); - } - - if (this->state == IKE_ESTABLISHED) - { - task = (task_t*)ike_init_create(&other->public, TRUE, NULL); - other->task_manager->queue_task(other->task_manager, task); - task = (task_t*)ike_natd_create(&other->public, TRUE); - other->task_manager->queue_task(other->task_manager, task); - task = (task_t*)ike_cert_create(&other->public, TRUE); - other->task_manager->queue_task(other->task_manager, task); - task = (task_t*)ike_config_create(&other->public, TRUE); - other->task_manager->queue_task(other->task_manager, task); - task = (task_t*)ike_auth_create(&other->public, TRUE); - other->task_manager->queue_task(other->task_manager, task); - } + task = (task_t*)ike_reauth_create(&this->public); + this->task_manager->queue_task(this->task_manager, task); - other->task_manager->adopt_tasks(other->task_manager, this->task_manager); + return this->task_manager->initiate(this->task_manager); +} + +/** + * Implementation of ike_sa_t.roam. + */ +static status_t roam(private_ike_sa_t *this, bool address) +{ + host_t *me, *other; + ike_mobike_t *mobike; - /* Create task for established children, adopt routed children directly */ - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while(iterator->iterate(iterator, (void**)&child_sa)) + /* responder just updates the peer about changed address config */ + if (!this->ike_sa_id->is_initiator(this->ike_sa_id)) { - switch (child_sa->get_state(child_sa)) + if (supports_extension(this, EXT_MOBIKE) && address) { - case CHILD_ROUTED: - { - iterator->remove(iterator); - other->child_sas->insert_first(other->child_sas, child_sa); - break; - } - default: - { - child_cfg = child_sa->get_config(child_sa); - task = (task_t*)child_create_create(&other->public, child_cfg); - other->task_manager->queue_task(other->task_manager, task); - break; - } + DBG1(DBG_IKE, "sending address list update using MOBIKE"); + mobike = ike_mobike_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, (task_t*)mobike); + return this->task_manager->initiate(this->task_manager); } + return SUCCESS; } - iterator->destroy(iterator); - other->task_manager->initiate(other->task_manager); + /* get best address pair to use */ + other = this->other_host; + me = charon->kernel_interface->get_source_addr(charon->kernel_interface, + other); + + /* TODO: find a better path using additional addresses of peer */ - charon->ike_sa_manager->checkin(charon->ike_sa_manager, &other->public); + if (!me) + { + /* no route found to host, set to stale, wait for a new route */ + set_condition(this, COND_STALE, TRUE); + return FAILED; + } + + set_condition(this, COND_STALE, FALSE); + if (me->ip_equals(me, this->my_host) && + other->ip_equals(other, this->other_host)) + { + DBG2(DBG_IKE, "%H still reached through %H, no update needed", + this->other_host, me); + me->destroy(me); + return SUCCESS; + } + me->set_port(me, this->my_host->get_port(this->my_host)); + other = other->clone(other); + other->set_port(other, this->other_host->get_port(this->other_host)); + set_my_host(this, me); + set_other_host(this, other); - job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->job_queue->add(charon->job_queue, job); + /* update addresses with mobike, if supported ... */ + if (supports_extension(this, EXT_MOBIKE)) + { + DBG1(DBG_IKE, "requesting address change using MOBIKE"); + mobike = ike_mobike_create(&this->public, TRUE); + mobike->roam(mobike, 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); } /** @@ -1680,32 +1834,6 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) } /** - * Implementation of ike_sa_t.is_natt_enabled. - */ -static bool is_natt_enabled(private_ike_sa_t *this) -{ - return this->nat_here || this->nat_there; -} - -/** - * Implementation of ike_sa_t.enable_natt. - */ -static void enable_natt(private_ike_sa_t *this, bool local) -{ - if (local) - { - DBG1(DBG_IKE, "local host is behind NAT, scheduling keep alives"); - this->nat_here = TRUE; - send_keepalive(this); - } - else - { - DBG1(DBG_IKE, "remote host is behind NAT"); - this->nat_there = TRUE; - } -} - -/** * Implementation of ike_sa_t.remove_dns_server */ static void remove_dns_servers(private_ike_sa_t *this) @@ -1857,13 +1985,16 @@ static void destroy(private_ike_sa_t *this) if (this->my_virtual_ip) { charon->kernel_interface->del_ip(charon->kernel_interface, - this->my_virtual_ip, this->my_host); + this->my_virtual_ip); this->my_virtual_ip->destroy(this->my_virtual_ip); } DESTROY_IF(this->other_virtual_ip); remove_dns_servers(this); - this->dns_servers->destroy_offset(this->dns_servers, offsetof(host_t, destroy)); + this->dns_servers->destroy_offset(this->dns_servers, + offsetof(host_t, destroy)); + this->additional_addresses->destroy_offset(this->additional_addresses, + offsetof(host_t, destroy)); DESTROY_IF(this->my_host); DESTROY_IF(this->other_host); @@ -1905,12 +2036,21 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.set_my_host = (void (*)(ike_sa_t*,host_t*)) set_my_host; this->public.get_other_host = (host_t* (*)(ike_sa_t*)) get_other_host; this->public.set_other_host = (void (*)(ike_sa_t*,host_t*)) set_other_host; + this->public.update_hosts = (void(*)(ike_sa_t*, host_t *me, host_t *other))update_hosts; this->public.get_my_id = (identification_t* (*)(ike_sa_t*)) get_my_id; this->public.set_my_id = (void (*)(ike_sa_t*,identification_t*)) set_my_id; this->public.get_other_id = (identification_t* (*)(ike_sa_t*)) get_other_id; this->public.set_other_id = (void (*)(ike_sa_t*,identification_t*)) set_other_id; this->public.get_other_ca = (ca_info_t* (*)(ike_sa_t*)) get_other_ca; this->public.set_other_ca = (void (*)(ike_sa_t*,ca_info_t*)) set_other_ca; + this->public.enable_extension = (void(*)(ike_sa_t*, ike_extension_t extension))enable_extension; + this->public.supports_extension = (bool(*)(ike_sa_t*, ike_extension_t extension))supports_extension; + this->public.set_condition = (void (*)(ike_sa_t*, ike_condition_t,bool)) set_condition; + this->public.has_condition = (bool (*)(ike_sa_t*,ike_condition_t)) has_condition; + this->public.set_pending_updates = (void(*)(ike_sa_t*, u_int32_t updates))set_pending_updates; + this->public.get_pending_updates = (u_int32_t(*)(ike_sa_t*))get_pending_updates; + this->public.create_additional_address_iterator = (iterator_t*(*)(ike_sa_t*))create_additional_address_iterator; + this->public.add_additional_address = (void(*)(ike_sa_t*, host_t *host))add_additional_address; this->public.retransmit = (status_t (*)(ike_sa_t *, u_int32_t)) retransmit; this->public.delete = (status_t (*)(ike_sa_t*))delete_; this->public.destroy = (void (*)(ike_sa_t*))destroy; @@ -1927,10 +2067,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.rekey_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa; 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.enable_natt = (void (*)(ike_sa_t*, bool)) enable_natt; - this->public.is_natt_enabled = (bool (*)(ike_sa_t*)) is_natt_enabled; this->public.rekey = (status_t (*)(ike_sa_t*))rekey; - this->public.reestablish = (void (*)(ike_sa_t*))reestablish; + this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish; + this->public.roam = (status_t(*)(ike_sa_t*,bool))roam; this->public.inherit = (status_t (*)(ike_sa_t*,ike_sa_t*))inherit; this->public.generate_message = (status_t (*)(ike_sa_t*,message_t*,packet_t**))generate_message; this->public.reset = (void (*)(ike_sa_t*))reset; @@ -1947,6 +2086,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->other_ca = NULL; + this->extensions = 0; + this->conditions = 0; this->crypter_in = NULL; this->crypter_out = NULL; this->signer_in = NULL; @@ -1955,8 +2096,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->skp_verify = chunk_empty; this->skp_build = chunk_empty; this->child_prf = NULL; - this->nat_here = FALSE; - this->nat_there = FALSE; this->state = IKE_CREATED; this->time.inbound = this->time.outbound = time(NULL); this->time.established = 0; @@ -1969,6 +2108,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->my_virtual_ip = NULL; this->other_virtual_ip = NULL; this->dns_servers = linked_list_create(); + this->additional_addresses = linked_list_create(); + this->pending_updates = 0; this->keyingtry = 0; return &this->public; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 76942b208..ba189577c 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -25,6 +25,8 @@ #ifndef IKE_SA_H_ #define IKE_SA_H_ +typedef enum ike_extension_t ike_extension_t; +typedef enum ike_condition_t ike_condition_t; typedef enum ike_sa_state_t ike_sa_state_t; typedef struct ike_sa_t ike_sa_t; @@ -70,6 +72,47 @@ typedef struct ike_sa_t ike_sa_t; */ #define RETRY_JITTER 20 +/** + * @brief Extensions (or optional features) the peer supports + */ +enum ike_extension_t { + + /** + * peer supports NAT traversal as specified in RFC4306 + */ + EXT_NATT = (1<<0), + + /** + * peer supports MOBIKE (RFC4555) + */ + EXT_MOBIKE = (1<<1), +}; + +/** + * @brief Conditions of an IKE_SA, change during its lifetime + */ +enum ike_condition_t { + + /** + * Connection is natted somewhere + */ + COND_NAT_ANY = (1<<0), + + /** + * we are behind NAT + */ + COND_NAT_HERE = (1<<1), + + /** + * other is behind NAT + */ + COND_NAT_THERE = (1<<2), + + /** + * peer is currently not reachable (due missing route, ...) + */ + COND_STALE = (1<<3), +}; /** * @brief State of an IKE_SA. @@ -240,6 +283,17 @@ struct ike_sa_t { void (*set_other_host) (ike_sa_t *this, host_t *other); /** + * @brief Update the IKE_SAs host. + * + * Hosts may be NULL to use current host. + * + * @param this calling object + * @param me new local host address, or NULL + * @param other new remote host address, or NULL + */ + void (*update_hosts)(ike_sa_t *this, host_t *me, host_t *other); + + /** * @brief Get the own identification. * * @param this calling object @@ -318,8 +372,83 @@ struct ike_sa_t { * @param config peer_config to use */ void (*set_peer_cfg) (ike_sa_t *this, peer_cfg_t *config); + + /** + * @brief Add an additional address for the peer. + * + * In MOBIKE, a peer may transmit additional addresses where it is + * reachable. These are stored in the IKE_SA. + * The own list of addresses is not stored, they are queried from + * the kernel when required. + * + * @param this calling object + * @param host host to add to list + */ + void (*add_additional_address)(ike_sa_t *this, host_t *host); + + /** + * @brief Create an iterator over all additional addresses of the peer. + * + * @param this calling object + * @return iterator over addresses + */ + iterator_t* (*create_additional_address_iterator)(ike_sa_t *this); + + /** + * @brief Enable an extension the peer supports. + * + * If support for an IKE extension is detected, this method is called + * to enable that extension and behave accordingly. + * + * @param this calling object + * @param extension extension to enable + */ + void (*enable_extension)(ike_sa_t *this, ike_extension_t extension); + + /** + * @brief Check if the peer supports an extension. + * + * @param this calling object + * @param extension extension to check for support + * @return TRUE if peer supports it, FALSE otherwise + */ + bool (*supports_extension)(ike_sa_t *this, ike_extension_t extension); + + /** + * @brief Enable/disable a condition flag for this IKE_SA. + * + * @param this calling object + * @param condition condition to enable/disable + * @param enable TRUE to enable condition, FALSE to disable + */ + void (*set_condition) (ike_sa_t *this, ike_condition_t condition, bool enable); /** + * @brief Check if a condition flag is set. + * + * @param this calling object + * @param condition condition to check + * @return TRUE if condition flag set, FALSE otherwise + */ + bool (*has_condition) (ike_sa_t *this, ike_condition_t condition); + + /** + * @brief Get the number of queued MOBIKE address updates. + * + * @param this calling object + * @return number of pending updates + */ + u_int32_t (*get_pending_updates)(ike_sa_t *this); + + /** + * @brief Set the number of queued MOBIKE address updates. + * + * @param this calling object + * @param updates number of pending updates + */ + void (*set_pending_updates)(ike_sa_t *this, u_int32_t updates); + + /** * @brief Initiate a new connection. * * The configs are owned by the IKE_SA after the call. @@ -389,6 +518,21 @@ struct ike_sa_t { status_t (*delete) (ike_sa_t *this); /** + * @brief Update IKE_SAs after network interfaces have changed. + * + * Whenever the network interface configuration changes, the kernel + * interface calls roam() on each IKE_SA. The IKE_SA then checks if + * the new network config requires changes, and handles appropriate. + * If MOBIKE is supported, addresses are updated; If not, the tunnel is + * restarted. + * + * @param this calling object + * @param address TRUE if address list changed, FALSE otherwise + * @return SUCCESS, FAILED, DESTROY_ME + */ + status_t (*roam)(ike_sa_t *this, bool address); + + /** * @brief Processes a incoming IKEv2-Message. * * Message processing may fail. If a critical failure occurs, @@ -457,29 +601,6 @@ struct ike_sa_t { * @param this calling object */ void (*send_keepalive) (ike_sa_t *this); - - /** - * @brief Check if NAT traversal is enabled for this IKE_SA. - * - * @param this calling object - * @return TRUE if NAT traversal enabled - */ - bool (*is_natt_enabled) (ike_sa_t *this); - - /** - * @brief Enable NAT detection for this IKE_SA. - * - * If a Network address translation is detected with - * NAT_DETECTION notifys, a SA must switch to ports - * 4500. To enable this behavior, call enable_natt(). - * It is relevant which peer is NATted, this is specified - * with the "local" parameter. Call it twice when both - * are NATted. - * - * @param this calling object - * @param local TRUE, if we are NATted, FALSE if other - */ - void (*enable_natt) (ike_sa_t *this, bool local); /** * @brief Derive all keys and create the transforms for IKE communication. @@ -621,11 +742,12 @@ struct ike_sa_t { * @brief Restablish the IKE_SA. * * Create a completely new IKE_SA with authentication, recreates all children - * within the IKE_SA, but lets the old IKE_SA untouched. + * within the IKE_SA, closes this IKE_SA. * * @param this calling object + * @return DESTROY_ME to destroy the IKE_SA */ - void (*reestablish) (ike_sa_t *this); + status_t (*reestablish) (ike_sa_t *this); /** * @brief Set the virtual IP to use for this IKE_SA and its children. diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index a62ec5e3c..56b865891 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -525,19 +525,21 @@ static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this, /* IKE_SA has no IDs yet, so we can't use it */ continue; } - + DBG2(DBG_MGR, "candidate IKE_SA for \n\t%H[%D]...%H[%D]\n\t%H[%D]...%H[%D]", + my_host, my_id, other_host, other_id, + found_my_host, found_my_id, found_other_host, found_other_id); /* compare ID and hosts. Supplied ID may contain wildcards, and IP * may be %any. */ - if ((found_my_host->is_anyaddr(found_my_host) || + if ((my_host->is_anyaddr(my_host) || my_host->ip_equals(my_host, found_my_host)) && - (found_other_host->is_anyaddr(found_other_host) || + (other_host->is_anyaddr(other_host) || other_host->ip_equals(other_host, found_other_host)) && found_my_id->matches(found_my_id, my_id, &wc) && found_other_id->matches(found_other_id, other_id, &wc)) { /* looks good, we take this one */ DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]", - my_host, other_host, my_id, other_id); + my_host, my_id, other_host, other_id); entry->checked_out = TRUE; ike_sa = entry->ike_sa; } @@ -682,16 +684,16 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name, /** * Iterator hook for iterate, gets ike_sas instead of entries */ -static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in, - ike_sa_t **out) +static hook_result_t iterator_hook(private_ike_sa_manager_t* this, entry_t *in, + ike_sa_t **out) { /* check out entry */ if (wait_for_entry(this, in)) { *out = in->ike_sa; - return TRUE; + return HOOK_NEXT; } - return FALSE; + return HOOK_SKIP; } /** @@ -701,6 +703,7 @@ static iterator_t *create_iterator(private_ike_sa_manager_t* this) { iterator_t *iterator = this->ike_sa_list->create_iterator_locked( this->ike_sa_list, &this->mutex); + /* register hook to iterator over ike_sas, not entries */ iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this); return iterator; diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index e67508ed1..55592f437 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -27,6 +27,7 @@ #include <daemon.h> #include <sa/tasks/ike_init.h> #include <sa/tasks/ike_natd.h> +#include <sa/tasks/ike_mobike.h> #include <sa/tasks/ike_auth.h> #include <sa/tasks/ike_cert.h> #include <sa/tasks/ike_rekey.h> @@ -130,6 +131,11 @@ struct private_task_manager_t { * List of tasks initiated by peer */ linked_list_t *passive_tasks; + + /** + * the task manager has been reset + */ + bool reset; }; /** @@ -140,7 +146,7 @@ static void flush(private_task_manager_t *this) task_t *task; this->queued_tasks->destroy_offset(this->queued_tasks, - offsetof(task_t, destroy)); + offsetof(task_t, destroy)); this->passive_tasks->destroy_offset(this->passive_tasks, offsetof(task_t, destroy)); @@ -235,7 +241,7 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id) this->initiating.packet->clone(this->initiating.packet)); job = (job_t*)retransmit_job_create(this->initiating.mid, this->ike_sa->get_id(this->ike_sa)); - charon->event_queue->add_relative(charon->event_queue, job, timeout); + charon->scheduler->schedule_job(charon->scheduler, job, timeout); } return SUCCESS; } @@ -274,6 +280,7 @@ static status_t build_request(private_task_manager_t *this) activate_task(this, IKE_AUTHENTICATE); activate_task(this, IKE_CONFIG); activate_task(this, CHILD_CREATE); + activate_task(this, IKE_MOBIKE); } break; case IKE_ESTABLISHED: @@ -302,7 +309,17 @@ static status_t build_request(private_task_manager_t *this) exchange = CREATE_CHILD_SA; break; } - if (activate_task(this, IKE_DEADPEER)) + if (activate_task(this, IKE_REAUTH)) + { + exchange = INFORMATIONAL; + break; + } + if (activate_task(this, IKE_MOBIKE)) + { + exchange = INFORMATIONAL; + break; + } + if (activate_task(this, IKE_DPD)) { exchange = INFORMATIONAL; break; @@ -338,6 +355,8 @@ static status_t build_request(private_task_manager_t *this) case IKE_REKEY: exchange = CREATE_CHILD_SA; break; + case IKE_MOBIKE: + exchange = INFORMATIONAL; default: continue; } @@ -415,6 +434,8 @@ static status_t process_response(private_task_manager_t *this, return DESTROY_ME; } + /* catch if we get resetted while processing */ + this->reset = FALSE; iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); while (iterator->iterate(iterator, (void*)&task)) { @@ -434,6 +455,12 @@ static status_t process_response(private_task_manager_t *this, iterator->destroy(iterator); return DESTROY_ME; } + if (this->reset) + { /* start all over again if we were reset */ + this->reset = FALSE; + iterator->destroy(iterator); + return build_request(this); + } } iterator->destroy(iterator); @@ -456,7 +483,7 @@ static void handle_collisions(private_task_manager_t *this, task_t *task) /* do we have to check */ if (type == IKE_REKEY || type == CHILD_REKEY || - type == CHILD_DELETE || type == IKE_DELETE) + type == CHILD_DELETE || type == IKE_DELETE || type == IKE_REAUTH) { /* find an exchange collision, and notify these tasks */ iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); @@ -465,7 +492,8 @@ static void handle_collisions(private_task_manager_t *this, task_t *task) switch (active->get_type(active)) { case IKE_REKEY: - if (type == IKE_REKEY || type == IKE_DELETE) + if (type == IKE_REKEY || type == IKE_DELETE || + type == IKE_REAUTH) { ike_rekey_t *rekey = (ike_rekey_t*)active; rekey->collide(rekey, task); @@ -571,6 +599,7 @@ static status_t process_request(private_task_manager_t *this, exchange_type_t exchange; payload_t *payload; notify_payload_t *notify; + delete_payload_t *delete; exchange = message->get_exchange_type(message); @@ -591,6 +620,8 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)child_create_create(this->ike_sa, NULL); this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_mobike_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); break; } case CREATE_CHILD_SA: @@ -646,27 +677,60 @@ static status_t process_request(private_task_manager_t *this, } case INFORMATIONAL: { - delete_payload_t *delete; - - delete = (delete_payload_t*)message->get_payload(message, DELETE); - if (delete) + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) { - if (delete->get_protocol_id(delete) == PROTO_IKE) + switch (payload->get_type(payload)) { - task = (task_t*)ike_delete_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + case NOTIFY: + { + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case ADDITIONAL_IP4_ADDRESS: + case ADDITIONAL_IP6_ADDRESS: + case NO_ADDITIONAL_ADDRESSES: + case UPDATE_SA_ADDRESSES: + case NO_NATS_ALLOWED: + case UNACCEPTABLE_ADDRESSES: + case UNEXPECTED_NAT_DETECTED: + case COOKIE2: + task = (task_t*)ike_mobike_create(this->ike_sa, + FALSE); + break; + default: + break; + } + break; + } + case DELETE: + { + delete = (delete_payload_t*)payload; + if (delete->get_protocol_id(delete) == PROTO_IKE) + { + task = (task_t*)ike_delete_create(this->ike_sa, FALSE); + } + else + { + task = (task_t*)child_delete_create(this->ike_sa, NULL); + } + break; + } + default: + break; } - else + if (task) { - task = (task_t*)child_delete_create(this->ike_sa, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); + break; } } - else + iterator->destroy(iterator); + + if (task == NULL) { task = (task_t*)ike_dpd_create(FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); } + this->passive_tasks->insert_last(this->passive_tasks, task); break; } default: @@ -806,7 +870,7 @@ static void reset(private_task_manager_t *this) this->responding.packet = NULL; this->initiating.packet = NULL; this->responding.mid = 0; - this->initiating.mid = -1; + this->initiating.mid = 0; this->initiating.type = EXCHANGE_TYPE_UNDEFINED; /* reset active tasks */ @@ -816,6 +880,8 @@ static void reset(private_task_manager_t *this) task->migrate(task, this->ike_sa); this->queued_tasks->insert_first(this->queued_tasks, task); } + + this->reset = TRUE; } /** @@ -859,6 +925,7 @@ task_manager_t *task_manager_create(ike_sa_t *ike_sa) this->queued_tasks = linked_list_create(); this->active_tasks = linked_list_create(); this->passive_tasks = linked_list_create(); + this->reset = FALSE; return &this->public; } diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index f70730b05..42f34a94b 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -297,7 +297,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) this->mode = MODE_TUNNEL; DBG1(DBG_IKE, "not using tranport mode, not host-to-host"); } - else if (this->ike_sa->is_natt_enabled(this->ike_sa)) + else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) { this->mode = MODE_TUNNEL; DBG1(DBG_IKE, "not using tranport mode, connection NATed"); @@ -493,6 +493,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) static status_t build_i(private_child_create_t *this, message_t *message) { host_t *me, *other, *vip; + bool propose_all = FALSE; peer_cfg_t *peer_cfg; switch (message->get_exchange_type(message)) @@ -523,33 +524,53 @@ static status_t build_i(private_child_create_t *this, message_t *message) SIG(CHILD_UP_START, "establishing CHILD_SA"); - me = this->ike_sa->get_my_host(this->ike_sa); - other = this->ike_sa->get_other_host(this->ike_sa); - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - vip = peer_cfg->get_my_virtual_ip(peer_cfg); + /* reuse virtual IP if we already have one */ + me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (me == NULL) + { + me = this->ike_sa->get_my_host(this->ike_sa); + } + other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); + if (other == NULL) + { + other = this->ike_sa->get_other_host(this->ike_sa); + } - if (vip) + /* check if we want a virtual IP, but don't have one */ + if (!this->reqid) + { + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + vip = peer_cfg->get_my_virtual_ip(peer_cfg); + if (vip) + { + propose_all = TRUE; + vip->destroy(vip); + } + } + + if (propose_all) { /* propose a 0.0.0.0/0 subnet when we use virtual ip */ this->tsi = this->config->get_traffic_selectors(this->config, TRUE, NULL, NULL); - vip->destroy(vip); } else - { /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */ + { /* but shorten a 0.0.0.0/0 subnet for host2host/we already have a vip */ this->tsi = this->config->get_traffic_selectors(this->config, TRUE, NULL, me); } this->tsr = this->config->get_traffic_selectors(this->config, FALSE, NULL, other); + this->proposals = this->config->get_proposals(this->config, this->dh_group == MODP_NONE); this->mode = this->config->get_mode(this->config); - this->child_sa = child_sa_create(me, other, - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->config, this->reqid, - this->ike_sa->is_natt_enabled(this->ike_sa)); + this->child_sa = child_sa_create( + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid, + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS) { @@ -609,9 +630,21 @@ static status_t process_r(private_child_create_t *this, message_t *message) peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); if (peer_cfg) { - this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, this->tsi, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); + host_t *me, *other; + + me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (me == NULL) + { + me = this->ike_sa->get_my_host(this->ike_sa); + } + other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); + if (other == NULL) + { + other = this->ike_sa->get_other_host(this->ike_sa); + } + + this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, + this->tsi, me, other); } return NEED_MORE; } @@ -660,12 +693,12 @@ static status_t build_r(private_child_create_t *this, message_t *message) return SUCCESS; } - this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->config, this->reqid, - this->ike_sa->is_natt_enabled(this->ike_sa)); + this->child_sa = child_sa_create( + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid, + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); switch (select_and_install(this, no_dh)) { diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c index 4f3c69034..3667d8fad 100644 --- a/src/charon/sa/tasks/child_rekey.c +++ b/src/charon/sa/tasks/child_rekey.c @@ -206,7 +206,7 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) DBG1(DBG_IKE, "CHILD_SA rekeying failed, " "trying again in %d seconds", retry); this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - charon->event_queue->add_relative(charon->event_queue, job, retry * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, retry * 1000); } return SUCCESS; } diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index d0dd49aee..c1c0cd5a2 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -636,7 +636,12 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) case INVALID_SELECTORS: /* these are errors, but are not critical as only the * CHILD_SA won't get build, but IKE_SA establishes anyway */ - break; + break; + case MOBIKE_SUPPORTED: + case ADDITIONAL_IP4_ADDRESS: + case ADDITIONAL_IP6_ADDRESS: + /* handled in ike_mobike task */ + break; default: { if (type < 16383) diff --git a/src/charon/sa/tasks/ike_dpd.c b/src/charon/sa/tasks/ike_dpd.c index 1cb05c45c..be751766e 100644 --- a/src/charon/sa/tasks/ike_dpd.c +++ b/src/charon/sa/tasks/ike_dpd.c @@ -61,7 +61,7 @@ static status_t return_success(private_ike_dpd_t *this, message_t *message) */ static task_type_t get_type(private_ike_dpd_t *this) { - return IKE_DEADPEER; + return IKE_DPD; } /** diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c new file mode 100644 index 000000000..8d4dce36c --- /dev/null +++ b/src/charon/sa/tasks/ike_mobike.c @@ -0,0 +1,431 @@ +/** + * @file ike_mobike.c + * + * @brief Implementation of the ike_mobike task. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_mobike.h" + +#include <string.h> + +#include <daemon.h> +#include <sa/tasks/ike_natd.h> +#include <encoding/payloads/notify_payload.h> + + +typedef struct private_ike_mobike_t private_ike_mobike_t; + +/** + * Private members of a ike_mobike_t task. + */ +struct private_ike_mobike_t { + + /** + * Public methods and task_t interface. + */ + ike_mobike_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * cookie2 value to verify new addresses + */ + chunk_t cookie2; + + /** + * NAT discovery reusing the IKE_NATD task + */ + ike_natd_t *natd; + + /** + * use task to update addresses + */ + bool roam; + + /** + * include address list update + */ + bool address; +}; + +/** + * flush the IKE_SAs list of additional addresses + */ +static void flush_additional_addresses(private_ike_mobike_t *this) +{ + iterator_t *iterator; + host_t *host; + + iterator = this->ike_sa->create_additional_address_iterator(this->ike_sa); + while (iterator->iterate(iterator, (void**)&host)) + { + iterator->remove(iterator); + host->destroy(host); + } + iterator->destroy(iterator); +} + + +/** + * read notifys from message and evaluate them + */ +static void process_payloads(private_ike_mobike_t *this, message_t *message) +{ + iterator_t *iterator; + payload_t *payload; + bool first = TRUE; + + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) + { + int family = AF_INET; + notify_payload_t *notify; + chunk_t data; + host_t *host; + + if (payload->get_type(payload) != NOTIFY) + { + continue; + } + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case MOBIKE_SUPPORTED: + { + DBG1(DBG_IKE, "peer supports MOBIKE"); + this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE); + break; + } + case ADDITIONAL_IP6_ADDRESS: + { + family = AF_INET6; + /* fall through */ + } + case ADDITIONAL_IP4_ADDRESS: + { + if (first) + { /* an ADDITIONAL_*_ADDRESS means replace, so flush once */ + flush_additional_addresses(this); + first = FALSE; + } + data = notify->get_notification_data(notify); + host = host_create_from_chunk(family, data, 0); + DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host); + this->ike_sa->add_additional_address(this->ike_sa, host); + break; + } + case UPDATE_SA_ADDRESSES: + { + this->roam = TRUE; + break; + } + case NO_ADDITIONAL_ADDRESSES: + { + flush_additional_addresses(this); + break; + } + case NAT_DETECTION_SOURCE_IP: + case NAT_DETECTION_DESTINATION_IP: + { + /* NAT check in this MOBIKE exchange, create subtask for it */ + if (this->natd == NULL) + { + this->natd = ike_natd_create(this->ike_sa, this->initiator); + } + break; + } + default: + break; + } + } + iterator->destroy(iterator); +} + +/** + * Add ADDITIONAL_*_ADDRESS notifys depending on our address list + */ +static void build_address_list(private_ike_mobike_t *this, message_t *message) +{ + iterator_t *iterator; + host_t *host, *me; + notify_type_t type; + bool additional = FALSE; + + me = this->ike_sa->get_my_host(this->ike_sa); + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + while (iterator->iterate(iterator, (void**)&host)) + { + if (me->ip_equals(me, host)) + { /* "ADDITIONAL" means do not include IKE_SAs host */ + continue; + } + switch (host->get_family(host)) + { + case AF_INET: + type = ADDITIONAL_IP4_ADDRESS; + break; + case AF_INET6: + type = ADDITIONAL_IP6_ADDRESS; + break; + default: + continue; + } + message->add_notify(message, FALSE, type, host->get_address(host)); + additional = TRUE; + } + if (!additional) + { + message->add_notify(message, FALSE, NO_ADDITIONAL_ADDRESSES, chunk_empty); + } + iterator->destroy(iterator); +} + +/** + * update addresses of associated CHILD_SAs + */ +static void update_children(private_ike_mobike_t *this) +{ + iterator_t *iterator; + child_sa_t *child_sa; + + iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa); + while (iterator->iterate(iterator, (void**)&child_sa)) + { + child_sa->update_hosts(child_sa, + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); + } + iterator->destroy(iterator); +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t build_i(private_ike_mobike_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_payload(message, SECURITY_ASSOCIATION)) + { + message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); + build_address_list(this, message); + } + else + { + if (this->roam) + { + message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty); + } + if (this->address) + { + build_address_list(this, message); + } + + this->natd = ike_natd_create(this->ike_sa, this->initiator); + this->natd->task.build(&this->natd->task, message); + update_children(this); + } + + return NEED_MORE; +} + +/** + * Implementation of task_t.process for responder + */ +static status_t process_r(private_ike_mobike_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_payload(message, SECURITY_ASSOCIATION)) + { + process_payloads(this, message); + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + process_payloads(this, message); + if (this->roam) + { + host_t *me, *other; + + me = message->get_destination(message); + other = message->get_source(message); + this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + } + + if (this->natd) + { + this->natd->task.process(&this->natd->task, message); + } + } + return NEED_MORE; +} + +/** + * Implementation of task_t.build for responder + */ +static status_t build_r(private_ike_mobike_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_payload(message, SECURITY_ASSOCIATION)) + { + if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) + { + message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); + build_address_list(this, message); + } + return SUCCESS; + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + if (this->natd) + { + this->natd->task.build(&this->natd->task, message); + } + if (this->roam) + { + update_children(this); + } + return SUCCESS; + } + return NEED_MORE; +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t process_i(private_ike_mobike_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_payload(message, SECURITY_ASSOCIATION)) + { + process_payloads(this, message); + + return SUCCESS; + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + u_int32_t updates = this->ike_sa->get_pending_updates(this->ike_sa) - 1; + this->ike_sa->set_pending_updates(this->ike_sa, updates); + if (updates > 0) + { + /* newer update queued, ignore this one */ + return SUCCESS; + } + process_payloads(this, message); + if (this->natd) + { + this->natd->task.process(&this->natd->task, message); + } + if (this->roam) + { + /* update again, as NAT state may have changed */ + update_children(this); + } + return SUCCESS; + } + return NEED_MORE; +} + +/** + * Implementation of ike_mobike_t.roam. + */ +static void roam(private_ike_mobike_t *this, bool address) +{ + this->roam = TRUE; + this->address = address; + this->ike_sa->set_pending_updates(this->ike_sa, + this->ike_sa->get_pending_updates(this->ike_sa) + 1); +} + +/** + * Implementation of task_t.get_type + */ +static task_type_t get_type(private_ike_mobike_t *this) +{ + return IKE_MOBIKE; +} + +/** + * Implementation of task_t.migrate + */ +static void migrate(private_ike_mobike_t *this, ike_sa_t *ike_sa) +{ + chunk_free(&this->cookie2); + this->ike_sa = ike_sa; + if (this->natd) + { + this->natd->task.migrate(&this->natd->task, ike_sa); + } +} + +/** + * Implementation of task_t.destroy + */ +static void destroy(private_ike_mobike_t *this) +{ + chunk_free(&this->cookie2); + if (this->natd) + { + this->natd->task.destroy(&this->natd->task); + } + free(this); +} + +/* + * Described in header. + */ +ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_mobike_t *this = malloc_thing(private_ike_mobike_t); + + this->public.roam = (void(*)(ike_mobike_t*,bool))roam; + this->public.task.get_type = (task_type_t(*)(task_t*))get_type; + this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; + this->public.task.destroy = (void(*)(task_t*))destroy; + + if (initiator) + { + this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + } + else + { + this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + } + + this->ike_sa = ike_sa; + this->initiator = initiator; + this->roam = FALSE; + this->address = TRUE; + this->cookie2 = chunk_empty; + this->natd = NULL; + + return &this->public; +} + diff --git a/src/charon/sa/tasks/ike_mobike.h b/src/charon/sa/tasks/ike_mobike.h new file mode 100644 index 000000000..db493c459 --- /dev/null +++ b/src/charon/sa/tasks/ike_mobike.h @@ -0,0 +1,73 @@ +/** + * @file ike_mobike.h + * + * @brief Interface ike_mobike_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef IKE_MOBIKE_H_ +#define IKE_MOBIKE_H_ + +typedef struct ike_mobike_t ike_mobike_t; + +#include <library.h> +#include <sa/ike_sa.h> +#include <sa/tasks/task.h> + +/** + * @brief Task of type ike_mobike, detects and handles MOBIKE extension. + * + * The MOBIKE extension is defined in RFC4555. It allows to update IKE + * and IPsec tunnel addresses. + * This tasks handles the MOBIKE_SUPPORTED notify exchange to detect MOBIKE + * support, allows the exchange of ADDITIONAL_*_ADDRESS to exchange additional + * endpoints and handles the UPDATE_SA_ADDRESS notify to finally update + * endpoints. + * + * @b Constructors: + * - ike_mobike_create() + * + * @ingroup tasks + */ +struct ike_mobike_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * @brief Use the task to roam to other addresses. + * + * @param this calling object + * @param address TRUE to include address list update + */ + void (*roam)(ike_mobike_t *this, bool address); +}; + +/** + * @brief Create a new ike_mobike task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if taks is initiated by us + * @return ike_mobike task to handle by the task_manager + */ +ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator); + +#endif /* IKE_MOBIKE_H_ */ + diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index 50b5d652b..84a28d024 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -203,14 +203,12 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) if (this->src_seen && this->dst_seen) { - if (!this->dst_matched) - { - this->ike_sa->enable_natt(this->ike_sa, TRUE); - } - if (!this->src_matched) - { - this->ike_sa->enable_natt(this->ike_sa, FALSE); - } + this->ike_sa->enable_extension(this->ike_sa, EXT_NATT); + + this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, + !this->dst_matched); + this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, + !this->src_matched); } } @@ -220,8 +218,11 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) static status_t process_i(private_ike_natd_t *this, message_t *message) { process_payloads(this, message); - - if (this->ike_sa->is_natt_enabled(this->ike_sa)) + + /* if peer supports NAT-T, we switch to port 4500 even + * if no NAT is detected. MOBIKE requires this. */ + if (message->get_exchange_type(message) == IKE_SA_INIT && + this->ike_sa->supports_extension(this->ike_sa, EXT_NATT)) { host_t *me, *other; @@ -240,33 +241,49 @@ static status_t process_i(private_ike_natd_t *this, message_t *message) static status_t build_i(private_ike_natd_t *this, message_t *message) { notify_payload_t *notify; - linked_list_t *list; + iterator_t *iterator; host_t *host; - /* include one notify if our address is defined, all addresses otherwise */ + /* destination is always set */ + host = this->ike_sa->get_other_host(this->ike_sa); + notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host); + message->add_payload(message, (payload_t*)notify); + + /* source may be any, we have 3 possibilities to get our source address: + * 1. It is defined in the config => use the one of the IKE_SA + * 2. We do a routing lookup in the kernel interface + * 3. Include all possbile addresses + */ host = this->ike_sa->get_my_host(this->ike_sa); - if (host->is_anyaddr(host)) + if (!host->is_anyaddr(host)) + { /* 1. */ + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); + message->add_payload(message, (payload_t*)notify); + } + else { - /* TODO: we could get the src address from netlink!? */ - list = charon->kernel_interface->create_address_list(charon->kernel_interface); - while (list->remove_first(list, (void**)&host) == SUCCESS) - { + host = charon->kernel_interface->get_source_addr( + charon->kernel_interface, + this->ike_sa->get_other_host(this->ike_sa)); + if (host) + { /* 2. */ + host->set_port(host, IKEV2_UDP_PORT); notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); - host->destroy(host); message->add_payload(message, (payload_t*)notify); + host->destroy(host); + } + else + { /* 3. */ + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + while (iterator->iterate(iterator, (void**)&host)) + { + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); + message->add_payload(message, (payload_t*)notify); + } + iterator->destroy(iterator); } - list->destroy(list); - } - else - { - notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); - message->add_payload(message, (payload_t*)notify); } - - host = this->ike_sa->get_other_host(this->ike_sa); - notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host); - message->add_payload(message, (payload_t*)notify); - return NEED_MORE; } @@ -279,7 +296,8 @@ static status_t build_r(private_ike_natd_t *this, message_t *message) host_t *me, *other; /* only add notifies on successfull responses. */ - if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) + if (message->get_exchange_type(message) == IKE_SA_INIT && + message->get_payload(message, SECURITY_ASSOCIATION) == NULL) { return SUCCESS; } diff --git a/src/charon/sa/tasks/ike_reauth.c b/src/charon/sa/tasks/ike_reauth.c new file mode 100644 index 000000000..0e98382a8 --- /dev/null +++ b/src/charon/sa/tasks/ike_reauth.c @@ -0,0 +1,175 @@ +/** + * @file ike_reauth.c + * + * @brief Implementation of the ike_reauth task. + * + */ + +/* + * Copyright (C) 2006-2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_reauth.h" + +#include <daemon.h> +#include <sa/tasks/ike_delete.h> + + +typedef struct private_ike_reauth_t private_ike_reauth_t; + +/** + * Private members of a ike_reauth_t task. + */ +struct private_ike_reauth_t { + + /** + * Public methods and task_t interface. + */ + ike_reauth_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * reused ike_delete task + */ + ike_delete_t *ike_delete; +}; + +/** + * Implementation of task_t.build for initiator + */ +static status_t build_i(private_ike_reauth_t *this, message_t *message) +{ + return this->ike_delete->task.build(&this->ike_delete->task, message); +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t process_i(private_ike_reauth_t *this, message_t *message) +{ + ike_sa_t *new; + host_t *host; + iterator_t *iterator; + child_sa_t *child_sa; + + /* process delete response first */ + this->ike_delete->task.process(&this->ike_delete->task, message); + + /* reestablish only if we have children */ + iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa); + if (iterator->get_count(iterator) == 0) + { + DBG1(DBG_IKE, "unable to reestablish IKE_SA, no CHILD_SA to recreate"); + iterator->destroy(iterator); + return FAILED; + } + + new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE); + + new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa)); + host = this->ike_sa->get_other_host(this->ike_sa); + new->set_other_host(new, host->clone(host)); + host = this->ike_sa->get_my_host(this->ike_sa); + new->set_my_host(new, host->clone(host)); + /* if we already have a virtual IP, we reuse it */ + host = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (host) + { + new->set_virtual_ip(new, TRUE, host); + } + + while (iterator->iterate(iterator, (void**)&child_sa)) + { + switch (child_sa->get_state(child_sa)) + { + case CHILD_ROUTED: + { + /* move routed child directly */ + iterator->remove(iterator); + new->add_child_sa(new, child_sa); + break; + } + default: + { + /* initiate/queue all child SAs */ + child_cfg_t *child_cfg = child_sa->get_config(child_sa); + child_cfg->get_ref(child_cfg); + if (new->initiate(new, child_cfg) == DESTROY_ME) + { + iterator->destroy(iterator); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, new); + DBG1(DBG_IKE, "reestablishing IKE_SA failed"); + return FAILED; + } + break; + } + } + } + iterator->destroy(iterator); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); + + /* we always return failed to delete the obsolete IKE_SA */ + return FAILED; +} + +/** + * Implementation of task_t.get_type + */ +static task_type_t get_type(private_ike_reauth_t *this) +{ + return IKE_REAUTH; +} + +/** + * Implementation of task_t.migrate + */ +static void migrate(private_ike_reauth_t *this, ike_sa_t *ike_sa) +{ + this->ike_delete->task.migrate(&this->ike_delete->task, ike_sa); + this->ike_sa = ike_sa; +} + +/** + * Implementation of task_t.destroy + */ +static void destroy(private_ike_reauth_t *this) +{ + this->ike_delete->task.destroy(&this->ike_delete->task); + free(this); +} + +/* + * Described in header. + */ +ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa) +{ + private_ike_reauth_t *this = malloc_thing(private_ike_reauth_t); + + this->public.task.get_type = (task_type_t(*)(task_t*))get_type; + this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; + this->public.task.destroy = (void(*)(task_t*))destroy; + this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + + this->ike_sa = ike_sa; + this->ike_delete = ike_delete_create(ike_sa, TRUE); + + return &this->public; +} + diff --git a/src/charon/sa/tasks/ike_reauth.h b/src/charon/sa/tasks/ike_reauth.h new file mode 100644 index 000000000..3c872e1e1 --- /dev/null +++ b/src/charon/sa/tasks/ike_reauth.h @@ -0,0 +1,59 @@ +/** + * @file ike_reauth.h + * + * @brief Interface ike_reauth_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef IKE_REAUTH_H_ +#define IKE_REAUTH_H_ + +typedef struct ike_reauth_t ike_reauth_t; + +#include <library.h> +#include <sa/ike_sa.h> +#include <sa/tasks/task.h> + +/** + * @brief Task of type ike_reauth, reestablishes an IKE_SA. + * + * @b Constructors: + * - ike_reauth_create() + * + * @ingroup tasks + */ +struct ike_reauth_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * @brief Create a new ike_reauth task. + * + * This task is initiator only. + * + * @param ike_sa IKE_SA this task works for + * @return ike_reauth task to handle by the task_manager + */ +ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa); + +#endif /* IKE_REAUTH_H_ */ + diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index d54fc3524..827f95156 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -170,8 +170,9 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) { case FAILED: /* rekeying failed, fallback to old SA */ - if (!(this->collision && - this->collision->get_type(this->collision) == IKE_DELETE)) + if (!(this->collision && ( + this->collision->get_type(this->collision) == IKE_DELETE || + this->collision->get_type(this->collision) == IKE_REAUTH))) { job_t *job; u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); @@ -180,7 +181,7 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) DBG1(DBG_IKE, "IKE_SA rekeying failed, " "trying again in %d seconds", retry); this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->event_queue->add_relative(charon->event_queue, job, retry * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, retry * 1000); } return SUCCESS; case NEED_MORE: @@ -231,7 +232,7 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) } job = (job_t*)delete_ike_sa_job_create(to_delete, TRUE); - charon->job_queue->add(charon->job_queue, job); + charon->processor->queue_job(charon->processor, job); return SUCCESS; } diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c index 68d8ebf0c..713403d47 100644 --- a/src/charon/sa/tasks/task.c +++ b/src/charon/sa/tasks/task.c @@ -25,14 +25,16 @@ ENUM(task_type_names, IKE_INIT, CHILD_REKEY, "IKE_INIT", "IKE_NATD", + "IKE_MOBIKE", "IKE_AUTHENTICATE", "IKE_CERT", "IKE_CONFIG", - "IKE_DPD", "IKE_REKEY", + "IKE_REAUTH", "IKE_DELETE", - "IKE_DEADPEER", + "IKE_DPD", "CHILD_CREATE", "CHILD_DELETE", "CHILD_REKEY", ); + diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h index 128d7db4a..ff60ea816 100644 --- a/src/charon/sa/tasks/task.h +++ b/src/charon/sa/tasks/task.h @@ -40,16 +40,18 @@ enum task_type_t { IKE_INIT, /** detect NAT situation */ IKE_NATD, + /** handle MOBIKE stuff */ + IKE_MOBIKE, /** authenticate the initiated IKE_SA */ IKE_AUTHENTICATE, /** exchange certificates and requests */ IKE_CERT, /** Configuration payloads, virtual IP and such */ IKE_CONFIG, - /** DPD detection */ - IKE_DEADPEER, /** rekey an IKE_SA */ IKE_REKEY, + /** reestablish a complete IKE_SA */ + IKE_REAUTH, /** delete an IKE_SA */ IKE_DELETE, /** liveness check */ |