kernel-netlink: Add SA direction attribute
This commit is contained in:
@@ -1187,114 +1187,6 @@ METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
|
||||
(this->sa_lastused ? KERNEL_SA_USE_TIME : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SPI for a specific protocol from the kernel.
|
||||
*/
|
||||
static status_t get_spi_internal(private_kernel_netlink_ipsec_t *this,
|
||||
host_t *src, host_t *dst, uint8_t proto, uint32_t min, uint32_t max,
|
||||
uint32_t *spi)
|
||||
{
|
||||
netlink_buf_t request;
|
||||
struct nlmsghdr *hdr, *out;
|
||||
struct xfrm_userspi_info *userspi;
|
||||
uint32_t received_spi = 0;
|
||||
size_t len;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
|
||||
hdr = &request.hdr;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST;
|
||||
hdr->nlmsg_type = XFRM_MSG_ALLOCSPI;
|
||||
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userspi_info));
|
||||
|
||||
userspi = NLMSG_DATA(hdr);
|
||||
host2xfrm(src, &userspi->info.saddr);
|
||||
host2xfrm(dst, &userspi->info.id.daddr);
|
||||
userspi->info.id.proto = proto;
|
||||
userspi->info.mode = XFRM_MODE_TUNNEL;
|
||||
userspi->info.family = src->get_family(src);
|
||||
userspi->min = min;
|
||||
userspi->max = max;
|
||||
|
||||
if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
|
||||
{
|
||||
hdr = out;
|
||||
while (NLMSG_OK(hdr, len))
|
||||
{
|
||||
switch (hdr->nlmsg_type)
|
||||
{
|
||||
case XFRM_MSG_NEWSA:
|
||||
{
|
||||
struct xfrm_usersa_info* usersa = NLMSG_DATA(hdr);
|
||||
received_spi = usersa->id.spi;
|
||||
break;
|
||||
}
|
||||
case NLMSG_ERROR:
|
||||
{
|
||||
netlink_log_error(hdr, "allocating SPI failed");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
hdr = NLMSG_NEXT(hdr, len);
|
||||
continue;
|
||||
case NLMSG_DONE:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
free(out);
|
||||
}
|
||||
|
||||
if (received_spi == 0)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
*spi = received_spi;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, get_spi, status_t,
|
||||
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
|
||||
uint8_t protocol, uint32_t *spi)
|
||||
{
|
||||
uint32_t spi_min, spi_max;
|
||||
|
||||
spi_min = lib->settings->get_int(lib->settings, "%s.spi_min",
|
||||
KERNEL_SPI_MIN, lib->ns);
|
||||
spi_max = lib->settings->get_int(lib->settings, "%s.spi_max",
|
||||
KERNEL_SPI_MAX, lib->ns);
|
||||
|
||||
if (get_spi_internal(this, src, dst, protocol, min(spi_min, spi_max),
|
||||
max(spi_min, spi_max), spi) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to get SPI");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
DBG2(DBG_KNL, "got SPI %.8x", ntohl(*spi));
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, get_cpi, status_t,
|
||||
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
|
||||
uint16_t *cpi)
|
||||
{
|
||||
uint32_t received_spi = 0;
|
||||
|
||||
if (get_spi_internal(this, src, dst, IPPROTO_COMP,
|
||||
0x100, 0xEFFF, &received_spi) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to get CPI");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
*cpi = htons((uint16_t)ntohl(received_spi));
|
||||
|
||||
DBG2(DBG_KNL, "got CPI %.4x", ntohs(*cpi));
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the mark for debug messages
|
||||
*/
|
||||
@@ -1384,6 +1276,136 @@ static bool add_uint32(struct nlmsghdr *hdr, int buflen,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a uint8 attribute to message
|
||||
*/
|
||||
static bool add_uint8(struct nlmsghdr *hdr, int buflen,
|
||||
enum xfrm_attr_type_t type, uint8_t value)
|
||||
{
|
||||
uint8_t *xvalue;
|
||||
|
||||
xvalue = netlink_reserve(hdr, buflen, type, sizeof(*xvalue));
|
||||
if (!xvalue)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
*xvalue = value;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SPI for a specific protocol from the kernel.
|
||||
*/
|
||||
static status_t get_spi_internal(private_kernel_netlink_ipsec_t *this,
|
||||
host_t *src, host_t *dst, uint8_t proto, uint32_t min, uint32_t max,
|
||||
uint32_t *spi)
|
||||
{
|
||||
netlink_buf_t request;
|
||||
struct nlmsghdr *hdr, *out;
|
||||
struct xfrm_userspi_info *userspi;
|
||||
uint32_t received_spi = 0;
|
||||
size_t len;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
|
||||
hdr = &request.hdr;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST;
|
||||
hdr->nlmsg_type = XFRM_MSG_ALLOCSPI;
|
||||
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userspi_info));
|
||||
|
||||
userspi = NLMSG_DATA(hdr);
|
||||
host2xfrm(src, &userspi->info.saddr);
|
||||
host2xfrm(dst, &userspi->info.id.daddr);
|
||||
userspi->info.id.proto = proto;
|
||||
userspi->info.mode = XFRM_MODE_TUNNEL;
|
||||
userspi->info.family = src->get_family(src);
|
||||
userspi->min = min;
|
||||
userspi->max = max;
|
||||
|
||||
if (!add_uint8(hdr, sizeof(request), XFRMA_SA_DIR, XFRM_SA_DIR_IN))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
|
||||
{
|
||||
hdr = out;
|
||||
while (NLMSG_OK(hdr, len))
|
||||
{
|
||||
switch (hdr->nlmsg_type)
|
||||
{
|
||||
case XFRM_MSG_NEWSA:
|
||||
{
|
||||
struct xfrm_usersa_info* usersa = NLMSG_DATA(hdr);
|
||||
received_spi = usersa->id.spi;
|
||||
break;
|
||||
}
|
||||
case NLMSG_ERROR:
|
||||
{
|
||||
netlink_log_error(hdr, "allocating SPI failed");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
hdr = NLMSG_NEXT(hdr, len);
|
||||
continue;
|
||||
case NLMSG_DONE:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
free(out);
|
||||
}
|
||||
|
||||
if (received_spi == 0)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
*spi = received_spi;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, get_spi, status_t,
|
||||
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
|
||||
uint8_t protocol, uint32_t *spi)
|
||||
{
|
||||
uint32_t spi_min, spi_max;
|
||||
|
||||
spi_min = lib->settings->get_int(lib->settings, "%s.spi_min",
|
||||
KERNEL_SPI_MIN, lib->ns);
|
||||
spi_max = lib->settings->get_int(lib->settings, "%s.spi_max",
|
||||
KERNEL_SPI_MAX, lib->ns);
|
||||
|
||||
if (get_spi_internal(this, src, dst, protocol, min(spi_min, spi_max),
|
||||
max(spi_min, spi_max), spi) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to get SPI");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
DBG2(DBG_KNL, "got SPI %.8x", ntohl(*spi));
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, get_cpi, status_t,
|
||||
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
|
||||
uint16_t *cpi)
|
||||
{
|
||||
uint32_t received_spi = 0;
|
||||
|
||||
if (get_spi_internal(this, src, dst, IPPROTO_COMP,
|
||||
0x100, 0xEFFF, &received_spi) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to get CPI");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
*cpi = htons((uint16_t)ntohl(received_spi));
|
||||
|
||||
DBG2(DBG_KNL, "got CPI %.4x", ntohs(*cpi));
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* ETHTOOL_GSSET_INFO is available since 2.6.34 and ETH_SS_FEATURES (enum) and
|
||||
* ETHTOOL_GFEATURES since 2.6.39, so check for the latter */
|
||||
#ifdef ETHTOOL_GFEATURES
|
||||
@@ -2046,6 +2068,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||
}
|
||||
}
|
||||
|
||||
if (!add_uint8(hdr, sizeof(request), XFRMA_SA_DIR,
|
||||
data->inbound ? XFRM_SA_DIR_IN : XFRM_SA_DIR_OUT))
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (id->proto != IPPROTO_COMP)
|
||||
{
|
||||
/* generally, we don't need a replay window for outbound SAs, however,
|
||||
|
||||
Reference in New Issue
Block a user