kernel-pfkey: Added IPComp support
- get_cpi function was implemented to retrieve a CPI from the kernel. - add_sa/update_sa/del_sa were updated to accommodate for IPComp SA. - Updated add_policy_internal to update the SPD to support IPComp.
This commit is contained in:
parent
8dcde902e4
commit
6afa7761a5
|
@ -13,6 +13,27 @@
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Nanoteq Pty Ltd
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
@ -825,18 +846,20 @@ static kernel_algorithm_t integrity_algs[] = {
|
||||||
{END_OF_LIST, 0, },
|
{END_OF_LIST, 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
|
||||||
/**
|
/**
|
||||||
* Algorithms for IPComp, unused yet
|
* Algorithms for IPComp, unused yet
|
||||||
*/
|
*/
|
||||||
static kernel_algorithm_t compression_algs[] = {
|
static kernel_algorithm_t compression_algs[] = {
|
||||||
/* {IPCOMP_OUI, 0 }, */
|
/* {IPCOMP_OUI, 0 }, */
|
||||||
{IPCOMP_DEFLATE, SADB_X_CALG_DEFLATE },
|
{IPCOMP_DEFLATE, SADB_X_CALG_DEFLATE },
|
||||||
|
#ifdef SADB_X_CALG_LZS
|
||||||
{IPCOMP_LZS, SADB_X_CALG_LZS },
|
{IPCOMP_LZS, SADB_X_CALG_LZS },
|
||||||
|
#endif
|
||||||
|
#ifdef SADB_X_CALG_LZJH
|
||||||
{IPCOMP_LZJH, SADB_X_CALG_LZJH },
|
{IPCOMP_LZJH, SADB_X_CALG_LZJH },
|
||||||
|
#endif
|
||||||
{END_OF_LIST, 0 },
|
{END_OF_LIST, 0 },
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up a kernel algorithm ID and its key size
|
* Look up a kernel algorithm ID and its key size
|
||||||
|
@ -854,6 +877,9 @@ static int lookup_algorithm(transform_type_t type, int ikev2)
|
||||||
case INTEGRITY_ALGORITHM:
|
case INTEGRITY_ALGORITHM:
|
||||||
list = integrity_algs;
|
list = integrity_algs;
|
||||||
break;
|
break;
|
||||||
|
case COMPRESSION_ALGORITHM:
|
||||||
|
list = compression_algs;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1483,9 +1509,13 @@ static bool receive_events(private_kernel_pfkey_ipsec_t *this, int fd,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(kernel_ipsec_t, get_spi, status_t,
|
/**
|
||||||
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
|
* Get an SPI for a specific protocol from the kernel.
|
||||||
u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
|
*/
|
||||||
|
|
||||||
|
static status_t get_spi_internal(private_kernel_pfkey_ipsec_t *this,
|
||||||
|
host_t *src, host_t *dst, u_int8_t proto, u_int32_t min, u_int32_t max,
|
||||||
|
u_int32_t reqid, u_int32_t *spi)
|
||||||
{
|
{
|
||||||
unsigned char request[PFKEY_BUFFER_SIZE];
|
unsigned char request[PFKEY_BUFFER_SIZE];
|
||||||
struct sadb_msg *msg, *out;
|
struct sadb_msg *msg, *out;
|
||||||
|
@ -1500,7 +1530,7 @@ METHOD(kernel_ipsec_t, get_spi, status_t,
|
||||||
msg = (struct sadb_msg*)request;
|
msg = (struct sadb_msg*)request;
|
||||||
msg->sadb_msg_version = PF_KEY_V2;
|
msg->sadb_msg_version = PF_KEY_V2;
|
||||||
msg->sadb_msg_type = SADB_GETSPI;
|
msg->sadb_msg_type = SADB_GETSPI;
|
||||||
msg->sadb_msg_satype = proto2satype(protocol);
|
msg->sadb_msg_satype = proto2satype(proto);
|
||||||
msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
|
msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
|
||||||
|
|
||||||
sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg);
|
sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg);
|
||||||
|
@ -1515,8 +1545,8 @@ METHOD(kernel_ipsec_t, get_spi, status_t,
|
||||||
range = (struct sadb_spirange*)PFKEY_EXT_ADD_NEXT(msg);
|
range = (struct sadb_spirange*)PFKEY_EXT_ADD_NEXT(msg);
|
||||||
range->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
|
range->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
|
||||||
range->sadb_spirange_len = PFKEY_LEN(sizeof(struct sadb_spirange));
|
range->sadb_spirange_len = PFKEY_LEN(sizeof(struct sadb_spirange));
|
||||||
range->sadb_spirange_min = 0xc0000000;
|
range->sadb_spirange_min = min;
|
||||||
range->sadb_spirange_max = 0xcFFFFFFF;
|
range->sadb_spirange_max = max;
|
||||||
PFKEY_EXT_ADD(msg, range);
|
PFKEY_EXT_ADD(msg, range);
|
||||||
|
|
||||||
if (pfkey_send(this, msg, &out, &len) == SUCCESS)
|
if (pfkey_send(this, msg, &out, &len) == SUCCESS)
|
||||||
|
@ -1542,11 +1572,42 @@ METHOD(kernel_ipsec_t, get_spi, status_t,
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(kernel_ipsec_t, get_spi, status_t,
|
||||||
|
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
|
||||||
|
u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
|
||||||
|
{
|
||||||
|
DBG2(DBG_KNL, "getting SPI for reqid {%u}", reqid);
|
||||||
|
|
||||||
|
if (get_spi_internal(this, src, dst, protocol,
|
||||||
|
0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "unable to get SPI for reqid {%u}", reqid);
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG2(DBG_KNL, "got SPI %.8x for reqid {%u}", ntohl(*spi), reqid);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(kernel_ipsec_t, get_cpi, status_t,
|
METHOD(kernel_ipsec_t, get_cpi, status_t,
|
||||||
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
|
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
|
||||||
u_int32_t reqid, u_int16_t *cpi)
|
u_int32_t reqid, u_int16_t *cpi)
|
||||||
{
|
{
|
||||||
return FAILED;
|
u_int32_t received_spi = 0;
|
||||||
|
|
||||||
|
DBG2(DBG_KNL, "getting CPI for reqid {%u}", reqid);
|
||||||
|
|
||||||
|
if (get_spi_internal(this, src, dst, IPPROTO_COMP,
|
||||||
|
0x100, 0xEFFF, reqid, &received_spi) != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "unable to get CPI for reqid {%u}", reqid);
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cpi = htons((u_int16_t)ntohl(received_spi));
|
||||||
|
|
||||||
|
DBG2(DBG_KNL, "got CPI %.4x for reqid {%u}", ntohs(*cpi), reqid);
|
||||||
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(kernel_ipsec_t, add_sa, status_t,
|
METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||||
|
@ -1565,6 +1626,20 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||||
struct sadb_key *key;
|
struct sadb_key *key;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
/* if IPComp is used, we install an additional IPComp SA. if the cpi is 0
|
||||||
|
* we are in the recursive call below */
|
||||||
|
if (ipcomp != IPCOMP_NONE && cpi != 0)
|
||||||
|
{
|
||||||
|
lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}};
|
||||||
|
add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, mark,
|
||||||
|
tfc, &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED,
|
||||||
|
chunk_empty, mode, ipcomp, 0, FALSE, FALSE, FALSE, inbound,
|
||||||
|
NULL, NULL);
|
||||||
|
ipcomp = IPCOMP_NONE;
|
||||||
|
/* use transport mode ESP SA, IPComp uses tunnel mode */
|
||||||
|
mode = MODE_TRANSPORT;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&request, 0, sizeof(request));
|
memset(&request, 0, sizeof(request));
|
||||||
|
|
||||||
DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}",
|
DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}",
|
||||||
|
@ -1595,9 +1670,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||||
sa->sadb_sa_exttype = SADB_EXT_SA;
|
sa->sadb_sa_exttype = SADB_EXT_SA;
|
||||||
sa->sadb_sa_len = PFKEY_LEN(len);
|
sa->sadb_sa_len = PFKEY_LEN(len);
|
||||||
sa->sadb_sa_spi = spi;
|
sa->sadb_sa_spi = spi;
|
||||||
sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32;
|
if (protocol == IPPROTO_COMP)
|
||||||
sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg);
|
{
|
||||||
sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg);
|
sa->sadb_sa_encrypt = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sa->sadb_sa_replay = 32;
|
||||||
|
sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg);
|
||||||
|
sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg);
|
||||||
|
}
|
||||||
PFKEY_EXT_ADD(msg, sa);
|
PFKEY_EXT_ADD(msg, sa);
|
||||||
|
|
||||||
sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg);
|
sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg);
|
||||||
|
@ -1668,11 +1750,6 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||||
PFKEY_EXT_ADD(msg, key);
|
PFKEY_EXT_ADD(msg, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipcomp != IPCOMP_NONE)
|
|
||||||
{
|
|
||||||
/*TODO*/
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_NATT
|
#ifdef HAVE_NATT
|
||||||
if (encap)
|
if (encap)
|
||||||
{
|
{
|
||||||
|
@ -1719,6 +1796,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
|
||||||
return NOT_SUPPORTED;
|
return NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if IPComp is used, we first update the IPComp SA */
|
||||||
|
if (cpi)
|
||||||
|
{
|
||||||
|
update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0,
|
||||||
|
src, dst, new_src, new_dst, FALSE, FALSE, mark);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&request, 0, sizeof(request));
|
memset(&request, 0, sizeof(request));
|
||||||
|
|
||||||
DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi));
|
DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi));
|
||||||
|
@ -1919,6 +2003,12 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
|
||||||
struct sadb_sa *sa;
|
struct sadb_sa *sa;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
/* if IPComp was used, we first delete the additional IPComp SA */
|
||||||
|
if (cpi)
|
||||||
|
{
|
||||||
|
del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0, mark);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&request, 0, sizeof(request));
|
memset(&request, 0, sizeof(request));
|
||||||
|
|
||||||
DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi));
|
DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi));
|
||||||
|
@ -2230,6 +2320,7 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this,
|
||||||
ipsec_sa_t *ipsec = mapping->sa;
|
ipsec_sa_t *ipsec = mapping->sa;
|
||||||
pfkey_msg_t response;
|
pfkey_msg_t response;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
ipsec_mode_t proto_mode;
|
||||||
|
|
||||||
memset(&request, 0, sizeof(request));
|
memset(&request, 0, sizeof(request));
|
||||||
|
|
||||||
|
@ -2251,15 +2342,43 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this,
|
||||||
|
|
||||||
/* one or more sadb_x_ipsecrequest extensions are added to the
|
/* one or more sadb_x_ipsecrequest extensions are added to the
|
||||||
* sadb_x_policy extension */
|
* sadb_x_policy extension */
|
||||||
|
proto_mode = ipsec->cfg.mode;
|
||||||
|
|
||||||
req = (struct sadb_x_ipsecrequest*)(pol + 1);
|
req = (struct sadb_x_ipsecrequest*)(pol + 1);
|
||||||
|
|
||||||
|
if (ipsec->cfg.ipcomp.transform != IPCOMP_NONE)
|
||||||
|
{
|
||||||
|
req->sadb_x_ipsecrequest_proto = IPPROTO_COMP;
|
||||||
|
|
||||||
|
/* !!! the length here MUST be in octets instead of 64 bit words */
|
||||||
|
req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest);
|
||||||
|
req->sadb_x_ipsecrequest_mode = mode2kernel(ipsec->cfg.mode);
|
||||||
|
req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid;
|
||||||
|
req->sadb_x_ipsecrequest_level = (policy->direction == POLICY_OUT) ?
|
||||||
|
IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_USE;
|
||||||
|
if (ipsec->cfg.mode == MODE_TUNNEL)
|
||||||
|
{
|
||||||
|
len = hostcpy(req + 1, ipsec->src, FALSE);
|
||||||
|
req->sadb_x_ipsecrequest_len += len;
|
||||||
|
len = hostcpy((char*)(req + 1) + len, ipsec->dst, FALSE);
|
||||||
|
req->sadb_x_ipsecrequest_len += len;
|
||||||
|
/* use transport mode for other SAs */
|
||||||
|
proto_mode = MODE_TRANSPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pol->sadb_x_policy_len += PFKEY_LEN(req->sadb_x_ipsecrequest_len);
|
||||||
|
req = (struct sadb_x_ipsecrequest*)((char*)(req) +
|
||||||
|
req->sadb_x_ipsecrequest_len);
|
||||||
|
}
|
||||||
|
|
||||||
req->sadb_x_ipsecrequest_proto = ipsec->cfg.esp.use ? IPPROTO_ESP
|
req->sadb_x_ipsecrequest_proto = ipsec->cfg.esp.use ? IPPROTO_ESP
|
||||||
: IPPROTO_AH;
|
: IPPROTO_AH;
|
||||||
/* !!! the length here MUST be in octets instead of 64 bit words */
|
/* !!! the length here MUST be in octets instead of 64 bit words */
|
||||||
req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest);
|
req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest);
|
||||||
req->sadb_x_ipsecrequest_mode = mode2kernel(ipsec->cfg.mode);
|
req->sadb_x_ipsecrequest_mode = mode2kernel(proto_mode);
|
||||||
req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid;
|
req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid;
|
||||||
req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE;
|
req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE;
|
||||||
if (ipsec->cfg.mode == MODE_TUNNEL)
|
if (proto_mode == MODE_TUNNEL)
|
||||||
{
|
{
|
||||||
len = hostcpy(req + 1, ipsec->src, FALSE);
|
len = hostcpy(req + 1, ipsec->src, FALSE);
|
||||||
req->sadb_x_ipsecrequest_len += len;
|
req->sadb_x_ipsecrequest_len += len;
|
||||||
|
|
Loading…
Reference in New Issue