From: Martin Willi Date: Fri, 12 Apr 2013 11:56:03 +0000 (+0200) Subject: kernel-utun: add_sa() installs SA to utun X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=f361ef6b3211fd3e7705c06eebd2da07a72e1fd0;p=thirdparty%2Fstrongswan.git kernel-utun: add_sa() installs SA to utun --- diff --git a/src/libhydra/plugins/kernel_utun/kernel_utun_ipsec.c b/src/libhydra/plugins/kernel_utun/kernel_utun_ipsec.c index 00a7afa02e..a0ccb5b90d 100644 --- a/src/libhydra/plugins/kernel_utun/kernel_utun_ipsec.c +++ b/src/libhydra/plugins/kernel_utun/kernel_utun_ipsec.c @@ -14,10 +14,28 @@ */ #include "kernel_utun_ipsec.h" +#include "kernel_utun_net.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include typedef struct private_kernel_utun_ipsec_t private_kernel_utun_ipsec_t; @@ -66,6 +84,148 @@ METHOD(kernel_ipsec_t, get_cpi, status_t, return FAILED; } +/** + * Integrity IKEv2 identifiers => utun identifiers + */ +static struct { + integrity_algorithm_t alg; + if_utun_crypto_ipsec_auth_t utun; +} int_alg_map[] = { + { AUTH_HMAC_MD5_96, IF_UTUN_CRYPTO_IPSEC_AUTH_MD5 }, + { AUTH_HMAC_SHA1_96, IF_UTUN_CRYPTO_IPSEC_AUTH_SHA1 }, + { AUTH_HMAC_SHA2_256_128, IF_UTUN_CRYPTO_IPSEC_AUTH_SHA256 }, + { AUTH_HMAC_SHA2_384_192, IF_UTUN_CRYPTO_IPSEC_AUTH_SHA384 }, + { AUTH_HMAC_SHA2_512_256, IF_UTUN_CRYPTO_IPSEC_AUTH_SHA512 }, +}; + +/** + * Mapping function for integrity algs + */ +static if_utun_crypto_ipsec_auth_t map_int_alg(integrity_algorithm_t alg) +{ + int i; + + for (i = 0; i < countof(int_alg_map); i++) + { + if (int_alg_map[i].alg == alg) + { + return int_alg_map[i].utun; + } + } + return IF_UTUN_CRYPTO_IPSEC_AUTH_NONE; +} + +/** + * Encryption IKEv2 identifiers => utun identifiers + */ +static struct { + encryption_algorithm_t alg; + int key_size; + if_utun_crypto_ipsec_enc_t utun; +} enc_alg_map[] = { + { ENCR_DES, 0, IF_UTUN_CRYPTO_IPSEC_ENC_DES }, + { ENCR_3DES, 0, IF_UTUN_CRYPTO_IPSEC_ENC_3DES }, + { ENCR_AES_CBC, 16, IF_UTUN_CRYPTO_IPSEC_ENC_AES128 }, + { ENCR_AES_CBC, 32, IF_UTUN_CRYPTO_IPSEC_ENC_AES256 }, +}; + +/** + * Mapping function for encryption algs + */ +static if_utun_crypto_ipsec_enc_t map_enc_alg(encryption_algorithm_t alg, + int key_size) +{ + int i; + + for (i = 0; i < countof(int_alg_map); i++) + { + if (enc_alg_map[i].alg == alg) + { + if (enc_alg_map[i].key_size == 0 || + enc_alg_map[i].key_size == key_size) + { + return enc_alg_map[i].utun; + } + } + } + return IF_UTUN_CRYPTO_IPSEC_ENC_NONE; +} + +/** + * Install an SA to a crypto-enabled utun device + */ +static status_t add_sa_tun(private_kernel_utun_ipsec_t *this, tun_device_t *tun, + host_t *src, host_t *dst, u_int32_t spi, u_int32_t reqid, + u_int16_t enc_alg, chunk_t enc_key, u_int16_t int_alg, chunk_t int_key, + bool encap, bool inbound, u_int64_t hard, u_int64_t soft) +{ + struct __attribute__((__packed__)){ + utun_crypto_keys_args_t args; + u_int8_t auth[int_key.len]; + u_int8_t enc[enc_key.len]; + } keys; + + keys.args = (utun_crypto_keys_args_t) { + .ver = UTUN_CRYPTO_VER_1, + .type = UTUN_CRYPTO_TYPE_IPSEC, + .dir = inbound ? UTUN_CRYPTO_DIR_IN : UTUN_CRYPTO_DIR_OUT, + .args_ulen = sizeof(utun_crypto_keys_ipsec_args_v1_t), + .varargs_buflen = int_key.len + enc_key.len, + .u = { + .ipsec_v1 = { + .proto = IF_UTUN_CRYPTO_IPSEC_PROTO_ESP, + .mode = IF_UTUN_CRYPTO_IPSEC_MODE_TUNNEL, + .alg_auth = map_int_alg(int_alg), + .alg_enc = map_enc_alg(enc_alg, enc_key.len), + .keepalive = IF_UTUN_CRYPTO_IPSEC_KEEPALIVE_NONE, + .natd = IF_UTUN_CRYPTO_IPSEC_NATD_NONE, + .replay = 32, + .key_auth_len = int_key.len * 8, + .key_enc_len = enc_key.len * 8, + .spi = spi, + .pid = getpid(), + .reqid = reqid, + .lifetime_hard = hard, + .lifetime_soft = soft, + }, + }, + }; + + if (keys.args.u.ipsec_v1.alg_auth == IF_UTUN_CRYPTO_IPSEC_AUTH_NONE) + { + DBG1(DBG_KNL, "%N integrity not supported by utun", + integrity_algorithm_names, int_alg); + return NOT_SUPPORTED; + } + if (keys.args.u.ipsec_v1.alg_enc == IF_UTUN_CRYPTO_IPSEC_ENC_NONE) + { + DBG1(DBG_KNL, "%N encryption not supported by utun", + encryption_algorithm_names, enc_alg); + return NOT_SUPPORTED; + } + + if (encap) + { + keys.args.u.ipsec_v1.natd = IF_UTUN_CRYPTO_IPSEC_NATD_MINE; + keys.args.u.ipsec_v1.keepalive = IF_UTUN_CRYPTO_IPSEC_KEEPALIVE_NATT; + } + memcpy(keys.auth, int_key.ptr, int_key.len); + memcpy(keys.enc, enc_key.ptr, enc_key.len); + memcpy(&keys.args.u.ipsec_v1.src_addr, + src->get_sockaddr(src), *src->get_sockaddr_len(src)); + memcpy(&keys.args.u.ipsec_v1.dst_addr, + dst->get_sockaddr(dst), *dst->get_sockaddr_len(dst)); + + if (setsockopt(tun->get_fd(tun), SYSPROTO_CONTROL, + UTUN_OPT_CONFIG_CRYPTO_KEYS, &keys, sizeof(keys)) < 0) + { + DBG1(DBG_KNL, "adding SA to %s failed: %s", + tun->get_name(tun), strerror(errno)); + return FAILED; + } + return SUCCESS; +} + METHOD(kernel_ipsec_t, add_sa, status_t, private_kernel_utun_ipsec_t *this, host_t *src, host_t *dst, u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark, @@ -74,7 +234,33 @@ METHOD(kernel_ipsec_t, add_sa, status_t, u_int16_t cpi, bool encap, bool esn, bool inbound, traffic_selector_t* src_ts, traffic_selector_t* dst_ts) { - return FAILED; + enumerator_t *enumerator; + tun_device_t *tun; + traffic_selector_t *ts; + status_t status = NOT_FOUND; + host_t *host; + + if (protocol != IPPROTO_ESP || mode != MODE_TUNNEL || esn) + { + return NOT_SUPPORTED; + } + + ts = inbound ? dst_ts : src_ts; + enumerator = kernel_utun_create_enumerator(); + while (enumerator->enumerate(enumerator, &tun)) + { + host = tun->get_address(tun, NULL); + if (host && ts->includes(ts, host)) + { + status = add_sa_tun(this, tun, src, dst, spi, reqid, + enc_alg, enc_key, int_alg, int_key, encap, inbound, + lifetime->time.life, lifetime->time.rekey); + break; + } + } + enumerator->destroy(enumerator); + + return status; } METHOD(kernel_ipsec_t, query_sa, status_t, @@ -112,7 +298,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark, policy_priority_t priority) { - return FAILED; + return SUCCESS; } METHOD(kernel_ipsec_t, query_policy, status_t,