diff options
author | Tobias Brunner <tobias@strongswan.org> | 2008-05-08 16:19:11 +0000 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2008-05-08 16:19:11 +0000 |
commit | d4aad55434b121df0a774265aac81082b4525ddf (patch) | |
tree | 4d460cd8f328f1645ada771d9dcadc1956c1f583 /src | |
parent | 0f074a4344f002fa3f1440fbcdfc5b28ce0b5afb (diff) | |
download | strongswan-d4aad55434b121df0a774265aac81082b4525ddf.tar.bz2 strongswan-d4aad55434b121df0a774265aac81082b4525ddf.tar.xz |
IPComp for IKEv2
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/config/child_cfg.c | 27 | ||||
-rw-r--r-- | src/charon/config/child_cfg.h | 32 | ||||
-rw-r--r-- | src/charon/encoding/payloads/notify_payload.c | 8 | ||||
-rw-r--r-- | src/charon/kernel/kernel_interface.c | 175 | ||||
-rw-r--r-- | src/charon/kernel/kernel_interface.h | 23 | ||||
-rw-r--r-- | src/charon/plugins/sql/mysql.sql | 1 | ||||
-rw-r--r-- | src/charon/plugins/sql/sql_config.c | 8 | ||||
-rw-r--r-- | src/charon/plugins/sql/sqlite.sql | 3 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_config.c | 2 | ||||
-rw-r--r-- | src/charon/sa/child_sa.c | 94 | ||||
-rw-r--r-- | src/charon/sa/child_sa.h | 19 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 2 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_create.c | 112 | ||||
-rw-r--r-- | src/starter/starterstroke.c | 1 | ||||
-rw-r--r-- | src/stroke/stroke_msg.h | 1 |
15 files changed, 452 insertions, 56 deletions
diff --git a/src/charon/config/child_cfg.c b/src/charon/config/child_cfg.c index 2c7201972..33dd73c44 100644 --- a/src/charon/config/child_cfg.c +++ b/src/charon/config/child_cfg.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2008 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -34,6 +35,15 @@ ENUM(action_names, ACTION_NONE, ACTION_RESTART, "ACTION_RESTART", ); +ENUM_BEGIN(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_NONE, + "IPCOMP_NONE"); +ENUM_NEXT(ipcomp_transform_names, IPCOMP_OUI, IPCOMP_LZJH, IPCOMP_NONE, + "IPCOMP_OUI", + "IPCOMP_DEFLATE", + "IPCOMP_LZS", + "IPCOMP_LZJH"); +ENUM_END(ipcomp_transform_names, IPCOMP_LZJH); + typedef struct private_child_cfg_t private_child_cfg_t; /** @@ -111,6 +121,11 @@ struct private_child_cfg_t { * substracted from rekeytime. */ u_int32_t jitter; + + /** + * enable IPComp + */ + bool use_ipcomp; }; /** @@ -399,6 +414,14 @@ static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this) } /** + * Implementation of child_cfg_t.use_ipcomp. + */ +static bool use_ipcomp(private_child_cfg_t *this) +{ + return this->use_ipcomp; +} + +/** * Implementation of child_cfg_t.get_name */ static child_cfg_t* get_ref(private_child_cfg_t *this) @@ -432,7 +455,7 @@ static void destroy(private_child_cfg_t *this) child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, u_int32_t rekeytime, u_int32_t jitter, char *updown, bool hostaccess, mode_t mode, - action_t dpd_action, action_t close_action) + action_t dpd_action, action_t close_action, bool ipcomp) { private_child_cfg_t *this = malloc_thing(private_child_cfg_t); @@ -449,6 +472,7 @@ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, this->public.get_close_action = (action_t (*) (child_cfg_t *))get_close_action; this->public.get_lifetime = (u_int32_t (*) (child_cfg_t *,bool))get_lifetime; this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group; + this->public.use_ipcomp = (bool (*) (child_cfg_t *))use_ipcomp; this->public.get_ref = (child_cfg_t* (*) (child_cfg_t*))get_ref; this->public.destroy = (void (*) (child_cfg_t*))destroy; @@ -461,6 +485,7 @@ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, this->mode = mode; this->dpd_action = dpd_action; this->close_action = close_action; + this->use_ipcomp = ipcomp; this->refcount = 1; this->proposals = linked_list_create(); this->my_ts = linked_list_create(); diff --git a/src/charon/config/child_cfg.h b/src/charon/config/child_cfg.h index 3d4889b53..228f0d888 100644 --- a/src/charon/config/child_cfg.h +++ b/src/charon/config/child_cfg.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2008 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -26,6 +27,7 @@ typedef enum mode_t mode_t; typedef enum action_t action_t; +typedef enum ipcomp_transform_t ipcomp_transform_t; typedef struct child_cfg_t child_cfg_t; #include <library.h> @@ -69,6 +71,22 @@ enum action_t { extern enum_name_t *action_names; /** + * IPComp transform IDs, as in RFC 4306 + */ +enum ipcomp_transform_t { + IPCOMP_NONE = 241, + IPCOMP_OUI = 1, + IPCOMP_DEFLATE = 2, + IPCOMP_LZS = 3, + IPCOMP_LZJH = 4, +}; + +/** + * enum strings for ipcomp_transform_t. + */ +extern enum_name_t *ipcomp_transform_names; + +/** * A child_cfg_t defines the config template for a CHILD_SA. * * After creation, proposals and traffic selectors may be added to the config. @@ -214,6 +232,14 @@ struct child_cfg_t { diffie_hellman_group_t (*get_dh_group)(child_cfg_t *this); /** + * Check whether IPComp should be used, if the other peer supports it. + * + * @return TRUE, if IPComp should be used + * FALSE, otherwise + */ + bool (*use_ipcomp)(child_cfg_t *this); + + /** * Increase the reference count. * * @return reference to this @@ -247,12 +273,14 @@ struct child_cfg_t { * @param hostaccess TRUE to allow access to the local host * @param mode mode to propose for CHILD_SA, transport, tunnel or BEET * @param dpd_action DPD action - * @param close_action lose action + * @param close_action close action + * @param ipcomp use IPComp, if peer supports it * @return child_cfg_t object */ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, u_int32_t rekeytime, u_int32_t jitter, char *updown, bool hostaccess, mode_t mode, - action_t dpd_action, action_t close_action); + action_t dpd_action, action_t close_action, + bool ipcomp); #endif /* CHILD_CFG_H_ @} */ diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c index ec22d0688..6bf260d68 100644 --- a/src/charon/encoding/payloads/notify_payload.c +++ b/src/charon/encoding/payloads/notify_payload.c @@ -332,6 +332,14 @@ static status_t verify(private_notify_payload_t *this) } break; } + case IPCOMP_SUPPORTED: + { + if (this->notification_data.len != 3) + { + bad_length = TRUE; + } + break; + } case ME_ENDPOINT: if (this->notification_data.len != 8 && this->notification_data.len != 12 && diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c index b1cabfa06..43837a29c 100644 --- a/src/charon/kernel/kernel_interface.c +++ b/src/charon/kernel/kernel_interface.c @@ -1,6 +1,6 @@ /* + * Copyright (C) 2006-2008 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi - * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -143,6 +143,17 @@ static kernel_algorithm_t integrity_algs[] = { }; /** + * Algorithms for IPComp + */ +static kernel_algorithm_t compression_algs[] = { +/* {IPCOMP_OUI, "***", 0}, */ + {IPCOMP_DEFLATE, "deflate", 0}, + {IPCOMP_LZS, "lzs", 0}, + {IPCOMP_LZJH, "lzjh", 0}, + {END_OF_LIST, NULL, 0}, +}; + +/** * Look up a kernel algorithm name and its key size */ static char* lookup_algorithm(kernel_algorithm_t *kernel_algo, @@ -153,8 +164,8 @@ static char* lookup_algorithm(kernel_algorithm_t *kernel_algo, if (ikev2_algo == kernel_algo->ikev2_id) { /* match, evaluate key length */ - if (*key_size == 0) - { /* update key size of not set */ + if (key_size && *key_size == 0) + { /* update key size if not set */ *key_size = kernel_algo->key_size; } return kernel_algo->name; @@ -518,11 +529,20 @@ static void process_expire(private_kernel_interface_t *this, struct nlmsghdr *hd struct xfrm_user_expire *expire; expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr); - protocol = expire->state.id.proto == KERNEL_ESP ? PROTO_ESP : PROTO_AH; + protocol = expire->state.id.proto; + protocol = (protocol == KERNEL_ESP) ? PROTO_ESP : (protocol == KERNEL_AH) ? PROTO_AH : protocol; spi = expire->state.id.spi; reqid = expire->state.reqid; DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE"); + + if (protocol != PROTO_ESP && protocol != PROTO_AH) + { + DBG2(DBG_KNL, "ignoring XFRM_MSG_EXPIRE for SA 0x%x (reqid %d) which is " + "not a CHILD_SA", ntohl(spi), reqid); + return; + } + DBG1(DBG_KNL, "creating %s job for %N CHILD_SA 0x%x (reqid %d)", expire->hard ? "delete" : "rekey", protocol_id_names, protocol, ntohl(spi), reqid); @@ -1814,12 +1834,11 @@ static status_t del_ip(private_kernel_interface_t *this, host_t *virtual_ip) } /** - * Implementation of kernel_interface_t.get_spi. + * Get an SPI for a specific protocol from the kernel. */ -static status_t get_spi(private_kernel_interface_t *this, - host_t *src, host_t *dst, - protocol_id_t protocol, u_int32_t reqid, - u_int32_t *spi) +static status_t get_spi_internal(private_kernel_interface_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[BUFFER_SIZE]; struct nlmsghdr *hdr, *out; @@ -1829,8 +1848,6 @@ static status_t get_spi(private_kernel_interface_t *this, memset(&request, 0, sizeof(request)); - DBG2(DBG_KNL, "getting SPI for reqid %d", reqid); - hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST; hdr->nlmsg_type = XFRM_MSG_ALLOCSPI; @@ -1839,12 +1856,12 @@ static status_t get_spi(private_kernel_interface_t *this, userspi = (struct xfrm_userspi_info*)NLMSG_DATA(hdr); host2xfrm(src, &userspi->info.saddr); host2xfrm(dst, &userspi->info.id.daddr); - userspi->info.id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; + userspi->info.id.proto = proto; userspi->info.mode = TRUE; /* tunnel mode */ userspi->info.reqid = reqid; userspi->info.family = src->get_family(src); - userspi->min = 0xc0000000; - userspi->max = 0xcFFFFFFF; + userspi->min = min; + userspi->max = max; if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) { @@ -1880,13 +1897,57 @@ static status_t get_spi(private_kernel_interface_t *this, if (received_spi == 0) { + return FAILED; + } + + *spi = received_spi; + return SUCCESS; +} + +/** + * Implementation of kernel_interface_t.get_spi. + */ +static status_t get_spi(private_kernel_interface_t *this, + host_t *src, host_t *dst, + protocol_id_t protocol, u_int32_t reqid, + u_int32_t *spi) +{ + DBG2(DBG_KNL, "getting SPI for reqid %d", reqid); + + if (get_spi_internal(this, src, dst, + (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH, + 0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS) + { DBG1(DBG_KNL, "unable to get SPI for reqid %d", reqid); return FAILED; } - DBG2(DBG_KNL, "got SPI 0x%x for reqid %d", received_spi, reqid); + DBG2(DBG_KNL, "got SPI 0x%x for reqid %d", *spi, reqid); + + return SUCCESS; +} + +/** + * Implementation of kernel_interface_t.get_cpi. + */ +static status_t get_cpi(private_kernel_interface_t *this, + host_t *src, host_t *dst, + u_int32_t reqid, u_int16_t *cpi) +{ + u_int32_t received_spi = 0; + DBG2(DBG_KNL, "getting CPI for reqid %d", 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 %d", reqid); + return FAILED; + } + + *cpi = htons((u_int16_t)ntohl(received_spi)); + + DBG2(DBG_KNL, "got CPI 0x%x for reqid %d", *cpi, reqid); - *spi = received_spi; return SUCCESS; } @@ -1899,7 +1960,8 @@ static status_t add_sa(private_kernel_interface_t *this, u_int64_t expire_soft, u_int64_t expire_hard, u_int16_t enc_alg, u_int16_t enc_size, u_int16_t int_alg, u_int16_t int_size, - prf_plus_t *prf_plus, mode_t mode, bool encap, + prf_plus_t *prf_plus, mode_t mode, + u_int16_t ipcomp, bool encap, bool replace) { unsigned char request[BUFFER_SIZE]; @@ -1909,7 +1971,7 @@ static status_t add_sa(private_kernel_interface_t *this, memset(&request, 0, sizeof(request)); - DBG2(DBG_KNL, "adding SAD entry with SPI 0x%x", spi); + DBG2(DBG_KNL, "adding SAD entry with SPI 0x%x and reqid %d", spi, reqid); hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; @@ -1920,10 +1982,10 @@ static status_t add_sa(private_kernel_interface_t *this, host2xfrm(src, &sa->saddr); host2xfrm(dst, &sa->id.daddr); sa->id.spi = spi; - sa->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; + sa->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : (protocol == PROTO_AH) ? KERNEL_AH : protocol; sa->family = src->get_family(src); sa->mode = mode; - sa->replay_window = 32; + sa->replay_window = (protocol == IPPROTO_COMP) ? 0 : 32; sa->reqid = reqid; /* we currently do not expire SAs by volume/packet count */ sa->lft.soft_byte_limit = XFRM_INF; @@ -1994,7 +2056,32 @@ static status_t add_sa(private_kernel_interface_t *this, rthdr = XFRM_RTA_NEXT(rthdr); } - /* TODO: add IPComp here */ + if (ipcomp != IPCOMP_NONE) + { + rthdr->rta_type = XFRMA_ALG_COMP; + alg_name = lookup_algorithm(compression_algs, ipcomp, NULL); + if (alg_name == NULL) + { + DBG1(DBG_KNL, "algorithm %N not supported by kernel!", + ipcomp_transform_names, ipcomp); + return FAILED; + } + DBG2(DBG_KNL, " using compression algorithm %N", + ipcomp_transform_names, ipcomp); + + rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo)); + hdr->nlmsg_len += rthdr->rta_len; + if (hdr->nlmsg_len > sizeof(request)) + { + return FAILED; + } + + struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); + algo->alg_key_len = 0; + strcpy(algo->alg_name, alg_name); + + rthdr = XFRM_RTA_NEXT(rthdr); + } if (encap) { @@ -2062,7 +2149,7 @@ static status_t update_sa(private_kernel_interface_t *this, sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); host2xfrm(dst, &sa_id->daddr); sa_id->spi = spi; - sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; + sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : (protocol == PROTO_AH) ? KERNEL_AH : protocol; sa_id->family = dst->get_family(dst); if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) @@ -2190,7 +2277,7 @@ static status_t query_sa(private_kernel_interface_t *this, host_t *dst, sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); host2xfrm(dst, &sa_id->daddr); sa_id->spi = spi; - sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; + sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : (protocol == PROTO_AH) ? KERNEL_AH : protocol; sa_id->family = dst->get_family(dst); if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) @@ -2256,7 +2343,7 @@ static status_t del_sa(private_kernel_interface_t *this, host_t *dst, sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); host2xfrm(dst, &sa_id->daddr); sa_id->spi = spi; - sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; + sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : (protocol == PROTO_AH) ? KERNEL_AH : protocol; sa_id->family = dst->get_family(dst); if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) @@ -2276,7 +2363,8 @@ static status_t add_policy(private_kernel_interface_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, protocol_id_t protocol, - u_int32_t reqid, bool high_prio, mode_t mode) + u_int32_t reqid, bool high_prio, mode_t mode, + u_int16_t ipcomp) { iterator_t *iterator; policy_entry_t *current, *policy; @@ -2301,7 +2389,7 @@ static status_t add_policy(private_kernel_interface_t *this, { /* use existing policy */ current->refcount++; - DBG2(DBG_KNL, "policy %R===%R already exists, increasing ", + DBG2(DBG_KNL, "policy %R===%R already exists, increasing " "refcount", src_ts, dst_ts); free(policy); policy = current; @@ -2348,10 +2436,8 @@ static status_t add_policy(private_kernel_interface_t *this, struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info); rthdr->rta_type = XFRMA_TMPL; - - rthdr->rta_len = sizeof(struct xfrm_user_tmpl); - rthdr->rta_len = RTA_LENGTH(rthdr->rta_len); - + rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); + hdr->nlmsg_len += rthdr->rta_len; if (hdr->nlmsg_len > sizeof(request)) { @@ -2359,6 +2445,30 @@ static status_t add_policy(private_kernel_interface_t *this, } struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr); + + if (ipcomp != IPCOMP_NONE) + { + tmpl->reqid = reqid; + tmpl->id.proto = IPPROTO_COMP; + tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; + tmpl->mode = mode; + tmpl->optional = direction != POLICY_OUT; + tmpl->family = src->get_family(src); + + host2xfrm(src, &tmpl->saddr); + host2xfrm(dst, &tmpl->id.daddr); + + /* add an additional xfrm_user_tmpl */ + rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); + hdr->nlmsg_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); + if (hdr->nlmsg_len > sizeof(request)) + { + return FAILED; + } + + tmpl++; + } + tmpl->reqid = reqid; tmpl->id.proto = (protocol == PROTO_AH) ? KERNEL_AH : KERNEL_ESP; tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; @@ -2588,11 +2698,12 @@ kernel_interface_t *kernel_interface_create() /* public functions */ this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi; - this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,mode_t,bool,bool))add_sa; + this->public.get_cpi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi; + this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,mode_t,u_int16_t,bool,bool))add_sa; this->public.update_sa = (status_t(*)(kernel_interface_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa; this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa; this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa; - this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t))add_policy; + this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t,u_int16_t))add_policy; this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy; this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy; this->public.get_interface = (char*(*)(kernel_interface_t*,host_t*))get_interface_name; diff --git a/src/charon/kernel/kernel_interface.h b/src/charon/kernel/kernel_interface.h index 5e2bff5d8..0978b05e3 100644 --- a/src/charon/kernel/kernel_interface.h +++ b/src/charon/kernel/kernel_interface.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * Copyright (C) 2006-2008 Tobias Brunner + * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -78,6 +79,18 @@ struct kernel_interface_t { protocol_id_t protocol, u_int32_t reqid, u_int32_t *spi); /** + * Get a Compression Parameter Index (CPI) from the kernel. + * + * @param src source address of SA + * @param dst destination address of SA + * @param reqid unique ID for the corresponding SA + * @param cpi allocated cpi + * @return SUCCESS if operation completed + */ + status_t (*get_cpi)(kernel_interface_t *this, host_t *src, host_t *dst, + u_int32_t reqid, u_int16_t *cpi); + + /** * Add an SA to the SAD. * * add_sa() may update an already allocated @@ -101,6 +114,7 @@ struct kernel_interface_t { * @param int_size key length of integrity algorithm, if dynamic * @param prf_plus PRF to derive keys from * @param mode mode of the SA (tunnel, transport) + * @param ipcomp IPComp transform to use * @param encap enable UDP encapsulation for NAT traversal * @param replace Should an already installed SA be updated? * @return SUCCESS if operation completed @@ -111,7 +125,8 @@ struct kernel_interface_t { u_int64_t expire_soft, u_int64_t expire_hard, u_int16_t enc_alg, u_int16_t enc_size, u_int16_t int_alg, u_int16_t int_size, - prf_plus_t *prf_plus, mode_t mode, bool encap, + prf_plus_t *prf_plus, mode_t mode, + u_int16_t ipcomp, bool encap, bool update); /** @@ -177,6 +192,7 @@ struct kernel_interface_t { * @param reqid uniqe ID of an SA to use to enforce policy * @param high_prio if TRUE, uses a higher priority than any with FALSE * @param mode mode of SA (tunnel, transport) + * @param ipcomp the IPComp transform used * @return SUCCESS if operation completed */ status_t (*add_policy) (kernel_interface_t *this, @@ -184,7 +200,8 @@ struct kernel_interface_t { traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, protocol_id_t protocol, - u_int32_t reqid, bool high_prio, mode_t mode); + u_int32_t reqid, bool high_prio, mode_t mode, + u_int16_t ipcomp); /** * Query the use time of a policy. diff --git a/src/charon/plugins/sql/mysql.sql b/src/charon/plugins/sql/mysql.sql index aca8b83af..6c04aef68 100644 --- a/src/charon/plugins/sql/mysql.sql +++ b/src/charon/plugins/sql/mysql.sql @@ -22,6 +22,7 @@ CREATE TABLE `child_configs` ( `mode` tinyint(4) unsigned NOT NULL default '1', `dpd_action` tinyint(4) unsigned NOT NULL default '0', `close_action` tinyint(4) unsigned NOT NULL default '0', + `ipcomp` tinyint(4) unsigned NOT NULL default '0', PRIMARY KEY (`id`), INDEX (`name`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/src/charon/plugins/sql/sql_config.c b/src/charon/plugins/sql/sql_config.c index 3777c6ebb..9b703643b 100644 --- a/src/charon/plugins/sql/sql_config.c +++ b/src/charon/plugins/sql/sql_config.c @@ -125,15 +125,15 @@ static void add_traffic_selectors(private_sql_config_t *this, */ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e) { - int id, lifetime, rekeytime, jitter, hostaccess, mode, dpd, close; + int id, lifetime, rekeytime, jitter, hostaccess, mode, dpd, close, ipcomp; char *name, *updown; child_cfg_t *child_cfg; if (e->enumerate(e, &id, &name, &lifetime, &rekeytime, &jitter, - &updown, &hostaccess, &mode, &dpd, &close)) + &updown, &hostaccess, &mode, &dpd, &close, &ipcomp)) { child_cfg = child_cfg_create(name, lifetime, rekeytime, jitter, - updown, hostaccess, mode, dpd, close); + updown, hostaccess, mode, dpd, close, ipcomp); /* TODO: read proposal from db */ child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); add_traffic_selectors(this, child_cfg, id); @@ -152,7 +152,7 @@ static void add_child_cfgs(private_sql_config_t *this, peer_cfg_t *peer, int id) e = this->db->query(this->db, "SELECT id, name, lifetime, rekeytime, jitter, " - "updown, hostaccess, mode, dpd_action, close_action " + "updown, hostaccess, mode, dpd_action, close_action, ipcomp " "FROM child_configs JOIN peer_config_child_config ON id = child_cfg " "WHERE peer_cfg = ?", DB_INT, id, diff --git a/src/charon/plugins/sql/sqlite.sql b/src/charon/plugins/sql/sqlite.sql index a3f527b90..97c304a16 100644 --- a/src/charon/plugins/sql/sqlite.sql +++ b/src/charon/plugins/sql/sqlite.sql @@ -20,7 +20,8 @@ CREATE TABLE child_configs ( hostaccess INTEGER NOT NULL DEFAULT '0', mode INTEGER NOT NULL DEFAULT '1', dpd_action INTEGER NOT NULL DEFAULT '0', - close_action INTEGER NOT NULL DEFAULT '0' + close_action INTEGER NOT NULL DEFAULT '0', + ipcomp INTEGER NOT NULL DEFAULT '0' ); DROP INDEX IF EXISTS child_configs_name; CREATE INDEX child_configs_name ON child_configs ( diff --git a/src/charon/plugins/stroke/stroke_config.c b/src/charon/plugins/stroke/stroke_config.c index 54b3bf896..f8b4db063 100644 --- a/src/charon/plugins/stroke/stroke_config.c +++ b/src/charon/plugins/stroke/stroke_config.c @@ -710,7 +710,7 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this, msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, msg->add_conn.me.updown, msg->add_conn.me.hostaccess, - msg->add_conn.mode, dpd, ACTION_NONE); + msg->add_conn.mode, dpd, ACTION_NONE, msg->add_conn.ipcomp); add_ts(this, &msg->add_conn.me, child_cfg, TRUE); add_ts(this, &msg->add_conn.other, child_cfg, FALSE); diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 7cd36d68e..21f29a35e 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -1,6 +1,7 @@ /* + * Copyright (C) 2006-2008 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi - * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -70,6 +71,8 @@ struct private_child_sa_t { identification_t *id; /** actual used SPI, 0 if unused */ u_int32_t spi; + /** Compression Parameter Index (CPI) used, 0 if unused */ + u_int16_t cpi; } me, other; /** @@ -148,6 +151,16 @@ struct private_child_sa_t { bool encap; /** + * Specifies the IPComp transform used (IPCOMP_NONE if disabled) + */ + ipcomp_transform_t ipcomp; + + /** + * TRUE if we allocated (or tried to allocate) a CPI + */ + bool cpi_allocated; + + /** * mode this SA uses, tunnel/transport */ mode_t mode; @@ -570,10 +583,21 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, /* send SA down to the kernel */ DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst); + + if (this->ipcomp != IPCOMP_NONE) + { + /* we install an additional IPComp SA */ + u_int32_t cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi)); + status = charon->kernel_interface->add_sa(charon->kernel_interface, + src, dst, cpi, IPPROTO_COMP, this->reqid, 0, 0, + ENCR_UNDEFINED, 0, AUTH_UNDEFINED, 0, NULL, mode, + this->ipcomp, FALSE, mine); + } + status = charon->kernel_interface->add_sa(charon->kernel_interface, src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard, this->enc_alg, this->enc_size, this->int_alg, this->int_size, - prf_plus, mode, this->encap, mine); + prf_plus, mode, IPCOMP_NONE, this->encap, mine); this->install_time = time(NULL); this->rekey_time = this->install_time + soft; @@ -677,15 +701,15 @@ static status_t add_policies(private_child_sa_t *this, /* install 3 policies: out, in and forward */ status = charon->kernel_interface->add_policy(charon->kernel_interface, this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT, - this->protocol, this->reqid, high_prio, mode); + this->protocol, this->reqid, high_prio, mode, this->ipcomp); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN, - this->protocol, this->reqid, high_prio, mode); + this->protocol, this->reqid, high_prio, mode, this->ipcomp); status |= charon->kernel_interface->add_policy(charon->kernel_interface, this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD, - this->protocol, this->reqid, high_prio, mode); + this->protocol, this->reqid, high_prio, mode, this->ipcomp); if (status != SUCCESS) { @@ -786,10 +810,20 @@ static status_t update_hosts(private_child_sa_t *this, this->encap = encap; - /* update our (initator) SAs */ + if (this->ipcomp != IPCOMP_NONE) + { + /* update our (initator) IPComp SA */ + charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->me.cpi)), + IPPROTO_COMP, this->other.addr, this->me.addr, other, me, FALSE); + /* update his (responder) IPComp SA */ + charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->other.cpi)), + IPPROTO_COMP, this->me.addr, this->other.addr, me, other, FALSE); + } + + /* update our (initator) SA */ charon->kernel_interface->update_sa(charon->kernel_interface, this->me.spi, this->protocol, this->other.addr, this->me.addr, other, me, encap); - /* update his (responder) SAs */ + /* update his (responder) SA */ charon->kernel_interface->update_sa(charon->kernel_interface, this->other.spi, this->protocol, this->me.addr, this->other.addr, me, other, encap); @@ -837,13 +871,13 @@ static status_t update_hosts(private_child_sa_t *this, /* reinstall updated policies */ charon->kernel_interface->add_policy(charon->kernel_interface, me, other, policy->my_ts, policy->other_ts, POLICY_OUT, - this->protocol, this->reqid, TRUE, this->mode); + this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); charon->kernel_interface->add_policy(charon->kernel_interface, other, me, policy->other_ts, policy->my_ts, POLICY_IN, - this->protocol, this->reqid, TRUE, this->mode); + this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); charon->kernel_interface->add_policy(charon->kernel_interface, other, me, policy->other_ts, policy->my_ts, POLICY_FWD, - this->protocol, this->reqid, TRUE, this->mode); + this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); } iterator->destroy(iterator); } @@ -875,6 +909,30 @@ static void set_virtual_ip(private_child_sa_t *this, host_t *ip) } /** + * Implementation of child_sa_t.activate_ipcomp. + */ +static void activate_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp, + u_int16_t other_cpi) +{ + this->ipcomp = ipcomp; + this->other.cpi = other_cpi; +} + +/** + * Implementation of child_sa_t.get_my_cpi. + */ +static u_int16_t get_my_cpi(private_child_sa_t *this) +{ + if (!this->cpi_allocated) + { + charon->kernel_interface->get_cpi(charon->kernel_interface, + this->other.addr, this->me.addr, this->reqid, &this->me.cpi); + this->cpi_allocated = TRUE; + } + return this->me.cpi; +} + +/** * Implementation of child_sa_t.destroy. */ static void destroy(private_child_sa_t *this) @@ -907,6 +965,16 @@ static void destroy(private_child_sa_t *this) charon->kernel_interface->del_sa(charon->kernel_interface, this->other.addr, this->other.spi, this->protocol); } + if (this->me.cpi) + { + charon->kernel_interface->del_sa(charon->kernel_interface, + this->other.addr, htonl(ntohs(this->me.cpi)), IPPROTO_COMP); + } + if (this->other.cpi) + { + charon->kernel_interface->del_sa(charon->kernel_interface, + this->other.addr, htonl(ntohs(this->other.cpi)), IPPROTO_COMP); + } /* delete all policies in the kernel */ while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS) @@ -967,6 +1035,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state; this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state; this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config; + this->public.activate_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t,u_int16_t))activate_ipcomp; + this->public.get_my_cpi = (u_int16_t(*)(child_sa_t*))get_my_cpi; this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip; this->public.destroy = (void(*)(child_sa_t*))destroy; @@ -976,10 +1046,14 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->me.id = my_id->clone(my_id); this->other.id = other_id->clone(other_id); this->me.spi = 0; + this->me.cpi = 0; this->other.spi = 0; + this->other.cpi = 0; this->alloc_ah_spi = 0; this->alloc_esp_spi = 0; this->encap = encap; + this->cpi_allocated = FALSE; + this->ipcomp = IPCOMP_NONE; this->state = CHILD_CREATED; /* reuse old reqid if we are rekeying an existing CHILD_SA */ this->reqid = rekey ? rekey : ++reqid; diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index b8186ef51..018f9225c 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -1,6 +1,7 @@ /* + * Copyright (C) 2006-2008 Tobias Brunner * Copyright (C) 2006-2007 Martin Willi - * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * Copyright (C) 2006 Daniel Roethlisberger * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -254,6 +255,22 @@ struct child_sa_t { void (*set_virtual_ip) (child_sa_t *this, host_t *ip); /** + * Activate IPComp by setting the transform ID and CPI values. + * + * @param ipcomp the IPComp transform to use + * @param other_cpi other Compression Parameter Index + */ + void (*activate_ipcomp) (child_sa_t *this, ipcomp_transform_t ipcomp, + u_int16_t other_cpi); + + /** + * Returns the Compression Parameter Index (CPI) allocated from the kernel. + * + * @return allocated CPI + */ + u_int16_t (*get_my_cpi) (child_sa_t *this); + + /** * Destroys a child_sa. */ void (*destroy) (child_sa_t *this); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 1b2ce47ba..eb5e67739 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -1219,7 +1219,7 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) /* install kernel policies */ child_sa = child_sa_create(this->my_host, this->other_host, this->my_id, - this->other_id, child_cfg, FALSE, 0); + this->other_id, child_cfg, 0, FALSE); me = this->my_host; if (this->my_virtual_ip) { diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index 9dd5add8f..456eafd3c 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2008 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -100,6 +101,21 @@ struct private_child_create_t { mode_t mode; /** + * IPComp transform to use + */ + ipcomp_transform_t ipcomp; + + /** + * IPComp transform proposed or accepted by the other peer + */ + ipcomp_transform_t ipcomp_received; + + /** + * Other Compression Parameter Index (CPI) + */ + u_int16_t other_cpi; + + /** * reqid to use if we are rekeying */ u_int32_t reqid; @@ -326,6 +342,12 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) } prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); + if (this->ipcomp != IPCOMP_NONE) + { + this->child_sa->activate_ipcomp(this->child_sa, this->ipcomp, + this->other_cpi); + } + if (this->initiator) { status = this->child_sa->update(this->child_sa, this->proposal, @@ -416,6 +438,36 @@ static void build_payloads(private_child_create_t *this, message_t *message) } /** + * Adds an IPCOMP_SUPPORTED notify to the message, if possible + */ +static void build_ipcomp_supported_notify(private_child_create_t *this, message_t *message) +{ + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + { + DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, IPComp is disabled"); + this->ipcomp = IPCOMP_NONE; + return; + } + + u_int16_t cpi = this->child_sa->get_my_cpi(this->child_sa); + if (cpi) + { + chunk_t cpi_chunk, tid_chunk, data; + u_int8_t tid = this->ipcomp; + cpi_chunk = chunk_from_thing(cpi); + tid_chunk = chunk_from_thing(tid); + data = chunk_cat("cc", cpi_chunk, tid_chunk); + message->add_notify(message, FALSE, IPCOMP_SUPPORTED, data); + chunk_free(&data); + } + else + { + DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp is disabled"); + this->ipcomp = IPCOMP_NONE; + } +} + +/** * Read payloads from message */ static void process_payloads(private_child_create_t *this, message_t *message) @@ -470,6 +522,25 @@ static void process_payloads(private_child_create_t *this, message_t *message) case USE_BEET_MODE: this->mode = MODE_BEET; break; + case IPCOMP_SUPPORTED: + { + chunk_t data = notify_payload->get_notification_data(notify_payload); + u_int16_t cpi = *(u_int16_t*)data.ptr; + ipcomp_transform_t ipcomp = (ipcomp_transform_t)(*(data.ptr + 2)); + switch(ipcomp) + { + case IPCOMP_DEFLATE: + this->other_cpi = cpi; + this->ipcomp_received = ipcomp; + break; + case IPCOMP_LZS: + case IPCOMP_LZJH: + default: + DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify with a transform" + " ID we don't support %N", ipcomp_transform_names, ipcomp); + break; + } + } default: break; } @@ -576,6 +647,12 @@ static status_t build_i(private_child_create_t *this, message_t *message) this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); } + if (this->config->use_ipcomp(this->config)) { + /* IPCOMP_DEFLATE is the only transform we support at the moment */ + this->ipcomp = IPCOMP_DEFLATE; + build_ipcomp_supported_notify(this, message); + } + build_payloads(this, message); this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); @@ -693,6 +770,16 @@ static status_t build_r(private_child_create_t *this, message_t *message) this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid, this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); + if (this->config->use_ipcomp(this->config) && this->ipcomp_received != IPCOMP_NONE) + { + this->ipcomp = this->ipcomp_received; + build_ipcomp_supported_notify(this, message); + } + else if (this->ipcomp_received != IPCOMP_NONE) + { + DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify but IPComp is disabled, ignoring"); + } + switch (select_and_install(this, no_dh)) { case SUCCESS: @@ -799,6 +886,25 @@ static status_t process_i(private_child_create_t *this, message_t *message) process_payloads(this, message); + if (this->ipcomp == IPCOMP_NONE && this->ipcomp_received != IPCOMP_NONE) + { + SIG(CHILD_UP_FAILED, "received an IPCOMP_SUPPORTED notify but we did not " + "send one previously, no CHILD_SA built"); + return SUCCESS; + } + else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE) + { + DBG1(DBG_IKE, "peer didn't accept our proposed IPComp transforms, " + "IPComp is disabled"); + this->ipcomp = IPCOMP_NONE; + } + else if (this->ipcomp != IPCOMP_NONE && this->ipcomp != this->ipcomp_received) + { + SIG(CHILD_UP_FAILED, "received an IPCOMP_SUPPORTED notify for a transform " + "we did not propose, no CHILD_SA built"); + return SUCCESS; + } + if (select_and_install(this, no_dh) == SUCCESS) { SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' established successfully", @@ -877,6 +983,9 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa) this->dh = NULL; this->child_sa = NULL; this->mode = MODE_TUNNEL; + this->ipcomp = IPCOMP_NONE; + this->ipcomp_received = IPCOMP_NONE; + this->other_cpi = 0; this->reqid = 0; this->established = FALSE; } @@ -950,6 +1059,9 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config) this->dh_group = MODP_NONE; this->child_sa = NULL; this->mode = MODE_TUNNEL; + this->ipcomp = IPCOMP_NONE; + this->ipcomp_received = IPCOMP_NONE; + this->other_cpi = 0; this->reqid = 0; this->established = FALSE; diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 66b007e39..4aacbce77 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -253,6 +253,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) } msg.add_conn.mobike = conn->policy & POLICY_MOBIKE; msg.add_conn.force_encap = conn->policy & POLICY_FORCE_ENCAP; + msg.add_conn.ipcomp = conn->policy & POLICY_COMPRESS; msg.add_conn.crl_policy = cfg->setup.strictcrlpolicy; msg.add_conn.unique = cfg->setup.uniqueids; msg.add_conn.algorithms.ike = push_string(&msg, conn->ike); diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index 9fa3449ec..8258fdc7d 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -198,6 +198,7 @@ struct stroke_msg_t { int mode; int mobike; int force_encap; + int ipcomp; crl_policy_t crl_policy; int unique; struct { |