added support for transport mode and (experimental!) BEET mode
authorMartin Willi <martin@strongswan.org>
Thu, 21 Dec 2006 14:35:17 +0000 (14:35 -0000)
committerMartin Willi <martin@strongswan.org>
Thu, 21 Dec 2006 14:35:17 +0000 (14:35 -0000)
support for the type=transport/tunnel parameter in charon

17 files changed:
src/charon/config/policies/policy.c
src/charon/config/policies/policy.h
src/charon/config/traffic_selector.c
src/charon/config/traffic_selector.h
src/charon/encoding/payloads/notify_payload.h
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/ike_sa.c
src/charon/sa/transactions/create_child_sa.c
src/charon/sa/transactions/ike_auth.c
src/charon/threads/kernel_interface.c
src/charon/threads/kernel_interface.h
src/charon/threads/stroke_interface.c
src/starter/ipsec.conf.5
src/starter/starterstroke.c
src/stroke/stroke.c
src/stroke/stroke.h

index b52ae33..f7e2eb4 100644 (file)
@@ -130,6 +130,11 @@ struct private_policy_t {
         * What to do with an SA when other peer seams to be dead?
         */
        bool dpd_action;
+       
+       /**
+        * Mode to propose for a initiated CHILD: tunnel/transport
+        */
+       mode_t mode;
 };
 
 /**
@@ -378,7 +383,6 @@ static dpd_action_t get_dpd_action(private_policy_t *this)
        return this->dpd_action;
 }
 
-
 /**
  * Implementation of policy_t.add_my_traffic_selector
  */
@@ -424,6 +428,14 @@ static u_int32_t get_hard_lifetime(private_policy_t *this)
 }
 
 /**
+ * Implementation of policy_t.get_mode.
+ */
+static mode_t get_mode(private_policy_t *this)
+{
+       return this->mode;
+}
+
+/**
  * Implements policy_t.get_ref.
  */
 static void get_ref(private_policy_t *this)
@@ -475,7 +487,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
                                                auth_method_t auth_method,
                                                u_int32_t hard_lifetime, u_int32_t soft_lifetime, 
                                                u_int32_t jitter, char *updown, bool hostaccess,
-                                               dpd_action_t dpd_action)
+                                               mode_t mode, dpd_action_t dpd_action)
 {
        private_policy_t *this = malloc_thing(private_policy_t);
 
@@ -501,6 +513,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
        this->public.get_dpd_action = (dpd_action_t (*) (policy_t*))get_dpd_action;
        this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
        this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
+       this->public.get_mode = (mode_t (*) (policy_t *))get_mode;
        this->public.get_ref = (void (*) (policy_t*))get_ref;
        this->public.destroy = (void (*) (policy_t*))destroy;
        
@@ -515,6 +528,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
        this->updown = (updown == NULL) ? NULL : strdup(updown);
        this->hostaccess = hostaccess;
        this->dpd_action = dpd_action;
+       this->mode = mode;
        
        /* initialize private members*/
        this->refcount = 1;
index a040434..76b20f6 100644 (file)
@@ -53,6 +53,22 @@ enum dpd_action_t {
 };
 
 /**
+ * @brief Mode of an IPsec SA.
+ *
+ * These are equal to those defined in XFRM, so don't change.
+ *
+ * @ingroup config
+ */
+enum mode_t {
+       /** transport mode, no inner address */
+       MODE_TRANSPORT = 0,
+       /** tunnel mode, inner and outer addresses */
+       MODE_TUNNEL = 1,
+       /** BEET mode, tunnel mode but fixed, bound inner addresses */
+       MODE_BEET = 4,
+};
+
+/**
  * enum names for dpd_action_t.
  */
 extern enum_name_t *dpd_action_names;
@@ -291,6 +307,14 @@ struct policy_t {
        u_int32_t (*get_hard_lifetime) (policy_t *this);
        
        /**
+        * @brief Get the mode to use for the CHILD_SA, tunnel, transport or BEET.
+        * 
+        * @param this                  policy
+        * @return                              lifetime in seconds
+        */
+       mode_t (*get_mode) (policy_t *this);
+       
+       /**
         * @brief Get a new reference.
         *
         * Get a new reference to this policy by increasing
@@ -334,6 +358,7 @@ struct policy_t {
  * @param jitter                       range of randomization time
  * @param updown                       updown script to execute on up/down event
  * @param hostaccess           allow access to the host itself (used by the updown script)
+ * @param mode                         mode to propose for CHILD_SA, transport, tunnel or BEET
  * @param dpd_action           what to to with a CHILD_SA when other peer does not respond
  * @return                                     policy_t object
  * 
@@ -343,8 +368,7 @@ policy_t *policy_create(char *name,
                                                identification_t *my_id, identification_t *other_id,
                                                auth_method_t auth_method,
                                                u_int32_t hard_lifetime, u_int32_t soft_lifetime,
-                                               u_int32_t jitter,
-                                               char *updown, bool hostaccess,
-                                               dpd_action_t dpd_action);
+                                               u_int32_t jitter, char *updown, bool hostaccess,
+                                               mode_t mode, dpd_action_t dpd_action);
 
 #endif /* POLICY_H_ */
index 2b99b91..2afeb5e 100644 (file)
@@ -447,15 +447,27 @@ static u_int8_t get_protocol(private_traffic_selector_t *this)
  */
 static bool is_host(private_traffic_selector_t *this, host_t *host)
 {
-       chunk_t addr;
-       int family = host->get_family(host);
-       
-       if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
-               (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
+       if (host)
        {
-               addr = host->get_address(host);
-               if (memeq(addr.ptr, this->from, addr.len) &&
-                       memeq(addr.ptr, this->to, addr.len))
+               chunk_t addr;
+               int family = host->get_family(host);
+               
+               if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
+                       (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
+               {
+                       addr = host->get_address(host);
+                       if (memeq(addr.ptr, this->from, addr.len) &&
+                               memeq(addr.ptr, this->to, addr.len))
+                       {
+                               return TRUE;
+                       }
+               }
+       }
+       else
+       {
+               size_t length =  (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+               
+               if (memeq(this->from, this->to, length))
                {
                        return TRUE;
                }
index b611b61..5d1ccaf 100644 (file)
@@ -164,6 +164,8 @@ struct traffic_selector_t {
         * Traffic selector may describe the end of *-to-host tunnel. In this
         * case, the address range is a single address equal to the hosts
         * peer address.
+        * If host is NULL, the traffic selector is checked if it is a single host,
+        * but not a specific one.
         *
         * @param this          calling obect
         * @param host          host_t specifying the address range
index 2b419bb..8861b9f 100644 (file)
@@ -88,6 +88,8 @@ enum notify_type_t {
        NO_NATS_ALLOWED = 16402,
        /* repeated authentication extension, RFC4478 */
        AUTH_LIFETIME = 16403,
+       /* BEET mode, not even a draft yet. private use */
+       USE_BEET_MODE = 40960,
 };
 
 /**
@@ -97,7 +99,6 @@ enum notify_type_t {
  */
 extern enum_name_t *notify_type_names;
 
-
 /**
  * @brief Class representing an IKEv2-Notify Payload.
  * 
index 3433977..874937d 100644 (file)
@@ -167,6 +167,11 @@ struct private_child_sa_t {
         * Specifies if NAT traversal is used
         */
        bool use_natt;
+       
+       /**
+        * mode this SA uses, tunnel/transport
+        */
+       mode_t mode;
 };
 
 /**
@@ -439,7 +444,8 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
        return SUCCESS;
 }
 
-static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine)
+static status_t install(private_child_sa_t *this, proposal_t *proposal,
+                                               mode_t mode, prf_plus_t *prf_plus, bool mine)
 {
        u_int32_t spi;
        algorithm_t *enc_algo, *int_algo;
@@ -536,7 +542,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
                                                                                          mine ? this->soft_lifetime : 0,
                                                                                          this->hard_lifetime,
                                                                                          enc_algo, int_algo,
-                                                                                         prf_plus, natt, mine);
+                                                                                         prf_plus, natt, mode, mine);
        
        this->encryption = *enc_algo;
        this->integrity = *int_algo;
@@ -545,7 +551,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
        return status;
 }
 
-static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
+static status_t add(private_child_sa_t *this, proposal_t *proposal, 
+                                       mode_t mode, prf_plus_t *prf_plus)
 {
        u_int32_t outbound_spi, inbound_spi;
        
@@ -560,14 +567,14 @@ static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *
        inbound_spi = proposal->get_spi(proposal);
        
        /* install inbound SAs */
-       if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
+       if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS)
        {
                return FAILED;
        }
        
        /* install outbound SAs, restore spi*/
        proposal->set_spi(proposal, outbound_spi);
-       if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
+       if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
        {
                return FAILED;
        }
@@ -576,7 +583,8 @@ static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *
        return SUCCESS;
 }
 
-static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
+static status_t update(private_child_sa_t *this, proposal_t *proposal,
+                                          mode_t mode, prf_plus_t *prf_plus)
 {
        u_int32_t inbound_spi;
        
@@ -584,7 +592,7 @@ static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_
        inbound_spi = proposal->get_spi(proposal);
        
        /* install outbound SAs */
-       if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
+       if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
        {
                return FAILED;
        }
@@ -592,7 +600,7 @@ static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_
        /* restore spi */
        proposal->set_spi(proposal, inbound_spi);
        /* install inbound SAs */
-       if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
+       if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS)
        {
                return FAILED;
        }
@@ -600,7 +608,9 @@ static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_
        return SUCCESS;
 }
 
-static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list)
+static status_t add_policies(private_child_sa_t *this,
+                                                        linked_list_t *my_ts_list,
+                                                        linked_list_t *other_ts_list, mode_t mode)
 {
        iterator_t *my_iter, *other_iter;
        traffic_selector_t *my_ts, *other_ts;
@@ -637,16 +647,16 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
                        
                        /* 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, FALSE);
+                                       this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT,
+                                       this->protocol, this->reqid, high_prio, mode, FALSE);
                        
                        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, FALSE);
+                                       this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN,
+                                       this->protocol, this->reqid, high_prio, mode, FALSE);
                        
                        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, FALSE);
+                                       this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD,
+                                       this->protocol, this->reqid, high_prio, mode, FALSE);
                        
                        if (status != SUCCESS)
                        {
@@ -673,7 +683,8 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
        {
                this->state = CHILD_ROUTED;
        }
-       
+       /* needed to update hosts */
+       this->mode = mode;
        return SUCCESS;
 }
 
@@ -928,19 +939,19 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho
                                charon->kernel_interface,
                                new_me, new_other,
                                policy->my_ts, policy->other_ts,
-                               POLICY_OUT, this->protocol, this->reqid, TRUE, TRUE);
+                               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, TRUE);
+                               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, TRUE);
+                               POLICY_FWD, this->protocol, this->reqid, TRUE, this->mode, TRUE);
                
                if (status != SUCCESS)
                {
@@ -1085,10 +1096,10 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
        this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
        this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
-       this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
-       this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
+       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.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
+       this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies;
        this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors;
        this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors;
        this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
@@ -1124,6 +1135,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->my_ts = linked_list_create();
        this->other_ts = linked_list_create();
        this->protocol = PROTO_NONE;
+       this->mode = MODE_TUNNEL;
        this->rekeying_transaction = NULL;
        
        return &this->public;
index 5b1df9e..06362f3 100644 (file)
@@ -167,10 +167,12 @@ struct child_sa_t {
         *
         * @param this          calling object
         * @param proposal      proposal for which SPIs are allocated
+        * @param mode          mode for the CHILD_SA
         * @param prf_plus      key material to use for key derivation
         * @return                      SUCCESS or FAILED
         */
-       status_t (*add)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
+       status_t (*add)(child_sa_t *this, proposal_t *proposal, mode_t mode,
+                                       prf_plus_t *prf_plus);
        
        /**
         * @brief Install the kernel SAs for a proposal, after SPIs have been allocated.
@@ -179,10 +181,12 @@ struct child_sa_t {
         *
         * @param this          calling object
         * @param proposal      proposal for which SPIs are allocated
+        * @param mode          mode for the CHILD_SA
         * @param prf_plus      key material to use for key derivation
         * @return                      SUCCESS or FAILED
         */
-       status_t (*update)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
+       status_t (*update)(child_sa_t *this, proposal_t *proposal, mode_t mode,
+                                          prf_plus_t *prf_plus);
 
        /**
         * @brief Update the hosts in the kernel SAs and policies
@@ -208,11 +212,11 @@ struct child_sa_t {
         * @param this          calling object
         * @param my_ts         traffic selectors for local site
         * @param other_ts      traffic selectors for remote site
+        * @param mode          mode for the SA: tunnel/transport
         * @return                      SUCCESS or FAILED
         */     
-       status_t (*add_policies)(child_sa_t *this, 
-                                                        linked_list_t *my_ts_list,
-                                                        linked_list_t *other_ts_list);
+       status_t (*add_policies)(child_sa_t *this, linked_list_t *my_ts_list,
+                                                        linked_list_t *other_ts_list, mode_t mode);
        
        /**
         * @brief Get the traffic selectors of added policies of local host.
index 5aed70b..af6060b 100644 (file)
@@ -1173,7 +1173,8 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t
        child_sa->set_name(child_sa, policy->get_name(policy));
        my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
        other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
-       status = child_sa->add_policies(child_sa, my_ts, other_ts);
+       status = child_sa->add_policies(child_sa, my_ts, other_ts,
+                                                                       policy->get_mode(policy));
        my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
        other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
        this->child_sas->insert_last(this->child_sas, child_sa);
index cd53c5e..37f35ec 100644 (file)
@@ -120,6 +120,11 @@ struct private_create_child_sa_t {
        child_sa_t *rekeyed_sa;
        
        /**
+        * mode of the CHILD_SA to create: transport/tunnel
+        */
+       mode_t mode;
+       
+       /**
         * Have we lost the simultaneous rekeying nonce compare?
         */
        bool lost;
@@ -187,6 +192,31 @@ static void cancel(private_create_child_sa_t *this)
 }
 
 /**
+ * Build a notify message.
+ */
+static void build_notify(notify_type_t type, chunk_t data, message_t *message, bool flush_message)
+{
+       notify_payload_t *notify;
+       
+       if (flush_message)
+       {
+               payload_t *payload;
+               iterator_t *iterator = message->get_payload_iterator(message);
+               while (iterator->iterate(iterator, (void**)&payload))
+               {
+                       payload->destroy(payload);
+                       iterator->remove(iterator);
+               }
+               iterator->destroy(iterator);
+       }
+       
+       notify = notify_payload_create();
+       notify->set_notify_type(notify, type);
+       notify->set_notification_data(notify, data);
+       message->add_payload(message, (payload_t*)notify);
+}
+
+/**
  * Implementation of transaction_t.get_request.
  */
 static status_t get_request(private_create_child_sa_t *this, message_t **result)
@@ -293,6 +323,28 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result)
                request->add_payload(request, (payload_t*)sa_payload);
        }
        
+       /* notify for transport/BEET mode, we propose it 
+        * independent of the traffic selectors */
+       switch (this->policy->get_mode(this->policy))
+       {
+               case MODE_TUNNEL:
+                       /* is the default */
+                       break;
+               case MODE_TRANSPORT:
+                       if (this->ike_sa->is_natt_enabled(this->ike_sa))
+                       {
+                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+                       }
+                       else
+                       {
+                               build_notify(USE_TRANSPORT_MODE, chunk_empty, request, FALSE);
+                       }
+                       break;
+               case MODE_BEET:
+                       build_notify(USE_BEET_MODE, chunk_empty, request, FALSE);
+                       break;
+       }
+       
        {       /* build the NONCE payload for us (initiator) */
                nonce_payload_t *nonce_payload;
                
@@ -374,6 +426,16 @@ static status_t process_notifys(private_create_child_sa_t *this, notify_payload_
                        SIG(this->failsig, "received NO_PROPOSAL_CHOSEN notify");
                        return FAILED;
                }
+               case USE_TRANSPORT_MODE:
+               {
+                       this->mode = MODE_TRANSPORT;
+                       return SUCCESS;
+               }
+               case USE_BEET_MODE:
+               {
+                       this->mode = MODE_BEET;
+                       return SUCCESS;
+               }
                case REKEY_SA:
                {
                        u_int32_t spi;
@@ -414,28 +476,20 @@ static status_t process_notifys(private_create_child_sa_t *this, notify_payload_
 }
 
 /**
- * Build a notify message.
+ * Check a list of traffic selectors if any selector belongs to host
  */
-static void build_notify(notify_type_t type, chunk_t data, message_t *message, bool flush_message)
+static bool ts_list_is_host(linked_list_t *list, host_t *host)
 {
-       notify_payload_t *notify;
+       traffic_selector_t *ts;
+       bool is_host = TRUE;
+       iterator_t *iterator = list->create_iterator(list, TRUE);
        
-       if (flush_message)
+       while (is_host && iterator->iterate(iterator, (void**)&ts))
        {
-               payload_t *payload;
-               iterator_t *iterator = message->get_payload_iterator(message);
-               while (iterator->iterate(iterator, (void**)&payload))
-               {
-                       payload->destroy(payload);
-                       iterator->remove(iterator);
-               }
-               iterator->destroy(iterator);
+               is_host = is_host && ts->is_host(ts, host);
        }
-       
-       notify = notify_payload_create();
-       notify->set_notify_type(notify, type);
-       notify->set_notification_data(notify, data);
-       message->add_payload(message, (payload_t*)notify);
+       iterator->destroy(iterator);
+       return is_host;
 }
 
 /**
@@ -455,11 +509,11 @@ static status_t install_child_sa(private_create_child_sa_t *this, bool initiator
        
        if (initiator)
        {
-               status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
+               status = this->child_sa->update(this->child_sa, this->proposal, 1, prf_plus);
        }
        else
        {
-               status = this->child_sa->add(this->child_sa, this->proposal, prf_plus);
+               status = this->child_sa->add(this->child_sa, this->proposal, 1, prf_plus);
        }
        prf_plus->destroy(prf_plus);
        if (status != SUCCESS)
@@ -468,11 +522,11 @@ static status_t install_child_sa(private_create_child_sa_t *this, bool initiator
        }
        if (initiator)
        {
-               status = this->child_sa->add_policies(this->child_sa, this->tsi, this->tsr);
+               status = this->child_sa->add_policies(this->child_sa, this->tsi, this->tsr, 1);
        }
        else
        {
-               status = this->child_sa->add_policies(this->child_sa, this->tsr, this->tsi);
+               status = this->child_sa->add_policies(this->child_sa, this->tsr, this->tsi, 1);
        }
        if (status != SUCCESS)
        {
@@ -697,6 +751,44 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request
                                                                                         this->policy->get_hostaccess(this->policy),
                                                                                         use_natt);
                        this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
+                       
+                       /* check mode, and include notify into reply */
+                       switch (this->mode)
+                       {
+                               case MODE_TUNNEL:
+                                       /* is the default */
+                                       break;
+                               case MODE_TRANSPORT:
+                                       if (!ts_list_is_host(this->tsi, other) ||
+                                               !ts_list_is_host(this->tsr, me))
+                                       {
+                                               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))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+                                       }
+                                       else 
+                                       {
+                                               build_notify(USE_TRANSPORT_MODE, chunk_empty, response, FALSE);
+                                       }
+                                       break;
+                               case MODE_BEET:
+                                       if (!ts_list_is_host(this->tsi, NULL) ||
+                                               !ts_list_is_host(this->tsr, NULL))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+                                       }
+                                       else
+                                       {
+                                               build_notify(USE_BEET_MODE, chunk_empty, response, FALSE);
+                                       }
+                                       break;
+                       }
+                       
                        if (install_child_sa(this, FALSE) != SUCCESS)
                        {
                                SIG(this->failsig, "installing CHILD_SA failed, sending NO_PROPOSAL_CHOSEN notify");
@@ -855,6 +947,38 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response,
                        SIG(this->failsig, "CHILD_SA negotiation failed, no CHILD_SA built");
                        return FAILED;
                }
+               
+               /* check mode if it is acceptable */
+               switch (this->mode)
+               {
+                       case MODE_TUNNEL:
+                               /* is the default */
+                               break;
+                       case MODE_TRANSPORT:
+                               /* TODO: we should close the CHILD_SA if negotiated
+                                * mode is not acceptable for us */
+                               if (!ts_list_is_host(this->tsi, me) ||
+                                       !ts_list_is_host(this->tsr, other))
+                               {
+                                       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))
+                               {
+                                       this->mode = MODE_TUNNEL;
+                                       DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+                               }
+                               break;
+                       case MODE_BEET:
+                               if (!ts_list_is_host(this->tsi, NULL) ||
+                                       !ts_list_is_host(this->tsr, NULL))
+                               {
+                                       this->mode = MODE_TUNNEL;
+                                       DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+                               }
+                               break;
+               }
+               
                new_child = this->child_sa;
                if (install_child_sa(this, TRUE) != SUCCESS)
                {
@@ -985,6 +1109,7 @@ create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa)
        this->policy = NULL;
        this->tsi = NULL;
        this->tsr = NULL;
+       this->mode = MODE_TUNNEL;
        this->randomizer = randomizer_create();
        this->failsig = CHILD_UP_FAILED;
        
index ae155ec..3ab4d8a 100644 (file)
@@ -128,6 +128,11 @@ struct private_ike_auth_t {
         * reqid to use for CHILD_SA setup
         */
        u_int32_t reqid;
+       
+       /**
+        * mode the CHILD_SA uses: tranport, tunnel, BEET
+        */
+       mode_t mode;
 };
 
 /**
@@ -183,6 +188,30 @@ static void set_init_messages(private_ike_auth_t *this, chunk_t init_request, ch
 }
 
 /**
+ * Build a notify message.
+ */
+static void build_notify(notify_type_t type, message_t *message, bool flush_message)
+{
+       notify_payload_t *notify;
+       
+       if (flush_message)
+       {
+               payload_t *payload;
+               iterator_t *iterator = message->get_payload_iterator(message);
+               while (iterator->iterate(iterator, (void**)&payload))
+               {
+                       payload->destroy(payload);
+                       iterator->remove(iterator);
+               }
+               iterator->destroy(iterator);
+       }
+       
+       notify = notify_payload_create();
+       notify->set_notify_type(notify, type);
+       message->add_payload(message, (payload_t*)notify);
+}
+
+/**
  * Implementation of transaction_t.get_request.
  */
 static status_t get_request(private_ike_auth_t *this, message_t **result)
@@ -319,6 +348,28 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
                request->add_payload(request, (payload_t*)sa_payload);
        }
        
+       /* notify for transport/BEET mode, we propose it 
+        * independent of the traffic selectors */
+       switch (this->policy->get_mode(this->policy))
+       {
+               case MODE_TUNNEL:
+                       /* is the default */
+                       break;
+               case MODE_TRANSPORT:
+                       if (this->ike_sa->is_natt_enabled(this->ike_sa))
+                       {
+                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+                       }
+                       else
+                       {
+                               build_notify(USE_TRANSPORT_MODE, request, FALSE);
+                       }
+                       break;
+               case MODE_BEET:
+                       build_notify(USE_BEET_MODE, request, FALSE);
+                       break;
+       }
+       
        {       /* build TSi payload */
                linked_list_t *ts_list;
                ts_payload_t *ts_payload;
@@ -376,6 +427,16 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not
                        this->build_child = FALSE;
                        return SUCCESS;
                }
+               case USE_TRANSPORT_MODE:
+               {
+                       this->mode = MODE_TRANSPORT;
+                       return SUCCESS;
+               }
+               case USE_BEET_MODE:
+               {
+                       this->mode = MODE_BEET;
+                       return SUCCESS;
+               }
                default:
                {
                        if (notify_type < 16383)
@@ -395,30 +456,6 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not
 }
 
 /**
- * Build a notify message.
- */
-static void build_notify(notify_type_t type, message_t *message, bool flush_message)
-{
-       notify_payload_t *notify;
-       
-       if (flush_message)
-       {
-               payload_t *payload;
-               iterator_t *iterator = message->get_payload_iterator(message);
-               while (iterator->iterate(iterator, (void**)&payload))
-               {
-                       payload->destroy(payload);
-                       iterator->remove(iterator);
-               }
-               iterator->destroy(iterator);
-       }
-       
-       notify = notify_payload_create();
-       notify->set_notify_type(notify, type);
-       message->add_payload(message, (payload_t*)notify);
-}
-
-/**
  * Import certificate requests from a certreq payload
  */
 static void add_certificate_request(certreq_payload_t *certreq_payload,
@@ -502,6 +539,23 @@ static void import_certificate(cert_payload_t *cert_payload)
 }
 
 /**
+ * Check a list of traffic selectors if any selector belongs to host
+ */
+static bool ts_list_is_host(linked_list_t *list, host_t *host)
+{
+       traffic_selector_t *ts;
+       bool is_host = TRUE;
+       iterator_t *iterator = list->create_iterator(list, TRUE);
+       
+       while (is_host && iterator->iterate(iterator, (void**)&ts))
+       {
+               is_host = is_host && ts->is_host(ts, host);
+       }
+       iterator->destroy(iterator);
+       return is_host;
+}
+
+/**
  * Install a CHILD_SA for usage
  */
 static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
@@ -518,11 +572,13 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
        
        if (initiator)
        {
-               status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
+               status = this->child_sa->update(this->child_sa, this->proposal, 
+                                                                               this->mode, prf_plus);
        }
        else
        {
-               status = this->child_sa->add(this->child_sa, this->proposal, prf_plus);
+               status = this->child_sa->add(this->child_sa, this->proposal, 
+                                                                        this->mode, prf_plus);
        }
        prf_plus->destroy(prf_plus);
        if (status != SUCCESS)
@@ -531,11 +587,13 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
        }
        if (initiator)
        {
-               status = this->child_sa->add_policies(this->child_sa, this->tsi, this->tsr);
+               status = this->child_sa->add_policies(this->child_sa, this->tsi,
+                                                                                         this->tsr, this->mode);
        }
        else
        {
-               status = this->child_sa->add_policies(this->child_sa, this->tsr, this->tsi);
+               status = this->child_sa->add_policies(this->child_sa, this->tsr,
+                                                                                         this->tsi, this->mode);
        }
        if (status != SUCCESS)
        {
@@ -850,6 +908,44 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
                                                                                         this->policy->get_hostaccess(this->policy),
                                                                                         use_natt);
                        this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
+                       
+                       /* check mode, and include notify into reply */
+                       switch (this->mode)
+                       {
+                               case MODE_TUNNEL:
+                                       /* is the default */
+                                       break;
+                               case MODE_TRANSPORT:
+                                       if (!ts_list_is_host(this->tsi, other) ||
+                                               !ts_list_is_host(this->tsr, me))
+                                       {
+                                               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))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+                                       }
+                                       else 
+                                       {
+                                               build_notify(USE_TRANSPORT_MODE, response, FALSE);
+                                       }
+                                       break;
+                               case MODE_BEET:
+                                       if (!ts_list_is_host(this->tsi, NULL) ||
+                                               !ts_list_is_host(this->tsr, NULL))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+                                       }
+                                       else
+                                       {
+                                               build_notify(USE_BEET_MODE, response, FALSE);
+                                       }
+                                       break;
+                       }
+                       
                        if (install_child_sa(this, FALSE) != SUCCESS)
                        {
                                SIG(CHILD_UP_FAILED, "installing CHILD_SA failed, no CHILD_SA created");
@@ -1048,6 +1144,37 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
                }
                else
                {
+                       /* check mode if it is acceptable */
+                       switch (this->mode)
+                       {
+                               case MODE_TUNNEL:
+                                       /* is the default */
+                                       break;
+                               case MODE_TRANSPORT:
+                                       /* TODO: we should close the CHILD_SA if negotiated
+                                        * mode is not acceptable for us */
+                                       if (!ts_list_is_host(this->tsi, me) ||
+                                               !ts_list_is_host(this->tsr, other))
+                                       {
+                                               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))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+                                       }
+                                       break;
+                               case MODE_BEET:
+                                       if (!ts_list_is_host(this->tsi, NULL) ||
+                                               !ts_list_is_host(this->tsr, NULL))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+                                       }
+                                       break;
+                       }
+               
                        if (install_child_sa(this, TRUE) != SUCCESS)
                        {
                                SIG(CHILD_UP_FAILED, "installing CHILD_SA failed, no CHILD_SA built");
@@ -1126,6 +1253,7 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa)
        this->tsr = NULL;
        this->build_child = TRUE;
        this->reqid = 0;
+       this->mode = MODE_TUNNEL;
        
        return &this->public;
 }
index 092e57c..074e7fc 100644 (file)
@@ -503,7 +503,7 @@ static status_t add_sa(private_kernel_interface_t *this,
                                           protocol_id_t protocol, u_int32_t reqid,
                                           u_int64_t expire_soft, u_int64_t expire_hard,
                                           algorithm_t *enc_alg, algorithm_t *int_alg,
-                                          prf_plus_t *prf_plus, natt_conf_t *natt,
+                                          prf_plus_t *prf_plus, natt_conf_t *natt, mode_t mode,
                                           bool replace)
 {
        unsigned char request[BUFFER_SIZE];
@@ -529,7 +529,7 @@ static status_t add_sa(private_kernel_interface_t *this,
        sa->id.spi = spi;
        sa->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
        sa->family = src->get_family(src);
-       sa->mode = TRUE; /* tunnel mode */
+       sa->mode = mode;
        sa->replay_window = 32;
        sa->reqid = reqid;
        /* we currently do not expire SAs by volume/packet count */
@@ -970,7 +970,8 @@ static status_t add_policy(private_kernel_interface_t *this,
                                                   traffic_selector_t *src_ts,
                                                   traffic_selector_t *dst_ts,
                                                   policy_dir_t direction, protocol_id_t protocol,
-                                                  u_int32_t reqid, bool high_prio, bool update)
+                                                  u_int32_t reqid, bool high_prio, mode_t mode,
+                                                  bool update)
 {
        iterator_t *iterator;
        kernel_policy_t *current, *policy;
@@ -992,7 +993,7 @@ static status_t add_policy(private_kernel_interface_t *this,
        iterator = this->policies->create_iterator(this->policies, TRUE);
        while (iterator->iterate(iterator, (void**)&current))
        {
-               if (memcmp(current, policy, sizeof(struct xfrm_selector)) == 0 &&
+               if (memcmp(&current->sel, &policy->sel, sizeof(struct xfrm_selector)) == 0 &&
                        policy->direction == current->direction)
                {
                        free(policy);
@@ -1068,7 +1069,7 @@ static status_t add_policy(private_kernel_interface_t *this,
        tmpl->reqid = reqid;
        tmpl->id.proto = (protocol == PROTO_AH) ? KERNEL_AH : KERNEL_ESP;
        tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
-       tmpl->mode = TRUE;
+       tmpl->mode = mode;
        tmpl->family = src->get_family(src);
        
        host2xfrm(src, &tmpl->saddr);
@@ -1266,11 +1267,11 @@ kernel_interface_t *kernel_interface_create()
        
        /* public functions */
        this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
-       this->public.add_sa  = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,bool))add_sa;
+       this->public.add_sa  = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,mode_t,bool))add_sa;
        this->public.update_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_diff_t,host_diff_t))update_sa;
        this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa;
        this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
-       this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,bool))add_policy;
+       this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t,bool))add_policy;
        this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy;
        this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy;
        this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
index 2655745..991d8e1 100644 (file)
@@ -118,6 +118,7 @@ struct kernel_interface_t {
         * @param int_alg               Algorithm to use for integrity protection
         * @param prf_plus              PRF to derive keys from
         * @param natt                  NAT-T Configuration, or NULL of no NAT-T used
+        * @param mode                  mode of the SA (tunnel, transport)
         * @param replace               Should an already installed SA be updated?
         * @return
         *                                              - SUCCESS
@@ -128,7 +129,8 @@ struct kernel_interface_t {
                                                protocol_id_t protocol, u_int32_t reqid,
                                                u_int64_t expire_soft, u_int64_t expire_hard,
                                                algorithm_t *enc_alg, algorithm_t *int_alg,
-                                               prf_plus_t *prf_plus, natt_conf_t *natt, bool update);
+                                               prf_plus_t *prf_plus, natt_conf_t *natt,
+                                               mode_t mode, bool update);
        
        /**
         * @brief Update the hosts on an installed SA.
@@ -206,6 +208,7 @@ struct kernel_interface_t {
         * @param protocol              protocol to use to protect traffic (AH/ESP)
         * @param reqid                 uniqe ID of an SA to use to enforce policy
         * @param high_prio             if TRUE, uses a higher priority than any with FALSE
+        * @param mode                  mode of SA (tunnel, transport)
         * @param update                update an existing policy, if TRUE
         * @return
         *                                              - SUCCESS
@@ -216,7 +219,8 @@ struct kernel_interface_t {
                                                        traffic_selector_t *src_ts,
                                                        traffic_selector_t *dst_ts,
                                                        policy_dir_t direction, protocol_id_t protocol,
-                                                       u_int32_t reqid, bool high_prio, bool update);
+                                                       u_int32_t reqid, bool high_prio, 
+                                                       mode_t mode, bool update);
        
        /**
         * @brief Query the use time of a policy.
index dd646aa..a982845 100755 (executable)
@@ -398,7 +398,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                                                   msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
                                                   msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, 
                                                   msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
-                                                  msg->add_conn.dpd.action);
+                                                  msg->add_conn.mode, msg->add_conn.dpd.action);
        policy->add_my_traffic_selector(policy, my_ts);
        policy->add_other_traffic_selector(policy, other_ts);
        policy->add_authorities(policy, my_ca, other_ca);
index 981b8d3..9ca2e67 100644 (file)
@@ -234,9 +234,11 @@ signifying that no IPsec processing should be done at all;
 signifying that packets should be discarded; and
 .BR reject ,
 signifying that packets should be discarded and a diagnostic ICMP returned.
-Charon currently supports only the
+Charon currently supports only 
 .BR tunnel
-connection type.
+and
+.BR transport
+connection types.
 .TP
 .B left
 (required)
index eff157a..41f67c8 100644 (file)
@@ -194,6 +194,7 @@ int starter_stroke_add_conn(starter_conn_t *conn)
        msg.add_conn.name = push_string(&msg, connection_name(conn));
        msg.add_conn.auth_method = (conn->policy & POLICY_PSK)?
                SHARED_KEY_MESSAGE_INTEGRITY_CODE : RSA_DIGITAL_SIGNATURE;
+       msg.add_conn.mode = (conn->policy & POLICY_TUNNEL) ? 1 : 0;
  
        if (conn->policy & POLICY_DONT_REKEY)
        {
index 2221915..31293a7 100644 (file)
@@ -106,6 +106,7 @@ static int add_connection(char *name,
        
        msg.add_conn.name = push_string(&msg, name);
        msg.add_conn.ikev2 = 1;
+       msg.add_conn.mode = 1;
        
        msg.add_conn.rekey.reauth = 0;
        msg.add_conn.rekey.ipsec_lifetime = 0;
index c818075..bbc1e6e 100644 (file)
@@ -137,6 +137,7 @@ struct stroke_msg_t {
                        char *name;
                        int ikev2;
                        int auth_method;
+                       int mode;
                        struct {
                                char *ike;
                                char *esp;