diff options
author | Francois ten Krooden <ftk@nanoteq.com> | 2014-04-22 15:34:41 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2014-04-24 17:36:17 +0200 |
commit | 6afa7761a5404f7eb45dd9445fca37d87314f030 (patch) | |
tree | 77258948d6690da8aa3e46b098c7ddb3a91dd6b2 /src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | |
parent | 8dcde902e4e7951748926146232e709478940dac (diff) | |
download | strongswan-6afa7761a5404f7eb45dd9445fca37d87314f030.tar.bz2 strongswan-6afa7761a5404f7eb45dd9445fca37d87314f030.tar.xz |
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.
Diffstat (limited to 'src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c')
-rw-r--r-- | src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 157 |
1 files changed, 138 insertions, 19 deletions
diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 4704d419f..d82d6720d 100644 --- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -13,6 +13,27 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * 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/socket.h> @@ -825,18 +846,20 @@ static kernel_algorithm_t integrity_algs[] = { {END_OF_LIST, 0, }, }; -#if 0 /** * Algorithms for IPComp, unused yet */ static kernel_algorithm_t compression_algs[] = { /* {IPCOMP_OUI, 0 }, */ {IPCOMP_DEFLATE, SADB_X_CALG_DEFLATE }, +#ifdef SADB_X_CALG_LZS {IPCOMP_LZS, SADB_X_CALG_LZS }, +#endif +#ifdef SADB_X_CALG_LZJH {IPCOMP_LZJH, SADB_X_CALG_LZJH }, +#endif {END_OF_LIST, 0 }, }; -#endif /** * 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: list = integrity_algs; break; + case COMPRESSION_ALGORITHM: + list = compression_algs; + break; default: return 0; } @@ -1483,9 +1509,13 @@ static bool receive_events(private_kernel_pfkey_ipsec_t *this, int fd, return TRUE; } -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) +/** + * Get an SPI for a specific protocol from the kernel. + */ + +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]; struct sadb_msg *msg, *out; @@ -1500,7 +1530,7 @@ METHOD(kernel_ipsec_t, get_spi, status_t, msg = (struct sadb_msg*)request; msg->sadb_msg_version = PF_KEY_V2; 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)); 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->sadb_spirange_exttype = SADB_EXT_SPIRANGE; range->sadb_spirange_len = PFKEY_LEN(sizeof(struct sadb_spirange)); - range->sadb_spirange_min = 0xc0000000; - range->sadb_spirange_max = 0xcFFFFFFF; + range->sadb_spirange_min = min; + range->sadb_spirange_max = max; PFKEY_EXT_ADD(msg, range); if (pfkey_send(this, msg, &out, &len) == SUCCESS) @@ -1542,11 +1572,42 @@ METHOD(kernel_ipsec_t, get_spi, status_t, 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, private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, 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, @@ -1565,6 +1626,20 @@ METHOD(kernel_ipsec_t, add_sa, status_t, struct sadb_key *key; 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)); 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_len = PFKEY_LEN(len); sa->sadb_sa_spi = spi; - sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32; - sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); - sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); + if (protocol == IPPROTO_COMP) + { + 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); 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); } - if (ipcomp != IPCOMP_NONE) - { - /*TODO*/ - } - #ifdef HAVE_NATT if (encap) { @@ -1719,6 +1796,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t, 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)); 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; 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)); 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; pfkey_msg_t response; size_t len; + ipsec_mode_t proto_mode; 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 * sadb_x_policy extension */ + proto_mode = ipsec->cfg.mode; + 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 : IPPROTO_AH; /* !!! 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_mode = mode2kernel(proto_mode); req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid; 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); req->sadb_x_ipsecrequest_len += len; |