preliminary support of Mobile IPv6
authorAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 11 Nov 2008 06:37:37 +0000 (06:37 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 11 Nov 2008 06:37:37 +0000 (06:37 -0000)
17 files changed:
src/charon/config/peer_cfg.c
src/charon/plugins/stroke/stroke_config.c
src/charon/processing/jobs/migrate_job.c
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/tasks/child_create.c
src/pluto/constants.c
src/pluto/constants.h
src/starter/args.c
src/starter/confread.c
src/starter/confread.h
src/starter/keywords.h
src/starter/keywords.txt
src/starter/starterstroke.c
src/stroke/stroke_msg.h

index 34e466b..398244f 100644 (file)
@@ -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, &current))
        {
-               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;
 }
 
index d339f26..d4ab691 100644 (file)
@@ -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);
        
index 100158a..f9b1df2 100644 (file)
@@ -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);
 }
 
index f60ea3f..24d91a5 100644 (file)
@@ -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;
 }
index 3e13814..cbf1f3b 100644 (file)
@@ -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);
index 6af92e1..ab2a789 100644 (file)
@@ -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;
index 6a8de69..23098f5 100644 (file)
@@ -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
index ab12b48..628d139 100644 (file)
@@ -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");
index da4d9fc..7021544 100644 (file)
@@ -517,6 +517,8 @@ const char *const sa_policy_bit_names[] = {
        "DONTREAUTH",
        "BEET",
        "MOBIKE",
+       "ECDSA",
+       "PROXY",
        NULL
     };
 
index 9505d34..13251dc 100644 (file)
@@ -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.)
index b373be9..b5f7160 100644 (file)
@@ -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 */                                              },
index 1b3f31a..9528f6a 100644 (file)
@@ -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 */
                                }
index 8e15845..ed344fe 100644 (file)
@@ -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;
index 9470c75..17789d9 100644 (file)
@@ -68,6 +68,7 @@ typedef enum {
     KW_TYPE,
     KW_PFS,
     KW_COMPRESS,
+       KW_INSTALLPOLICY,
     KW_AUTH,
     KW_AUTHBY,
     KW_EAP,
index b54da8c..d834fe4 100644 (file)
@@ -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
index 07be12e..0fe87df 100644 (file)
@@ -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);
index 3ab1c46..a5fe17d 100644 (file)
@@ -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 {