further mobike improvements, regarding to NAT-T
authorMartin Willi <martin@strongswan.org>
Wed, 27 Jun 2007 13:10:55 +0000 (13:10 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 27 Jun 2007 13:10:55 +0000 (13:10 -0000)
src/charon/bus/bus.c
src/charon/kernel/kernel_interface.c
src/charon/kernel/kernel_interface.h
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa_manager.c
src/charon/sa/tasks/ike_mobike.c
src/charon/sa/tasks/ike_natd.c

index d1984d7..5fda369 100644 (file)
@@ -372,7 +372,7 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level,
                        active_listener->format = format;
                        va_copy(active_listener->args, args);
                        active_listener->state = REGISTERED;
-                       pthread_cond_signal(&active_listener->cond);
+                       pthread_cond_broadcast(&active_listener->cond);
                }
        }
        
index 76b488e..63e265a 100644 (file)
@@ -1645,7 +1645,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, mode_t mode,
+                                          prf_plus_t *prf_plus, mode_t mode, bool encap,
                                           bool replace)
 {
        unsigned char request[BUFFER_SIZE];
@@ -1743,7 +1743,7 @@ static status_t add_sa(private_kernel_interface_t *this,
        
        /* TODO: add IPComp here */
        
-       if (natt)
+       if (encap)
        {
                rthdr->rta_type = XFRMA_ENCAP;
                rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
@@ -1756,8 +1756,8 @@ static status_t add_sa(private_kernel_interface_t *this,
 
                struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
                encap->encap_type = UDP_ENCAP_ESPINUDP;
-               encap->encap_sport = htons(natt->sport);
-               encap->encap_dport = htons(natt->dport);
+               encap->encap_sport = htons(src->get_port(src));
+               encap->encap_dport = htons(dst->get_port(dst));
                memset(&encap->encap_oa, 0, sizeof (xfrm_address_t));
                /* encap_oa could probably be derived from the 
                 * traffic selectors [rfc4306, p39]. In the netlink kernel implementation 
@@ -2314,7 +2314,7 @@ 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*,mode_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*,mode_t,bool,bool))add_sa;
        this->public.update_sa = (status_t(*)(kernel_interface_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_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;
index d3d3c9b..4474e70 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef KERNEL_INTERFACE_H_
 #define KERNEL_INTERFACE_H_
 
-typedef struct natt_conf_t natt_conf_t;
 typedef enum policy_dir_t policy_dir_t;
 typedef struct kernel_interface_t kernel_interface_t;
 
@@ -33,17 +32,6 @@ typedef struct kernel_interface_t kernel_interface_t;
 #include <crypto/prf_plus.h>
 #include <encoding/payloads/proposal_substructure.h>
 
-/**
- * Configuration for NAT-T
- *
- * @ingroup kernel
- */
-struct natt_conf_t {
-       /** source port to use for UDP-encapsulated packets */
-       u_int16_t sport;
-       /** dest port to use for UDP-encapsulated packets */
-       u_int16_t dport;
-};
 
 /**
  * Direction of a policy. These are equal to those
@@ -121,8 +109,8 @@ struct kernel_interface_t {
         * @param enc_alg               Algorithm to use for encryption (ESP only)
         * @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 encap                 enable UDP encapsulation for NAT traversal
         * @param replace               Should an already installed SA be updated?
         * @return
         *                                              - SUCCESS
@@ -133,8 +121,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,
-                                               mode_t mode, bool update);
+                                               prf_plus_t *prf_plus, mode_t mode, bool encap,
+                                               bool update);
        
        /**
         * @brief Update the hosts on an installed SA.
index e5cddf0..9fe19bc 100644 (file)
@@ -138,9 +138,9 @@ struct private_child_sa_t {
        child_sa_state_t state;
 
        /**
-        * Specifies if NAT traversal is used
+        * Specifies if UDP encapsulation is enabled (NAT traversal)
         */
-       bool use_natt;
+       bool encap;
        
        /**
         * mode this SA uses, tunnel/transport
@@ -494,7 +494,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
        algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
        host_t *src;
        host_t *dst;
-       natt_conf_t *natt;
        status_t status;
        
        this->protocol = proposal->get_protocol(proposal);
@@ -561,18 +560,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
                int_algo = &int_algo_none;
        }
        
-       /* setup nat-t */
-       if (this->use_natt)
-       {
-               natt = alloca(sizeof(natt_conf_t));
-               natt->sport = src->get_port(src);
-               natt->dport = dst->get_port(dst);
-       }
-       else
-       {
-               natt = NULL;
-       }
-       
        soft = this->config->get_lifetime(this->config, TRUE);
        hard = this->config->get_lifetime(this->config, FALSE);
        
@@ -582,7 +569,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
                                                                                          src, dst, spi, this->protocol,
                                                                                          this->reqid, mine ? soft : 0,
                                                                                          hard, enc_algo, int_algo,
-                                                                                         prf_plus, natt, mode, mine);
+                                                                                         prf_plus, mode, this->encap, mine);
        
        this->encryption = *enc_algo;
        this->integrity = *int_algo;
@@ -784,7 +771,8 @@ static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use
 /**
  * Implementation of child_sa_t.update_hosts.
  */
-static status_t update_hosts(private_child_sa_t *this, host_t *me, host_t *other) 
+static status_t update_hosts(private_child_sa_t *this, 
+                                                        host_t *me, host_t *other, bool encap) 
 {
        /* anything changed at all? */
        if (me->equals(me, this->me.addr) && other->equals(other, this->other.addr))
@@ -937,7 +925,7 @@ static void destroy(private_child_sa_t *this)
  */
 child_sa_t * child_sa_create(host_t *me, host_t* other,
                                                         identification_t *my_id, identification_t *other_id,
-                                                        child_cfg_t *config, u_int32_t rekey, bool use_natt)
+                                                        child_cfg_t *config, u_int32_t rekey, bool encap)
 {
        static u_int32_t reqid = 0;
        private_child_sa_t *this = malloc_thing(private_child_sa_t);
@@ -951,7 +939,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
        this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
        this->public.add = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))add;
        this->public.update = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))update;
-       this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*))update_hosts;
+       this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,bool))update_hosts;
        this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies;
        this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
        this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
@@ -970,7 +958,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
        this->other.spi = 0;
        this->alloc_ah_spi = 0;
        this->alloc_esp_spi = 0;
-       this->use_natt = use_natt;
+       this->encap = encap;
        this->state = CHILD_CREATED;
        /* reuse old reqid if we are rekeying an existing CHILD_SA */
        this->reqid = rekey ? rekey : ++reqid;
index 0118df4..b801dd0 100644 (file)
@@ -35,11 +35,6 @@ typedef struct child_sa_t child_sa_t;
 #include <config/child_cfg.h>
 
 /**
- * Where we should start with reqid enumeration
- */
-#define REQID_START 2000000000
-
-/**
  * @brief States of a CHILD_SA
  */
 enum child_sa_state_t {
@@ -207,9 +202,11 @@ struct child_sa_t {
         * @param this          calling object
         * @param me            the new local host
         * @param other         the new remote host
+        * @param                       TRUE to use UDP encapsulation for NAT traversal
         * @return                      SUCCESS or FAILED
         */
-       status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other);
+       status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other,
+                                                        bool encap);
        
        /**
         * @brief Install the policies using some traffic selectors.
@@ -295,13 +292,13 @@ struct child_sa_t {
  * @param other_id             id of remote peer
  * @param config               config to use for this CHILD_SA
  * @param reqid                        reqid of old CHILD_SA when rekeying, 0 otherwise
- * @param use_natt             TRUE if NAT traversal is used
+ * @param encap                        TRUE to enable UDP encapsulation (NAT traversal)
  * @return                             child_sa_t object
  * 
  * @ingroup sa
  */
 child_sa_t * child_sa_create(host_t *me, host_t *other,
                                                         identification_t *my_id, identification_t* other_id,
-                                                        child_cfg_t *config, u_int32_t reqid, bool use_natt);
+                                                        child_cfg_t *config, u_int32_t reqid, bool encap);
 
 #endif /*CHILD_SA_H_*/
index 1d6b8ec..ab66b6d 100644 (file)
@@ -469,6 +469,7 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition,
        {
                if (enable)
                {
+                       this->conditions |= condition;
                        switch (condition)
                        {
                                case COND_STALE:
@@ -487,19 +488,24 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition,
                                default:
                                        break;
                        }
-                       this->conditions |= condition;
                }
                else
                {
+                       this->conditions &= ~condition;
                        switch (condition)
                        {
                                case COND_STALE:
                                        DBG1(DBG_IKE, "new route to %H found", this->other_host);
                                        break;
+                               case COND_NAT_HERE:
+                               case COND_NAT_THERE:
+                                       set_condition(this, COND_NAT_ANY,
+                                                                 has_condition(this, COND_NAT_HERE) ||
+                                                                 has_condition(this, COND_NAT_THERE));
+                                       break;
                                default:
                                        break;
                        }
-                       this->conditions &= ~condition;
                }
        }
 }
@@ -695,7 +701,8 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
                iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
                while (iterator->iterate(iterator, (void**)&child_sa))
                {
-                       child_sa->update_hosts(child_sa, this->my_host, this->other_host);
+                       child_sa->update_hosts(child_sa, this->my_host, this->other_host,
+                                                                  has_condition(this, COND_NAT_ANY));
                }
                iterator->destroy(iterator);
        }
index 0a0d5e5..9848114 100644 (file)
@@ -503,6 +503,8 @@ static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this,
                host_t *found_my_host, *found_other_host;
                int wc;
                
+               break;
+               
                if (!wait_for_entry(this, entry))
                {
                        continue;
index 43ede2e..1a6d76c 100644 (file)
@@ -143,6 +143,16 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message)
                                flush_additional_addresses(this);
                                break;
                        }
+                       case NAT_DETECTION_SOURCE_IP:
+                       case NAT_DETECTION_DESTINATION_IP:
+                       {
+                               /* NAT check in this MOBIKE exchange, create subtask for it */
+                               if (this->natd == NULL)
+                               {
+                                       this->natd = ike_natd_create(this->ike_sa, this->initiator);
+                               }
+                               break;
+                       }
                        default:
                                break;
                }
@@ -205,10 +215,12 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message)
        {       /* address change */
                message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty);
                build_address_list(this, message);
-               /* TODO: NAT discovery */
-               
                /* set new addresses */
                this->ike_sa->update_hosts(this->ike_sa, this->me, this->other);
+               if (this->natd)
+               {
+                       this->natd->task.build(&this->natd->task, message);
+               }
        }
        
        return NEED_MORE;
@@ -219,13 +231,19 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message)
  */
 static status_t process_r(private_ike_mobike_t *this, message_t *message)
 {
-       if ((message->get_exchange_type(message) == IKE_AUTH &&
-                message->get_payload(message, SECURITY_ASSOCIATION)) ||
-               message->get_exchange_type(message) == INFORMATIONAL)
+       if (message->get_exchange_type(message) == IKE_AUTH &&
+               message->get_payload(message, SECURITY_ASSOCIATION))
        {
                process_payloads(this, message);
        }
-       
+       else if (message->get_exchange_type(message) == INFORMATIONAL)
+       {
+               process_payloads(this, message);
+               if (this->natd)
+               {
+                       this->natd->task.process(&this->natd->task, message);
+               }
+       }
        return NEED_MORE;
 }
 
@@ -246,6 +264,10 @@ static status_t build_r(private_ike_mobike_t *this, message_t *message)
        }
        else if (message->get_exchange_type(message) == INFORMATIONAL)
        {
+               if (this->natd)
+               {
+                       this->natd->task.build(&this->natd->task, message);
+               }
                return SUCCESS;
        }
        return NEED_MORE;
@@ -260,10 +282,16 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message)
                message->get_payload(message, SECURITY_ASSOCIATION))
        {
                process_payloads(this, message);
+
                return SUCCESS;
        }
        else if (message->get_exchange_type(message) == INFORMATIONAL)
        {
+               process_payloads(this, message);
+               if (this->natd)
+               {
+                       this->natd->task.process(&this->natd->task, message);
+               }
                return SUCCESS;
        }
        return NEED_MORE;
@@ -276,6 +304,9 @@ static void roam(private_ike_mobike_t *this, host_t *me, host_t *other)
 {
        this->me = me;
        this->other = other;
+       
+       /* include NAT detection when roaming */
+       this->natd = ike_natd_create(this->ike_sa, this->initiator);
 }
 
 /**
index db8a400..84a28d0 100644 (file)
@@ -204,15 +204,11 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
        if (this->src_seen && this->dst_seen)
        {
                this->ike_sa->enable_extension(this->ike_sa, EXT_NATT);
-       
-               if (!this->dst_matched)
-               {
-                       this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, TRUE);
-               }
-               if (!this->src_matched)
-               {
-                       this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, TRUE);
-               }
+
+               this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE,
+                                                                       !this->dst_matched);
+               this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE,
+                                                                       !this->src_matched);
        }
 }
 
@@ -222,8 +218,11 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
 static status_t process_i(private_ike_natd_t *this, message_t *message)
 {
        process_payloads(this, message);
-
-       if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
+                       
+       /* if peer supports NAT-T, we switch to port 4500 even
+        * if no NAT is detected. MOBIKE requires this. */
+       if (message->get_exchange_type(message) == IKE_SA_INIT &&
+               this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
        {
                host_t *me, *other;
        
@@ -297,7 +296,8 @@ static status_t build_r(private_ike_natd_t *this, message_t *message)
        host_t *me, *other;
        
        /* only add notifies on successfull responses. */
-       if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
+       if (message->get_exchange_type(message) == IKE_SA_INIT &&
+               message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
        {
                return SUCCESS;
        }