diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2008-11-11 06:37:37 +0000 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2008-11-11 06:37:37 +0000 |
commit | d487b4b727ca423aeca2b047c8d28d28dea57b02 (patch) | |
tree | 6a706c07a47c0d8f42f76e301d8690e39f322f5d /src | |
parent | 91db979cdda4943ab6512dc309ebe1b07273e717 (diff) | |
download | strongswan-d487b4b727ca423aeca2b047c8d28d28dea57b02.tar.bz2 strongswan-d487b4b727ca423aeca2b047c8d28d28dea57b02.tar.xz |
preliminary support of Mobile IPv6
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/config/peer_cfg.c | 39 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_config.c | 3 | ||||
-rw-r--r-- | src/charon/processing/jobs/migrate_job.c | 84 | ||||
-rw-r--r-- | src/charon/sa/child_sa.c | 239 | ||||
-rw-r--r-- | src/charon/sa/child_sa.h | 18 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 79 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.h | 11 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_create.c | 6 | ||||
-rw-r--r-- | src/pluto/constants.c | 2 | ||||
-rw-r--r-- | src/pluto/constants.h | 3 | ||||
-rw-r--r-- | src/starter/args.c | 1 | ||||
-rw-r--r-- | src/starter/confread.c | 29 | ||||
-rw-r--r-- | src/starter/confread.h | 2 | ||||
-rw-r--r-- | src/starter/keywords.h | 1 | ||||
-rw-r--r-- | src/starter/keywords.txt | 1 | ||||
-rw-r--r-- | src/starter/starterstroke.c | 15 | ||||
-rw-r--r-- | src/stroke/stroke_msg.h | 3 |
17 files changed, 336 insertions, 200 deletions
diff --git a/src/charon/config/peer_cfg.c b/src/charon/config/peer_cfg.c index 34e466bfb..398244f6d 100644 --- a/src/charon/config/peer_cfg.c +++ b/src/charon/config/peer_cfg.c @@ -21,6 +21,8 @@ #include "peer_cfg.h" +#include <daemon.h> + #include <utils/mutex.h> #include <utils/linked_list.h> #include <utils/identification.h> @@ -228,16 +230,20 @@ static enumerator_t* create_child_cfg_enumerator(private_peer_cfg_t *this) /** * Check if child_cfg contains traffic selectors */ -static bool contains_ts(child_cfg_t *child, bool mine, linked_list_t *ts, +static int contains_ts(child_cfg_t *child, bool mine, linked_list_t *ts, host_t *host) { linked_list_t *selected; - bool contains = FALSE; + int prio; + if (child->equal_traffic_selectors(child, mine, ts, host)) + { + return 2; + } selected = child->get_traffic_selectors(child, mine, ts, host); - contains = selected->get_count(selected); + prio = selected->get_count(selected) ? 1 : 0; selected->destroy_offset(selected, offsetof(traffic_selector_t, destroy)); - return contains; + return prio; } /** @@ -250,18 +256,33 @@ static child_cfg_t* select_child_cfg(private_peer_cfg_t *this, { child_cfg_t *current, *found = NULL; enumerator_t *enumerator; - + int best = 0; + + DBG2(DBG_CFG, "looking for a child config for %#R=== %#R", my_ts, other_ts); enumerator = create_child_cfg_enumerator(this); while (enumerator->enumerate(enumerator, ¤t)) { - if (contains_ts(current, TRUE, my_ts, my_host) && - contains_ts(current, FALSE, other_ts, other_host)) + int prio = contains_ts(current, TRUE, my_ts, my_host) + + contains_ts(current, FALSE, other_ts, other_host); + + if (prio) { - found = current->get_ref(current); - break; + DBG2(DBG_CFG, " candidate \"%s\" with prio %d", + current->get_name(current), prio); + if (prio > best) + { + best = prio; + DESTROY_IF(found); + found = current->get_ref(current); + } } } enumerator->destroy(enumerator); + if (found) + { + DBG2(DBG_CFG, "found matching child config \"%s\" with prio %d", + found->get_name(found), best); + } return found; } diff --git a/src/charon/plugins/stroke/stroke_config.c b/src/charon/plugins/stroke/stroke_config.c index d339f2698..d4ab691bd 100644 --- a/src/charon/plugins/stroke/stroke_config.c +++ b/src/charon/plugins/stroke/stroke_config.c @@ -775,7 +775,8 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this, 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, dpd, dpd, msg->add_conn.ipcomp); - + child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy, + msg->add_conn.install_policy); add_ts(this, &msg->add_conn.me, child_cfg, TRUE); add_ts(this, &msg->add_conn.other, child_cfg, FALSE); diff --git a/src/charon/processing/jobs/migrate_job.c b/src/charon/processing/jobs/migrate_job.c index 100158a67..f9b1df26b 100644 --- a/src/charon/processing/jobs/migrate_job.c +++ b/src/charon/processing/jobs/migrate_job.c @@ -83,90 +83,16 @@ static void execute(private_migrate_job_t *this) ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, this->reqid, TRUE); } - if (ike_sa == NULL) + if (ike_sa) { - enumerator_t *enumerator, *children; - peer_cfg_t *peer_cfg; - child_cfg_t *found_cfg = NULL; - - enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends); - while (enumerator->enumerate(enumerator, (void**)&peer_cfg)) - { - child_cfg_t *child_cfg; - - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { - continue; - } - - children = peer_cfg->create_child_cfg_enumerator(peer_cfg); - while (children->enumerate(children, &child_cfg)) - { - if (child_cfg->equal_traffic_selectors(child_cfg, TRUE, this->src_ts) && - child_cfg->equal_traffic_selectors(child_cfg, FALSE, this->dst_ts)) - { - found_cfg = child_cfg; - break; - } - } - children->destroy(children); - if (found_cfg) - { - break; - } - } - enumerator->destroy(enumerator); - - if (found_cfg == NULL) - { - DBG1(DBG_JOB, "no matching child config found for policy %R === %R", - this->src_ts, this->dst_ts); - destroy(this); - return; - } - DBG1(DBG_JOB, "found matching child config '%s' for policy %R === %R", - found_cfg->get_name(found_cfg), - this->src_ts, this->dst_ts); - - ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, - peer_cfg); - if (ike_sa->get_peer_cfg(ike_sa) == NULL) - { - host_t *my_host, *other_host; - ike_cfg_t *ike_cfg; - - ike_sa->set_peer_cfg(ike_sa, peer_cfg); - ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - my_host = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg), 0, 0); - other_host = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg), 0, 0); - ike_sa->set_my_host(ike_sa, my_host); - ike_sa->set_other_host(ike_sa, other_host); - } - if (this->local) - { - ike_sa->set_my_host(ike_sa, this->local->clone(this->local)); - } - if (this->remote) - { - ike_sa->set_other_host(ike_sa, this->remote->clone(this->remote)); - } - /* add a CHILD_SA for 'found_cfg' with a policy that has already been - * installed in the kernel - */ + DBG2(DBG_JOB, "found CHILD_SA with reqid {%d}", this->reqid); + ike_sa->set_kmaddress(ike_sa, this->local, this->remote); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } else { - DBG1(DBG_JOB, "found CHILD_SA with reqid {%d}", this->reqid); - if (this->local) - { - ike_sa->set_my_host(ike_sa, this->local); - } - if (this->remote) - { - ike_sa->set_other_host(ike_sa, this->remote->clone(this->remote)); - } + DBG1(DBG_JOB, "no CHILD_SA found with reqid {%d}", this->reqid); } - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); destroy(this); } diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index f60ea3ff1..24d91a5da 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -155,7 +155,7 @@ struct private_child_sa_t { }; /** - * Implementation of child_sa_t.get_namy_ + * Implementation of child_sa_t.get_name */ static char *get_name(private_child_sa_t *this) { @@ -334,10 +334,13 @@ static u_int32_t get_usetime(private_child_sa_t *this, bool inbound) { last_use = max(last_use, in); } - if (charon->kernel_interface->query_policy(charon->kernel_interface, - other_ts, my_ts, POLICY_FWD, &fwd) == SUCCESS) + if (this->mode == MODE_TUNNEL) { - last_use = max(last_use, fwd); + if (charon->kernel_interface->query_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_FWD, &fwd) == SUCCESS) + { + last_use = max(last_use, fwd); + } } } else @@ -595,7 +598,7 @@ static status_t add_policies(private_child_sa_t *this, { /* update if not set yet */ this->protocol = proto; } - + /* apply traffic selectors */ enumerator = my_ts_list->create_enumerator(my_ts_list); while (enumerator->enumerate(enumerator, &my_ts)) @@ -610,30 +613,36 @@ static status_t add_policies(private_child_sa_t *this, } enumerator->destroy(enumerator); - /* enumerate pairs of traffic selectors */ - enumerator = create_policy_enumerator(this); - while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + if (this->config->install_policy(this->config)) { - /* install 3 policies: out, in and forward */ - status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT, - this->protocol, this->reqid, high_prio, mode, this->ipcomp); + /* enumerate pairs of traffic selectors */ + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + { + /* install 3 policies: out, in and forward */ + status |= charon->kernel_interface->add_policy(charon->kernel_interface, + this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT, + this->protocol, this->reqid, high_prio, mode, this->ipcomp); - status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN, - this->protocol, this->reqid, high_prio, mode, this->ipcomp); + status |= charon->kernel_interface->add_policy(charon->kernel_interface, + this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN, + this->protocol, this->reqid, high_prio, mode, this->ipcomp); - status |= charon->kernel_interface->add_policy(charon->kernel_interface, + if (mode == MODE_TUNNEL) + { + status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other_addr, this->my_addr, other_ts, my_ts, POLICY_FWD, this->protocol, this->reqid, high_prio, mode, this->ipcomp); + } - if (status != SUCCESS) - { - break; + if (status != SUCCESS) + { + break; + } } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); - + if (status == SUCCESS) { /* switch to routed state if no SAD entry set up */ @@ -694,71 +703,82 @@ static status_t update_hosts(private_child_sa_t *this, charon->kernel_interface->update_sa(charon->kernel_interface, this->other_spi, this->protocol, this->my_addr, this->other_addr, me, other, encap); - /* update policies */ - if (!me->ip_equals(me, this->my_addr) || - !other->ip_equals(other, this->other_addr)) + if (this->config->install_policy(this->config)) { - enumerator_t *enumerator; - traffic_selector_t *my_ts, *other_ts; - - /* always use high priorities, as hosts getting updated are INSTALLED */ - enumerator = create_policy_enumerator(this); - while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + /* update policies */ + if (!me->ip_equals(me, this->my_addr) || + !other->ip_equals(other, this->other_addr)) { - /* remove old policies first */ - charon->kernel_interface->del_policy(charon->kernel_interface, + enumerator_t *enumerator; + traffic_selector_t *my_ts, *other_ts; + + /* always use high priorities, as hosts getting updated are INSTALLED */ + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + { + /* remove old policies first */ + charon->kernel_interface->del_policy(charon->kernel_interface, my_ts, other_ts, POLICY_OUT); - charon->kernel_interface->del_policy(charon->kernel_interface, + charon->kernel_interface->del_policy(charon->kernel_interface, other_ts, my_ts, POLICY_IN); - charon->kernel_interface->del_policy(charon->kernel_interface, + if (this->mode == MODE_TUNNEL) + { + charon->kernel_interface->del_policy(charon->kernel_interface, other_ts, my_ts, POLICY_FWD); - - /* check whether we have to update a "dynamic" traffic selector */ - if (!me->ip_equals(me, this->my_addr) && - my_ts->is_host(my_ts, this->my_addr)) - { - my_ts->set_address(my_ts, me); - } - if (!other->ip_equals(other, this->other_addr) && - other_ts->is_host(other_ts, this->other_addr)) - { - other_ts->set_address(other_ts, other); - } + } + + /* check whether we have to update a "dynamic" traffic selector */ + if (!me->ip_equals(me, this->my_addr) && + my_ts->is_host(my_ts, this->my_addr)) + { + my_ts->set_address(my_ts, me); + } + if (!other->ip_equals(other, this->other_addr) && + other_ts->is_host(other_ts, this->other_addr)) + { + other_ts->set_address(other_ts, other); + } - /* we reinstall the virtual IP to handle interface roaming - * correctly */ - if (vip) - { - charon->kernel_interface->del_ip(charon->kernel_interface, vip); - charon->kernel_interface->add_ip(charon->kernel_interface, vip, me); - } + /* we reinstall the virtual IP to handle interface roaming + * correctly */ + if (vip) + { + charon->kernel_interface->del_ip(charon->kernel_interface, vip); + charon->kernel_interface->add_ip(charon->kernel_interface, vip, me); + } - /* reinstall updated policies */ - charon->kernel_interface->add_policy(charon->kernel_interface, + /* reinstall updated policies */ + charon->kernel_interface->add_policy(charon->kernel_interface, me, other, my_ts, other_ts, POLICY_OUT, this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); - charon->kernel_interface->add_policy(charon->kernel_interface, + charon->kernel_interface->add_policy(charon->kernel_interface, other, me, other_ts, my_ts, POLICY_IN, this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); - charon->kernel_interface->add_policy(charon->kernel_interface, + if (this->mode == MODE_TUNNEL) + { + charon->kernel_interface->add_policy(charon->kernel_interface, other, me, other_ts, my_ts, POLICY_FWD, this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); + } + } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); } /* apply hosts */ - if (!me->equals(me, this->my_addr)) + if (!this->config->use_proxy_mode(this->config) || this->mode != MODE_TRANSPORT) { - this->my_addr->destroy(this->my_addr); - this->my_addr = me->clone(me); - } - if (!other->equals(other, this->other_addr)) - { - this->other_addr->destroy(this->other_addr); - this->other_addr = other->clone(other); + if (!me->equals(me, this->my_addr)) + { + this->my_addr->destroy(this->my_addr); + this->my_addr = me->clone(me); + } + if (!other->equals(other, this->other_addr)) + { + this->other_addr->destroy(this->other_addr); + this->other_addr = other->clone(other); + } } - set_state(this, old); return SUCCESS; @@ -830,19 +850,25 @@ static void destroy(private_child_sa_t *this) this->other_addr, htonl(ntohs(this->other_cpi)), IPPROTO_COMP); } - /* delete all policies in the kernel */ - enumerator = create_policy_enumerator(this); - while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + if (this->config->install_policy(this->config)) { - charon->kernel_interface->del_policy(charon->kernel_interface, - my_ts, other_ts, POLICY_OUT); - charon->kernel_interface->del_policy(charon->kernel_interface, - other_ts, my_ts, POLICY_IN); - charon->kernel_interface->del_policy(charon->kernel_interface, - other_ts, my_ts, POLICY_FWD); + /* delete all policies in the kernel */ + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + { + charon->kernel_interface->del_policy(charon->kernel_interface, + my_ts, other_ts, POLICY_OUT); + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_IN); + if (this->mode == MODE_TUNNEL) + { + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_FWD); + } + } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); - + this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy)); this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy)); this->my_addr->destroy(this->my_addr); @@ -909,6 +935,63 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->proposal = NULL; this->config = config; config->get_ref(config); + + /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */ + if (config->get_mode(config) == MODE_TRANSPORT && + config->use_proxy_mode(config)) + { + ts_type_t type; + int family; + chunk_t addr; + host_t *host; + enumerator_t *enumerator; + linked_list_t *my_ts_list, *other_ts_list; + traffic_selector_t *my_ts, *other_ts; + + this->mode = MODE_TRANSPORT; + + my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me); + enumerator = my_ts_list->create_enumerator(my_ts_list); + if (enumerator->enumerate(enumerator, &my_ts)) + { + if (my_ts->is_host(my_ts, NULL) && + !my_ts->is_host(my_ts, this->my_addr)) + { + type = my_ts->get_type(my_ts); + family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; + addr = my_ts->get_from_address(my_ts); + host = host_create_from_chunk(family, addr, 0); + free(addr.ptr); + DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H", + this->my_addr, host); + this->my_addr->destroy(this->my_addr); + this->my_addr = host; + } + } + enumerator->destroy(enumerator); + my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy)); + + other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other); + enumerator = other_ts_list->create_enumerator(other_ts_list); + if (enumerator->enumerate(enumerator, &other_ts)) + { + if (other_ts->is_host(other_ts, NULL) && + !other_ts->is_host(other_ts, this->other_addr)) + { + type = other_ts->get_type(other_ts); + family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; + addr = other_ts->get_from_address(other_ts); + host = host_create_from_chunk(family, addr, 0); + free(addr.ptr); + DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H", + this->other_addr, host); + this->other_addr->destroy(this->other_addr); + this->other_addr = host; + } + } + enumerator->destroy(enumerator); + other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy)); + } return &this->public; } diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 3e138143d..cbf1f3b5c 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -323,14 +323,16 @@ struct child_sa_t { /** * Constructor to create a new child_sa_t. * - * @param me own address - * @param other remote address - * @param my_id id of own peer - * @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 encap TRUE to enable UDP encapsulation (NAT traversal) - * @return child_sa_t object + * @param me own address + * @param other remote address + * @param my_id id of own peer + * @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 encap TRUE to enable UDP encapsulation (NAT traversal) + * @param proxy TRUE if IPsec transport SA is to be set up in proxy mode + * @param install_policy TRUE if kernel policies are to be installed + * @return child_sa_t object */ child_sa_t * child_sa_create(host_t *me, host_t *other, child_cfg_t *config, u_int32_t reqid, bool encap); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 6af92e141..ab2a789d0 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -250,6 +250,16 @@ struct private_ike_sa_t { * are we the initiator of this IKE_SA (rekeying does not affect this flag) */ bool ike_initiator; + + /** + * local host address to be used for IKE, set via MIGRATE kernel message + */ + host_t *local_host; + + /** + * remote host address to be used for IKE, set via MIGRATE kernel message + */ + host_t *remote_host; }; /** @@ -943,6 +953,17 @@ static void send_notify_response(private_ike_sa_t *this, message_t *request, response->destroy(response); } +/** + * Implementation of ike_sa_t.set_kmaddress. + */ +static void set_kmaddress(private_ike_sa_t *this, host_t *local, host_t *remote) +{ + DESTROY_IF(this->local_host); + DESTROY_IF(this->remote_host); + this->local_host = local->clone(local); + this->remote_host = remote->clone(remote); +} + #ifdef ME /** * Implementation of ike_sa_t.act_as_mediation_server. @@ -1047,26 +1068,42 @@ static void resolve_hosts(private_ike_sa_t *this) { host_t *host; - host = host_create_from_dns(this->ike_cfg->get_other_addr(this->ike_cfg), - 0, IKEV2_UDP_PORT); + if (this->remote_host) + { + host = this->remote_host->clone(this->remote_host); + host->set_port(host, IKEV2_UDP_PORT); + } + else + { + host = host_create_from_dns(this->ike_cfg->get_other_addr(this->ike_cfg), + 0, IKEV2_UDP_PORT); + } if (host) { set_other_host(this, host); } - host = host_create_from_dns(this->ike_cfg->get_my_addr(this->ike_cfg), - this->my_host->get_family(this->my_host), - IKEV2_UDP_PORT); - - if (host && host->is_anyaddr(host) && - !this->other_host->is_anyaddr(this->other_host)) + if (this->local_host) { - host->destroy(host); - host = charon->kernel_interface->get_source_addr( - charon->kernel_interface, this->other_host, NULL); - if (host) + host = this->local_host->clone(this->local_host); + host->set_port(host, IKEV2_UDP_PORT); + } + else + { + host = host_create_from_dns(this->ike_cfg->get_my_addr(this->ike_cfg), + this->my_host->get_family(this->my_host), + IKEV2_UDP_PORT); + + if (host && host->is_anyaddr(host) && + !this->other_host->is_anyaddr(this->other_host)) { - host->set_port(host, IKEV2_UDP_PORT); + host->destroy(host); + host = charon->kernel_interface->get_source_addr( + charon->kernel_interface, this->other_host, NULL); + if (host) + { + host->set_port(host, IKEV2_UDP_PORT); + } } } if (host) @@ -1264,8 +1301,10 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) 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), PROTO_NONE); + child_cfg->get_mode(child_cfg), PROTO_NONE); + my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); if (status == SUCCESS) @@ -1318,6 +1357,7 @@ static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) } return SUCCESS; } + /** * Implementation of ike_sa_t.process_message. */ @@ -1389,7 +1429,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) me = message->get_destination(message); other = message->get_source(message); - + /* if this IKE_SA is virgin, we check for a config */ if (this->ike_cfg == NULL) { @@ -2235,6 +2275,8 @@ static void destroy(private_ike_sa_t *this) DESTROY_IF(this->other_host); DESTROY_IF(this->my_id); DESTROY_IF(this->other_id); + DESTROY_IF(this->local_host); + DESTROY_IF(this->remote_host); DESTROY_IF(this->eap_identity); DESTROY_IF(this->ike_cfg); @@ -2319,6 +2361,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.set_virtual_ip = (void (*)(ike_sa_t*,bool,host_t*))set_virtual_ip; this->public.get_virtual_ip = (host_t* (*)(ike_sa_t*,bool))get_virtual_ip; this->public.add_dns_server = (void (*)(ike_sa_t*,host_t*))add_dns_server; + this->public.set_kmaddress = (void (*)(ike_sa_t*,host_t*,host_t*))set_kmaddress; #ifdef ME this->public.act_as_mediation_server = (void (*)(ike_sa_t*)) act_as_mediation_server; this->public.get_server_reflexive_host = (host_t* (*)(ike_sa_t*)) get_server_reflexive_host; @@ -2334,8 +2377,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) /* initialize private fields */ this->ike_sa_id = ike_sa_id->clone(ike_sa_id); this->child_sas = linked_list_create(); - this->my_host = host_create_from_string("%any", IKEV2_UDP_PORT); - this->other_host = host_create_from_string("%any", IKEV2_UDP_PORT); + this->my_host = host_create_any(AF_INET); + this->other_host = host_create_any(AF_INET); this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->eap_identity = NULL; @@ -2362,6 +2405,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->pending_updates = 0; this->keyingtry = 0; this->ike_initiator = FALSE; + this->local_host = NULL; + this->remote_host = NULL; #ifdef ME this->is_mediation_server = FALSE; this->server_reflexive_host = NULL; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 6a8de6984..23098f58e 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -865,6 +865,17 @@ struct ike_sa_t { void (*add_dns_server) (ike_sa_t *this, host_t *dns); /** + * Set local and remote host addresses to be used for IKE. + * + * These addresses are communicated via the KMADDRESS field of a MIGRATE + * message sent via the NETLINK or PF _KEY kernel socket interface. + * + * @param local local kmaddress + * @param remote remote kmaddress + */ + void (*set_kmaddress) (ike_sa_t *this, host_t *local, host_t *remote); + + /** * Inherit all attributes of other to this after rekeying. * * When rekeying is completed, all CHILD_SAs, the virtual IP and all diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index ab12b48b1..628d1397c 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -300,8 +300,10 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) switch (this->mode) { case MODE_TRANSPORT: - if (!ts_list_is_host(this->tsi, other) || - !ts_list_is_host(this->tsr, me)) + if (!this->config->use_proxy_mode(this->config) && + (!ts_list_is_host(this->tsi, other) || + !ts_list_is_host(this->tsr, me)) + ) { this->mode = MODE_TUNNEL; DBG1(DBG_IKE, "not using transport mode, not host-to-host"); diff --git a/src/pluto/constants.c b/src/pluto/constants.c index da4d9fc7a..70215441b 100644 --- a/src/pluto/constants.c +++ b/src/pluto/constants.c @@ -517,6 +517,8 @@ const char *const sa_policy_bit_names[] = { "DONTREAUTH", "BEET", "MOBIKE", + "ECDSA", + "PROXY", NULL }; diff --git a/src/pluto/constants.h b/src/pluto/constants.h index 9505d3426..13251dc3b 100644 --- a/src/pluto/constants.h +++ b/src/pluto/constants.h @@ -877,7 +877,8 @@ extern const char *prettypolicy(lset_t policy); #define POLICY_BEET LELEM(22) /* bound end2end tunnel, IKEv2 */ #define POLICY_MOBIKE LELEM(23) /* enable MOBIKE for IKEv2 */ #define POLICY_FORCE_ENCAP LELEM(24) /* force UDP encapsulation (IKEv2) */ -#define POLICY_ECDSASIG LELEM(25) /* ecdsa signature (IKEv2) */ +#define POLICY_ECDSASIG LELEM(25) /* ECDSA signature (IKEv2) */ +#define POLICY_PROXY LELEM(26) /* proxy transport mode (MIPv6) */ /* Any IPsec policy? If not, a connection description * is only for ISAKMP SA, not IPSEC SA. (A pun, I admit.) diff --git a/src/starter/args.c b/src/starter/args.c index b373be97c..b5f716069 100644 --- a/src/starter/args.c +++ b/src/starter/args.c @@ -199,6 +199,7 @@ static const token_info_t token_info[] = { ARG_MISC, 0, NULL /* KW_TYPE */ }, { ARG_MISC, 0, NULL /* KW_PFS */ }, { ARG_MISC, 0, NULL /* KW_COMPRESS */ }, + { ARG_ENUM, offsetof(starter_conn_t, install_policy), LST_bool }, { ARG_MISC, 0, NULL /* KW_AUTH */ }, { ARG_MISC, 0, NULL /* KW_AUTHBY */ }, { ARG_MISC, 0, NULL /* KW_EAP */ }, diff --git a/src/starter/confread.c b/src/starter/confread.c index 1b3f31a55..9528f6a98 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -79,6 +79,7 @@ static void default_values(starter_config_t *cfg) cfg->conn_default.sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT; cfg->conn_default.addr_family = AF_INET; cfg->conn_default.tunnel_addr_family = AF_INET; + cfg->conn_default.install_policy = TRUE; cfg->conn_default.dpd_delay = 30; /* seconds */ cfg->conn_default.dpd_timeout = 150; /* seconds */ @@ -497,15 +498,29 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) case KW_TYPE: conn->policy &= ~(POLICY_TUNNEL | POLICY_SHUNT_MASK); if (streq(kw->value, "tunnel")) + { conn->policy |= POLICY_TUNNEL; + } else if (streq(kw->value, "beet")) + { conn->policy |= POLICY_BEET; + } + else if (streq(kw->value, "transport_proxy")) + { + conn->policy |= POLICY_PROXY; + } else if (streq(kw->value, "passthrough") || streq(kw->value, "pass")) + { conn->policy |= POLICY_SHUNT_PASS; + } else if (streq(kw->value, "drop")) + { conn->policy |= POLICY_SHUNT_DROP; + } else if (streq(kw->value, "reject")) + { conn->policy |= POLICY_SHUNT_REJECT; + } else if (strcmp(kw->value, "transport") != 0) { plog("# bad policy value: %s=%s", kw->entry->name, kw->value); @@ -530,21 +545,33 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) char *second = strchr(kw->value, '|'); if (second != NULL) + { *second = '\0'; + } /* also handles the cases secret|rsasig and rsasig|secret */ for (;;) { if (streq(value, "rsa") || streq(value, "rsasig")) + { conn->policy |= POLICY_RSASIG | POLICY_ENCRYPT; + } else if (streq(value, "secret") || streq(value, "psk")) + { conn->policy |= POLICY_PSK | POLICY_ENCRYPT; + } else if (streq(value, "ecdsa") || streq(value, "ecdsasig")) + { conn->policy |= POLICY_ECDSASIG | POLICY_ENCRYPT; + } else if (streq(value, "xauthrsasig")) + { conn->policy |= POLICY_XAUTH_RSASIG | POLICY_ENCRYPT; + } else if (streq(value, "xauthpsk")) + { conn->policy |= POLICY_XAUTH_PSK | POLICY_ENCRYPT; + } else { plog("# bad policy value: %s=%s", kw->entry->name, kw->value); @@ -552,7 +579,9 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) break; } if (second == NULL) + { break; + } value = second; second = NULL; /* traverse the loop no more than twice */ } diff --git a/src/starter/confread.h b/src/starter/confread.h index 8e1584526..ed344fe6f 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -114,7 +114,7 @@ struct starter_conn { unsigned long sa_rekey_fuzz; sa_family_t addr_family; sa_family_t tunnel_addr_family; - + bool install_policy; starter_end_t left, right; unsigned long id; diff --git a/src/starter/keywords.h b/src/starter/keywords.h index 9470c75e5..17789d9bd 100644 --- a/src/starter/keywords.h +++ b/src/starter/keywords.h @@ -68,6 +68,7 @@ typedef enum { KW_TYPE, KW_PFS, KW_COMPRESS, + KW_INSTALLPOLICY, KW_AUTH, KW_AUTHBY, KW_EAP, diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt index b54da8ca8..d834fe425 100644 --- a/src/starter/keywords.txt +++ b/src/starter/keywords.txt @@ -61,6 +61,7 @@ keyexchange, KW_KEYEXCHANGE type, KW_TYPE pfs, KW_PFS compress, KW_COMPRESS +installpolicy, KW_INSTALLPOLICY auth, KW_AUTH authby, KW_AUTHBY keylife, KW_KEYLIFE diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 07be12e26..0fe87dfc5 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -24,6 +24,7 @@ #include <errno.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <linux/xfrm.h> #include <freeswan.h> @@ -242,17 +243,22 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) if (conn->policy & POLICY_TUNNEL) { - msg.add_conn.mode = 1; /* XFRM_MODE_TRANSPORT */ + msg.add_conn.mode = XFRM_MODE_TUNNEL; } else if (conn->policy & POLICY_BEET) { - msg.add_conn.mode = 4; /* XFRM_MODE_BEET */ + msg.add_conn.mode = XFRM_MODE_BEET; } + else if (conn->policy & POLICY_PROXY) + { + msg.add_conn.mode = XFRM_MODE_TRANSPORT; + msg.add_conn.proxy = TRUE; + } else { - msg.add_conn.mode = 0; /* XFRM_MODE_TUNNEL */ + msg.add_conn.mode = XFRM_MODE_TRANSPORT; } - + if (!(conn->policy & POLICY_DONT_REKEY)) { msg.add_conn.rekey.reauth = (conn->policy & POLICY_DONT_REAUTH) == LEMPTY; @@ -265,6 +271,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) msg.add_conn.mobike = conn->policy & POLICY_MOBIKE; msg.add_conn.force_encap = conn->policy & POLICY_FORCE_ENCAP; msg.add_conn.ipcomp = conn->policy & POLICY_COMPRESS; + msg.add_conn.install_policy = conn->install_policy; msg.add_conn.crl_policy = cfg->setup.strictcrlpolicy; msg.add_conn.unique = cfg->setup.uniqueids; msg.add_conn.algorithms.ike = push_string(&msg, conn->ike); diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index 3ab1c4643..a5fe17df6 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -212,6 +212,9 @@ struct stroke_msg_t { int mobike; int force_encap; int ipcomp; + int install_policy; + int proxy; + crl_policy_t crl_policy; int unique; struct { |