kernel-netlink: Offload bypass policies for IKE ports on interfaces
While this uses the same mechanism, it's not necessary to explicitly enable port_bypass, the regular socket policies work fine to bypass any software policies.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2006-2022 Tobias Brunner
|
* Copyright (C) 2006-2023 Tobias Brunner
|
||||||
* Copyright (C) 2005-2009 Martin Willi
|
* Copyright (C) 2005-2009 Martin Willi
|
||||||
* Copyright (C) 2008-2016 Andreas Steffen
|
* Copyright (C) 2008-2016 Andreas Steffen
|
||||||
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
|
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
|
||||||
@@ -358,10 +358,34 @@ struct private_kernel_netlink_ipsec_t {
|
|||||||
bool policy_update;
|
bool policy_update;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installed port based IKE bypass policies, as bypass_t
|
* Whether to use port-based policies instead of socket policies for the
|
||||||
|
* IKE sockets/ports
|
||||||
|
*/
|
||||||
|
bool port_bypass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installed port-based IKE bypass policies, as bypass_t
|
||||||
|
*
|
||||||
|
* If they are potentially offloaded, the offload mutex has to be locked
|
||||||
|
* when modifying it
|
||||||
*/
|
*/
|
||||||
array_t *bypass;
|
array_t *bypass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interfaces that potentially support HW offloading, as offload_iface_t
|
||||||
|
*/
|
||||||
|
hashtable_t *offload_interfaces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex to safely access the interfaces and bypasses
|
||||||
|
*/
|
||||||
|
mutex_t *offload_mutex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Netlink routing socket to receive link events
|
||||||
|
*/
|
||||||
|
netlink_event_socket_t *socket_link_events;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom priority calculation function
|
* Custom priority calculation function
|
||||||
*/
|
*/
|
||||||
@@ -1352,7 +1376,7 @@ static struct {
|
|||||||
/**
|
/**
|
||||||
* Check if kernel supports HW offload and determine feature flag
|
* Check if kernel supports HW offload and determine feature flag
|
||||||
*/
|
*/
|
||||||
static void netlink_find_offload_feature(const char *ifname)
|
static bool netlink_find_offload_feature(const char *ifname)
|
||||||
{
|
{
|
||||||
struct ethtool_sset_info *sset_info;
|
struct ethtool_sset_info *sset_info;
|
||||||
struct ethtool_gstrings *cmd = NULL;
|
struct ethtool_gstrings *cmd = NULL;
|
||||||
@@ -1364,7 +1388,7 @@ static void netlink_find_offload_feature(const char *ifname)
|
|||||||
query_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
|
query_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
|
||||||
if (query_socket < 0)
|
if (query_socket < 0)
|
||||||
{
|
{
|
||||||
return;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* determine number of device features */
|
/* determine number of device features */
|
||||||
@@ -1416,10 +1440,11 @@ out:
|
|||||||
free(sset_info);
|
free(sset_info);
|
||||||
free(cmd);
|
free(cmd);
|
||||||
close(query_socket);
|
close(query_socket);
|
||||||
|
return netlink_hw_offload.supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if interface supported HW offload
|
* Check if interface supports HW offload
|
||||||
*/
|
*/
|
||||||
static bool netlink_detect_offload(const char *ifname)
|
static bool netlink_detect_offload(const char *ifname)
|
||||||
{
|
{
|
||||||
@@ -1460,11 +1485,6 @@ static bool netlink_detect_offload(const char *ifname)
|
|||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
DBG1(DBG_KNL, "HW offload is not supported by device");
|
|
||||||
}
|
|
||||||
free(cmd);
|
free(cmd);
|
||||||
close(query_socket);
|
close(query_socket);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1472,8 +1492,9 @@ static bool netlink_detect_offload(const char *ifname)
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static void netlink_find_offload_feature(const char *ifname)
|
static bool netlink_find_offload_feature(const char *ifname)
|
||||||
{
|
{
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool netlink_detect_offload(const char *ifname)
|
static bool netlink_detect_offload(const char *ifname)
|
||||||
@@ -1526,6 +1547,7 @@ static bool add_hw_offload(struct nlmsghdr *hdr, int buflen, host_t *local,
|
|||||||
/* check if interface supports hw_offload */
|
/* check if interface supports hw_offload */
|
||||||
if (!netlink_detect_offload(ifname))
|
if (!netlink_detect_offload(ifname))
|
||||||
{
|
{
|
||||||
|
DBG1(DBG_KNL, "HW offload is not supported by device %s", ifname);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3424,6 +3446,44 @@ static bool add_socket_bypass(private_kernel_netlink_ipsec_t *this,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep track of interface and its offload support
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface index
|
||||||
|
*/
|
||||||
|
int ifindex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the interface
|
||||||
|
*/
|
||||||
|
char ifname[IFNAMSIZ];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface flags
|
||||||
|
*/
|
||||||
|
u_int flags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offload state
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
/** Offload support unknown */
|
||||||
|
IFACE_OFFLOAD_UNKNOWN,
|
||||||
|
/** No offload supported */
|
||||||
|
IFACE_OFFLOAD_NONE,
|
||||||
|
/** Interface supports at least crypto offload */
|
||||||
|
IFACE_OFFLOAD_DETECTED,
|
||||||
|
/** Interface supports crypto offload, but no packet and policy offload */
|
||||||
|
IFACE_OFFLOAD_CRYPTO,
|
||||||
|
/** Packet and policy offload supported */
|
||||||
|
IFACE_OFFLOAD_PACKET,
|
||||||
|
} offload;
|
||||||
|
|
||||||
|
} offload_iface_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Port based IKE bypass policy
|
* Port based IKE bypass policy
|
||||||
*/
|
*/
|
||||||
@@ -3437,13 +3497,16 @@ typedef struct {
|
|||||||
} bypass_t;
|
} bypass_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add or remove a bypass policy from/to kernel
|
* Add or remove a bypass policy from/to kernel. If an interface is given,
|
||||||
|
* the policy is tried to be offloaded to that interface.
|
||||||
*/
|
*/
|
||||||
static bool manage_bypass(private_kernel_netlink_ipsec_t *this,
|
static bool manage_bypass(private_kernel_netlink_ipsec_t *this,
|
||||||
int type, policy_dir_t dir, bypass_t *bypass)
|
int type, policy_dir_t dir, bypass_t *bypass,
|
||||||
|
char *ifname)
|
||||||
{
|
{
|
||||||
netlink_buf_t request;
|
netlink_buf_t request;
|
||||||
struct xfrm_selector *sel;
|
struct xfrm_selector *sel;
|
||||||
|
struct xfrm_user_offload *offload = NULL;
|
||||||
struct nlmsghdr *hdr;
|
struct nlmsghdr *hdr;
|
||||||
|
|
||||||
memset(&request, 0, sizeof(request));
|
memset(&request, 0, sizeof(request));
|
||||||
@@ -3469,6 +3532,13 @@ static bool manage_bypass(private_kernel_netlink_ipsec_t *this,
|
|||||||
policy->lft.hard_packet_limit = XFRM_INF;
|
policy->lft.hard_packet_limit = XFRM_INF;
|
||||||
|
|
||||||
sel = &policy->sel;
|
sel = &policy->sel;
|
||||||
|
|
||||||
|
if (ifname &&
|
||||||
|
!add_hw_offload(hdr, sizeof(request), NULL, ifname,
|
||||||
|
HW_OFFLOAD_PACKET, &offload))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else /* XFRM_MSG_DELPOLICY */
|
else /* XFRM_MSG_DELPOLICY */
|
||||||
{
|
{
|
||||||
@@ -3494,14 +3564,137 @@ static bool manage_bypass(private_kernel_netlink_ipsec_t *this,
|
|||||||
sel->sport = bypass->port;
|
sel->sport = bypass->port;
|
||||||
sel->sport_mask = 0xffff;
|
sel->sport_mask = 0xffff;
|
||||||
}
|
}
|
||||||
|
if (ifname)
|
||||||
|
{
|
||||||
|
sel->ifindex = if_nametoindex(ifname);
|
||||||
|
}
|
||||||
return this->socket_xfrm->send_ack(this->socket_xfrm, hdr) == SUCCESS;
|
return this->socket_xfrm->send_ack(this->socket_xfrm, hdr) == SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CALLBACK(remove_port_bypass, void,
|
||||||
|
bypass_t *bypass, int idx, void *user)
|
||||||
|
{
|
||||||
|
private_kernel_netlink_ipsec_t *this = user;
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
offload_iface_t *iface;
|
||||||
|
|
||||||
|
if (this->port_bypass)
|
||||||
|
{
|
||||||
|
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_OUT, bypass, NULL);
|
||||||
|
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, bypass, NULL);
|
||||||
|
}
|
||||||
|
if (this->offload_interfaces)
|
||||||
|
{
|
||||||
|
enumerator = this->offload_interfaces->create_enumerator(this->offload_interfaces);
|
||||||
|
while (enumerator->enumerate(enumerator, NULL, &iface))
|
||||||
|
{
|
||||||
|
if (iface->offload == IFACE_OFFLOAD_PACKET &&
|
||||||
|
iface->flags & IFF_UP)
|
||||||
|
{
|
||||||
|
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_OUT, bypass,
|
||||||
|
iface->ifname);
|
||||||
|
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, bypass,
|
||||||
|
iface->ifname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bypass socket using a port-based bypass policy
|
* Bypass socket using a port-based bypass policy, optionally offloaded to a
|
||||||
|
* given interface
|
||||||
*/
|
*/
|
||||||
static bool add_port_bypass(private_kernel_netlink_ipsec_t *this,
|
static bool add_port_bypass(private_kernel_netlink_ipsec_t *this,
|
||||||
int fd, int family)
|
bypass_t *bypass, char *ifname)
|
||||||
|
{
|
||||||
|
if (!manage_bypass(this, XFRM_MSG_NEWPOLICY, POLICY_IN, bypass, ifname))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!manage_bypass(this, XFRM_MSG_NEWPOLICY, POLICY_OUT, bypass, ifname))
|
||||||
|
{
|
||||||
|
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, bypass, ifname);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offload the given port-based bypass policy to the given interface if possible.
|
||||||
|
*
|
||||||
|
* offload_mutex is assumed to be locked.
|
||||||
|
*/
|
||||||
|
static bool offload_bypass_iface(private_kernel_netlink_ipsec_t *this,
|
||||||
|
bypass_t *bypass, offload_iface_t *iface)
|
||||||
|
{
|
||||||
|
if ((iface->offload == IFACE_OFFLOAD_DETECTED ||
|
||||||
|
iface->offload == IFACE_OFFLOAD_PACKET))
|
||||||
|
{
|
||||||
|
if (add_port_bypass(this, bypass, iface->ifname))
|
||||||
|
{
|
||||||
|
iface->offload = IFACE_OFFLOAD_PACKET;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else if (iface->offload == IFACE_OFFLOAD_DETECTED)
|
||||||
|
{
|
||||||
|
iface->offload = IFACE_OFFLOAD_CRYPTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offload all known port-based bypass policies to the given interface.
|
||||||
|
*
|
||||||
|
* offload_mutex is assumed to be locked.
|
||||||
|
*/
|
||||||
|
static void offload_bypasses(private_kernel_netlink_ipsec_t *this,
|
||||||
|
offload_iface_t *iface)
|
||||||
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
bypass_t *bypass;
|
||||||
|
|
||||||
|
enumerator = array_create_enumerator(this->bypass);
|
||||||
|
while (enumerator->enumerate(enumerator, &bypass))
|
||||||
|
{
|
||||||
|
if (!offload_bypass_iface(this, bypass, iface))
|
||||||
|
{ /* could indicate a failure but generally means that the interface
|
||||||
|
* does not support offloading */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offload a new port-based bypass policy to all known interfaces.
|
||||||
|
*
|
||||||
|
* offload_mutex is assumed to be locked.
|
||||||
|
*/
|
||||||
|
static void offload_bypass(private_kernel_netlink_ipsec_t *this,
|
||||||
|
bypass_t *bypass)
|
||||||
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
offload_iface_t *iface;
|
||||||
|
|
||||||
|
enumerator = this->offload_interfaces->create_enumerator(this->offload_interfaces);
|
||||||
|
while (enumerator->enumerate(enumerator, NULL, &iface))
|
||||||
|
{
|
||||||
|
if (iface->flags & IFF_UP)
|
||||||
|
{
|
||||||
|
offload_bypass_iface(this, bypass, iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offload a bypass policy on supported hardware if the kernel supports it and
|
||||||
|
* optionally install a port-based bypass policy in software.
|
||||||
|
*/
|
||||||
|
static bool add_and_offload_port_bypass(private_kernel_netlink_ipsec_t *this,
|
||||||
|
int fd, int family)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
@@ -3537,39 +3730,38 @@ static bool add_port_bypass(private_kernel_netlink_ipsec_t *this,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!manage_bypass(this, XFRM_MSG_NEWPOLICY, POLICY_IN, &bypass))
|
if (this->port_bypass &&
|
||||||
|
!add_port_bypass(this, &bypass, NULL))
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (!manage_bypass(this, XFRM_MSG_NEWPOLICY, POLICY_OUT, &bypass))
|
if (this->offload_interfaces)
|
||||||
{
|
{
|
||||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, &bypass);
|
this->offload_mutex->lock(this->offload_mutex);
|
||||||
return FALSE;
|
offload_bypass(this, &bypass);
|
||||||
|
/* store it even if no policy was offloaded because an interface that
|
||||||
|
* supports offloading might get activated later */
|
||||||
|
array_insert_create_value(&this->bypass, sizeof(bypass_t),
|
||||||
|
ARRAY_TAIL, &bypass);
|
||||||
|
this->offload_mutex->unlock(this->offload_mutex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
array_insert_create_value(&this->bypass, sizeof(bypass_t),
|
||||||
|
ARRAY_TAIL, &bypass);
|
||||||
}
|
}
|
||||||
array_insert(this->bypass, ARRAY_TAIL, &bypass);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove installed port based bypass policy
|
|
||||||
*/
|
|
||||||
static void remove_port_bypass(bypass_t *bypass, int idx,
|
|
||||||
private_kernel_netlink_ipsec_t *this)
|
|
||||||
{
|
|
||||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_OUT, bypass);
|
|
||||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, bypass);
|
|
||||||
}
|
|
||||||
|
|
||||||
METHOD(kernel_ipsec_t, bypass_socket, bool,
|
METHOD(kernel_ipsec_t, bypass_socket, bool,
|
||||||
private_kernel_netlink_ipsec_t *this, int fd, int family)
|
private_kernel_netlink_ipsec_t *this, int fd, int family)
|
||||||
{
|
{
|
||||||
if (lib->settings->get_bool(lib->settings,
|
if ((this->offload_interfaces || this->port_bypass) &&
|
||||||
"%s.plugins.kernel-netlink.port_bypass", FALSE, lib->ns))
|
!add_and_offload_port_bypass(this, fd, family))
|
||||||
{
|
{
|
||||||
return add_port_bypass(this, fd, family);
|
return FALSE;
|
||||||
}
|
}
|
||||||
return add_socket_bypass(this, fd, family);
|
return this->port_bypass || add_socket_bypass(this, fd, family);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(kernel_ipsec_t, enable_udp_decap, bool,
|
METHOD(kernel_ipsec_t, enable_udp_decap, bool,
|
||||||
@@ -3585,26 +3777,161 @@ METHOD(kernel_ipsec_t, enable_udp_decap, bool,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CALLBACK(receive_link_events, void,
|
||||||
|
private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
|
||||||
|
{
|
||||||
|
struct ifinfomsg *msg = NLMSG_DATA(hdr);
|
||||||
|
struct rtattr *rta = IFLA_RTA(msg);
|
||||||
|
size_t rtasize = IFLA_PAYLOAD (hdr);
|
||||||
|
offload_iface_t *iface = NULL;
|
||||||
|
char *name = NULL;
|
||||||
|
|
||||||
|
if (hdr->nlmsg_type != RTM_NEWLINK &&
|
||||||
|
hdr->nlmsg_type != RTM_DELLINK)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (RTA_OK(rta, rtasize))
|
||||||
|
{
|
||||||
|
switch (rta->rta_type)
|
||||||
|
{
|
||||||
|
case IFLA_IFNAME:
|
||||||
|
name = RTA_DATA(rta);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rta = RTA_NEXT(rta, rtasize);
|
||||||
|
}
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->offload_mutex->lock(this->offload_mutex);
|
||||||
|
if (hdr->nlmsg_type == RTM_NEWLINK)
|
||||||
|
{
|
||||||
|
iface = this->offload_interfaces->get(this->offload_interfaces,
|
||||||
|
(void*)(uintptr_t)msg->ifi_index);
|
||||||
|
if (!iface)
|
||||||
|
{
|
||||||
|
INIT(iface,
|
||||||
|
.ifindex = msg->ifi_index
|
||||||
|
);
|
||||||
|
this->offload_interfaces->put(this->offload_interfaces,
|
||||||
|
(void*)(uintptr_t)msg->ifi_index,
|
||||||
|
iface);
|
||||||
|
}
|
||||||
|
/* update name in case an interface is renamed */
|
||||||
|
strncpy(iface->ifname, name, IFNAMSIZ-1);
|
||||||
|
iface->ifname[IFNAMSIZ-1] = '\0';
|
||||||
|
|
||||||
|
if (iface->offload == IFACE_OFFLOAD_UNKNOWN)
|
||||||
|
{
|
||||||
|
if (netlink_detect_offload(iface->ifname))
|
||||||
|
{
|
||||||
|
iface->offload = IFACE_OFFLOAD_DETECTED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iface->offload = IFACE_OFFLOAD_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if an interface is activated or newly detected, try to offload known
|
||||||
|
* IKE bypass policies. we don't have to do anything if the interface
|
||||||
|
* goes down as the kernel automatically removes the state it has for
|
||||||
|
* offloaded policies */
|
||||||
|
if (!(iface->flags & IFF_UP) && (msg->ifi_flags & IFF_UP))
|
||||||
|
{
|
||||||
|
offload_bypasses(this, iface);
|
||||||
|
}
|
||||||
|
iface->flags = msg->ifi_flags;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iface = this->offload_interfaces->remove(this->offload_interfaces,
|
||||||
|
(void*)(uintptr_t)msg->ifi_index);
|
||||||
|
free(iface);
|
||||||
|
}
|
||||||
|
this->offload_mutex->unlock(this->offload_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumerate all interfaces and check if they support offloading
|
||||||
|
*/
|
||||||
|
static bool init_offload_interfaces(private_kernel_netlink_ipsec_t *this)
|
||||||
|
{
|
||||||
|
netlink_buf_t request;
|
||||||
|
netlink_socket_t *socket;
|
||||||
|
struct nlmsghdr *out, *current, *in;
|
||||||
|
struct rtgenmsg *msg;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE);
|
||||||
|
if (!socket)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&request, 0, sizeof(request));
|
||||||
|
|
||||||
|
in = &request.hdr;
|
||||||
|
in->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||||
|
in->nlmsg_type = RTM_GETLINK;
|
||||||
|
in->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
|
||||||
|
|
||||||
|
msg = NLMSG_DATA(in);
|
||||||
|
msg->rtgen_family = AF_UNSPEC;
|
||||||
|
|
||||||
|
if (socket->send(socket, in, &out, &len) != SUCCESS)
|
||||||
|
{
|
||||||
|
socket->destroy(socket);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = out;
|
||||||
|
while (NLMSG_OK(current, len))
|
||||||
|
{
|
||||||
|
receive_link_events(this, current);
|
||||||
|
current = NLMSG_NEXT(current, len);
|
||||||
|
}
|
||||||
|
free(out);
|
||||||
|
socket->destroy(socket);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(kernel_ipsec_t, destroy, void,
|
METHOD(kernel_ipsec_t, destroy, void,
|
||||||
private_kernel_netlink_ipsec_t *this)
|
private_kernel_netlink_ipsec_t *this)
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
policy_entry_t *policy;
|
policy_entry_t *policy;
|
||||||
|
offload_iface_t *iface;
|
||||||
|
|
||||||
array_destroy_function(this->bypass,
|
DESTROY_IF(this->socket_link_events);
|
||||||
(array_callback_t)remove_port_bypass, this);
|
|
||||||
DESTROY_IF(this->socket_xfrm_events);
|
DESTROY_IF(this->socket_xfrm_events);
|
||||||
|
array_destroy_function(this->bypass, remove_port_bypass, this);
|
||||||
DESTROY_IF(this->socket_xfrm);
|
DESTROY_IF(this->socket_xfrm);
|
||||||
enumerator = this->policies->create_enumerator(this->policies);
|
enumerator = this->policies->create_enumerator(this->policies);
|
||||||
while (enumerator->enumerate(enumerator, &policy, &policy))
|
while (enumerator->enumerate(enumerator, NULL, &policy))
|
||||||
{
|
{
|
||||||
policy_entry_destroy(this, policy);
|
policy_entry_destroy(this, policy);
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
this->policies->destroy(this->policies);
|
this->policies->destroy(this->policies);
|
||||||
this->sas->destroy(this->sas);
|
this->sas->destroy(this->sas);
|
||||||
|
if (this->offload_interfaces)
|
||||||
|
{
|
||||||
|
enumerator = this->offload_interfaces->create_enumerator(this->offload_interfaces);
|
||||||
|
while (enumerator->enumerate(enumerator, NULL, &iface))
|
||||||
|
{
|
||||||
|
free(iface);
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
this->offload_interfaces->destroy(this->offload_interfaces);
|
||||||
|
}
|
||||||
this->condvar->destroy(this->condvar);
|
this->condvar->destroy(this->condvar);
|
||||||
this->mutex->destroy(this->mutex);
|
this->mutex->destroy(this->mutex);
|
||||||
|
DESTROY_IF(this->offload_mutex);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3742,7 +4069,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
|||||||
(hashtable_equals_t)policy_equals, 32),
|
(hashtable_equals_t)policy_equals, 32),
|
||||||
.sas = hashtable_create((hashtable_hash_t)ipsec_sa_hash,
|
.sas = hashtable_create((hashtable_hash_t)ipsec_sa_hash,
|
||||||
(hashtable_equals_t)ipsec_sa_equals, 32),
|
(hashtable_equals_t)ipsec_sa_equals, 32),
|
||||||
.bypass = array_create(sizeof(bypass_t), 0),
|
|
||||||
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||||
.condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
|
.condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
|
||||||
.get_priority = dlsym(RTLD_DEFAULT,
|
.get_priority = dlsym(RTLD_DEFAULT,
|
||||||
@@ -3754,6 +4080,8 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
|||||||
.proto_port_transport = lib->settings->get_bool(lib->settings,
|
.proto_port_transport = lib->settings->get_bool(lib->settings,
|
||||||
"%s.plugins.kernel-netlink.set_proto_port_transport_sa",
|
"%s.plugins.kernel-netlink.set_proto_port_transport_sa",
|
||||||
FALSE, lib->ns),
|
FALSE, lib->ns),
|
||||||
|
.port_bypass = lib->settings->get_bool(lib->settings,
|
||||||
|
"%s.plugins.kernel-netlink.port_bypass", FALSE, lib->ns),
|
||||||
);
|
);
|
||||||
|
|
||||||
this->socket_xfrm = netlink_socket_create(NETLINK_XFRM, xfrm_msg_names,
|
this->socket_xfrm = netlink_socket_create(NETLINK_XFRM, xfrm_msg_names,
|
||||||
@@ -3778,9 +4106,22 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
netlink_find_offload_feature(lib->settings->get_str(lib->settings,
|
if (netlink_find_offload_feature(lib->settings->get_str(lib->settings,
|
||||||
"%s.plugins.kernel-netlink.hw_offload_feature_interface",
|
"%s.plugins.kernel-netlink.hw_offload_feature_interface",
|
||||||
"lo", lib->ns));
|
"lo", lib->ns)))
|
||||||
|
{
|
||||||
|
this->offload_interfaces = hashtable_create(hashtable_hash_ptr,
|
||||||
|
hashtable_equals_ptr, 8);
|
||||||
|
this->offload_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
|
||||||
|
this->socket_link_events = netlink_event_socket_create(NETLINK_ROUTE,
|
||||||
|
nl_group(RTNLGRP_LINK),
|
||||||
|
receive_link_events, this);
|
||||||
|
if (!this->socket_link_events ||
|
||||||
|
!init_offload_interfaces(this))
|
||||||
|
{
|
||||||
|
destroy(this);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user