From 42555e6c657429e6ae94200e170e9e67bf39b4e0 Mon Sep 17 00:00:00 2001 From: Denis Vinogradov Date: Wed, 2 Dec 2020 17:09:09 +0900 Subject: [PATCH] [APR-6371]create XFRM device instead of tun if possible 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 --- src/libcharon/kernel/kernel_interface.c | 26 +++++ src/libcharon/kernel/kernel_interface.h | 10 ++ src/libcharon/kernel/kernel_net.h | 10 ++ .../kernel_netlink/kernel_netlink_net.c | 96 +++++++++++++++++++ src/libcharon/sa/child_sa.c | 12 +++ src/libcharon/sa/child_sa.h | 5 + src/libcharon/sa/ike_sa.c | 49 +++++++++- src/libcharon/sa/ike_sa.h | 5 + src/libcharon/sa/ikev2/tasks/child_create.c | 9 ++ src/libstrongswan/networking/tun_device.c | 49 ++++++++++ src/libstrongswan/networking/tun_device.h | 8 ++ 11 files changed, 278 insertions(+), 1 deletion(-) diff --git a/src/libcharon/kernel/kernel_interface.c b/src/libcharon/kernel/kernel_interface.c index e216c97..0c7d72d 100755 --- a/src/libcharon/kernel/kernel_interface.c +++ b/src/libcharon/kernel/kernel_interface.c @@ -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, diff --git a/src/libcharon/kernel/kernel_interface.h b/src/libcharon/kernel/kernel_interface.h index b7e3686..9c066ba 100755 --- a/src/libcharon/kernel/kernel_interface.h +++ b/src/libcharon/kernel/kernel_interface.h @@ -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. */ diff --git a/src/libcharon/kernel/kernel_net.h b/src/libcharon/kernel/kernel_net.h index 12475b1..199179d 100755 --- a/src/libcharon/kernel/kernel_net.h +++ b/src/libcharon/kernel/kernel_net.h @@ -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. */ diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c index 2608475..4196fab 100755 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c @@ -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, }, }, diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 986a774..a1d2a5c 100755 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -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, diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h index c9b3f63..7881b2e 100755 --- a/src/libcharon/sa/child_sa.h +++ b/src/libcharon/sa/child_sa.h @@ -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. */ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 2a4749e..d4205b6 100755 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -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, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index d3b3bcc..9533fe4 100755 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -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 }; diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index 9adf4da..1148575 100755 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -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) { diff --git a/src/libstrongswan/networking/tun_device.c b/src/libstrongswan/networking/tun_device.c index a8e4dd6..676d69a 100755 --- a/src/libstrongswan/networking/tun_device.c +++ b/src/libstrongswan/networking/tun_device.c @@ -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 */ diff --git a/src/libstrongswan/networking/tun_device.h b/src/libstrongswan/networking/tun_device.h index 8fafa60..4f63849 100755 --- a/src/libstrongswan/networking/tun_device.h +++ b/src/libstrongswan/networking/tun_device.h @@ -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_ @}*/ -- 2.20.1