Fixed BEET mode by installing SAs with negotiated address in traffic selector
authorMartin Willi <martin@strongswan.org>
Thu, 17 Dec 2009 09:50:37 +0000 (10:50 +0100)
committerMartin Willi <martin@strongswan.org>
Thu, 17 Dec 2009 09:52:07 +0000 (10:52 +0100)
NEWS
src/charon/kernel/kernel_interface.c
src/charon/kernel/kernel_interface.h
src/charon/kernel/kernel_ipsec.c
src/charon/kernel/kernel_ipsec.h
src/charon/plugins/kernel_klips/kernel_klips_ipsec.c
src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/tasks/child_create.c

diff --git a/NEWS b/NEWS
index f1e09d9..3b2f0d0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,9 @@ strongswan-4.3.6
   change makes IPcomp tunnel mode connections incompatible with previous
   releases; disable compression on such tunnels.
 
+- Fixed BEET mode connections on recent kernels by installing SAs with
+  appropriate traffic selectors, based on a patch by Michael Rossberg.
+
 - The IKEv1 daemon ignores the Juniper SRX notification type 40001, thus
   allowing interoperability.
 
index b1a1d70..17118f6 100644 (file)
@@ -77,7 +77,8 @@ static status_t add_sa(private_kernel_interface_t *this, host_t *src, host_t *ds
                                u_int16_t enc_alg, chunk_t enc_key,
                                u_int16_t int_alg, chunk_t int_key,
                                ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, bool encap,
-                               bool inbound)
+                               bool inbound, traffic_selector_t *src_ts,
+                               traffic_selector_t *dst_ts)
 {
        if (!this->ipsec)
        {
@@ -85,7 +86,7 @@ static status_t add_sa(private_kernel_interface_t *this, host_t *src, host_t *ds
        }
        return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid,
                        lifetime, enc_alg, enc_key, int_alg, int_key, mode, ipcomp, cpi,
-                       encap, inbound);
+                       encap, inbound, src_ts, dst_ts);
 }
 
 /**
@@ -398,7 +399,7 @@ kernel_interface_t *kernel_interface_create()
 
        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.get_cpi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi;
-       this->public.add_sa  = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,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,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool,traffic_selector_t*,traffic_selector_t*))add_sa;
        this->public.update_sa = (status_t(*)(kernel_interface_t*,u_int32_t,protocol_id_t,u_int16_t,host_t*,host_t*,host_t*,host_t*,bool,bool))update_sa;
        this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int64_t*))query_sa;
        this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int16_t))del_sa;
index da4660b..c39246e 100644 (file)
@@ -100,6 +100,8 @@ struct kernel_interface_t {
         * @param cpi                   CPI for IPComp
         * @param encap                 enable UDP encapsulation for NAT traversal
         * @param inbound               TRUE if this is an inbound SA
+        * @param src_ts                traffic selector with BEET source address
+        * @param dst_ts                traffic selector with BEET destination address
         * @return                              SUCCESS if operation completed
         */
        status_t (*add_sa) (kernel_interface_t *this,
@@ -109,7 +111,8 @@ struct kernel_interface_t {
                                                u_int16_t enc_alg, chunk_t enc_key,
                                                u_int16_t int_alg, chunk_t int_key,
                                                ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
-                                               bool encap, bool inbound);
+                                               bool encap, bool inbound,
+                                               traffic_selector_t *src_ts, traffic_selector_t *dst_ts);
 
        /**
         * Update the hosts on an installed SA.
index 45eef49..5b0335b 100644 (file)
@@ -18,8 +18,6 @@
 ENUM(ipsec_mode_names, MODE_TRANSPORT, MODE_BEET,
        "TRANSPORT",
        "TUNNEL",
-       "2",
-       "3",
        "BEET",
 );
 
index 1f58799..73ad29b 100644 (file)
@@ -131,6 +131,8 @@ struct kernel_ipsec_t {
         * @param cpi                   CPI for IPComp
         * @param encap                 enable UDP encapsulation for NAT traversal
         * @param inbound               TRUE if this is an inbound SA
+        * @param src_ts                traffic selector with BEET source address
+        * @param dst_ts                traffic selector with BEET destination address
         * @return                              SUCCESS if operation completed
         */
        status_t (*add_sa) (kernel_ipsec_t *this,
@@ -140,7 +142,8 @@ struct kernel_ipsec_t {
                                                u_int16_t enc_alg, chunk_t enc_key,
                                                u_int16_t int_alg, chunk_t int_key,
                                                ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
-                                               bool encap, bool inbound);
+                                               bool encap, bool inbound,
+                                               traffic_selector_t *src_ts, traffic_selector_t *dst_ts);
 
        /**
         * Update the hosts on an installed SA.
index fc2c2a7..e0e4a76 100644 (file)
@@ -1704,7 +1704,8 @@ static status_t add_sa(private_kernel_klips_ipsec_t *this,
                                           u_int16_t enc_alg, chunk_t enc_key,
                                           u_int16_t int_alg, chunk_t int_key,
                                           ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
-                                          bool encap, bool inbound)
+                                          bool encap, bool inbound, traffic_selector_t *src_ts,
+                                          traffic_selector_t *dst_ts)
 {
        unsigned char request[PFKEY_BUFFER_SIZE];
        struct sadb_msg *msg, *out;
@@ -2617,7 +2618,7 @@ kernel_klips_ipsec_t *kernel_klips_ipsec_create()
        /* public functions */
        this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
        this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi;
-       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool))add_sa;
+       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool,traffic_selector_t*,traffic_selector_t*))add_sa;
        this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,u_int16_t,host_t*,host_t*,host_t*,host_t*,bool,bool))update_sa;
        this->public.interface.query_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int64_t*))query_sa;
        this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int16_t))del_sa;
index 62434b3..9cebd46 100644 (file)
@@ -930,7 +930,8 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                                           u_int16_t enc_alg, chunk_t enc_key,
                                           u_int16_t int_alg, chunk_t int_key,
                                           ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
-                                          bool encap, bool inbound)
+                                          bool encap, bool inbound,
+                                          traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
 {
        netlink_buf_t request;
        char *alg_name;
@@ -945,7 +946,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
                lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}};
                add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, &lft,
                           ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty,
-                          mode, ipcomp, 0, FALSE, inbound);
+                          mode, ipcomp, 0, FALSE, inbound, NULL, NULL);
                ipcomp = IPCOMP_NONE;
                /* use transport mode ESP SA, IPComp uses tunnel mode */
                mode = MODE_TRANSPORT;
@@ -968,10 +969,21 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
        sa->id.proto = proto_ike2kernel(protocol);
        sa->family = src->get_family(src);
        sa->mode = mode2kernel(mode);
-       if (mode == MODE_TUNNEL)
+       switch (mode)
        {
-               sa->flags |= XFRM_STATE_AF_UNSPEC;
+               case MODE_TUNNEL:
+                       sa->flags |= XFRM_STATE_AF_UNSPEC;
+                       break;
+               case MODE_BEET:
+                       if(src_ts && dst_ts)
+                       {
+                               sa->sel = ts2selector(src_ts, dst_ts);
+                       }
+                       break;
+               default:
+                       break;
        }
+
        sa->replay_window = (protocol == IPPROTO_COMP) ? 0 : 32;
        sa->reqid = reqid;
        sa->lft.soft_byte_limit = XFRM_LIMIT(lifetime->bytes.rekey);
@@ -1695,7 +1707,7 @@ static status_t add_policy(private_kernel_netlink_ipsec_t *this,
        /* install a route, if:
         * - we are NOT updating a policy
         * - this is a forward policy (to just get one for each child)
-        * - we are in tunnel mode
+        * - we are in tunnel/BEET mode
         * - routing is not disabled via strongswan.conf
         */
        if (policy->route == NULL && direction == POLICY_FWD &&
@@ -1999,7 +2011,7 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
        /* public functions */
        this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
        this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi;
-       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool))add_sa;
+       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool,traffic_selector_t*,traffic_selector_t*))add_sa;
        this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,u_int16_t,host_t*,host_t*,host_t*,host_t*,bool,bool))update_sa;
        this->public.interface.query_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int64_t*))query_sa;
        this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int16_t))del_sa;
index 0ebdafa..b26a2bc 100644 (file)
@@ -1230,7 +1230,8 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this,
                                           u_int16_t enc_alg, chunk_t enc_key,
                                           u_int16_t int_alg, chunk_t int_key,
                                           ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
-                                          bool encap, bool inbound)
+                                          bool encap, bool inbound, traffic_selector_t *src_ts,
+                                          traffic_selector_t *dst_ts)
 {
        unsigned char request[PFKEY_BUFFER_SIZE];
        struct sadb_msg *msg, *out;
@@ -2159,7 +2160,7 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
        /* public functions */
        this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
        this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi;
-       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool))add_sa;
+       this->public.interface.add_sa  = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool,traffic_selector_t*,traffic_selector_t*))add_sa;
        this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,u_int16_t,host_t*,host_t*,host_t*,host_t*,bool,bool))update_sa;
        this->public.interface.query_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int64_t*))query_sa;
        this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int16_t))del_sa;
index f2ffdab..3fdfb51 100644 (file)
@@ -544,9 +544,11 @@ static u_int16_t alloc_cpi(private_child_sa_t *this)
  * Implementation of child_sa_t.install
  */
 static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ,
-                                               u_int32_t spi, u_int16_t cpi, bool inbound)
+                                               u_int32_t spi, u_int16_t cpi, bool inbound,
+                                               linked_list_t *my_ts, linked_list_t *other_ts)
 {
        u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
+       traffic_selector_t *src_ts = NULL, *dst_ts = NULL;
        time_t now;
        lifetime_cfg_t *lifetime;
        host_t *src, *dst;
@@ -603,10 +605,27 @@ static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ,
                lifetime->time.rekey = 0;
        }
 
+       if (this->mode == MODE_BEET)
+       {
+               /* BEET requires the bound address from the traffic selectors.
+                * TODO: We add just the first traffic selector for now, as the
+                * kernel accepts a single TS per SA only */
+               if (inbound)
+               {
+                       my_ts->get_first(my_ts, (void**)&dst_ts);
+                       other_ts->get_first(other_ts, (void**)&src_ts);
+               }
+               else
+               {
+                       my_ts->get_first(my_ts, (void**)&src_ts);
+                       other_ts->get_first(other_ts, (void**)&dst_ts);
+               }
+       }
+
        status = charon->kernel_interface->add_sa(charon->kernel_interface,
                                src, dst, spi, this->protocol, this->reqid, lifetime,
                                enc_alg, encr, int_alg, integ, this->mode, this->ipcomp, cpi,
-                               this->encap, update);
+                               this->encap, update, src_ts, dst_ts);
 
        free(lifetime);
 
@@ -902,7 +921,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
        this->public.set_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t))set_ipcomp;
        this->public.alloc_spi = (u_int32_t(*)(child_sa_t*, protocol_id_t protocol))alloc_spi;
        this->public.alloc_cpi = (u_int16_t(*)(child_sa_t*))alloc_cpi;
-       this->public.install = (status_t(*)(child_sa_t*, chunk_t encr, chunk_t integ, u_int32_t spi, u_int16_t cpi, bool inbound))install;
+       this->public.install = (status_t(*)(child_sa_t*, chunk_t encr, chunk_t integ, u_int32_t spi, u_int16_t cpi, bool inbound, linked_list_t *my_ts_list, linked_list_t *other_ts_list))install;
        this->public.update = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update;
        this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
        this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
index a45b4c3..d70bed6 100644 (file)
@@ -285,10 +285,13 @@ struct child_sa_t {
         * @param spi           SPI to use, allocated for inbound
         * @param cpi           CPI to use, allocated for outbound
         * @param inbound       TRUE to install an inbound SA, FALSE for outbound
+        * @param my_ts         negotiated local traffic selector list
+        * @param other_ts      negotiated remote traffic selector list
         * @return                      SUCCESS or FAILED
         */
        status_t (*install)(child_sa_t *this, chunk_t encr, chunk_t integ,
-                                               u_int32_t spi, u_int16_t cpi, bool inbound);
+                                               u_int32_t spi, u_int16_t cpi, bool inbound,
+                                               linked_list_t *my_ts, linked_list_t *other_ts);
        /**
         * Install the policies using some traffic selectors.
         *
index f6719aa..1bf73b8 100644 (file)
@@ -408,21 +408,21 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
        }
        status_i = status_o = FAILED;
        if (this->keymat->derive_child_keys(this->keymat, this->proposal,
-                       this->dh, nonce_i, nonce_r,     &encr_i, &integ_i, &encr_r, &integ_r))
+                       this->dh, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
        {
                if (this->initiator)
                {
                        status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
-                                                                               this->my_spi, this->my_cpi, TRUE);
+                                       this->my_spi, this->my_cpi, TRUE, my_ts, other_ts);
                        status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
-                                                                               this->other_spi, this->other_cpi, FALSE);
+                                       this->other_spi, this->other_cpi, FALSE, my_ts, other_ts);
                }
                else
                {
                        status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
-                                                                               this->my_spi, this->my_cpi, TRUE);
+                                       this->my_spi, this->my_cpi, TRUE, my_ts, other_ts);
                        status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
-                                                                               this->other_spi, this->other_cpi, FALSE);
+                                       this->other_spi, this->other_cpi, FALSE, my_ts, other_ts);
                }
        }
        chunk_clear(&integ_i);