Copy ESN enabled replay state during update_sa, if supported
This commit is contained in:
parent
ee8c89e2ee
commit
05e9589783
|
@ -353,9 +353,14 @@ struct private_kernel_netlink_ipsec_t {
|
||||||
bool install_routes;
|
bool install_routes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of the replay window
|
* Size of the replay window, in packets
|
||||||
*/
|
*/
|
||||||
u_int32_t replay_window;
|
u_int32_t replay_window;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the replay window bitmap, in bytes
|
||||||
|
*/
|
||||||
|
u_int32_t replay_bmp;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1199,8 +1204,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||||
|
|
||||||
replay = (struct xfrm_replay_state_esn*)RTA_DATA(rthdr);
|
replay = (struct xfrm_replay_state_esn*)RTA_DATA(rthdr);
|
||||||
/* bmp_len contains number uf __u32's */
|
/* bmp_len contains number uf __u32's */
|
||||||
replay->bmp_len = (this->replay_window + sizeof(u_int32_t) * 8 - 1)
|
replay->bmp_len = this->replay_bmp;
|
||||||
/ (sizeof(u_int32_t) * 8);
|
|
||||||
replay->replay_window = this->replay_window;
|
replay->replay_window = this->replay_window;
|
||||||
|
|
||||||
rthdr = XFRM_RTA_NEXT(rthdr);
|
rthdr = XFRM_RTA_NEXT(rthdr);
|
||||||
|
@ -1232,11 +1236,14 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the replay state (i.e. sequence numbers) of an SA.
|
* Get the ESN replay state (i.e. sequence numbers) of an SA.
|
||||||
|
*
|
||||||
|
* Allocates into one the replay state structure we get from the kernel.
|
||||||
*/
|
*/
|
||||||
static status_t get_replay_state(private_kernel_netlink_ipsec_t *this,
|
static void get_replay_state(private_kernel_netlink_ipsec_t *this,
|
||||||
u_int32_t spi, u_int8_t protocol, host_t *dst,
|
u_int32_t spi, u_int8_t protocol, host_t *dst,
|
||||||
struct xfrm_replay_state *replay)
|
struct xfrm_replay_state_esn **replay_esn,
|
||||||
|
struct xfrm_replay_state **replay)
|
||||||
{
|
{
|
||||||
netlink_buf_t request;
|
netlink_buf_t request;
|
||||||
struct nlmsghdr *hdr, *out = NULL;
|
struct nlmsghdr *hdr, *out = NULL;
|
||||||
|
@ -1247,7 +1254,8 @@ static status_t get_replay_state(private_kernel_netlink_ipsec_t *this,
|
||||||
|
|
||||||
memset(&request, 0, sizeof(request));
|
memset(&request, 0, sizeof(request));
|
||||||
|
|
||||||
DBG2(DBG_KNL, "querying replay state from SAD entry with SPI %.8x", ntohl(spi));
|
DBG2(DBG_KNL, "querying replay state from SAD entry with SPI %.8x",
|
||||||
|
ntohl(spi));
|
||||||
|
|
||||||
hdr = (struct nlmsghdr*)request;
|
hdr = (struct nlmsghdr*)request;
|
||||||
hdr->nlmsg_flags = NLM_F_REQUEST;
|
hdr->nlmsg_flags = NLM_F_REQUEST;
|
||||||
|
@ -1291,32 +1299,30 @@ static status_t get_replay_state(private_kernel_netlink_ipsec_t *this,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out_aevent == NULL)
|
if (out_aevent)
|
||||||
{
|
{
|
||||||
DBG1(DBG_KNL, "unable to query replay state from SAD entry with SPI %.8x",
|
rta = XFRM_RTA(out, struct xfrm_aevent_id);
|
||||||
ntohl(spi));
|
rtasize = XFRM_PAYLOAD(out, struct xfrm_aevent_id);
|
||||||
free(out);
|
while (RTA_OK(rta, rtasize))
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
rta = XFRM_RTA(out, struct xfrm_aevent_id);
|
|
||||||
rtasize = XFRM_PAYLOAD(out, struct xfrm_aevent_id);
|
|
||||||
while(RTA_OK(rta, rtasize))
|
|
||||||
{
|
|
||||||
if (rta->rta_type == XFRMA_REPLAY_VAL &&
|
|
||||||
RTA_PAYLOAD(rta) == sizeof(struct xfrm_replay_state))
|
|
||||||
{
|
{
|
||||||
memcpy(replay, RTA_DATA(rta), RTA_PAYLOAD(rta));
|
if (rta->rta_type == XFRMA_REPLAY_VAL &&
|
||||||
free(out);
|
RTA_PAYLOAD(rta) == sizeof(**replay))
|
||||||
return SUCCESS;
|
{
|
||||||
|
*replay = malloc(RTA_PAYLOAD(rta));
|
||||||
|
memcpy(*replay, RTA_DATA(rta), RTA_PAYLOAD(rta));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rta->rta_type == XFRMA_REPLAY_ESN_VAL &&
|
||||||
|
RTA_PAYLOAD(rta) >= sizeof(**replay_esn) + this->replay_bmp)
|
||||||
|
{
|
||||||
|
*replay_esn = malloc(RTA_PAYLOAD(rta));
|
||||||
|
memcpy(*replay_esn, RTA_DATA(rta), RTA_PAYLOAD(rta));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rta = RTA_NEXT(rta, rtasize);
|
||||||
}
|
}
|
||||||
rta = RTA_NEXT(rta, rtasize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG1(DBG_KNL, "unable to query replay state from SAD entry with SPI %.8x",
|
|
||||||
ntohl(spi));
|
|
||||||
free(out);
|
free(out);
|
||||||
return FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(kernel_ipsec_t, query_sa, status_t,
|
METHOD(kernel_ipsec_t, query_sa, status_t,
|
||||||
|
@ -1515,8 +1521,9 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
|
||||||
struct rtattr *rta;
|
struct rtattr *rta;
|
||||||
size_t rtasize;
|
size_t rtasize;
|
||||||
struct xfrm_encap_tmpl* tmpl = NULL;
|
struct xfrm_encap_tmpl* tmpl = NULL;
|
||||||
bool got_replay_state = FALSE;
|
struct xfrm_replay_state *replay = NULL;
|
||||||
struct xfrm_replay_state replay;
|
struct xfrm_replay_state_esn *replay_esn = NULL;
|
||||||
|
status_t status = FAILED;
|
||||||
|
|
||||||
/* if IPComp is used, we first update the IPComp SA */
|
/* if IPComp is used, we first update the IPComp SA */
|
||||||
if (cpi)
|
if (cpi)
|
||||||
|
@ -1572,22 +1579,16 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
|
||||||
if (out_sa == NULL)
|
if (out_sa == NULL)
|
||||||
{
|
{
|
||||||
DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi));
|
DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi));
|
||||||
free(out);
|
goto failed;
|
||||||
return FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to get the replay state */
|
get_replay_state(this, spi, protocol, dst, &replay_esn, &replay);
|
||||||
if (get_replay_state(this, spi, protocol, dst, &replay) == SUCCESS)
|
|
||||||
{
|
|
||||||
got_replay_state = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* delete the old SA (without affecting the IPComp SA) */
|
/* delete the old SA (without affecting the IPComp SA) */
|
||||||
if (del_sa(this, src, dst, spi, protocol, 0, mark) != SUCCESS)
|
if (del_sa(this, src, dst, spi, protocol, 0, mark) != SUCCESS)
|
||||||
{
|
{
|
||||||
DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x", ntohl(spi));
|
DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x", ntohl(spi));
|
||||||
free(out);
|
goto failed;
|
||||||
return FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
|
DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
|
||||||
|
@ -1640,7 +1641,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
|
||||||
hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
|
hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
|
||||||
if (hdr->nlmsg_len > sizeof(request))
|
if (hdr->nlmsg_len > sizeof(request))
|
||||||
{
|
{
|
||||||
return FAILED;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta);
|
tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta);
|
||||||
|
@ -1652,30 +1653,55 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
|
||||||
rta = XFRM_RTA_NEXT(rta);
|
rta = XFRM_RTA_NEXT(rta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (got_replay_state)
|
if (replay_esn)
|
||||||
{ /* copy the replay data if available */
|
{
|
||||||
|
rta->rta_type = XFRMA_REPLAY_ESN_VAL;
|
||||||
|
rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) +
|
||||||
|
this->replay_bmp);
|
||||||
|
|
||||||
|
hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
|
||||||
|
if (hdr->nlmsg_len > sizeof(request))
|
||||||
|
{
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
memcpy(RTA_DATA(rta), replay_esn,
|
||||||
|
sizeof(struct xfrm_replay_state_esn) + this->replay_bmp);
|
||||||
|
|
||||||
|
rta = XFRM_RTA_NEXT(rta);
|
||||||
|
}
|
||||||
|
else if (replay)
|
||||||
|
{
|
||||||
rta->rta_type = XFRMA_REPLAY_VAL;
|
rta->rta_type = XFRMA_REPLAY_VAL;
|
||||||
rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state));
|
rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state));
|
||||||
|
|
||||||
hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
|
hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
|
||||||
if (hdr->nlmsg_len > sizeof(request))
|
if (hdr->nlmsg_len > sizeof(request))
|
||||||
{
|
{
|
||||||
return FAILED;
|
goto failed;
|
||||||
}
|
}
|
||||||
memcpy(RTA_DATA(rta), &replay, sizeof(replay));
|
memcpy(RTA_DATA(rta), replay, sizeof(replay));
|
||||||
|
|
||||||
rta = XFRM_RTA_NEXT(rta);
|
rta = XFRM_RTA_NEXT(rta);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "unable to copy replay state from old SAD entry "
|
||||||
|
"with SPI %.8x", ntohl(spi));
|
||||||
|
}
|
||||||
|
|
||||||
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
|
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
|
||||||
{
|
{
|
||||||
DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi));
|
DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi));
|
||||||
free(out);
|
goto failed;
|
||||||
return FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = SUCCESS;
|
||||||
|
failed:
|
||||||
|
free(replay);
|
||||||
|
free(replay_esn);
|
||||||
free(out);
|
free(out);
|
||||||
|
|
||||||
return SUCCESS;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(kernel_ipsec_t, add_policy, status_t,
|
METHOD(kernel_ipsec_t, add_policy, status_t,
|
||||||
|
@ -2243,6 +2269,9 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
||||||
"%s.replay_window", DEFAULT_REPLAY_WINDOW, hydra->daemon),
|
"%s.replay_window", DEFAULT_REPLAY_WINDOW, hydra->daemon),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this->replay_bmp = (this->replay_window + sizeof(u_int32_t) * 8 - 1) /
|
||||||
|
(sizeof(u_int32_t) * 8);
|
||||||
|
|
||||||
if (streq(hydra->daemon, "pluto"))
|
if (streq(hydra->daemon, "pluto"))
|
||||||
{ /* no routes for pluto, they are installed via updown script */
|
{ /* no routes for pluto, they are installed via updown script */
|
||||||
this->install_routes = FALSE;
|
this->install_routes = FALSE;
|
||||||
|
|
Loading…
Reference in New Issue