[APR-6371]create XFRM device instead of tun if possible
authorDenis Vinogradov <denis.vinogradov@samsung.com>
Wed, 2 Dec 2020 08:09:09 +0000 (17:09 +0900)
committerI am Robot <robot_ap@samsung.com>
Thu, 10 Dec 2020 16:32:47 +0000 (01:32 +0900)
  If we can create XFRM vitrual device,
  it is possible to link it to CHILD_SA.
  It can allow to receive data packets
  after binding to created adapter.
  Note: adapter index will start with 10, i.e epdg10,
  in case successful creation.

Change-Id: I47414bda1748bfda858e2395e4ce2ded7b50ac77
Signed-off-by: Denis Vinogradov <denis.vinogradov@samsung.com>
src/libcharon/kernel/kernel_interface.c
src/libcharon/kernel/kernel_interface.h
src/libcharon/kernel/kernel_net.h
src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c
src/libcharon/sa/child_sa.c
src/libcharon/sa/child_sa.h
src/libcharon/sa/ike_sa.c
src/libcharon/sa/ike_sa.h
src/libcharon/sa/ikev2/tasks/child_create.c
src/libstrongswan/networking/tun_device.c
src/libstrongswan/networking/tun_device.h

index e216c972cfbfd79ae88d30a174431bc917b7a85c..0c7d72db5f1f2cad89c221cf1b3bdfca8fdafe3f 100755 (executable)
@@ -1001,6 +1001,28 @@ METHOD(kernel_interface_t, destroy, void,
        free(this);
 }
 
+#ifdef VOWIFI_CFG
+METHOD(kernel_interface_t, create_interface, status_t,
+       private_kernel_interface_t *this, char *iface_template, char* iface_buffer)
+{
+       if (!this->net || !this->net->create_interface)
+       {
+               return NOT_SUPPORTED;
+       }
+       return this->net->create_interface(this->net, iface_template, iface_buffer);
+}
+
+METHOD(kernel_interface_t, remove_interface, status_t,
+       private_kernel_interface_t *this, char *iface)
+{
+       if (!this->net || !this->net->remove_interface)
+       {
+               return NOT_SUPPORTED;
+       }
+       return this->net->remove_interface(this->net, iface);
+}
+#endif
+
 /*
  * Described in header-file
  */
@@ -1036,6 +1058,10 @@ kernel_interface_t *kernel_interface_create()
                        .del_route = _del_route,
                        .bypass_socket = _bypass_socket,
                        .enable_udp_decap = _enable_udp_decap,
+#ifdef VOWIFI_CFG
+                       .create_interface = _create_interface,
+                       .remove_interface = _remove_interface,
+#endif
 
                        .is_interface_usable = _is_interface_usable,
                        .all_interfaces_usable = _all_interfaces_usable,
index b7e3686d1bca26b3f0d85ea1c7337f4b736b580a..9c066ba221f29192c5c6b825c6daa728e938cd22 100755 (executable)
@@ -594,6 +594,16 @@ struct kernel_interface_t {
                                                         transform_type_t type, uint16_t *kernel_id,
                                                         char **kernel_name);
 
+#ifdef VOWIFI_CFG
+       /**
+       *
+       * Create and delete XFRM interfaces
+       *
+       */
+       status_t (*create_interface)(kernel_interface_t *this, char *name_template, char* name_buf);
+       status_t (*remove_interface)(kernel_interface_t *this, char *if_name);
+#endif
+
        /**
         * Destroys a kernel_interface_t object.
         */
index 12475b1230e4f798be20fa1bd7a605180b4ae141..199179d602fe400cbd5ce090074f39bb6bc3dbf4 100755 (executable)
@@ -186,6 +186,16 @@ struct kernel_net_t {
                                                   uint8_t prefixlen, host_t *gateway, host_t *src_ip,
                                                   char *if_name);
 
+#ifdef VOWIFI_CFG
+       /**
+       *
+       * Create and delete XFRM interfaces
+       *
+       */
+       status_t (*create_interface)(kernel_net_t *this, char *name_template, char* name_buffer);
+       status_t (*remove_interface)(kernel_net_t *this, char *if_name);
+#endif
+
        /**
         * Destroy the implementation.
         */
index 26084755caec912be941240ba5a37ed7901926d4..4196fab885fc469f57169e827f08b55c58dc45d8 100755 (executable)
@@ -536,6 +536,13 @@ struct private_kernel_netlink_net_t {
         * MSS to set on installed routes
         */
        uint32_t mss;
+
+#ifdef VOWIFI_CFG
+       /**
+       * Internal interface index
+       */
+       int interface_index;
+#endif
 };
 
 /**
@@ -2673,6 +2680,91 @@ METHOD(kernel_net_t, del_ip, status_t,
        return SUCCESS;
 }
 
+#ifdef VOWIFI_CFG
+
+#define INTERFACE_INDEX_START  10
+#define INFO_KIND_MAX_LENGTH   8
+
+METHOD(kernel_net_t, create_interface, status_t,
+       private_kernel_netlink_net_t *this, char *iface_template, char* iface_buffer)
+{
+       netlink_buf_t request;
+       struct nlmsghdr *hdr;
+       chunk_t chunk;
+       char name[IFNAMSIZ];
+       void *attr_outer, *attr_inner;
+       uint32_t index; uint32_t link = 1;
+       status_t res;
+
+       memset(&request, 0, sizeof(request));
+
+       this->lock->write_lock(this->lock);
+       if (this->interface_index < INTERFACE_INDEX_START)
+               this->interface_index = INTERFACE_INDEX_START;
+
+       index = this->interface_index++;
+       snprintf(name, IFNAMSIZ, iface_template, index);
+       this->lock->unlock(this->lock);
+
+       hdr = &request.hdr;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
+       hdr->nlmsg_type = RTM_NEWLINK;
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+       chunk = chunk_alloc(IFNAMSIZ);
+       memcpy(chunk.ptr, name, IFNAMSIZ);
+       netlink_add_attribute(hdr, IFLA_IFNAME, chunk, sizeof(request));
+       chunk_free(&chunk);
+
+       attr_outer = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
+       chunk = chunk_alloc(INFO_KIND_MAX_LENGTH);
+       strncpy(chunk.ptr, "xfrm", INFO_KIND_MAX_LENGTH);
+       netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk, sizeof(request));
+       chunk_free(&chunk);
+       attr_inner = netlink_nested_start(hdr, sizeof(request), IFLA_INFO_DATA);
+       chunk = chunk_from_thing(link);
+       netlink_add_attribute(hdr, IFLA_XFRM_LINK, chunk, sizeof(request));
+       chunk = chunk_from_thing(index);
+       netlink_add_attribute(hdr, IFLA_XFRM_IF_ID, chunk, sizeof(request));
+       netlink_nested_end(hdr, attr_inner);
+       netlink_nested_end(hdr, attr_outer);
+
+       res = this->socket->send_ack(this->socket, hdr);
+       if ((res == SUCCESS) && iface_buffer)
+       {
+               strcpy(iface_buffer, name);
+       }
+       return res;
+}
+
+METHOD(kernel_net_t, remove_interface, status_t,
+       private_kernel_netlink_net_t *this, char *iface_name)
+{
+       netlink_buf_t request;
+       struct nlmsghdr *hdr;
+       chunk_t chunk;
+
+       memset(&request, 0, sizeof(request));
+
+       hdr = &request.hdr;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       hdr->nlmsg_type = RTM_DELLINK;
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+       chunk = chunk_alloc(strlen(iface_name) + 1);
+       strncpy(chunk.ptr, iface_name, chunk.len);
+       netlink_add_attribute(hdr, IFLA_IFNAME, chunk, sizeof(request));
+       chunk_free(&chunk);
+
+       this->lock->write_lock(this->lock);
+       if (--this->interface_index < INTERFACE_INDEX_START)
+               this->interface_index = INTERFACE_INDEX_START;
+       this->lock->unlock(this->lock);
+
+       return this->socket->send_ack(this->socket, hdr);
+}
+#endif
+
 /**
  * Manages source routes in the routing table.
  * By setting the appropriate nlmsg_type, the route gets added or removed.
@@ -3204,6 +3296,10 @@ kernel_netlink_net_t *kernel_netlink_net_create()
                                .del_ip = _del_ip,
                                .add_route = _add_route,
                                .del_route = _del_route,
+#ifdef VOWIFI_CFG
+                               .create_interface = _create_interface,
+                               .remove_interface = _remove_interface,
+#endif
                                .destroy = _destroy,
                        },
                },
index 986a774affca9fa466e3db90563a54d11f5c977e..a1d2a5c175212fede9adcd39d0a7523b49760fc0 100755 (executable)
@@ -730,6 +730,15 @@ METHOD(child_sa_t, get_if_id, uint32_t,
        return inbound ? this->if_id_in : this->if_id_out;
 }
 
+#ifdef VOWIFI_CFG
+METHOD(child_sa_t, set_if_id, void,
+       private_child_sa_t *this, int in, int out)
+{
+       this->if_id_in = in;
+       this->if_id_out = out;
+}
+#endif
+
 METHOD(child_sa_t, get_lifetime, time_t,
           private_child_sa_t *this, bool hard)
 {
@@ -1839,6 +1848,9 @@ child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
                        .install_policies = _install_policies,
                        .create_ts_enumerator = _create_ts_enumerator,
                        .create_policy_enumerator = _create_policy_enumerator,
+#ifdef VOWIFI_CFG
+                       .set_if_id = _set_if_id,
+#endif
                        .destroy = _destroy,
                },
                .encap = data->encap,
index c9b3f63e2bce507b39b4e78644dad3b490dc8a13..7881b2e539a084bd83860fc58c82d76771d9e4ca 100755 (executable)
@@ -507,6 +507,11 @@ struct child_sa_t {
         */
        status_t (*update)(child_sa_t *this, host_t *me, host_t *other,
                                           linked_list_t *vips, bool encap);
+
+#ifdef VOWIFI_CFG
+       void (*set_if_id)(child_sa_t *this, int in, int out);
+#endif
+
        /**
         * Destroys a child_sa.
         */
index 2a4749ef164302ff48b2725c16816c36e25519f3..d4205b6ee81ceedee01ee9b13b7bcf55117d0d9e 100755 (executable)
@@ -1322,6 +1322,8 @@ METHOD(ike_sa_t, add_virtual_ip, void,
 
                if (this->tun == NULL)
                {
+                       char name[32];
+
                        int mtu = 0;
 #ifdef VOWIFI_PMTU_DISCOVERY
                        mtu = pmtu_discovery_stage2(this);
@@ -1330,7 +1332,17 @@ METHOD(ike_sa_t, add_virtual_ip, void,
                        {
                                mtu = TUN_DEFAULT_MTU;
                        }
-                       this->tun = tun_device_create("epdg%d");
+                       if (charon->kernel->create_interface(charon->kernel, "epdg%d", name) == SUCCESS)
+                       {
+                               sscanf(name, "epdg%d", &this->if_id_in);
+                               this->if_id_out = this->if_id_in;
+
+                               this->tun = xfrm_device_create(name);
+                       }
+                       else
+                       {
+                               this->tun = tun_device_create("epdg%d");
+                       }
                        if (!this->tun)
                        {
                                DBG1(DBG_IKE, "failed to create TUN device");
@@ -1345,6 +1357,11 @@ METHOD(ike_sa_t, add_virtual_ip, void,
                        if (!this->tun->set_mtu(this->tun, mtu))
                        {
                                DBG1(DBG_IKE, "failed to configure TUN device");
+                               if (this->tun->is_xfrm_device(this->tun))
+                               {
+                                       charon->kernel->remove_interface(charon->kernel,
+                                                               this->tun->get_name(this->tun));
+                               }
                                this->tun->destroy(this->tun);
                                this->tun = NULL;
                                return;
@@ -1352,6 +1369,11 @@ METHOD(ike_sa_t, add_virtual_ip, void,
                        if (!this->tun->up(this->tun))
                        {
                                DBG1(DBG_IKE, "failed to up TUN device");
+                               if (this->tun->is_xfrm_device(this->tun))
+                               {
+                                       charon->kernel->remove_interface(charon->kernel,
+                                                               this->tun->get_name(this->tun));
+                               }
                                this->tun->destroy(this->tun);
                                this->tun = NULL;
                                return;
@@ -1372,6 +1394,11 @@ METHOD(ike_sa_t, add_virtual_ip, void,
                        if (charon->kernel->add_ip(charon->kernel, ip, -1, this->tun->get_name(this->tun)) != SUCCESS)
                        {
                                DBG1(DBG_IKE, "failed to set ip to TUN device");
+                               if (this->tun->is_xfrm_device(this->tun))
+                               {
+                                       charon->kernel->remove_interface(charon->kernel,
+                                                               this->tun->get_name(this->tun));
+                               }
                                this->tun->destroy(this->tun);
                                this->tun = NULL;
                                return;
@@ -1433,6 +1460,11 @@ METHOD(ike_sa_t, clear_virtual_ips, void,
                {
 #ifdef VOWIFI_CFG
                        if (this->tun) {
+                               if (this->tun->is_xfrm_device(this->tun))
+                               {
+                                       charon->kernel->remove_interface(charon->kernel,
+                                                               this->tun->get_name(this->tun));
+                               }
                                this->tun->destroy(this->tun);
                        }
                        this->tun = NULL;
@@ -3577,6 +3609,11 @@ METHOD(ike_sa_t, destroy, void,
        {
 #ifdef VOWIFI_CFG
                if (this->tun) {
+                       if (this->tun->is_xfrm_device(this->tun))
+                       {
+                               charon->kernel->remove_interface(charon->kernel,
+                                                               this->tun->get_name(this->tun));
+                       }
                        this->tun->destroy(this->tun);
                }
                this->tun = NULL;
@@ -3922,6 +3959,15 @@ METHOD(ike_sa_t, get_vendor_notifies, int,
        }
        return total;
 }
+
+METHOD(ike_sa_t, is_xfrm_interface_used, bool, private_ike_sa_t *this)
+{
+       if (this->tun)
+       {
+               return this->tun->is_xfrm_device(this->tun);
+       }
+       return FALSE;
+}
 #endif
 
 #ifdef VOWIFI_USE_TIMER
@@ -4076,6 +4122,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
                        .process_vendor_notify = _process_vendor_notify,
                        .process_failed_notify = _process_failed_notify,
                        .get_vendor_notifies = _get_vendor_notifies,
+                       .is_xfrm_interface_used = _is_xfrm_interface_used,
 #endif
 #ifdef ME
                        .act_as_mediation_server = _act_as_mediation_server,
index d3b3bcc2e5a65468b2c831730f1a974f6fc05e5b..9533fe474e43ae19a7a57e23b15e720657111f83 100755 (executable)
@@ -1272,6 +1272,11 @@ struct ike_sa_t {
        void (*process_vendor_notify)(ike_sa_t *this, int type, message_t *message);
        void* (*process_failed_notify)(ike_sa_t *this, int type, message_t *message);
        int (*get_vendor_notifies)(ike_sa_t *this, linked_list_t *list);
+
+       /**
+       * TRUE if XFRM device was used
+       */
+       bool (*is_xfrm_interface_used)(ike_sa_t *this);
 #endif
 };
 
index 9adf4dac404f870c93560fd0e42bcd0eaf7337e3..11485757156ac1c80ac82d66641d13a0ecb07167 100755 (executable)
@@ -719,6 +719,15 @@ static status_t select_and_install(private_child_create_t *this,
        this->child_sa->set_mode(this->child_sa, this->mode);
        this->child_sa->set_protocol(this->child_sa,
                                                                 this->proposal->get_protocol(this->proposal));
+#ifdef VOWIFI_CFG
+       if (this->ike_sa->is_xfrm_interface_used(this->ike_sa))
+       {
+               /* update XFRM device ID to child */
+               this->child_sa->set_if_id(this->child_sa, 
+                               this->ike_sa->get_if_id(this->ike_sa, TRUE), 
+                               this->ike_sa->get_if_id(this->ike_sa, FALSE));
+       }
+#endif
 
        if (this->my_cpi == 0 || this->other_cpi == 0 || this->ipcomp == IPCOMP_NONE)
        {
index a8e4dd680d37c7602c37056efaafab7512bb8f9d..676d69a6bb5838496fbc3480432ddbda62478ed7 100755 (executable)
@@ -102,6 +102,8 @@ struct private_tun_device_t {
         * Associated addresses
         */
        linked_list_t* addresses;
+
+       bool is_xfrm_device;
 #else
        /**
         * Associated address
@@ -573,6 +575,14 @@ static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
 #endif /* !__APPLE__ */
 }
 
+#ifdef VOWIFI_CFG
+METHOD(tun_device_t, is_xfrm_device, bool,
+       private_tun_device_t *this)
+{
+       return this->is_xfrm_device;
+}
+#endif
+
 /*
  * Described in header
  */
@@ -593,6 +603,7 @@ tun_device_t *tun_device_create(const char *name_tmpl)
                        .get_address = _get_address,
 #else
                        .create_addresses_enumerator = _create_addresses_enumerator,
+                       .is_xfrm_device = _is_xfrm_device,
 #endif
                        .up = _up,
                        .destroy = _destroy,
@@ -620,4 +631,42 @@ tun_device_t *tun_device_create(const char *name_tmpl)
        return &this->public;
 }
 
+#ifdef VOWIFI_CFG
+tun_device_t *xfrm_device_create(const char *name)
+{
+       private_tun_device_t *this;
+
+       INIT(this,
+               .public = {
+                       .read_packet = _read_packet,
+                       .write_packet = _write_packet,
+                       .get_mtu = _get_mtu,
+                       .set_mtu = _set_mtu,
+                       .get_name = _get_name,
+                       .get_fd = _get_fd,
+                       .set_address = _set_address,
+                       .create_addresses_enumerator = _create_addresses_enumerator,
+                       .is_xfrm_device = _is_xfrm_device,
+                       .up = _up,
+                       .destroy = _destroy,
+               },
+               .tunfd = -1,
+               .sock = -1,
+       );
+       strncpy(this->if_name, name, IFNAMSIZ);
+       this->addresses = linked_list_create();
+       this->is_xfrm_device = TRUE;
+
+       DBG1(DBG_LIB, "created XFRM device: %s", this->if_name);
+       this->sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (this->sock < 0)
+       {
+               DBG1(DBG_LIB, "failed to open socket to configure TUN device");
+               destroy(this);
+               return NULL;
+       }
+       return &this->public;
+}
+#endif
+
 #endif /* TUN devices supported */
index 8fafa60de05702d5eb7d2a58f5348cea5b6ee695..4f63849135b0821828f0706268ab755d78e8a6c2 100755 (executable)
@@ -114,6 +114,10 @@ struct tun_device_t {
         */
        int (*get_fd)(tun_device_t *this);
 
+#ifdef VOWIFI_CFG
+       bool (*is_xfrm_device)(tun_device_t *this);
+#endif
+
        /**
         * Destroy a tun_device_t
         */
@@ -128,4 +132,8 @@ struct tun_device_t {
  */
 tun_device_t *tun_device_create(const char *name_tmpl);
 
+#ifdef VOWIFI_CFG
+tun_device_t *xfrm_device_create(const char *name);
+#endif
+
 #endif /** TUN_DEVICE_H_ @}*/