From 89da06ace9c51fac25c9c9eaf242a642f11b501a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 31 Mar 2016 16:01:40 +0200 Subject: [PATCH 01/16] kernel: Use structs to pass information to the kernel-ipsec interface --- src/charon-tkm/src/tkm/tkm_kernel_ipsec.c | 87 ++-- .../libandroidbridge/kernel/android_ipsec.c | 76 ++- src/libcharon/kernel/kernel_interface.c | 68 +-- src/libcharon/kernel/kernel_interface.h | 151 ++---- src/libcharon/kernel/kernel_ipsec.h | 286 ++++++----- .../kernel_libipsec/kernel_libipsec_ipsec.c | 80 ++- .../kernel_netlink/kernel_netlink_ipsec.c | 466 ++++++++++-------- .../plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 373 +++++++------- .../plugins/kernel_wfp/kernel_wfp_ipsec.c | 154 +++--- .../plugins/load_tester/load_tester_ipsec.c | 41 +- src/libcharon/sa/child_sa.c | 249 +++++++--- src/libcharon/sa/shunt_manager.c | 82 +-- 12 files changed, 1135 insertions(+), 978 deletions(-) diff --git a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c index ba2e164c9..c9be8989a 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c +++ b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c @@ -81,13 +81,8 @@ METHOD(kernel_ipsec_t, get_cpi, status_t, } METHOD(kernel_ipsec_t, add_sa, status_t, - private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, - uint32_t tfc, lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, - uint16_t ipcomp, uint16_t cpi, uint32_t replay_window, - bool initiator, bool encap, bool esn, bool inbound, bool update, - linked_list_t* src_ts, linked_list_t* dst_ts) + private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data) { esa_info_t esa; esp_spi_type spi_loc, spi_rem; @@ -97,43 +92,43 @@ METHOD(kernel_ipsec_t, add_sa, status_t, esa_id_type esa_id; nonce_type nc_rem; - if (enc_key.ptr == NULL) + if (data->enc_key.ptr == NULL) { DBG1(DBG_KNL, "Unable to get ESA information"); return FAILED; } - esa = *(esa_info_t *)(enc_key.ptr); + esa = *(esa_info_t *)(data->enc_key.ptr); /* only handle the case where we have both distinct ESP spi's available */ - if (esa.spi_r == spi) + if (esa.spi_r == id->spi) { chunk_free(&esa.nonce_i); chunk_free(&esa.nonce_r); return SUCCESS; } - if (initiator) + if (data->initiator) { - spi_loc = spi; + spi_loc = id->spi; spi_rem = esa.spi_r; - local = dst; - peer = src; + local = id->dst; + peer = id->src; nonce_loc = &esa.nonce_i; nonce_rem = &esa.nonce_r; } else { spi_loc = esa.spi_r; - spi_rem = spi; - local = src; - peer = dst; + spi_rem = id->spi; + local = id->src; + peer = id->dst; nonce_loc = &esa.nonce_r; nonce_rem = &esa.nonce_i; } esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA); - if (!tkm->sad->insert(tkm->sad, esa_id, reqid, local, peer, spi_loc, spi_rem, - protocol)) + if (!tkm->sad->insert(tkm->sad, esa_id, data->reqid, local, peer, + spi_loc, spi_rem, id->proto)) { DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id); goto sad_failure; @@ -146,8 +141,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, nonce_loc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce_loc); if (nonce_loc_id == 0 && esa.dh_id == 0) { - if (ike_esa_create_first(esa_id, esa.isa_id, reqid, 1, spi_loc, spi_rem) - != TKM_OK) + if (ike_esa_create_first(esa_id, esa.isa_id, data->reqid, 1, spi_loc, + spi_rem) != TKM_OK) { DBG1(DBG_KNL, "child SA (%llu, first) creation failed", esa_id); goto failure; @@ -157,9 +152,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t, else if (nonce_loc_id != 0 && esa.dh_id == 0) { chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type)); - if (ike_esa_create_no_pfs(esa_id, esa.isa_id, reqid, 1, nonce_loc_id, - nc_rem, initiator, spi_loc, spi_rem) - != TKM_OK) + if (ike_esa_create_no_pfs(esa_id, esa.isa_id, data->reqid, 1, + nonce_loc_id, nc_rem, data->initiator, + spi_loc, spi_rem) != TKM_OK) { DBG1(DBG_KNL, "child SA (%llu, no PFS) creation failed", esa_id); goto failure; @@ -171,8 +166,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t, else { chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type)); - if (ike_esa_create(esa_id, esa.isa_id, reqid, 1, esa.dh_id, nonce_loc_id, - nc_rem, initiator, spi_loc, spi_rem) != TKM_OK) + if (ike_esa_create(esa_id, esa.isa_id, data->reqid, 1, esa.dh_id, + nonce_loc_id, nc_rem, data->initiator, spi_loc, + spi_rem) != TKM_OK) { DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id); goto failure; @@ -192,7 +188,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, DBG1(DBG_KNL, "added child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, " "esp_spi_rem: %x, role: %s)", esa_id, esa.isa_id, ntohl(spi_loc), - ntohl(spi_rem), initiator ? "initiator" : "responder"); + ntohl(spi_rem), data->initiator ? "initiator" : "responder"); chunk_free(&esa.nonce_i); chunk_free(&esa.nonce_r); @@ -208,20 +204,21 @@ sad_failure: } METHOD(kernel_ipsec_t, query_sa, status_t, - private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, uint64_t *bytes, - uint64_t *packets, time_t *time) + private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets, + time_t *time) { return NOT_SUPPORTED; } METHOD(kernel_ipsec_t, del_sa, status_t, - private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) + private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data) { esa_id_type esa_id, other_esa_id; - esa_id = tkm->sad->get_esa_id(tkm->sad, src, dst, spi, protocol); + esa_id = tkm->sad->get_esa_id(tkm->sad, id->src, id->dst, + id->spi, id->proto); if (esa_id) { other_esa_id = tkm->sad->get_other_esa_id(tkm->sad, esa_id); @@ -236,7 +233,7 @@ METHOD(kernel_ipsec_t, del_sa, status_t, } DBG1(DBG_KNL, "deleting child SA (esa: %llu, spi: %x)", esa_id, - ntohl(spi)); + ntohl(id->spi)); if (ike_esa_reset(esa_id) != TKM_OK) { DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id); @@ -249,9 +246,8 @@ METHOD(kernel_ipsec_t, del_sa, status_t, } METHOD(kernel_ipsec_t, update_sa, status_t, - private_tkm_kernel_ipsec_t *this, uint32_t spi, uint8_t protocol, - uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, - bool old_encap, bool new_encap, mark_t mark) + private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data) { return NOT_SUPPORTED; } @@ -264,27 +260,22 @@ METHOD(kernel_ipsec_t, flush_sas, status_t, } METHOD(kernel_ipsec_t, add_policy, status_t, - private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { return SUCCESS; } METHOD(kernel_ipsec_t, query_policy, status_t, - private_tkm_kernel_ipsec_t *this, traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - time_t *use_time) + private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, time_t *use_time) { return NOT_SUPPORTED; } METHOD(kernel_ipsec_t, del_policy, status_t, - private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { return SUCCESS; } diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_ipsec.c b/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_ipsec.c index 33b545aad..f49fc2b5d 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_ipsec.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_ipsec.c @@ -60,43 +60,40 @@ METHOD(kernel_ipsec_t, get_cpi, status_t, } METHOD(kernel_ipsec_t, add_sa, status_t, - private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, - uint32_t tfc, lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, - uint16_t ipcomp, uint16_t cpi, uint32_t replay_window, - bool initiator, bool encap, bool esn, bool inbound, bool update, - linked_list_t *src_ts, linked_list_t *dst_ts) + private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data) { - return ipsec->sas->add_sa(ipsec->sas, src, dst, spi, protocol, reqid, mark, - tfc, lifetime, enc_alg, enc_key, int_alg, int_key, - mode, ipcomp, cpi, initiator, encap, esn, - inbound, update); + return ipsec->sas->add_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto, + data->reqid, id->mark, data->tfc, data->lifetime, + data->enc_alg, data->enc_key, data->int_alg, data->int_key, + data->mode, data->ipcomp, data->cpi, data->initiator, + data->encap, data->esn, data->inbound, data->update); } METHOD(kernel_ipsec_t, update_sa, status_t, - private_kernel_android_ipsec_t *this, uint32_t spi, uint8_t protocol, - uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, - bool encap, bool new_encap, mark_t mark) + private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data) { - return ipsec->sas->update_sa(ipsec->sas, spi, protocol, cpi, src, dst, - new_src, new_dst, encap, new_encap, mark); + return ipsec->sas->update_sa(ipsec->sas, id->spi, id->proto, data->cpi, + id->src, id->dst, data->new_src, data->new_dst, data->encap, + data->new_encap, id->mark); } METHOD(kernel_ipsec_t, query_sa, status_t, - private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, - uint64_t *bytes, uint64_t *packets, time_t *time) + private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets, + time_t *time) { - return ipsec->sas->query_sa(ipsec->sas, src, dst, spi, protocol, mark, - bytes, packets, time); + return ipsec->sas->query_sa(ipsec->sas, id->src, id->dst, id->spi, + id->proto, id->mark, bytes, packets, time); } METHOD(kernel_ipsec_t, del_sa, status_t, - private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) + private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data) { - return ipsec->sas->del_sa(ipsec->sas, src, dst, spi, protocol, cpi, mark); + return ipsec->sas->del_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto, + data->cpi, id->mark); } METHOD(kernel_ipsec_t, flush_sas, status_t, @@ -106,33 +103,30 @@ METHOD(kernel_ipsec_t, flush_sas, status_t, } METHOD(kernel_ipsec_t, add_policy, status_t, - private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark, - policy_priority_t priority) + private_kernel_android_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { - return ipsec->policies->add_policy(ipsec->policies, src, dst, src_ts, - dst_ts, direction, type, sa, mark, - priority); + return ipsec->policies->add_policy(ipsec->policies, data->src, data->dst, + id->src_ts, id->dst_ts, id->dir, + data->type, data->sa, id->mark, + data->prio); } METHOD(kernel_ipsec_t, query_policy, status_t, - private_kernel_android_ipsec_t *this, traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - time_t *use_time) + private_kernel_android_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, time_t *use_time) { return NOT_SUPPORTED; } METHOD(kernel_ipsec_t, del_policy, status_t, - private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_kernel_android_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { - return ipsec->policies->del_policy(ipsec->policies, src, dst, src_ts, - dst_ts, direction, type, sa, mark, - priority); + return ipsec->policies->del_policy(ipsec->policies, data->src, data->dst, + id->src_ts, id->dst_ts, id->dir, + data->type, data->sa, id->mark, + data->prio); } METHOD(kernel_ipsec_t, flush_policies, status_t, diff --git a/src/libcharon/kernel/kernel_interface.c b/src/libcharon/kernel/kernel_interface.c index bc3f9079d..97d5ef1f7 100644 --- a/src/libcharon/kernel/kernel_interface.c +++ b/src/libcharon/kernel/kernel_interface.c @@ -1,6 +1,7 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2008-2016 Tobias Brunner + * HSR Hochschule fuer Technik Rapperswil + * * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * @@ -415,59 +416,48 @@ METHOD(kernel_interface_t, release_reqid, status_t, } METHOD(kernel_interface_t, add_sa, status_t, - private_kernel_interface_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, - uint32_t tfc, lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, - uint16_t ipcomp, uint16_t cpi, uint32_t replay_window, - bool initiator, bool encap, bool esn, bool inbound, bool update, - linked_list_t *src_ts, linked_list_t *dst_ts) + private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data) { if (!this->ipsec) { return NOT_SUPPORTED; } - return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid, - mark, tfc, lifetime, enc_alg, enc_key, int_alg, int_key, mode, - ipcomp, cpi, replay_window, initiator, encap, esn, inbound, - update, src_ts, dst_ts); + return this->ipsec->add_sa(this->ipsec, id, data); } METHOD(kernel_interface_t, update_sa, status_t, - private_kernel_interface_t *this, uint32_t spi, uint8_t protocol, - uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, - bool encap, bool new_encap, mark_t mark) + private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data) { if (!this->ipsec) { return NOT_SUPPORTED; } - return this->ipsec->update_sa(this->ipsec, spi, protocol, cpi, src, dst, - new_src, new_dst, encap, new_encap, mark); + return this->ipsec->update_sa(this->ipsec, id, data); } METHOD(kernel_interface_t, query_sa, status_t, - private_kernel_interface_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, - uint64_t *bytes, uint64_t *packets, time_t *time) + private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets, + time_t *time) { if (!this->ipsec) { return NOT_SUPPORTED; } - return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, mark, - bytes, packets, time); + return this->ipsec->query_sa(this->ipsec, id, data, bytes, packets, time); } METHOD(kernel_interface_t, del_sa, status_t, - private_kernel_interface_t *this, host_t *src, host_t *dst, uint32_t spi, - uint8_t protocol, uint16_t cpi, mark_t mark) + private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data) { if (!this->ipsec) { return NOT_SUPPORTED; } - return this->ipsec->del_sa(this->ipsec, src, dst, spi, protocol, cpi, mark); + return this->ipsec->del_sa(this->ipsec, id, data); } METHOD(kernel_interface_t, flush_sas, status_t, @@ -481,44 +471,36 @@ METHOD(kernel_interface_t, flush_sas, status_t, } METHOD(kernel_interface_t, add_policy, status_t, - private_kernel_interface_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_kernel_interface_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { if (!this->ipsec) { return NOT_SUPPORTED; } - return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts, - direction, type, sa, mark, priority); + return this->ipsec->add_policy(this->ipsec, id, data); } METHOD(kernel_interface_t, query_policy, status_t, - private_kernel_interface_t *this, traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - time_t *use_time) + private_kernel_interface_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, time_t *use_time) { if (!this->ipsec) { return NOT_SUPPORTED; } - return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts, - direction, mark, use_time); + return this->ipsec->query_policy(this->ipsec, id, data, use_time); } METHOD(kernel_interface_t, del_policy, status_t, - private_kernel_interface_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_kernel_interface_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { if (!this->ipsec) { return NOT_SUPPORTED; } - return this->ipsec->del_policy(this->ipsec, src, dst, src_ts, dst_ts, - direction, type, sa, mark, priority); + return this->ipsec->del_policy(this->ipsec, id, data); } METHOD(kernel_interface_t, flush_policies, status_t, diff --git a/src/libcharon/kernel/kernel_interface.h b/src/libcharon/kernel/kernel_interface.h index ec6e140ba..50f6d9829 100644 --- a/src/libcharon/kernel/kernel_interface.h +++ b/src/libcharon/kernel/kernel_interface.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2006-2015 Tobias Brunner + * Copyright (C) 2006-2016 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -160,41 +160,12 @@ struct kernel_interface_t { * This function does install a single SA for a single protocol in one * direction. * - * @param src source address for this SA - * @param dst destination address for this SA - * @param spi SPI allocated by us or remote peer - * @param protocol protocol for this SA (ESP/AH) - * @param reqid reqid for this SA - * @param mark optional mark for this SA - * @param tfc Traffic Flow Confidentiality padding for this SA - * @param lifetime lifetime_cfg_t for this SA - * @param enc_alg Algorithm to use for encryption (ESP only) - * @param enc_key key to use for encryption - * @param int_alg Algorithm to use for integrity protection - * @param int_key key to use for integrity protection - * @param mode mode of the SA (tunnel, transport) - * @param ipcomp IPComp transform to use - * @param cpi CPI for IPComp - * @param replay_window anti-replay window size - * @param initiator TRUE if initiator of the exchange creating this SA - * @param encap enable UDP encapsulation for NAT traversal - * @param esn TRUE to use Extended Sequence Numbers - * @param inbound TRUE if this is an inbound SA - * @param update TRUE if an SPI has already been allocated for SA - * @param src_ts list of source traffic selectors - * @param dst_ts list of destination traffic selectors + * @param id data identifying this SA + * @param data data for this SA * @return SUCCESS if operation completed */ - status_t (*add_sa) (kernel_interface_t *this, - host_t *src, host_t *dst, uint32_t spi, - uint8_t protocol, uint32_t reqid, mark_t mark, - uint32_t tfc, lifetime_cfg_t *lifetime, - uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, - ipsec_mode_t mode, uint16_t ipcomp, uint16_t cpi, - uint32_t replay_window, bool initiator, bool encap, - bool esn, bool inbound, bool update, - linked_list_t *src_ts, linked_list_t *dst_ts); + status_t (*add_sa)(kernel_interface_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data); /** * Update the hosts on an installed SA. @@ -204,85 +175,55 @@ struct kernel_interface_t { * to identify SAs. Therefore if the destination address changed we * create a new SA and delete the old one. * - * @param spi SPI of the SA - * @param protocol protocol for this SA (ESP/AH) - * @param cpi CPI for IPComp, 0 if no IPComp is used - * @param src current source address - * @param dst current destination address - * @param new_src new source address - * @param new_dst new destination address - * @param encap current use of UDP encapsulation - * @param new_encap new use of UDP encapsulation - * @param mark optional mark for this SA + * @param id data identifying this SA + * @param data updated data for this SA * @return SUCCESS if operation completed, NOT_SUPPORTED if - * the kernel interface can't update the SA + * the kernel interface can't update the SA */ - status_t (*update_sa)(kernel_interface_t *this, - uint32_t spi, uint8_t protocol, uint16_t cpi, - host_t *src, host_t *dst, - host_t *new_src, host_t *new_dst, - bool encap, bool new_encap, mark_t mark); + status_t (*update_sa)(kernel_interface_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data); /** * Query the number of bytes processed by an SA from the SAD. * - * @param src source address for this SA - * @param dst destination address for this SA - * @param spi SPI allocated by us or remote peer - * @param protocol protocol for this SA (ESP/AH) - * @param mark optional mark for this SA + * @param id data identifying this SA + * @param data data to query the SA * @param[out] bytes the number of bytes processed by SA * @param[out] packets number of packets processed by SA * @param[out] time last (monotonic) time of SA use * @return SUCCESS if operation completed */ - status_t (*query_sa) (kernel_interface_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, - uint64_t *bytes, uint64_t *packets, time_t *time); + status_t (*query_sa)(kernel_interface_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, + uint64_t *packets, time_t *time); /** * Delete a previously installed SA from the SAD. * - * @param src source address for this SA - * @param dst destination address for this SA - * @param spi SPI allocated by us or remote peer - * @param protocol protocol for this SA (ESP/AH) - * @param cpi CPI for IPComp or 0 - * @param mark optional mark for this SA + * @param id data identifying this SA + * @param data data to delete the SA * @return SUCCESS if operation completed */ - status_t (*del_sa) (kernel_interface_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint16_t cpi, - mark_t mark); + status_t (*del_sa)(kernel_interface_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data); /** * Flush all SAs from the SAD. * * @return SUCCESS if operation completed */ - status_t (*flush_sas) (kernel_interface_t *this); + status_t (*flush_sas)(kernel_interface_t *this); /** * Add a policy to the SPD. * - * @param src source address of SA - * @param dst dest address of SA - * @param src_ts traffic selector to match traffic source - * @param dst_ts traffic selector to match traffic dest - * @param direction direction of traffic, POLICY_(IN|OUT|FWD) - * @param type type of policy, POLICY_(IPSEC|PASS|DROP) - * @param sa details about the SA(s) tied to this policy - * @param mark mark for this policy - * @param priority priority of this policy + * @param id data identifying this policy + * @param data data for this policy * @return SUCCESS if operation completed */ - status_t (*add_policy) (kernel_interface_t *this, - host_t *src, host_t *dst, - traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, - ipsec_sa_cfg_t *sa, mark_t mark, - policy_priority_t priority); + status_t (*add_policy)(kernel_interface_t *this, + kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data); /** * Query the use time of a policy. @@ -290,47 +231,33 @@ struct kernel_interface_t { * The use time of a policy is the time the policy was used * for the last time. * - * @param src_ts traffic selector to match traffic source - * @param dst_ts traffic selector to match traffic dest - * @param direction direction of traffic, POLICY_(IN|OUT|FWD) - * @param mark optional mark - * @param[out] use_time the (monotonic) time of this SA's last use + * @param id data identifying this policy + * @param data data to query the policy + * @param[out] use_time the monotonic timestamp of this SA's last use * @return SUCCESS if operation completed */ - status_t (*query_policy) (kernel_interface_t *this, - traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, - policy_dir_t direction, mark_t mark, - time_t *use_time); + status_t (*query_policy)(kernel_interface_t *this, + kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, + time_t *use_time); /** * Remove a policy from the SPD. * - * @param src source address of SA - * @param dst dest address of SA - * @param src_ts traffic selector to match traffic source - * @param dst_ts traffic selector to match traffic dest - * @param direction direction of traffic, POLICY_(IN|OUT|FWD) - * @param type type of policy, POLICY_(IPSEC|PASS|DROP) - * @param sa details about the SA(s) tied to this policy - * @param mark mark for this policy - * @param priority priority of the policy + * @param id data identifying this policy + * @param data data for this policy * @return SUCCESS if operation completed */ - status_t (*del_policy) (kernel_interface_t *this, - host_t *src, host_t *dst, - traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, - ipsec_sa_cfg_t *sa, mark_t mark, - policy_priority_t priority); + status_t (*del_policy)(kernel_interface_t *this, + kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data); /** * Flush all policies from the SPD. * * @return SUCCESS if operation completed */ - status_t (*flush_policies) (kernel_interface_t *this); + status_t (*flush_policies)(kernel_interface_t *this); /** * Get our outgoing source address for a destination. diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h index fdb5fc761..a823814f3 100644 --- a/src/libcharon/kernel/kernel_ipsec.h +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2006-2015 Tobias Brunner + * Copyright (C) 2006-2016 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -25,6 +25,14 @@ #define KERNEL_IPSEC_H_ typedef struct kernel_ipsec_t kernel_ipsec_t; +typedef struct kernel_ipsec_sa_id_t kernel_ipsec_sa_id_t; +typedef struct kernel_ipsec_add_sa_t kernel_ipsec_add_sa_t; +typedef struct kernel_ipsec_update_sa_t kernel_ipsec_update_sa_t; +typedef struct kernel_ipsec_query_sa_t kernel_ipsec_query_sa_t; +typedef struct kernel_ipsec_del_sa_t kernel_ipsec_del_sa_t; +typedef struct kernel_ipsec_policy_id_t kernel_ipsec_policy_id_t; +typedef struct kernel_ipsec_manage_policy_t kernel_ipsec_manage_policy_t; +typedef struct kernel_ipsec_query_policy_t kernel_ipsec_query_policy_t; #include #include @@ -32,6 +40,131 @@ typedef struct kernel_ipsec_t kernel_ipsec_t; #include #include +/** + * Data required to identify an SA in the kernel + */ +struct kernel_ipsec_sa_id_t { + /** Source address */ + host_t *src; + /** Destination address */ + host_t *dst; + /** SPI */ + uint32_t spi; + /** Protocol (ESP/AH) */ + uint8_t proto; + /** Optional mark */ + mark_t mark; +}; + +/** + * Data required to add an SA to the kernel + */ +struct kernel_ipsec_add_sa_t { + /** Reqid */ + uint32_t reqid; + /** Mode (tunnel, transport...) */ + ipsec_mode_t mode; + /** List of source traffic selectors */ + linked_list_t *src_ts; + /** List of destination traffic selectors */ + linked_list_t *dst_ts; + /** Lifetime configuration */ + lifetime_cfg_t *lifetime; + /** Encryption algorithm */ + uint16_t enc_alg; + /** Encryption key */ + chunk_t enc_key; + /** Integrity protection algorithm */ + uint16_t int_alg; + /** Integrity protection key */ + chunk_t int_key; + /** Anti-replay window size */ + uint32_t replay_window; + /** Traffic Flow Confidentiality padding */ + uint32_t tfc; + /** IPComp transform */ + uint16_t ipcomp; + /** CPI for IPComp */ + uint16_t cpi; + /** TRUE to enable UDP encapsulation for NAT traversal */ + bool encap; + /** TRUE to use Extended Sequence Numbers */ + bool esn; + /** TRUE if initiator of the exchange creating the SA */ + bool initiator; + /** TRUE if this is an inbound SA */ + bool inbound; + /** TRUE if an SPI has already been allocated for this SA */ + bool update; +}; + +/** + * Data required to update the hosts of an SA in the kernel + */ +struct kernel_ipsec_update_sa_t { + /** CPI in case IPComp is used */ + uint16_t cpi; + /** New source address */ + host_t *new_src; + /** New destination address */ + host_t *new_dst; + /** TRUE if UDP encapsulation is currently enabled */ + bool encap; + /** TRUE to enable UDP encapsulation */ + bool new_encap; +}; + +/** + * Data required to query an SA in the kernel + */ +struct kernel_ipsec_query_sa_t { + uint16_t cpi; +}; + +/** + * Data required to delete an SA in the kernel + */ +struct kernel_ipsec_del_sa_t { + /** CPI in case IPComp is used */ + uint16_t cpi; +}; + +/** + * Data identifying a policy in the kernel + */ +struct kernel_ipsec_policy_id_t { + /** Direction of traffic */ + policy_dir_t dir; + /** Source traffic selector */ + traffic_selector_t *src_ts; + /** Destination traffic selector */ + traffic_selector_t *dst_ts; + /** Optional mark */ + mark_t mark; +}; + +/** + * Data required to add/delete a policy to/from the kernel + */ +struct kernel_ipsec_manage_policy_t { + /** Type of policy */ + policy_type_t type; + /** Priority class */ + policy_priority_t prio; + /** Source address of the SA(s) tied to this policy */ + host_t *src; + /** Destination address of the SA(s) tied to this policy */ + host_t *dst; + /** Details about the SA(s) tied to this policy */ + ipsec_sa_cfg_t *sa; +}; + +/** + * Data required to query a policy in the kernel + */ +struct kernel_ipsec_query_policy_t { +}; + /** * Interface to the ipsec subsystem of the kernel. * @@ -81,41 +214,12 @@ struct kernel_ipsec_t { * This function does install a single SA for a single protocol in one * direction. * - * @param src source address for this SA - * @param dst destination address for this SA - * @param spi SPI allocated by us or remote peer - * @param protocol protocol for this SA (ESP/AH) - * @param reqid unique ID for this SA - * @param mark mark for this SA - * @param tfc Traffic Flow Confidentiality padding for this SA - * @param lifetime lifetime_cfg_t for this SA - * @param enc_alg Algorithm to use for encryption (ESP only) - * @param enc_key key to use for encryption - * @param int_alg Algorithm to use for integrity protection - * @param int_key key to use for integrity protection - * @param mode mode of the SA (tunnel, transport) - * @param ipcomp IPComp transform to use - * @param cpi CPI for IPComp - * @param replay_window anti-replay window size - * @param initiator TRUE if initiator of the exchange creating this SA - * @param encap enable UDP encapsulation for NAT traversal - * @param esn TRUE to use Extended Sequence Numbers - * @param inbound TRUE if this is an inbound SA - * @param update TRUE if an SPI has already been allocated for SA - * @param src_ts list of source traffic selectors - * @param dst_ts list of destination traffic selectors + * @param id data identifying this SA + * @param data data for this SA * @return SUCCESS if operation completed */ - status_t (*add_sa) (kernel_ipsec_t *this, - host_t *src, host_t *dst, uint32_t spi, - uint8_t protocol, uint32_t reqid, - mark_t mark, uint32_t tfc, lifetime_cfg_t *lifetime, - uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, - ipsec_mode_t mode, uint16_t ipcomp, uint16_t cpi, - uint32_t replay_window, bool initiator, bool encap, - bool esn, bool inbound, bool update, - linked_list_t *src_ts, linked_list_t *dst_ts); + status_t (*add_sa)(kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data); /** * Update the hosts on an installed SA. @@ -125,85 +229,55 @@ struct kernel_ipsec_t { * to identify SAs. Therefore if the destination address changed we * create a new SA and delete the old one. * - * @param spi SPI of the SA - * @param protocol protocol for this SA (ESP/AH) - * @param cpi CPI for IPComp, 0 if no IPComp is used - * @param src current source address - * @param dst current destination address - * @param new_src new source address - * @param new_dst new destination address - * @param encap current use of UDP encapsulation - * @param new_encap new use of UDP encapsulation - * @param mark optional mark for this SA + * @param id data identifying this SA + * @param data updated data for this SA * @return SUCCESS if operation completed, NOT_SUPPORTED if - * the kernel interface can't update the SA + * the kernel interface can't update the SA */ - status_t (*update_sa)(kernel_ipsec_t *this, - uint32_t spi, uint8_t protocol, uint16_t cpi, - host_t *src, host_t *dst, - host_t *new_src, host_t *new_dst, - bool encap, bool new_encap, mark_t mark); + status_t (*update_sa)(kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data); /** * Query the number of bytes processed by an SA from the SAD. * - * @param src source address for this SA - * @param dst destination address for this SA - * @param spi SPI allocated by us or remote peer - * @param protocol protocol for this SA (ESP/AH) - * @param mark optional mark for this SA + * @param id data identifying this SA + * @param data data to query the SA * @param[out] bytes the number of bytes processed by SA * @param[out] packets number of packets processed by SA * @param[out] time last (monotonic) time of SA use * @return SUCCESS if operation completed */ - status_t (*query_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, - uint64_t *bytes, uint64_t *packets, time_t *time); + status_t (*query_sa)(kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, + uint64_t *packets, time_t *time); /** - * Delete a previusly installed SA from the SAD. + * Delete a previously installed SA from the SAD. * - * @param src source address for this SA - * @param dst destination address for this SA - * @param spi SPI allocated by us or remote peer - * @param protocol protocol for this SA (ESP/AH) - * @param cpi CPI for IPComp or 0 - * @param mark optional mark for this SA + * @param id data identifying this SA + * @param data data to delete the SA * @return SUCCESS if operation completed */ - status_t (*del_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint16_t cpi, - mark_t mark); + status_t (*del_sa)(kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data); /** * Flush all SAs from the SAD. * * @return SUCCESS if operation completed */ - status_t (*flush_sas) (kernel_ipsec_t *this); + status_t (*flush_sas)(kernel_ipsec_t *this); /** * Add a policy to the SPD. * - * @param src source address of SA - * @param dst dest address of SA - * @param src_ts traffic selector to match traffic source - * @param dst_ts traffic selector to match traffic dest - * @param direction direction of traffic, POLICY_(IN|OUT|FWD) - * @param type type of policy, POLICY_(IPSEC|PASS|DROP) - * @param sa details about the SA(s) tied to this policy - * @param mark mark for this policy - * @param priority priority of this policy + * @param id data identifying this policy + * @param data data for this policy * @return SUCCESS if operation completed */ - status_t (*add_policy) (kernel_ipsec_t *this, - host_t *src, host_t *dst, - traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, - ipsec_sa_cfg_t *sa, mark_t mark, - policy_priority_t priority); + status_t (*add_policy)(kernel_ipsec_t *this, + kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data); /** * Query the use time of a policy. @@ -212,47 +286,33 @@ struct kernel_ipsec_t { * time. It is not the system time, but a monotonic timestamp as returned * by time_monotonic. * - * @param src_ts traffic selector to match traffic source - * @param dst_ts traffic selector to match traffic dest - * @param direction direction of traffic, POLICY_(IN|OUT|FWD) - * @param mark optional mark + * @param id data identifying this policy + * @param data data to query the policy * @param[out] use_time the monotonic timestamp of this SA's last use * @return SUCCESS if operation completed */ - status_t (*query_policy) (kernel_ipsec_t *this, - traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, - policy_dir_t direction, mark_t mark, - time_t *use_time); + status_t (*query_policy)(kernel_ipsec_t *this, + kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, + time_t *use_time); /** * Remove a policy from the SPD. * - * @param src source address of SA - * @param dst dest address of SA - * @param src_ts traffic selector to match traffic source - * @param dst_ts traffic selector to match traffic dest - * @param direction direction of traffic, POLICY_(IN|OUT|FWD) - * @param type type of policy, POLICY_(IPSEC|PASS|DROP) - * @param sa details about the SA(s) tied to this policy - * @param mark mark for this policy - * @param priority priority of the policy + * @param id data identifying this policy + * @param data data for this policy * @return SUCCESS if operation completed */ - status_t (*del_policy) (kernel_ipsec_t *this, - host_t *src, host_t *dst, - traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, - ipsec_sa_cfg_t *sa, mark_t mark, - policy_priority_t priority); + status_t (*del_policy)(kernel_ipsec_t *this, + kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data); /** * Flush all policies from the SPD. * * @return SUCCESS if operation completed */ - status_t (*flush_policies) (kernel_ipsec_t *this); + status_t (*flush_policies)(kernel_ipsec_t *this); /** * Install a bypass policy for the given socket. @@ -277,7 +337,7 @@ struct kernel_ipsec_t { /** * Destroy the implementation. */ - void (*destroy) (kernel_ipsec_t *this); + void (*destroy)(kernel_ipsec_t *this); }; /** diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c index e6274e846..f1340320a 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c @@ -248,42 +248,38 @@ METHOD(kernel_ipsec_t, get_cpi, status_t, } METHOD(kernel_ipsec_t, add_sa, status_t, - private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, - uint32_t tfc, lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, - uint16_t ipcomp, uint16_t cpi, uint32_t replay_window, - bool initiator, bool encap, bool esn, bool inbound, bool update, - linked_list_t *src_ts, linked_list_t *dst_ts) + private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data) { - return ipsec->sas->add_sa(ipsec->sas, src, dst, spi, protocol, reqid, mark, - tfc, lifetime, enc_alg, enc_key, int_alg, int_key, - mode, ipcomp, cpi, initiator, encap, esn, - inbound, update); + return ipsec->sas->add_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto, + data->reqid, id->mark, data->tfc, data->lifetime, + data->enc_alg, data->enc_key, data->int_alg, data->int_key, + data->mode, data->ipcomp, data->cpi, data->initiator, + data->encap, data->esn, data->inbound, data->update); } METHOD(kernel_ipsec_t, update_sa, status_t, - private_kernel_libipsec_ipsec_t *this, uint32_t spi, uint8_t protocol, - uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, - bool encap, bool new_encap, mark_t mark) + private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data) { return NOT_SUPPORTED; } METHOD(kernel_ipsec_t, query_sa, status_t, - private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, uint64_t *bytes, - uint64_t *packets, time_t *time) + private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets, + time_t *time) { - return ipsec->sas->query_sa(ipsec->sas, src, dst, spi, protocol, mark, - bytes, packets, time); + return ipsec->sas->query_sa(ipsec->sas, id->src, id->dst, id->spi, + id->proto, id->mark, bytes, packets, time); } METHOD(kernel_ipsec_t, del_sa, status_t, - private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) + private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data) { - return ipsec->sas->del_sa(ipsec->sas, src, dst, spi, protocol, cpi, mark); + return ipsec->sas->del_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto, + data->cpi, id->mark); } METHOD(kernel_ipsec_t, flush_sas, status_t, @@ -509,22 +505,22 @@ static bool install_route(private_kernel_libipsec_ipsec_t *this, } METHOD(kernel_ipsec_t, add_policy, status_t, - private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark, - policy_priority_t priority) + private_kernel_libipsec_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { policy_entry_t *policy, *found = NULL; status_t status; - status = ipsec->policies->add_policy(ipsec->policies, src, dst, src_ts, - dst_ts, direction, type, sa, mark, priority); + status = ipsec->policies->add_policy(ipsec->policies, data->src, data->dst, + id->src_ts, id->dst_ts, id->dir, + data->type, data->sa, id->mark, + data->prio); if (status != SUCCESS) { return status; } /* we track policies in order to install routes */ - policy = create_policy_entry(src_ts, dst_ts, direction); + policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); this->mutex->lock(this->mutex); if (this->policies->find_first(this->policies, @@ -540,7 +536,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t, } policy->refs++; - if (!install_route(this, src, dst, src_ts, dst_ts, policy)) + if (!install_route(this, data->src, data->dst, id->src_ts, id->dst_ts, + policy)) { return FAILED; } @@ -548,26 +545,25 @@ METHOD(kernel_ipsec_t, add_policy, status_t, } METHOD(kernel_ipsec_t, query_policy, status_t, - private_kernel_libipsec_ipsec_t *this, traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - time_t *use_time) + private_kernel_libipsec_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, time_t *use_time) { return NOT_SUPPORTED; } METHOD(kernel_ipsec_t, del_policy, status_t, - private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_kernel_libipsec_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { policy_entry_t *policy, *found = NULL; status_t status; - status = ipsec->policies->del_policy(ipsec->policies, src, dst, src_ts, - dst_ts, direction, type, sa, mark, priority); + status = ipsec->policies->del_policy(ipsec->policies, data->src, data->dst, + id->src_ts, id->dst_ts, id->dir, + data->type, data->sa, id->mark, + data->prio); - policy = create_policy_entry(src_ts, dst_ts, direction); + policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); this->mutex->lock(this->mutex); if (this->policies->find_first(this->policies, @@ -596,8 +592,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t, route->src_ip, route->if_name) != SUCCESS) { DBG1(DBG_KNL, "error uninstalling route installed with " - "policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); + "policy %R === %R %N", id->src_ts, id->dst_ts, + policy_dir_names, id->dir); } remove_exclude_route(this, route); } diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index cbce0a57b..7baea3e44 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1,11 +1,11 @@ /* - * Copyright (C) 2006-2015 Tobias Brunner + * Copyright (C) 2006-2016 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2008-2016 Andreas Steffen * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -1200,32 +1200,45 @@ static bool add_mark(struct nlmsghdr *hdr, int buflen, mark_t mark) } METHOD(kernel_ipsec_t, add_sa, status_t, - private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, - uint32_t tfc, lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, - uint16_t ipcomp, uint16_t cpi, uint32_t replay_window, - bool initiator, bool encap, bool esn, bool inbound, bool update, - linked_list_t* src_ts, linked_list_t* dst_ts) + private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data) { netlink_buf_t request; char *alg_name; struct nlmsghdr *hdr; struct xfrm_usersa_info *sa; - uint16_t icv_size = 64; - ipsec_mode_t original_mode = mode; + uint16_t icv_size = 64, ipcomp = data->ipcomp; + ipsec_mode_t mode = data->mode, original_mode = data->mode; traffic_selector_t *first_src_ts, *first_dst_ts; status_t status = FAILED; /* 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) + if (ipcomp != IPCOMP_NONE && data->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, 0, initiator, FALSE, FALSE, - inbound, update, src_ts, dst_ts); + kernel_ipsec_sa_id_t ipcomp_id = { + .src = id->src, + .dst = id->dst, + .spi = htonl(ntohs(data->cpi)), + .proto = IPPROTO_COMP, + .mark = id->mark, + }; + kernel_ipsec_add_sa_t ipcomp_sa = { + .reqid = data->reqid, + .mode = data->mode, + .src_ts = data->src_ts, + .dst_ts = data->dst_ts, + .lifetime = &lft, + .enc_alg = ENCR_UNDEFINED, + .int_alg = AUTH_UNDEFINED, + .tfc = data->tfc, + .ipcomp = data->ipcomp, + .initiator = data->initiator, + .inbound = data->inbound, + .update = data->update, + }; + add_sa(this, &ipcomp_id, &ipcomp_sa); ipcomp = IPCOMP_NONE; /* use transport mode ESP SA, IPComp uses tunnel mode */ mode = MODE_TRANSPORT; @@ -1234,19 +1247,20 @@ METHOD(kernel_ipsec_t, add_sa, status_t, memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u} (mark " - "%u/0x%08x)", ntohl(spi), reqid, mark.value, mark.mask); + "%u/0x%08x)", ntohl(id->spi), data->reqid, id->mark.value, + id->mark.mask); hdr = &request.hdr; hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - hdr->nlmsg_type = update ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; + hdr->nlmsg_type = data->update ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); sa = NLMSG_DATA(hdr); - host2xfrm(src, &sa->saddr); - host2xfrm(dst, &sa->id.daddr); - sa->id.spi = spi; - sa->id.proto = protocol; - sa->family = src->get_family(src); + host2xfrm(id->src, &sa->saddr); + host2xfrm(id->dst, &sa->id.daddr); + sa->id.spi = id->spi; + sa->id.proto = id->proto; + sa->family = id->src->get_family(id->src); sa->mode = mode2kernel(mode); switch (mode) { @@ -1260,8 +1274,10 @@ METHOD(kernel_ipsec_t, add_sa, status_t, * selector can be installed other traffic would get dropped */ break; } - if (src_ts->get_first(src_ts, (void**)&first_src_ts) == SUCCESS && - dst_ts->get_first(dst_ts, (void**)&first_dst_ts) == SUCCESS) + if (data->src_ts->get_first(data->src_ts, + (void**)&first_src_ts) == SUCCESS && + data->dst_ts->get_first(data->dst_ts, + (void**)&first_dst_ts) == SUCCESS) { sa->sel = ts2selector(first_src_ts, first_dst_ts); if (!this->proto_port_transport) @@ -1279,18 +1295,18 @@ METHOD(kernel_ipsec_t, add_sa, status_t, break; } - sa->reqid = reqid; - sa->lft.soft_byte_limit = XFRM_LIMIT(lifetime->bytes.rekey); - sa->lft.hard_byte_limit = XFRM_LIMIT(lifetime->bytes.life); - sa->lft.soft_packet_limit = XFRM_LIMIT(lifetime->packets.rekey); - sa->lft.hard_packet_limit = XFRM_LIMIT(lifetime->packets.life); + sa->reqid = data->reqid; + sa->lft.soft_byte_limit = XFRM_LIMIT(data->lifetime->bytes.rekey); + sa->lft.hard_byte_limit = XFRM_LIMIT(data->lifetime->bytes.life); + sa->lft.soft_packet_limit = XFRM_LIMIT(data->lifetime->packets.rekey); + sa->lft.hard_packet_limit = XFRM_LIMIT(data->lifetime->packets.life); /* we use lifetimes since added, not since used */ - sa->lft.soft_add_expires_seconds = lifetime->time.rekey; - sa->lft.hard_add_expires_seconds = lifetime->time.life; + sa->lft.soft_add_expires_seconds = data->lifetime->time.rekey; + sa->lft.hard_add_expires_seconds = data->lifetime->time.life; sa->lft.soft_use_expires_seconds = 0; sa->lft.hard_use_expires_seconds = 0; - switch (enc_alg) + switch (data->enc_alg) { case ENCR_UNDEFINED: /* no encryption */ @@ -1313,71 +1329,73 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { struct xfrm_algo_aead *algo; - alg_name = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); + alg_name = lookup_algorithm(ENCRYPTION_ALGORITHM, data->enc_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", - encryption_algorithm_names, enc_alg); + encryption_algorithm_names, data->enc_alg); goto failed; } DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", - encryption_algorithm_names, enc_alg, enc_key.len * 8); + encryption_algorithm_names, data->enc_alg, + data->enc_key.len * 8); algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AEAD, - sizeof(*algo) + enc_key.len); + sizeof(*algo) + data->enc_key.len); if (!algo) { goto failed; } - algo->alg_key_len = enc_key.len * 8; + algo->alg_key_len = data->enc_key.len * 8; algo->alg_icv_len = icv_size; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; - memcpy(algo->alg_key, enc_key.ptr, enc_key.len); + memcpy(algo->alg_key, data->enc_key.ptr, data->enc_key.len); break; } default: { struct xfrm_algo *algo; - alg_name = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); + alg_name = lookup_algorithm(ENCRYPTION_ALGORITHM, data->enc_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", - encryption_algorithm_names, enc_alg); + encryption_algorithm_names, data->enc_alg); goto failed; } DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", - encryption_algorithm_names, enc_alg, enc_key.len * 8); + encryption_algorithm_names, data->enc_alg, + data->enc_key.len * 8); algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_CRYPT, - sizeof(*algo) + enc_key.len); + sizeof(*algo) + data->enc_key.len); if (!algo) { goto failed; } - algo->alg_key_len = enc_key.len * 8; + algo->alg_key_len = data->enc_key.len * 8; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; - memcpy(algo->alg_key, enc_key.ptr, enc_key.len); + memcpy(algo->alg_key, data->enc_key.ptr, data->enc_key.len); } } - if (int_alg != AUTH_UNDEFINED) + if (data->int_alg != AUTH_UNDEFINED) { u_int trunc_len = 0; - alg_name = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); + alg_name = lookup_algorithm(INTEGRITY_ALGORITHM, data->int_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", - integrity_algorithm_names, int_alg); + integrity_algorithm_names, data->int_alg); goto failed; } DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", - integrity_algorithm_names, int_alg, int_key.len * 8); + integrity_algorithm_names, data->int_alg, data->int_key.len * 8); - switch (int_alg) + switch (data->int_alg) { case AUTH_HMAC_MD5_128: case AUTH_HMAC_SHA2_256_128: @@ -1398,31 +1416,31 @@ METHOD(kernel_ipsec_t, add_sa, status_t, * use specified truncation size supported by newer kernels. * also use this for untruncated MD5 and SHA1. */ algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH_TRUNC, - sizeof(*algo) + int_key.len); + sizeof(*algo) + data->int_key.len); if (!algo) { goto failed; } - algo->alg_key_len = int_key.len * 8; + algo->alg_key_len = data->int_key.len * 8; algo->alg_trunc_len = trunc_len; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; - memcpy(algo->alg_key, int_key.ptr, int_key.len); + memcpy(algo->alg_key, data->int_key.ptr, data->int_key.len); } else { struct xfrm_algo* algo; algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH, - sizeof(*algo) + int_key.len); + sizeof(*algo) + data->int_key.len); if (!algo) { goto failed; } - algo->alg_key_len = int_key.len * 8; + algo->alg_key_len = data->int_key.len * 8; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; - memcpy(algo->alg_key, int_key.ptr, int_key.len); + memcpy(algo->alg_key, data->int_key.ptr, data->int_key.len); } } @@ -1451,7 +1469,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; } - if (encap) + if (data->encap) { struct xfrm_encap_tmpl *tmpl; @@ -1461,8 +1479,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, goto failed; } tmpl->encap_type = UDP_ENCAP_ESPINUDP; - tmpl->encap_sport = htons(src->get_port(src)); - tmpl->encap_dport = htons(dst->get_port(dst)); + tmpl->encap_sport = htons(id->src->get_port(id->src)); + tmpl->encap_dport = htons(id->dst->get_port(id->dst)); memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); /* encap_oa could probably be derived from the * traffic selectors [rfc4306, p39]. In the netlink kernel @@ -1476,12 +1494,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t, * checks it marks them "checksum ok" so OA isn't needed. */ } - if (!add_mark(hdr, sizeof(request), mark)) + if (!add_mark(hdr, sizeof(request), id->mark)) { goto failed; } - if (tfc && protocol == IPPROTO_ESP && mode == MODE_TUNNEL) + if (data->tfc && id->proto == IPPROTO_ESP && mode == MODE_TUNNEL) { /* the kernel supports TFC padding only for tunnel mode ESP SAs */ uint32_t *tfcpad; @@ -1491,19 +1509,19 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { goto failed; } - *tfcpad = tfc; + *tfcpad = data->tfc; } - if (protocol != IPPROTO_COMP) + if (id->proto != IPPROTO_COMP) { - if (replay_window != 0 && (esn || replay_window > 32)) + if (data->replay_window != 0 && (data->esn || data->replay_window > 32)) { /* for ESN or larger replay windows we need the new * XFRMA_REPLAY_ESN_VAL attribute to configure a bitmap */ struct xfrm_replay_state_esn *replay; uint32_t bmp_size; - bmp_size = round_up(replay_window, sizeof(uint32_t) * 8) / 8; + bmp_size = round_up(data->replay_window, sizeof(uint32_t) * 8) / 8; replay = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL, sizeof(*replay) + bmp_size); if (!replay) @@ -1512,10 +1530,11 @@ METHOD(kernel_ipsec_t, add_sa, status_t, } /* bmp_len contains number uf __u32's */ replay->bmp_len = bmp_size / sizeof(uint32_t); - replay->replay_window = replay_window; - DBG2(DBG_KNL, " using replay window of %u packets", replay_window); + replay->replay_window = data->replay_window; + DBG2(DBG_KNL, " using replay window of %u packets", + data->replay_window); - if (esn) + if (data->esn) { DBG2(DBG_KNL, " using extended sequence numbers (ESN)"); sa->flags |= XFRM_STATE_ESN; @@ -1523,21 +1542,24 @@ METHOD(kernel_ipsec_t, add_sa, status_t, } else { - DBG2(DBG_KNL, " using replay window of %u packets", replay_window); - sa->replay_window = replay_window; + DBG2(DBG_KNL, " using replay window of %u packets", + data->replay_window); + sa->replay_window = data->replay_window; } } if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) { - if (mark.value) + if (id->mark.value) { - DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x " - "(mark %u/0x%08x)", ntohl(spi), mark.value, mark.mask); + DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x (mark " + "%u/0x%08x)", ntohl(id->spi), id->mark.value, + id->mark.mask); } else { - DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi)); + DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", + ntohl(id->spi)); } goto failed; } @@ -1555,8 +1577,7 @@ failed: * Allocates into one the replay state structure we get from the kernel. */ static void get_replay_state(private_kernel_netlink_ipsec_t *this, - uint32_t spi, uint8_t protocol, - host_t *dst, mark_t mark, + kernel_ipsec_sa_id_t *sa, struct xfrm_replay_state_esn **replay_esn, uint32_t *replay_esn_len, struct xfrm_replay_state **replay, @@ -1572,7 +1593,7 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this, memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "querying replay state from SAD entry with SPI %.8x", - ntohl(spi)); + ntohl(sa->spi)); hdr = &request.hdr; hdr->nlmsg_flags = NLM_F_REQUEST; @@ -1582,12 +1603,12 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this, aevent_id = NLMSG_DATA(hdr); aevent_id->flags = XFRM_AE_RVAL; - host2xfrm(dst, &aevent_id->sa_id.daddr); - aevent_id->sa_id.spi = spi; - aevent_id->sa_id.proto = protocol; - aevent_id->sa_id.family = dst->get_family(dst); + host2xfrm(sa->dst, &aevent_id->sa_id.daddr); + aevent_id->sa_id.spi = sa->spi; + aevent_id->sa_id.proto = sa->proto; + aevent_id->sa_id.family = sa->dst->get_family(sa->dst); - if (!add_mark(hdr, sizeof(request), mark)) + if (!add_mark(hdr, sizeof(request), sa->mark)) { return; } @@ -1657,9 +1678,9 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this, } METHOD(kernel_ipsec_t, query_sa, status_t, - private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, - uint64_t *bytes, uint64_t *packets, time_t *time) + private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets, + time_t *time) { netlink_buf_t request; struct nlmsghdr *out = NULL, *hdr; @@ -1671,7 +1692,7 @@ METHOD(kernel_ipsec_t, query_sa, status_t, memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "querying SAD entry with SPI %.8x (mark %u/0x%08x)", - ntohl(spi), mark.value, mark.mask); + ntohl(id->spi), id->mark.value, id->mark.mask); hdr = &request.hdr; hdr->nlmsg_flags = NLM_F_REQUEST; @@ -1679,12 +1700,12 @@ METHOD(kernel_ipsec_t, query_sa, status_t, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); sa_id = NLMSG_DATA(hdr); - host2xfrm(dst, &sa_id->daddr); - sa_id->spi = spi; - sa_id->proto = protocol; - sa_id->family = dst->get_family(dst); + host2xfrm(id->dst, &sa_id->daddr); + sa_id->spi = id->spi; + sa_id->proto = id->proto; + sa_id->family = id->dst->get_family(id->dst); - if (!add_mark(hdr, sizeof(request), mark)) + if (!add_mark(hdr, sizeof(request), id->mark)) { return FAILED; } @@ -1705,18 +1726,18 @@ METHOD(kernel_ipsec_t, query_sa, status_t, { struct nlmsgerr *err = NLMSG_DATA(hdr); - if (mark.value) + if (id->mark.value) { - DBG1(DBG_KNL, "querying SAD entry with SPI %.8x " - "(mark %u/0x%08x) failed: %s (%d)", - ntohl(spi), mark.value, mark.mask, - strerror(-err->error), -err->error); + DBG1(DBG_KNL, "querying SAD entry with SPI %.8x (mark " + "%u/0x%08x) failed: %s (%d)", ntohl(id->spi), + id->mark.value, id->mark.mask, + strerror(-err->error), -err->error); } else { DBG1(DBG_KNL, "querying SAD entry with SPI %.8x " - "failed: %s (%d)", ntohl(spi), - strerror(-err->error), -err->error); + "failed: %s (%d)", ntohl(id->spi), + strerror(-err->error), -err->error); } break; } @@ -1732,7 +1753,8 @@ METHOD(kernel_ipsec_t, query_sa, status_t, if (sa == NULL) { - DBG2(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi)); + DBG2(DBG_KNL, "unable to query SAD entry with SPI %.8x", + ntohl(id->spi)); } else { @@ -1758,23 +1780,31 @@ METHOD(kernel_ipsec_t, query_sa, status_t, } METHOD(kernel_ipsec_t, del_sa, status_t, - private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) + private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data) { netlink_buf_t request; struct nlmsghdr *hdr; struct xfrm_usersa_id *sa_id; /* if IPComp was used, we first delete the additional IPComp SA */ - if (cpi) + if (data->cpi) { - del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0, mark); + kernel_ipsec_sa_id_t ipcomp_id = { + .src = id->src, + .dst = id->dst, + .spi = htonl(ntohs(data->cpi)), + .proto = IPPROTO_COMP, + .mark = id->mark, + }; + kernel_ipsec_del_sa_t ipcomp = {}; + del_sa(this, &ipcomp_id, &ipcomp); } memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x (mark %u/0x%08x)", - ntohl(spi), mark.value, mark.mask); + ntohl(id->spi), id->mark.value, id->mark.mask); hdr = &request.hdr; hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; @@ -1782,12 +1812,12 @@ METHOD(kernel_ipsec_t, del_sa, status_t, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); sa_id = NLMSG_DATA(hdr); - host2xfrm(dst, &sa_id->daddr); - sa_id->spi = spi; - sa_id->proto = protocol; - sa_id->family = dst->get_family(dst); + host2xfrm(id->dst, &sa_id->daddr); + sa_id->spi = id->spi; + sa_id->proto = id->proto; + sa_id->family = id->dst->get_family(id->dst); - if (!add_mark(hdr, sizeof(request), mark)) + if (!add_mark(hdr, sizeof(request), id->mark)) { return FAILED; } @@ -1795,30 +1825,30 @@ METHOD(kernel_ipsec_t, del_sa, status_t, switch (this->socket_xfrm->send_ack(this->socket_xfrm, hdr)) { case SUCCESS: - DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x (mark %u/0x%08x)", - ntohl(spi), mark.value, mark.mask); + DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x (mark %u/0x%08x)", + ntohl(id->spi), id->mark.value, id->mark.mask); return SUCCESS; case NOT_FOUND: return NOT_FOUND; default: - if (mark.value) + if (id->mark.value) { - DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x " - "(mark %u/0x%08x)", ntohl(spi), mark.value, mark.mask); + DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x (mark " + "%u/0x%08x)", ntohl(id->spi), id->mark.value, + id->mark.mask); } else { DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", - ntohl(spi)); + ntohl(id->spi)); } return FAILED; } } METHOD(kernel_ipsec_t, update_sa, status_t, - private_kernel_netlink_ipsec_t *this, uint32_t spi, uint8_t protocol, - uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, - bool old_encap, bool new_encap, mark_t mark) + private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data) { netlink_buf_t request; struct nlmsghdr *hdr, *out = NULL; @@ -1832,18 +1862,30 @@ METHOD(kernel_ipsec_t, update_sa, status_t, struct xfrm_replay_state_esn *replay_esn = NULL; struct xfrm_lifetime_cur *lifetime = NULL; uint32_t replay_esn_len = 0; + kernel_ipsec_del_sa_t del = { 0 }; status_t status = FAILED; /* if IPComp is used, we first update the IPComp SA */ - if (cpi) + if (data->cpi) { - update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0, - src, dst, new_src, new_dst, FALSE, FALSE, mark); + kernel_ipsec_sa_id_t ipcomp_id = { + .src = id->src, + .dst = id->dst, + .spi = htonl(ntohs(data->cpi)), + .proto = IPPROTO_COMP, + .mark = id->mark, + }; + kernel_ipsec_update_sa_t ipcomp = { + .new_src = data->new_src, + .new_dst = data->new_dst, + }; + update_sa(this, &ipcomp_id, &ipcomp); } memset(&request, 0, sizeof(request)); - DBG2(DBG_KNL, "querying SAD entry with SPI %.8x for update", ntohl(spi)); + DBG2(DBG_KNL, "querying SAD entry with SPI %.8x for update", + ntohl(id->spi)); /* query the existing SA first */ hdr = &request.hdr; @@ -1852,12 +1894,12 @@ METHOD(kernel_ipsec_t, update_sa, status_t, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); sa_id = NLMSG_DATA(hdr); - host2xfrm(dst, &sa_id->daddr); - sa_id->spi = spi; - sa_id->proto = protocol; - sa_id->family = dst->get_family(dst); + host2xfrm(id->dst, &sa_id->daddr); + sa_id->spi = id->spi; + sa_id->proto = id->proto; + sa_id->family = id->dst->get_family(id->dst); - if (!add_mark(hdr, sizeof(request), mark)) + if (!add_mark(hdr, sizeof(request), id->mark)) { return FAILED; } @@ -1892,23 +1934,25 @@ METHOD(kernel_ipsec_t, update_sa, status_t, } 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(id->spi)); goto failed; } - get_replay_state(this, spi, protocol, dst, mark, &replay_esn, - &replay_esn_len, &replay, &lifetime); + get_replay_state(this, id, &replay_esn, &replay_esn_len, &replay, + &lifetime); /* delete the old SA (without affecting the IPComp SA) */ - if (del_sa(this, src, dst, spi, protocol, 0, mark) != SUCCESS) + if (del_sa(this, id, &del) != SUCCESS) { DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x", - ntohl(spi)); + ntohl(id->spi)); goto failed; } DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H", - ntohl(spi), src, dst, new_src, new_dst); + ntohl(id->spi), id->src, id->dst, data->new_src, + data->new_dst); /* copy over the SA from out to request */ hdr = &request.hdr; hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; @@ -1916,15 +1960,15 @@ METHOD(kernel_ipsec_t, update_sa, status_t, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); sa = NLMSG_DATA(hdr); memcpy(sa, NLMSG_DATA(out), sizeof(struct xfrm_usersa_info)); - sa->family = new_dst->get_family(new_dst); + sa->family = data->new_dst->get_family(data->new_dst); - if (!src->ip_equals(src, new_src)) + if (!id->src->ip_equals(id->src, data->new_src)) { - host2xfrm(new_src, &sa->saddr); + host2xfrm(data->new_src, &sa->saddr); } - if (!dst->ip_equals(dst, new_dst)) + if (!id->dst->ip_equals(id->dst, data->new_dst)) { - host2xfrm(new_dst, &sa->id.daddr); + host2xfrm(data->new_dst, &sa->id.daddr); } rta = XFRM_RTA(out, struct xfrm_usersa_info); @@ -1932,13 +1976,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t, while (RTA_OK(rta, rtasize)) { /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ - if (rta->rta_type != XFRMA_ENCAP || new_encap) + if (rta->rta_type != XFRMA_ENCAP || data->new_encap) { if (rta->rta_type == XFRMA_ENCAP) { /* update encap tmpl */ tmpl = RTA_DATA(rta); - tmpl->encap_sport = ntohs(new_src->get_port(new_src)); - tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); + tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src)); + tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); } netlink_add_attribute(hdr, rta->rta_type, chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)), @@ -1947,7 +1991,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rta = RTA_NEXT(rta, rtasize); } - if (tmpl == NULL && new_encap) + if (tmpl == NULL && data->new_encap) { /* add tmpl if we are enabling it */ tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl)); if (!tmpl) @@ -1955,8 +1999,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t, goto failed; } tmpl->encap_type = UDP_ENCAP_ESPINUDP; - tmpl->encap_sport = ntohs(new_src->get_port(new_src)); - tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); + tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src)); + tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); } @@ -1987,7 +2031,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, else { DBG1(DBG_KNL, "unable to copy replay state from old SAD entry with " - "SPI %.8x", ntohl(spi)); + "SPI %.8x", ntohl(id->spi)); } if (lifetime) { @@ -2004,12 +2048,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t, else { DBG1(DBG_KNL, "unable to copy usage stats from old SAD entry with " - "SPI %.8x", ntohl(spi)); + "SPI %.8x", ntohl(id->spi)); } 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(id->spi)); goto failed; } @@ -2303,10 +2348,8 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, } METHOD(kernel_ipsec_t, add_policy, status_t, - private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_kernel_netlink_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { policy_entry_t *policy, *current; policy_sa_t *assigned_sa, *current_sa; @@ -2315,10 +2358,10 @@ METHOD(kernel_ipsec_t, add_policy, status_t, /* create a policy */ INIT(policy, - .sel = ts2selector(src_ts, dst_ts), - .mark = mark.value & mark.mask, - .direction = direction, - .reqid = sa->reqid, + .sel = ts2selector(id->src_ts, id->dst_ts), + .mark = id->mark.value & id->mark.mask, + .direction = id->dir, + .reqid = data->sa->reqid, ); /* find the policy, which matches EXACTLY */ @@ -2326,21 +2369,21 @@ METHOD(kernel_ipsec_t, add_policy, status_t, current = this->policies->get(this->policies, policy); if (current) { - if (current->reqid && sa->reqid && current->reqid != sa->reqid) + if (current->reqid && data->sa->reqid && + current->reqid != data->sa->reqid) { DBG1(DBG_CFG, "unable to install policy %R === %R %N (mark " "%u/0x%08x) for reqid %u, the same policy for reqid %u exists", - src_ts, dst_ts, policy_dir_names, direction, - mark.value, mark.mask, sa->reqid, current->reqid); + id->src_ts, id->dst_ts, policy_dir_names, id->dir, + id->mark.value, id->mark.mask, data->sa->reqid, current->reqid); policy_entry_destroy(this, policy); this->mutex->unlock(this->mutex); return INVALID_STATE; } /* use existing policy */ - DBG2(DBG_KNL, "policy %R === %R %N (mark %u/0x%08x) " - "already exists, increasing refcount", - src_ts, dst_ts, policy_dir_names, direction, - mark.value, mark.mask); + DBG2(DBG_KNL, "policy %R === %R %N (mark %u/0x%08x) already exists, " + "increasing refcount", id->src_ts, id->dst_ts, policy_dir_names, + id->dir, id->mark.value, id->mark.mask); policy_entry_destroy(this, policy); policy = current; found = TRUE; @@ -2352,9 +2395,9 @@ METHOD(kernel_ipsec_t, add_policy, status_t, } /* cache the assigned IPsec SA */ - assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts, - dst_ts, mark, sa); - assigned_sa->priority = get_priority(policy, priority); + assigned_sa = policy_sa_create(this, id->dir, data->type, data->src, + data->dst, id->src_ts, id->dst_ts, id->mark, data->sa); + assigned_sa->priority = get_priority(policy, data->prio); /* insert the SA according to its priority */ enumerator = policy->used_by->create_enumerator(policy->used_by); @@ -2383,23 +2426,22 @@ METHOD(kernel_ipsec_t, add_policy, status_t, } DBG2(DBG_KNL, "%s policy %R === %R %N (mark %u/0x%08x)", - found ? "updating" : "adding", src_ts, dst_ts, - policy_dir_names, direction, mark.value, mark.mask); + found ? "updating" : "adding", id->src_ts, id->dst_ts, + policy_dir_names, id->dir, id->mark.value, id->mark.mask); if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS) { DBG1(DBG_KNL, "unable to %s policy %R === %R %N", - found ? "update" : "add", src_ts, dst_ts, - policy_dir_names, direction); + found ? "update" : "add", id->src_ts, id->dst_ts, + policy_dir_names, id->dir); return FAILED; } return SUCCESS; } METHOD(kernel_ipsec_t, query_policy, status_t, - private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - time_t *use_time) + private_kernel_netlink_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, time_t *use_time) { netlink_buf_t request; struct nlmsghdr *out = NULL, *hdr; @@ -2410,8 +2452,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t, memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "querying policy %R === %R %N (mark %u/0x%08x)", - src_ts, dst_ts, policy_dir_names, direction, - mark.value, mark.mask); + id->src_ts, id->dst_ts, policy_dir_names, id->dir, id->mark.value, + id->mark.mask); hdr = &request.hdr; hdr->nlmsg_flags = NLM_F_REQUEST; @@ -2419,10 +2461,10 @@ METHOD(kernel_ipsec_t, query_policy, status_t, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)); policy_id = NLMSG_DATA(hdr); - policy_id->sel = ts2selector(src_ts, dst_ts); - policy_id->dir = direction; + policy_id->sel = ts2selector(id->src_ts, id->dst_ts); + policy_id->dir = id->dir; - if (!add_mark(hdr, sizeof(request), mark)) + if (!add_mark(hdr, sizeof(request), id->mark)) { return FAILED; } @@ -2443,7 +2485,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t, { struct nlmsgerr *err = NLMSG_DATA(hdr); DBG1(DBG_KNL, "querying policy failed: %s (%d)", - strerror(-err->error), -err->error); + strerror(-err->error), -err->error); break; } default: @@ -2458,8 +2500,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t, if (policy == NULL) { - DBG2(DBG_KNL, "unable to query policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); + DBG2(DBG_KNL, "unable to query policy %R === %R %N", id->src_ts, + id->dst_ts, policy_dir_names, id->dir); free(out); return FAILED; } @@ -2479,10 +2521,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t, } METHOD(kernel_ipsec_t, del_policy, status_t, - private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t prio) + private_kernel_netlink_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { policy_entry_t *current, policy; enumerator_t *enumerator; @@ -2493,52 +2533,52 @@ METHOD(kernel_ipsec_t, del_policy, status_t, bool is_installed = TRUE; uint32_t priority; ipsec_sa_t assigned_sa = { - .src = src, - .dst = dst, - .mark = mark, - .cfg = *sa, + .src = data->src, + .dst = data->dst, + .mark = id->mark, + .cfg = *data->sa, }; DBG2(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%08x)", - src_ts, dst_ts, policy_dir_names, direction, - mark.value, mark.mask); + id->src_ts, id->dst_ts, policy_dir_names, id->dir, id->mark.value, + id->mark.mask); /* create a policy */ memset(&policy, 0, sizeof(policy_entry_t)); - policy.sel = ts2selector(src_ts, dst_ts); - policy.mark = mark.value & mark.mask; - policy.direction = direction; + policy.sel = ts2selector(id->src_ts, id->dst_ts); + policy.mark = id->mark.value & id->mark.mask; + policy.direction = id->dir; /* find the policy */ this->mutex->lock(this->mutex); current = this->policies->get(this->policies, &policy); if (!current) { - if (mark.value) + if (id->mark.value) { DBG1(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%08x) " - "failed, not found", src_ts, dst_ts, policy_dir_names, - direction, mark.value, mark.mask); + "failed, not found", id->src_ts, id->dst_ts, + policy_dir_names, id->dir, id->mark.value, id->mark.mask); } else { DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", - src_ts, dst_ts, policy_dir_names, direction); + id->src_ts, id->dst_ts, policy_dir_names, id->dir); } this->mutex->unlock(this->mutex); return NOT_FOUND; } /* remove mapping to SA by reqid and priority */ - priority = get_priority(current, prio); + priority = get_priority(current, data->prio); enumerator = current->used_by->create_enumerator(current->used_by); while (enumerator->enumerate(enumerator, (void**)&mapping)) { - if (priority == mapping->priority && type == mapping->type && + if (priority == mapping->priority && data->type == mapping->type && ipsec_sa_equals(mapping->sa, &assigned_sa)) { current->used_by->remove_at(current->used_by, enumerator); - policy_sa_destroy(mapping, &direction, this); + policy_sa_destroy(mapping, &id->dir, this); break; } is_installed = FALSE; @@ -2555,14 +2595,14 @@ METHOD(kernel_ipsec_t, del_policy, status_t, } DBG2(DBG_KNL, "updating policy %R === %R %N (mark %u/0x%08x)", - src_ts, dst_ts, policy_dir_names, direction, - mark.value, mark.mask); + id->src_ts, id->dst_ts, policy_dir_names, id->dir, id->mark.value, + id->mark.mask); current->used_by->get_first(current->used_by, (void**)&mapping); if (add_policy_internal(this, current, mapping, TRUE) != SUCCESS) { DBG1(DBG_KNL, "unable to update policy %R === %R %N", - src_ts, dst_ts, policy_dir_names, direction); + id->src_ts, id->dst_ts, policy_dir_names, id->dir); return FAILED; } return SUCCESS; @@ -2577,9 +2617,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t, policy_id = NLMSG_DATA(hdr); policy_id->sel = current->sel; - policy_id->dir = direction; + policy_id->dir = id->dir; - if (!add_mark(hdr, sizeof(request), mark)) + if (!add_mark(hdr, sizeof(request), id->mark)) { this->mutex->unlock(this->mutex); return FAILED; @@ -2592,9 +2632,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t, route->prefixlen, route->gateway, route->src_ip, route->if_name) != SUCCESS) { - DBG1(DBG_KNL, "error uninstalling route installed with " - "policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); + DBG1(DBG_KNL, "error uninstalling route installed with policy " + "%R === %R %N", id->src_ts, id->dst_ts, policy_dir_names, + id->dir); } } @@ -2604,16 +2644,16 @@ METHOD(kernel_ipsec_t, del_policy, status_t, if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) { - if (mark.value) + if (id->mark.value) { - DBG1(DBG_KNL, "unable to delete policy %R === %R %N " - "(mark %u/0x%08x)", src_ts, dst_ts, policy_dir_names, - direction, mark.value, mark.mask); + DBG1(DBG_KNL, "unable to delete policy %R === %R %N (mark " + "%u/0x%08x)", id->src_ts, id->dst_ts, policy_dir_names, + id->dir, id->mark.value, id->mark.mask); } else { DBG1(DBG_KNL, "unable to delete policy %R === %R %N", - src_ts, dst_ts, policy_dir_names, direction); + id->src_ts, id->dst_ts, policy_dir_names, id->dir); } return FAILED; } diff --git a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 880f2dc46..4c7dc8011 100644 --- a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -1,7 +1,7 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner + * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2008 Andreas Steffen - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -1605,13 +1605,8 @@ METHOD(kernel_ipsec_t, get_cpi, status_t, } METHOD(kernel_ipsec_t, add_sa, status_t, - private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, uint32_t spi, - uint8_t protocol, uint32_t reqid, mark_t mark, uint32_t tfc, - lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, - uint16_t ipcomp, uint16_t cpi, uint32_t replay_window, - bool initiator, bool encap, bool esn, bool inbound, bool update, - linked_list_t *src_ts, linked_list_t *dst_ts) + private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -1620,22 +1615,42 @@ METHOD(kernel_ipsec_t, add_sa, status_t, struct sadb_lifetime *lft; struct sadb_key *key; size_t len; + uint16_t ipcomp = data->ipcomp; + ipsec_mode_t mode = data->mode; /* 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) + if (ipcomp != IPCOMP_NONE && data->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, 0, FALSE, FALSE, FALSE, inbound, - update, NULL, NULL); + kernel_ipsec_sa_id_t ipcomp_id = { + .src = id->src, + .dst = id->dst, + .spi = htonl(ntohs(data->cpi)), + .proto = IPPROTO_COMP, + .mark = id->mark, + }; + kernel_ipsec_add_sa_t ipcomp_sa = { + .reqid = data->reqid, + .mode = data->mode, + .src_ts = data->src_ts, + .dst_ts = data->dst_ts, + .lifetime = &lft, + .enc_alg = ENCR_UNDEFINED, + .int_alg = AUTH_UNDEFINED, + .tfc = data->tfc, + .ipcomp = data->ipcomp, + .initiator = data->initiator, + .inbound = data->inbound, + .update = data->update, + }; + add_sa(this, &ipcomp_id, &ipcomp_sa); ipcomp = IPCOMP_NONE; /* use transport mode ESP SA, IPComp uses tunnel mode */ mode = MODE_TRANSPORT; } - if (update) + if (data->update) { /* As we didn't know the reqid during SPI allocation, we used reqid * zero. Unfortunately we can't SADB_UPDATE to the new reqid, hence we @@ -1643,10 +1658,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t, * selector does not count for that, therefore we have to delete * that state before installing the new SA to avoid deleting the * the new state after installing it. */ - mark_t zeromark = {0, 0}; + kernel_ipsec_sa_id_t del_id = { + .src = id->src, + .dst = id->dst, + .spi = id->spi, + .proto = id->proto, + }; + kernel_ipsec_del_sa_t del = { 0 }; - if (this->public.interface.del_sa(&this->public.interface, - src, dst, spi, protocol, 0, zeromark) != SUCCESS) + if (this->public.interface.del_sa(&this->public.interface, &del_id, + &del) != SUCCESS) { DBG1(DBG_KNL, "deleting SPI allocation SA failed"); } @@ -1655,20 +1676,20 @@ METHOD(kernel_ipsec_t, add_sa, status_t, memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", - ntohl(spi), reqid); + ntohl(id->spi), data->reqid); msg = (struct sadb_msg*)request; msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_type = SADB_ADD; - msg->sadb_msg_satype = proto2satype(protocol); + msg->sadb_msg_satype = proto2satype(id->proto); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); #ifdef __APPLE__ - if (encap) + if (data->encap) { struct sadb_sa_2 *sa_2; sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg); - sa_2->sadb_sa_natt_port = dst->get_port(dst); + sa_2->sadb_sa_natt_port = id->dst->get_port(id->dst); sa = &sa_2->sa; sa->sadb_sa_flags |= SADB_X_EXT_NATT; len = sizeof(struct sadb_sa_2); @@ -1681,22 +1702,24 @@ 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; - if (protocol == IPPROTO_COMP) + sa->sadb_sa_spi = id->spi; + if (id->proto == IPPROTO_COMP) { - sa->sadb_sa_encrypt = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp); + sa->sadb_sa_encrypt = lookup_algorithm(COMPRESSION_ALGORITHM, + ipcomp); } else { /* Linux interprets sadb_sa_replay as number of packets/bits in the * replay window, whereas on BSD it's the size of the window in bytes */ #ifdef __linux__ - sa->sadb_sa_replay = min(replay_window, 32); + sa->sadb_sa_replay = min(data->replay_window, 32); #else - sa->sadb_sa_replay = (replay_window + 7) / 8; + sa->sadb_sa_replay = (data->replay_window + 7) / 8; #endif - sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); - sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); + sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, data->int_alg); + sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, + data->enc_alg); } PFKEY_EXT_ADD(msg, sa); @@ -1704,86 +1727,88 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2; sa2->sadb_x_sa2_len = PFKEY_LEN(sizeof(struct sadb_spirange)); sa2->sadb_x_sa2_mode = mode2kernel(mode); - sa2->sadb_x_sa2_reqid = reqid; + sa2->sadb_x_sa2_reqid = data->reqid; PFKEY_EXT_ADD(msg, sa2); - add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); - add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); + add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); + add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg); lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime)); - lft->sadb_lifetime_allocations = lifetime->packets.rekey; - lft->sadb_lifetime_bytes = lifetime->bytes.rekey; - lft->sadb_lifetime_addtime = lifetime->time.rekey; + lft->sadb_lifetime_allocations = data->lifetime->packets.rekey; + lft->sadb_lifetime_bytes = data->lifetime->bytes.rekey; + lft->sadb_lifetime_addtime = data->lifetime->time.rekey; lft->sadb_lifetime_usetime = 0; /* we only use addtime */ PFKEY_EXT_ADD(msg, lft); lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg); lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime)); - lft->sadb_lifetime_allocations = lifetime->packets.life; - lft->sadb_lifetime_bytes = lifetime->bytes.life; - lft->sadb_lifetime_addtime = lifetime->time.life; + lft->sadb_lifetime_allocations = data->lifetime->packets.life; + lft->sadb_lifetime_bytes = data->lifetime->bytes.life; + lft->sadb_lifetime_addtime = data->lifetime->time.life; lft->sadb_lifetime_usetime = 0; /* we only use addtime */ PFKEY_EXT_ADD(msg, lft); - if (enc_alg != ENCR_UNDEFINED) + if (data->enc_alg != ENCR_UNDEFINED) { if (!sa->sadb_sa_encrypt) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", - encryption_algorithm_names, enc_alg); + encryption_algorithm_names, data->enc_alg); return FAILED; } DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", - encryption_algorithm_names, enc_alg, enc_key.len * 8); + encryption_algorithm_names, data->enc_alg, data->enc_key.len * 8); key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg); key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; - key->sadb_key_bits = enc_key.len * 8; - key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + enc_key.len); - memcpy(key + 1, enc_key.ptr, enc_key.len); + key->sadb_key_bits = data->enc_key.len * 8; + key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + data->enc_key.len); + memcpy(key + 1, data->enc_key.ptr, data->enc_key.len); PFKEY_EXT_ADD(msg, key); } - if (int_alg != AUTH_UNDEFINED) + if (data->int_alg != AUTH_UNDEFINED) { if (!sa->sadb_sa_auth) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", - integrity_algorithm_names, int_alg); + integrity_algorithm_names, data->int_alg); return FAILED; } DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", - integrity_algorithm_names, int_alg, int_key.len * 8); + integrity_algorithm_names, data->int_alg, data->int_key.len * 8); key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg); key->sadb_key_exttype = SADB_EXT_KEY_AUTH; - key->sadb_key_bits = int_key.len * 8; - key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + int_key.len); - memcpy(key + 1, int_key.ptr, int_key.len); + key->sadb_key_bits = data->int_key.len * 8; + key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + data->int_key.len); + memcpy(key + 1, data->int_key.ptr, data->int_key.len); PFKEY_EXT_ADD(msg, key); } #ifdef HAVE_NATT - if (encap) + if (data->encap) { - add_encap_ext(msg, src, dst); + add_encap_ext(msg, id->src, id->dst); } #endif /*HAVE_NATT*/ if (pfkey_send(this, msg, &out, &len) != SUCCESS) { - DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi)); + DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", + ntohl(id->spi)); return FAILED; } else if (out->sadb_msg_errno) { DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x: %s (%d)", - ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno); + ntohl(id->spi), strerror(out->sadb_msg_errno), + out->sadb_msg_errno); free(out); return FAILED; } @@ -1793,9 +1818,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, } METHOD(kernel_ipsec_t, update_sa, status_t, - private_kernel_pfkey_ipsec_t *this, uint32_t spi, uint8_t protocol, - uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, - bool encap, bool new_encap, mark_t mark) + private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -1806,72 +1830,84 @@ METHOD(kernel_ipsec_t, update_sa, status_t, /* we can't update the SA if any of the ip addresses have changed. * that's because we can't use SADB_UPDATE and by deleting and readding the * SA the sequence numbers would get lost */ - if (!src->ip_equals(src, new_src) || - !dst->ip_equals(dst, new_dst)) + if (!id->src->ip_equals(id->src, data->new_src) || + !id->dst->ip_equals(id->dst, data->new_dst)) { DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: address " - "changes are not supported", ntohl(spi)); + "changes are not supported", ntohl(id->spi)); return NOT_SUPPORTED; } /* if IPComp is used, we first update the IPComp SA */ - if (cpi) + if (data->cpi) { - update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0, - src, dst, new_src, new_dst, FALSE, FALSE, mark); + kernel_ipsec_sa_id_t ipcomp_id = { + .src = id->src, + .dst = id->dst, + .spi = htonl(ntohs(data->cpi)), + .proto = IPPROTO_COMP, + .mark = id->mark, + }; + kernel_ipsec_update_sa_t ipcomp = { + .new_src = data->new_src, + .new_dst = data->new_dst, + }; + update_sa(this, &ipcomp_id, &ipcomp); } 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 for update", + ntohl(id->spi)); msg = (struct sadb_msg*)request; msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_type = SADB_GET; - msg->sadb_msg_satype = proto2satype(protocol); + msg->sadb_msg_satype = proto2satype(id->proto); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa)); - sa->sadb_sa_spi = spi; + sa->sadb_sa_spi = id->spi; PFKEY_EXT_ADD(msg, sa); /* the kernel wants a SADB_EXT_ADDRESS_SRC to be present even though * it is not used for anything. */ - add_anyaddr_ext(msg, dst->get_family(dst), SADB_EXT_ADDRESS_SRC); - add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); + add_anyaddr_ext(msg, id->dst->get_family(id->dst), SADB_EXT_ADDRESS_SRC); + add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); if (pfkey_send(this, msg, &out, &len) != SUCCESS) { - DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi)); + DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", + ntohl(id->spi)); return FAILED; } else if (out->sadb_msg_errno) { DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)", - ntohl(spi), strerror(out->sadb_msg_errno), - out->sadb_msg_errno); + ntohl(id->spi), strerror(out->sadb_msg_errno), + out->sadb_msg_errno); free(out); return FAILED; } else if (parse_pfkey_message(out, &response) != SUCCESS) { DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: parsing " - "response from kernel failed", ntohl(spi)); + "response from kernel failed", ntohl(id->spi)); free(out); return FAILED; } DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H", - ntohl(spi), src, dst, new_src, new_dst); + ntohl(id->spi), id->src, id->dst, data->new_src, data->new_dst); memset(&request, 0, sizeof(request)); msg = (struct sadb_msg*)request; msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_type = SADB_UPDATE; - msg->sadb_msg_satype = proto2satype(protocol); + msg->sadb_msg_satype = proto2satype(id->proto); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); #ifdef __APPLE__ @@ -1880,9 +1916,9 @@ METHOD(kernel_ipsec_t, update_sa, status_t, sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg); sa_2->sa.sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa_2)); memcpy(&sa_2->sa, response.sa, sizeof(struct sadb_sa)); - if (encap) + if (data->encap) { - sa_2->sadb_sa_natt_port = new_dst->get_port(new_dst); + sa_2->sadb_sa_natt_port = data->new_dst->get_port(data->new_dst); sa_2->sa.sadb_sa_flags |= SADB_X_EXT_NATT; } } @@ -1908,9 +1944,9 @@ METHOD(kernel_ipsec_t, update_sa, status_t, } #ifdef HAVE_NATT - if (new_encap) + if (data->new_encap) { - add_encap_ext(msg, new_src, new_dst); + add_encap_ext(msg, data->new_src, data->new_dst); } #endif /*HAVE_NATT*/ @@ -1918,14 +1954,14 @@ METHOD(kernel_ipsec_t, update_sa, status_t, if (pfkey_send(this, msg, &out, &len) != 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(id->spi)); return FAILED; } else if (out->sadb_msg_errno) { DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: %s (%d)", - ntohl(spi), strerror(out->sadb_msg_errno), - out->sadb_msg_errno); + ntohl(id->spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno); free(out); return FAILED; } @@ -1935,9 +1971,9 @@ METHOD(kernel_ipsec_t, update_sa, status_t, } METHOD(kernel_ipsec_t, query_sa, status_t, - private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, - uint64_t *bytes, uint64_t *packets, time_t *time) + private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets, + time_t *time) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -1947,42 +1983,44 @@ METHOD(kernel_ipsec_t, query_sa, status_t, 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(id->spi)); msg = (struct sadb_msg*)request; msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_type = SADB_GET; - msg->sadb_msg_satype = proto2satype(protocol); + msg->sadb_msg_satype = proto2satype(id->proto); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa)); - sa->sadb_sa_spi = spi; + sa->sadb_sa_spi = id->spi; PFKEY_EXT_ADD(msg, sa); /* the Linux Kernel doesn't care for the src address, but other systems do * (e.g. FreeBSD) */ - add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); - add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); + add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); + add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); if (pfkey_send(this, msg, &out, &len) != SUCCESS) { - DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi)); + DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", + ntohl(id->spi)); return FAILED; } else if (out->sadb_msg_errno) { DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)", - ntohl(spi), strerror(out->sadb_msg_errno), - out->sadb_msg_errno); + ntohl(id->spi), strerror(out->sadb_msg_errno), + out->sadb_msg_errno); free(out); return FAILED; } else if (parse_pfkey_message(out, &response) != SUCCESS) { - DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi)); + DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", + ntohl(id->spi)); free(out); return FAILED; } @@ -2013,8 +2051,8 @@ METHOD(kernel_ipsec_t, query_sa, status_t, } METHOD(kernel_ipsec_t, del_sa, status_t, - private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) + private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -2022,48 +2060,57 @@ METHOD(kernel_ipsec_t, del_sa, status_t, size_t len; /* if IPComp was used, we first delete the additional IPComp SA */ - if (cpi) + if (data->cpi) { - del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0, mark); + kernel_ipsec_sa_id_t ipcomp_id = { + .src = id->src, + .dst = id->dst, + .spi = htonl(ntohs(data->cpi)), + .proto = IPPROTO_COMP, + .mark = id->mark, + }; + kernel_ipsec_del_sa_t ipcomp = { 0 }; + del_sa(this, &ipcomp_id, &ipcomp); } 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(id->spi)); msg = (struct sadb_msg*)request; msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_type = SADB_DELETE; - msg->sadb_msg_satype = proto2satype(protocol); + msg->sadb_msg_satype = proto2satype(id->proto); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa)); - sa->sadb_sa_spi = spi; + sa->sadb_sa_spi = id->spi; PFKEY_EXT_ADD(msg, sa); /* the Linux Kernel doesn't care for the src address, but other systems do * (e.g. FreeBSD) */ - add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); - add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); + add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); + add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); if (pfkey_send(this, msg, &out, &len) != SUCCESS) { - DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi)); + DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", + ntohl(id->spi)); return FAILED; } else if (out->sadb_msg_errno) { DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x: %s (%d)", - ntohl(spi), strerror(out->sadb_msg_errno), - out->sadb_msg_errno); + ntohl(id->spi), strerror(out->sadb_msg_errno), + out->sadb_msg_errno); free(out); return FAILED; } - DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi)); + DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(id->spi)); free(out); return SUCCESS; } @@ -2506,23 +2553,21 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, } METHOD(kernel_ipsec_t, add_policy, status_t, - private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { policy_entry_t *policy, *found = NULL; policy_sa_t *assigned_sa, *current_sa; enumerator_t *enumerator; bool update = TRUE; - if (dir2kernel(direction) == IPSEC_DIR_INVALID) + if (dir2kernel(id->dir) == IPSEC_DIR_INVALID) { /* FWD policies are not supported on all platforms */ return SUCCESS; } /* create a policy */ - policy = create_policy_entry(src_ts, dst_ts, direction); + policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); /* find a matching policy */ this->mutex->lock(this->mutex); @@ -2531,7 +2576,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, (void**)&found, policy) == SUCCESS) { /* use existing policy */ DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing " - "refcount", src_ts, dst_ts, policy_dir_names, direction); + "refcount", id->src_ts, id->dst_ts, policy_dir_names, id->dir); policy_entry_destroy(policy, this); policy = found; } @@ -2542,9 +2587,9 @@ METHOD(kernel_ipsec_t, add_policy, status_t, } /* cache the assigned IPsec SA */ - assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts, - dst_ts, sa); - assigned_sa->priority = get_priority(policy, priority); + assigned_sa = policy_sa_create(this, id->dir, data->type, data->src, + data->dst, id->src_ts, id->dst_ts, data->sa); + assigned_sa->priority = get_priority(policy, data->prio); /* insert the SA according to its priority */ enumerator = policy->used_by->create_enumerator(policy->used_by); @@ -2567,23 +2612,22 @@ METHOD(kernel_ipsec_t, add_policy, status_t, } DBG2(DBG_KNL, "%s policy %R === %R %N", - found ? "updating" : "adding", src_ts, dst_ts, - policy_dir_names, direction); + found ? "updating" : "adding", id->src_ts, id->dst_ts, + policy_dir_names, id->dir); if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS) { DBG1(DBG_KNL, "unable to %s policy %R === %R %N", - found ? "update" : "add", src_ts, dst_ts, - policy_dir_names, direction); + found ? "update" : "add", id->src_ts, id->dst_ts, + policy_dir_names, id->dir); return FAILED; } return SUCCESS; } METHOD(kernel_ipsec_t, query_policy, status_t, - private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - time_t *use_time) + private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, time_t *use_time) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -2592,16 +2636,16 @@ METHOD(kernel_ipsec_t, query_policy, status_t, pfkey_msg_t response; size_t len; - if (dir2kernel(direction) == IPSEC_DIR_INVALID) + if (dir2kernel(id->dir) == IPSEC_DIR_INVALID) { /* FWD policies are not supported on all platforms */ return NOT_FOUND; } - DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); + DBG2(DBG_KNL, "querying policy %R === %R %N", id->src_ts, id->dst_ts, + policy_dir_names, id->dir); /* create a policy */ - policy = create_policy_entry(src_ts, dst_ts, direction); + policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); /* find a matching policy */ this->mutex->lock(this->mutex); @@ -2609,8 +2653,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t, (linked_list_match_t)policy_entry_equals, (void**)&found, policy) != SUCCESS) { - DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found", src_ts, - dst_ts, policy_dir_names, direction); + DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found", + id->src_ts, id->dst_ts, policy_dir_names, id->dir); policy_entry_destroy(policy, this); this->mutex->unlock(this->mutex); return NOT_FOUND; @@ -2630,7 +2674,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t, pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; pol->sadb_x_policy_id = policy->index; pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy)); - pol->sadb_x_policy_dir = dir2kernel(direction); + pol->sadb_x_policy_dir = dir2kernel(id->dir); pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; PFKEY_EXT_ADD(msg, pol); @@ -2643,30 +2687,31 @@ METHOD(kernel_ipsec_t, query_policy, status_t, if (pfkey_send(this, msg, &out, &len) != SUCCESS) { - DBG1(DBG_KNL, "unable to query policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); + DBG1(DBG_KNL, "unable to query policy %R === %R %N", id->src_ts, + id->dst_ts, policy_dir_names, id->dir); return FAILED; } else if (out->sadb_msg_errno) { - DBG1(DBG_KNL, "unable to query policy %R === %R %N: %s (%d)", src_ts, - dst_ts, policy_dir_names, direction, - strerror(out->sadb_msg_errno), out->sadb_msg_errno); + DBG1(DBG_KNL, "unable to query policy %R === %R %N: %s (%d)", + id->src_ts, id->dst_ts, policy_dir_names, id->dir, + strerror(out->sadb_msg_errno), out->sadb_msg_errno); free(out); return FAILED; } else if (parse_pfkey_message(out, &response) != SUCCESS) { DBG1(DBG_KNL, "unable to query policy %R === %R %N: parsing response " - "from kernel failed", src_ts, dst_ts, policy_dir_names, - direction); + "from kernel failed", id->src_ts, id->dst_ts, policy_dir_names, + id->dir); free(out); return FAILED; } else if (response.lft_current == NULL) { DBG2(DBG_KNL, "unable to query policy %R === %R %N: kernel reports no " - "use time", src_ts, dst_ts, policy_dir_names, direction); + "use time", id->src_ts, id->dst_ts, policy_dir_names, + id->dir); free(out); return FAILED; } @@ -2686,10 +2731,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t, } METHOD(kernel_ipsec_t, del_policy, status_t, - private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t prio) + private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -2701,21 +2744,21 @@ METHOD(kernel_ipsec_t, del_policy, status_t, uint32_t priority; size_t len; ipsec_sa_t assigned_sa = { - .src = src, - .dst = dst, - .cfg = *sa, + .src = data->src, + .dst = data->dst, + .cfg = *data->sa, }; - if (dir2kernel(direction) == IPSEC_DIR_INVALID) + if (dir2kernel(id->dir) == IPSEC_DIR_INVALID) { /* FWD policies are not supported on all platforms */ return SUCCESS; } - DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); + DBG2(DBG_KNL, "deleting policy %R === %R %N", id->src_ts, id->dst_ts, + policy_dir_names, id->dir); /* create a policy */ - policy = create_policy_entry(src_ts, dst_ts, direction); + policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); /* find a matching policy */ this->mutex->lock(this->mutex); @@ -2723,8 +2766,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t, (linked_list_match_t)policy_entry_equals, (void**)&found, policy) != SUCCESS) { - DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts, - dst_ts, policy_dir_names, direction); + DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", + id->src_ts, id->dst_ts, policy_dir_names, id->dir); policy_entry_destroy(policy, this); this->mutex->unlock(this->mutex); return NOT_FOUND; @@ -2734,7 +2777,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, /* remove mapping to SA by reqid and priority, if multiple match, which * could happen when rekeying due to an address change, remove the oldest */ - priority = get_priority(policy, prio); + priority = get_priority(policy, data->prio); enumerator = policy->used_by->create_enumerator(policy->used_by); while (enumerator->enumerate(enumerator, (void**)&mapping)) { @@ -2762,7 +2805,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, if (policy->used_by->get_count(policy->used_by) > 0) { /* policy is used by more SAs, keep in kernel */ DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); - policy_sa_destroy(mapping, &direction, this); + policy_sa_destroy(mapping, &id->dir, this); if (!is_installed) { /* no need to update as the policy was not installed for this SA */ @@ -2770,13 +2813,13 @@ METHOD(kernel_ipsec_t, del_policy, status_t, return SUCCESS; } - DBG2(DBG_KNL, "updating policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); + DBG2(DBG_KNL, "updating policy %R === %R %N", id->src_ts, id->dst_ts, + policy_dir_names, id->dir); policy->used_by->get_first(policy->used_by, (void**)&mapping); if (add_policy_internal(this, policy, mapping, TRUE) != SUCCESS) { DBG1(DBG_KNL, "unable to update policy %R === %R %N", - src_ts, dst_ts, policy_dir_names, direction); + id->src_ts, id->dst_ts, policy_dir_names, id->dir); return FAILED; } return SUCCESS; @@ -2793,7 +2836,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, pol = (struct sadb_x_policy*)PFKEY_EXT_ADD_NEXT(msg); pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy)); - pol->sadb_x_policy_dir = dir2kernel(direction); + pol->sadb_x_policy_dir = dir2kernel(id->dir); pol->sadb_x_policy_type = type2kernel(mapping->type); PFKEY_EXT_ADD(msg, pol); @@ -2810,28 +2853,28 @@ METHOD(kernel_ipsec_t, del_policy, status_t, route->src_ip, route->if_name) != SUCCESS) { DBG1(DBG_KNL, "error uninstalling route installed with " - "policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); + "policy %R === %R %N", id->src_ts, id->dst_ts, + policy_dir_names, id->dir); } remove_exclude_route(this, route); } this->policies->remove(this->policies, found, NULL); - policy_sa_destroy(mapping, &direction, this); + policy_sa_destroy(mapping, &id->dir, this); policy_entry_destroy(policy, this); this->mutex->unlock(this->mutex); if (pfkey_send(this, msg, &out, &len) != SUCCESS) { - DBG1(DBG_KNL, "unable to delete policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); + DBG1(DBG_KNL, "unable to delete policy %R === %R %N", id->src_ts, + id->dst_ts, policy_dir_names, id->dir); return FAILED; } else if (out->sadb_msg_errno) { - DBG1(DBG_KNL, "unable to delete policy %R === %R %N: %s (%d)", src_ts, - dst_ts, policy_dir_names, direction, - strerror(out->sadb_msg_errno), out->sadb_msg_errno); + DBG1(DBG_KNL, "unable to delete policy %R === %R %N: %s (%d)", + id->src_ts, id->dst_ts, policy_dir_names, id->dir, + strerror(out->sadb_msg_errno), out->sadb_msg_errno); free(out); return FAILED; } diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c index 086d06e85..c12d38430 100644 --- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c @@ -2093,57 +2093,55 @@ static void schedule_expire(private_kernel_wfp_ipsec_t *this, uint32_t spi, } METHOD(kernel_ipsec_t, add_sa, status_t, - private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, - uint32_t tfc, lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, - uint16_t ipcomp, uint16_t cpi, uint32_t replay_window, - bool initiator, bool encap, bool esn, bool inbound, bool update, - linked_list_t *src_ts, linked_list_t *dst_ts) + private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data) { host_t *local, *remote; entry_t *entry; - if (inbound) + if (data->inbound) { /* comes first, create new entry */ - local = dst->clone(dst); - remote = src->clone(src); + local = id->dst->clone(id->dst); + remote = id->src->clone(id->src); INIT(entry, - .reqid = reqid, + .reqid = data->reqid, .isa = { - .spi = spi, + .spi = id->spi, .dst = local, - .protocol = protocol, - .lifetime = lifetime->time.life, + .protocol = id->proto, + .lifetime = data->lifetime->time.life, .encr = { - .alg = enc_alg, - .key = chunk_clone(enc_key), + .alg = data->enc_alg, + .key = chunk_clone(data->enc_key), }, .integ = { - .alg = int_alg, - .key = chunk_clone(int_key), + .alg = data->int_alg, + .key = chunk_clone(data->int_key), }, }, .sps = array_create(0, 0), .local = local, .remote = remote, - .mode = mode, - .encap = encap, + .mode = data->mode, + .encap = data->encap, ); - if (lifetime->time.life) + if (data->lifetime->time.life) { - schedule_expire(this, spi, local, lifetime->time.life, TRUE); + schedule_expire(this, id->spi, local, + data->lifetime->time.life, TRUE); } - if (lifetime->time.rekey && lifetime->time.rekey != lifetime->time.life) + if (data->lifetime->time.rekey && + data->lifetime->time.rekey != data->lifetime->time.life) { - schedule_expire(this, spi, local, lifetime->time.rekey, FALSE); + schedule_expire(this, id->spi, local, + data->lifetime->time.rekey, FALSE); } this->mutex->lock(this->mutex); - this->tsas->put(this->tsas, (void*)(uintptr_t)reqid, entry); + this->tsas->put(this->tsas, (void*)(uintptr_t)data->reqid, entry); this->isas->put(this->isas, &entry->isa, entry); this->mutex->unlock(this->mutex); } @@ -2151,29 +2149,29 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { /* comes after inbound, update entry */ this->mutex->lock(this->mutex); - entry = this->tsas->remove(this->tsas, (void*)(uintptr_t)reqid); + entry = this->tsas->remove(this->tsas, (void*)(uintptr_t)data->reqid); this->mutex->unlock(this->mutex); if (!entry) { DBG1(DBG_KNL, "adding outbound SA failed, no inbound SA found " - "for reqid %u ", reqid); + "for reqid %u ", data->reqid); return NOT_FOUND; } /* TODO: should we check for local/remote, mode etc.? */ entry->osa = (sa_entry_t){ - .spi = spi, + .spi = id->spi, .dst = entry->remote, - .protocol = protocol, - .lifetime = lifetime->time.life, + .protocol = id->proto, + .lifetime = data->lifetime->time.life, .encr = { - .alg = enc_alg, - .key = chunk_clone(enc_key), + .alg = data->enc_alg, + .key = chunk_clone(data->enc_key), }, .integ = { - .alg = int_alg, - .key = chunk_clone(int_key), + .alg = data->int_alg, + .key = chunk_clone(data->int_key), }, }; @@ -2186,14 +2184,13 @@ METHOD(kernel_ipsec_t, add_sa, status_t, } METHOD(kernel_ipsec_t, update_sa, status_t, - private_kernel_wfp_ipsec_t *this, uint32_t spi, uint8_t protocol, - uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, - bool encap, bool new_encap, mark_t mark) + private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data) { entry_t *entry; sa_entry_t key = { - .dst = dst, - .spi = spi, + .dst = id->dst, + .spi = id->spi, }; UINT64 sa_id = 0; IPSEC_SA_CONTEXT1 *ctx; @@ -2233,16 +2230,16 @@ METHOD(kernel_ipsec_t, update_sa, status_t, DBG1(DBG_KNL, "getting WFP SA context for updated failed: 0x%08x", res); return FAILED; } - if (!hosts2traffic(this, new_dst, new_src, &ctx->inboundSa->traffic) || - !hosts2traffic(this, new_dst, new_src, &ctx->outboundSa->traffic)) + if (!hosts2traffic(this, data->new_dst, data->new_src, &ctx->inboundSa->traffic) || + !hosts2traffic(this, data->new_dst, data->new_src, &ctx->outboundSa->traffic)) { FwpmFreeMemory0((void**)&ctx); return FAILED; } - if (new_encap != encap) + if (data->new_encap != data->encap) { - if (new_encap) + if (data->new_encap) { ctx->inboundSa->udpEncapsulation = &ports; ctx->outboundSa->udpEncapsulation = &ports; @@ -2273,8 +2270,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t, entry->local->destroy(entry->local); entry->remote->destroy(entry->remote); - entry->local = new_dst->clone(new_dst); - entry->remote = new_src->clone(new_src); + entry->local = data->new_dst->clone(data->new_dst); + entry->remote = data->new_src->clone(data->new_src); entry->isa.dst = entry->local; entry->osa.dst = entry->remote; @@ -2290,9 +2287,9 @@ METHOD(kernel_ipsec_t, update_sa, status_t, } METHOD(kernel_ipsec_t, query_sa, status_t, - private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, uint64_t *bytes, - uint64_t *packets, time_t *time) + private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets, + time_t *time) { /* It does not seem that WFP provides any means of getting per-SA traffic * statistics. IPsecGetStatistics0/1() provides global stats, and @@ -2302,13 +2299,13 @@ METHOD(kernel_ipsec_t, query_sa, status_t, } METHOD(kernel_ipsec_t, del_sa, status_t, - private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) + private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data) { entry_t *entry; sa_entry_t key = { - .dst = dst, - .spi = spi, + .dst = id->dst, + .spi = id->spi, }; this->mutex->lock(this->mutex); @@ -2341,25 +2338,23 @@ METHOD(kernel_ipsec_t, flush_sas, status_t, } METHOD(kernel_ipsec_t, add_policy, status_t, - private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark, - policy_priority_t priority) + private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { status_t status = SUCCESS; entry_t *entry; sp_entry_t *sp; sa_entry_t key = { - .spi = sa->esp.use ? sa->esp.spi : sa->ah.spi, - .dst = dst, + .spi = data->sa->esp.use ? data->sa->esp.spi : data->sa->ah.spi, + .dst = data->dst, }; - if (sa->esp.use && sa->ah.use) + if (data->sa->esp.use && data->sa->ah.use) { return NOT_SUPPORTED; } - switch (type) + switch (data->type) { case POLICY_IPSEC: break; @@ -2368,7 +2363,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, return NOT_SUPPORTED; } - switch (direction) + switch (id->dir) { case POLICY_OUT: break; @@ -2380,18 +2375,20 @@ METHOD(kernel_ipsec_t, add_policy, status_t, return NOT_SUPPORTED; } - switch (priority) + switch (data->prio) { case POLICY_PRIORITY_DEFAULT: break; case POLICY_PRIORITY_ROUTED: - if (!add_trap(this, sa->reqid, FALSE, src, dst, src_ts, dst_ts)) + if (!add_trap(this, data->sa->reqid, FALSE, data->src, data->dst, + id->src_ts, id->dst_ts)) { return FAILED; } - if (sa->mode == MODE_TUNNEL) + if (data->sa->mode == MODE_TUNNEL) { - if (!add_trap(this, sa->reqid, TRUE, src, dst, src_ts, dst_ts)) + if (!add_trap(this, data->sa->reqid, TRUE, data->src, data->dst, + id->src_ts, id->dst_ts)) { return FAILED; } @@ -2406,14 +2403,14 @@ METHOD(kernel_ipsec_t, add_policy, status_t, entry = this->osas->get(this->osas, &key); if (entry) { - if (sa->mode == MODE_TUNNEL || array_count(entry->sps) == 0) + if (data->sa->mode == MODE_TUNNEL || array_count(entry->sps) == 0) { INIT(sp, - .src = src_ts->clone(src_ts), - .dst = dst_ts->clone(dst_ts), + .src = id->src_ts->clone(id->src_ts), + .dst = id->dst_ts->clone(id->dst_ts), ); array_insert(entry->sps, -1, sp); - if (array_count(entry->sps) == sa->policy_count) + if (array_count(entry->sps) == data->sa->policy_count) { if (!install(this, entry)) { @@ -2442,25 +2439,24 @@ METHOD(kernel_ipsec_t, add_policy, status_t, } METHOD(kernel_ipsec_t, query_policy, status_t, - private_kernel_wfp_ipsec_t *this, traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - time_t *use_time) + private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, time_t *use_time) { /* see query_sa() for some notes */ return NOT_SUPPORTED; } METHOD(kernel_ipsec_t, del_policy, status_t, - private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { - if (direction == POLICY_OUT && priority == POLICY_PRIORITY_ROUTED) + if (id->dir == POLICY_OUT && data->prio == POLICY_PRIORITY_ROUTED) { - if (remove_trap(this, sa->reqid, FALSE, src_ts, dst_ts)) + if (remove_trap(this, data->sa->reqid, FALSE, id->src_ts, + id->dst_ts)) { - remove_trap(this, sa->reqid, TRUE, src_ts, dst_ts); + remove_trap(this, data->sa->reqid, TRUE, id->src_ts, + id->dst_ts); return SUCCESS; } return NOT_FOUND; diff --git a/src/libcharon/plugins/load_tester/load_tester_ipsec.c b/src/libcharon/plugins/load_tester/load_tester_ipsec.c index deca19088..4e20c8f3a 100644 --- a/src/libcharon/plugins/load_tester/load_tester_ipsec.c +++ b/src/libcharon/plugins/load_tester/load_tester_ipsec.c @@ -50,63 +50,52 @@ METHOD(kernel_ipsec_t, get_cpi, status_t, } METHOD(kernel_ipsec_t, add_sa, status_t, - private_load_tester_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, - uint32_t tfc, lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key, - uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, - uint16_t ipcomp, uint16_t cpi, uint32_t replay_window, - bool initiator, bool encap, bool esn, bool inbound, bool update, - linked_list_t *src_ts, linked_list_t *dst_ts) + private_load_tester_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_add_sa_t *data) { return SUCCESS; } METHOD(kernel_ipsec_t, update_sa, status_t, - private_load_tester_ipsec_t *this, uint32_t spi, uint8_t protocol, - uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, - host_t *new_dst, bool encap, bool new_encap, mark_t mark) + private_load_tester_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_update_sa_t *data) { return SUCCESS; } METHOD(kernel_ipsec_t, query_sa, status_t, - private_load_tester_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, mark_t mark, - uint64_t *bytes, uint64_t *packets, time_t *time) + private_load_tester_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets, + time_t *time) { return NOT_SUPPORTED; } METHOD(kernel_ipsec_t, del_sa, status_t, - private_load_tester_ipsec_t *this, host_t *src, host_t *dst, - uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) + private_load_tester_ipsec_t *this, kernel_ipsec_sa_id_t *id, + kernel_ipsec_del_sa_t *data) { return SUCCESS; } METHOD(kernel_ipsec_t, add_policy, status_t, - private_load_tester_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_load_tester_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { return SUCCESS; } METHOD(kernel_ipsec_t, query_policy, status_t, - private_load_tester_ipsec_t *this, traffic_selector_t *src_ts, - traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - time_t *use_time) + private_load_tester_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_query_policy_t *data, time_t *use_time) { *use_time = 1; return SUCCESS; } METHOD(kernel_ipsec_t, del_policy, status_t, - private_load_tester_ipsec_t *this, host_t *src, host_t *dst, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts, - policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, - mark_t mark, policy_priority_t priority) + private_load_tester_ipsec_t *this, kernel_ipsec_policy_id_t *id, + kernel_ipsec_manage_policy_t *data) { return SUCCESS; } diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index ed457cf61..9c1808b95 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2006-2015 Tobias Brunner + * Copyright (C) 2006-2016 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -468,10 +468,17 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) { if (this->my_spi) { - status = charon->kernel->query_sa(charon->kernel, this->other_addr, - this->my_addr, this->my_spi, - proto_ike2ip(this->protocol), this->mark_in, - &bytes, &packets, &time); + kernel_ipsec_sa_id_t id = { + .src = this->other_addr, + .dst = this->my_addr, + .spi = this->my_spi, + .proto = proto_ike2ip(this->protocol), + .mark = this->mark_in, + }; + kernel_ipsec_query_sa_t query = {}; + + status = charon->kernel->query_sa(charon->kernel, &id, &query, + &bytes, &packets, &time); if (status == SUCCESS) { if (bytes > this->my_usebytes) @@ -492,10 +499,17 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) { if (this->other_spi) { - status = charon->kernel->query_sa(charon->kernel, this->my_addr, - this->other_addr, this->other_spi, - proto_ike2ip(this->protocol), this->mark_out, - &bytes, &packets, &time); + kernel_ipsec_sa_id_t id = { + .src = this->my_addr, + .dst = this->other_addr, + .spi = this->other_spi, + .proto = proto_ike2ip(this->protocol), + .mark = this->mark_out, + }; + kernel_ipsec_query_sa_t query = {}; + + status = charon->kernel->query_sa(charon->kernel, &id, &query, + &bytes, &packets, &time); if (status == SUCCESS) { if (bytes > this->other_usebytes) @@ -531,15 +545,24 @@ static bool update_usetime(private_child_sa_t *this, bool inbound) if (inbound) { - if (charon->kernel->query_policy(charon->kernel, other_ts, - my_ts, POLICY_IN, this->mark_in, &in) == SUCCESS) + kernel_ipsec_policy_id_t id = { + .dir = POLICY_IN, + .src_ts = other_ts, + .dst_ts = my_ts, + .mark = this->mark_in, + }; + kernel_ipsec_query_policy_t query = {}; + + if (charon->kernel->query_policy(charon->kernel, &id, &query, + &in) == SUCCESS) { last_use = max(last_use, in); } if (this->mode != MODE_TRANSPORT) { - if (charon->kernel->query_policy(charon->kernel, other_ts, - my_ts, POLICY_FWD, this->mark_in, &fwd) == SUCCESS) + id.dir = POLICY_FWD; + if (charon->kernel->query_policy(charon->kernel, &id, &query, + &fwd) == SUCCESS) { last_use = max(last_use, fwd); } @@ -547,8 +570,16 @@ static bool update_usetime(private_child_sa_t *this, bool inbound) } else { - if (charon->kernel->query_policy(charon->kernel, my_ts, - other_ts, POLICY_OUT, this->mark_out, &out) == SUCCESS) + kernel_ipsec_policy_id_t id = { + .dir = POLICY_OUT, + .src_ts = my_ts, + .dst_ts = other_ts, + .mark = this->mark_out, + }; + kernel_ipsec_query_policy_t query = {}; + + if (charon->kernel->query_policy(charon->kernel, &id, &query, + &out) == SUCCESS) { last_use = max(last_use, out); } @@ -659,6 +690,8 @@ METHOD(child_sa_t, install, status_t, uint16_t esn = NO_EXT_SEQ_NUMBERS; linked_list_t *src_ts = NULL, *dst_ts = NULL; time_t now; + kernel_ipsec_sa_id_t id; + kernel_ipsec_add_sa_t sa; lifetime_cfg_t *lifetime; uint32_t tfc = 0; host_t *src, *dst; @@ -752,12 +785,35 @@ METHOD(child_sa_t, install, status_t, dst_ts = other_ts; } - status = charon->kernel->add_sa(charon->kernel, - src, dst, spi, proto_ike2ip(this->protocol), this->reqid, - inbound ? this->mark_in : this->mark_out, tfc, - lifetime, enc_alg, encr, int_alg, integ, this->mode, - this->ipcomp, cpi, this->config->get_replay_window(this->config), - initiator, this->encap, esn, inbound, update, src_ts, dst_ts); + id = (kernel_ipsec_sa_id_t){ + .src = src, + .dst = dst, + .spi = spi, + .proto = proto_ike2ip(this->protocol), + .mark = inbound ? this->mark_in : this->mark_out, + }; + sa = (kernel_ipsec_add_sa_t){ + .reqid = this->reqid, + .mode = this->mode, + .src_ts = src_ts, + .dst_ts = dst_ts, + .lifetime = lifetime, + .enc_alg = enc_alg, + .enc_key = encr, + .int_alg = int_alg, + .int_key = integ, + .replay_window = this->config->get_replay_window(this->config), + .tfc = tfc, + .ipcomp = this->ipcomp, + .cpi = cpi, + .encap = this->encap, + .esn = esn, + .initiator = initiator, + .inbound = inbound, + .update = update, + }; + + status = charon->kernel->add_sa(charon->kernel, &id, &sa); free(lifetime); @@ -827,22 +883,38 @@ static status_t install_policies_internal(private_child_sa_t *this, traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority) { + kernel_ipsec_policy_id_t out_id = { + .dir = POLICY_OUT, + .src_ts = my_ts, + .dst_ts = other_ts, + .mark = this->mark_out, + }, in_id = { + .dir = POLICY_IN, + .src_ts = other_ts, + .dst_ts = my_ts, + .mark = this->mark_in, + }; + kernel_ipsec_manage_policy_t out_policy = { + .type = type, + .prio = priority, + .src = my_addr, + .dst = other_addr, + .sa = other_sa, + }, in_policy = { + .type = type, + .prio = priority, + .src = other_addr, + .dst = my_addr, + .sa = my_sa, + }; status_t status = SUCCESS; - status |= charon->kernel->add_policy(charon->kernel, - my_addr, other_addr, my_ts, other_ts, - POLICY_OUT, type, other_sa, - this->mark_out, priority); - status |= charon->kernel->add_policy(charon->kernel, - other_addr, my_addr, other_ts, my_ts, - POLICY_IN, type, my_sa, - this->mark_in, priority); + status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy); + status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy); if (this->mode != MODE_TRANSPORT) { - status |= charon->kernel->add_policy(charon->kernel, - other_addr, my_addr, other_ts, my_ts, - POLICY_FWD, type, my_sa, - this->mark_in, priority); + in_id.dir = POLICY_FWD; + status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy); } return status; } @@ -855,18 +927,37 @@ static void del_policies_internal(private_child_sa_t *this, traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority) { + kernel_ipsec_policy_id_t out_id = { + .dir = POLICY_OUT, + .src_ts = my_ts, + .dst_ts = other_ts, + .mark = this->mark_out, + }, in_id = { + .dir = POLICY_IN, + .src_ts = other_ts, + .dst_ts = my_ts, + .mark = this->mark_in, + }; + kernel_ipsec_manage_policy_t out_policy = { + .type = type, + .prio = priority, + .src = my_addr, + .dst = other_addr, + .sa = other_sa, + }, in_policy = { + .type = type, + .prio = priority, + .src = other_addr, + .dst = my_addr, + .sa = my_sa, + }; - charon->kernel->del_policy(charon->kernel, - my_addr, other_addr, my_ts, other_ts, POLICY_OUT, type, - other_sa, this->mark_out, priority); - charon->kernel->del_policy(charon->kernel, - other_addr, my_addr, other_ts, my_ts, POLICY_IN, - type, my_sa, this->mark_in, priority); + charon->kernel->del_policy(charon->kernel, &out_id, &out_policy); + charon->kernel->del_policy(charon->kernel, &in_id, &in_policy); if (this->mode != MODE_TRANSPORT) { - charon->kernel->del_policy(charon->kernel, - other_addr, my_addr, other_ts, my_ts, POLICY_FWD, - type, my_sa, this->mark_in, priority); + in_id.dir = POLICY_FWD; + charon->kernel->del_policy(charon->kernel, &in_id, &in_policy); } } @@ -994,11 +1085,22 @@ METHOD(child_sa_t, update, status_t, /* update our (initiator) SA */ if (this->my_spi) { - if (charon->kernel->update_sa(charon->kernel, - this->my_spi, proto_ike2ip(this->protocol), - this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0, - this->other_addr, this->my_addr, other, me, - this->encap, encap, this->mark_in) == NOT_SUPPORTED) + kernel_ipsec_sa_id_t id = { + .src = this->other_addr, + .dst = this->my_addr, + .spi = this->my_spi, + .proto = proto_ike2ip(this->protocol), + .mark = this->mark_in, + }; + kernel_ipsec_update_sa_t sa = { + .cpi = this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0, + .new_src = other, + .new_dst = me, + .encap = this->encap, + .new_encap = encap, + }; + if (charon->kernel->update_sa(charon->kernel, &id, + &sa) == NOT_SUPPORTED) { set_state(this, old); return NOT_SUPPORTED; @@ -1008,11 +1110,22 @@ METHOD(child_sa_t, update, status_t, /* update his (responder) SA */ if (this->other_spi) { - if (charon->kernel->update_sa(charon->kernel, - this->other_spi, proto_ike2ip(this->protocol), - this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0, - this->my_addr, this->other_addr, me, other, - this->encap, encap, this->mark_out) == NOT_SUPPORTED) + kernel_ipsec_sa_id_t id = { + .src = this->my_addr, + .dst = this->other_addr, + .spi = this->other_spi, + .proto = proto_ike2ip(this->protocol), + .mark = this->mark_out, + }; + kernel_ipsec_update_sa_t sa = { + .cpi = this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0, + .new_src = me, + .new_dst = other, + .encap = this->encap, + .new_encap = encap, + }; + if (charon->kernel->update_sa(charon->kernel, &id, + &sa) == NOT_SUPPORTED) { set_state(this, old); return NOT_SUPPORTED; @@ -1137,17 +1250,31 @@ METHOD(child_sa_t, destroy, void, /* delete SAs in the kernel, if they are set up */ if (this->my_spi) { - charon->kernel->del_sa(charon->kernel, - this->other_addr, this->my_addr, this->my_spi, - proto_ike2ip(this->protocol), this->my_cpi, - this->mark_in); + kernel_ipsec_sa_id_t id = { + .src = this->other_addr, + .dst = this->my_addr, + .spi = this->my_spi, + .proto = proto_ike2ip(this->protocol), + .mark = this->mark_in, + }; + kernel_ipsec_del_sa_t sa = { + .cpi = this->my_cpi, + }; + charon->kernel->del_sa(charon->kernel, &id, &sa); } if (this->other_spi) { - charon->kernel->del_sa(charon->kernel, - this->my_addr, this->other_addr, this->other_spi, - proto_ike2ip(this->protocol), this->other_cpi, - this->mark_out); + kernel_ipsec_sa_id_t id = { + .src = this->my_addr, + .dst = this->other_addr, + .spi = this->other_spi, + .proto = proto_ike2ip(this->protocol), + .mark = this->mark_out, + }; + kernel_ipsec_del_sa_t sa = { + .cpi = this->other_cpi, + }; + charon->kernel->del_sa(charon->kernel, &id, &sa); } if (this->reqid_allocated) diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c index 0e9cf6e1f..13c8b5e3d 100644 --- a/src/libcharon/sa/shunt_manager.c +++ b/src/libcharon/sa/shunt_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Tobias Brunner + * Copyright (C) 2015-2016 Tobias Brunner * Copyright (C) 2011 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * @@ -110,25 +110,31 @@ static bool install_shunt_policy(child_cfg_t *child) continue; } /* install out policy */ - status |= charon->kernel->add_policy(charon->kernel, - host_any, host_any, - my_ts, other_ts, POLICY_OUT, policy_type, - &sa, child->get_mark(child, FALSE), - policy_prio); - + kernel_ipsec_policy_id_t id = { + .dir = POLICY_OUT, + .src_ts = my_ts, + .dst_ts = other_ts, + .mark = child->get_mark(child, FALSE), + }; + kernel_ipsec_manage_policy_t policy = { + .type = policy_type, + .prio = policy_prio, + .src = host_any, + .dst = host_any, + .sa = &sa, + }; + status |= charon->kernel->add_policy(charon->kernel, &id, &policy); /* install in policy */ - status |= charon->kernel->add_policy(charon->kernel, - host_any, host_any, - other_ts, my_ts, POLICY_IN, policy_type, - &sa, child->get_mark(child, TRUE), - policy_prio); - + id = (kernel_ipsec_policy_id_t){ + .dir = POLICY_IN, + .src_ts = other_ts, + .dst_ts = my_ts, + .mark = child->get_mark(child, TRUE), + }; + status |= charon->kernel->add_policy(charon->kernel, &id, &policy); /* install forward policy */ - status |= charon->kernel->add_policy(charon->kernel, - host_any, host_any, - other_ts, my_ts, POLICY_FWD, policy_type, - &sa, child->get_mark(child, TRUE), - policy_prio); + id.dir = POLICY_FWD; + status |= charon->kernel->add_policy(charon->kernel, &id, &policy); } e_other_ts->destroy(e_other_ts); } @@ -247,25 +253,31 @@ static void uninstall_shunt_policy(child_cfg_t *child) continue; } /* uninstall out policy */ - status |= charon->kernel->del_policy(charon->kernel, - host_any, host_any, - my_ts, other_ts, POLICY_OUT, policy_type, - &sa, child->get_mark(child, FALSE), - policy_prio); - + kernel_ipsec_policy_id_t id = { + .dir = POLICY_OUT, + .src_ts = my_ts, + .dst_ts = other_ts, + .mark = child->get_mark(child, FALSE), + }; + kernel_ipsec_manage_policy_t policy = { + .type = policy_type, + .prio = policy_prio, + .src = host_any, + .dst = host_any, + .sa = &sa, + }; + status |= charon->kernel->del_policy(charon->kernel, &id, &policy); /* uninstall in policy */ - status |= charon->kernel->del_policy(charon->kernel, - host_any, host_any, - other_ts, my_ts, POLICY_IN, policy_type, - &sa, child->get_mark(child, TRUE), - policy_prio); - + id = (kernel_ipsec_policy_id_t){ + .dir = POLICY_IN, + .src_ts = other_ts, + .dst_ts = my_ts, + .mark = child->get_mark(child, TRUE), + }; + status |= charon->kernel->del_policy(charon->kernel, &id, &policy); /* uninstall forward policy */ - status |= charon->kernel->del_policy(charon->kernel, - host_any, host_any, - other_ts, my_ts, POLICY_FWD, policy_type, - &sa, child->get_mark(child, TRUE), - policy_prio); + id.dir = POLICY_FWD; + status |= charon->kernel->del_policy(charon->kernel, &id, &policy); } e_other_ts->destroy(e_other_ts); } From c4387e991ac1efb7cd0293ebc57b8372046cf944 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 1 Apr 2016 16:26:07 +0200 Subject: [PATCH 02/16] kernel-netlink: Associate routes with IN policies instead of FWD policies This allows us to install more than one FWD policy. We already do this in the kernel-pfkey plugin (there the original reason was that not all kernels support FWD policies). --- .../kernel_netlink/kernel_netlink_ipsec.c | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 7baea3e44..df79f86fc 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -463,7 +463,7 @@ static void ipsec_sa_destroy(private_kernel_netlink_ipsec_t *this, } typedef struct policy_sa_t policy_sa_t; -typedef struct policy_sa_fwd_t policy_sa_fwd_t; +typedef struct policy_sa_in_t policy_sa_in_t; /** * Mapping between a policy and an IPsec SA. @@ -480,10 +480,10 @@ struct policy_sa_t { }; /** - * For forward policies we also cache the traffic selectors in order to install + * For inbound policies we also cache the traffic selectors in order to install * the route. */ -struct policy_sa_fwd_t { +struct policy_sa_in_t { /** Generic interface */ policy_sa_t generic; @@ -495,7 +495,7 @@ struct policy_sa_fwd_t { }; /** - * Create a policy_sa(_fwd)_t object + * Create a policy_sa(_in)_t object */ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this, policy_dir_t dir, policy_type_t type, host_t *src, host_t *dst, @@ -504,14 +504,14 @@ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this, { policy_sa_t *policy; - if (dir == POLICY_FWD) + if (dir == POLICY_IN) { - policy_sa_fwd_t *fwd; - INIT(fwd, + policy_sa_in_t *in; + INIT(in, .src_ts = src_ts->clone(src_ts), .dst_ts = dst_ts->clone(dst_ts), ); - policy = &fwd->generic; + policy = &in->generic; } else { @@ -523,16 +523,16 @@ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this, } /** - * Destroy a policy_sa(_fwd)_t object + * Destroy a policy_sa(_in)_t object */ static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir, private_kernel_netlink_ipsec_t *this) { - if (*dir == POLICY_FWD) + if (*dir == POLICY_IN) { - policy_sa_fwd_t *fwd = (policy_sa_fwd_t*)policy; - fwd->src_ts->destroy(fwd->src_ts); - fwd->dst_ts->destroy(fwd->dst_ts); + policy_sa_in_t *in = (policy_sa_in_t*)policy; + in->src_ts->destroy(in->src_ts); + in->dst_ts->destroy(in->dst_ts); } ipsec_sa_destroy(this, policy->sa); free(policy); @@ -2243,14 +2243,14 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, } /* install a route, if: - * - this is a forward policy (to just get one for each child) + * - this is a inbound policy (to just get one for each child) * - we are in tunnel/BEET mode or install a bypass policy * - routing is not disabled via strongswan.conf */ - if (policy->direction == POLICY_FWD && this->install_routes && + if (policy->direction == POLICY_IN && this->install_routes && (mapping->type != POLICY_IPSEC || ipsec->cfg.mode != MODE_TRANSPORT)) { - policy_sa_fwd_t *fwd = (policy_sa_fwd_t*)mapping; + policy_sa_in_t *in = (policy_sa_in_t*)mapping; route_entry_t *route; host_t *iface; @@ -2258,10 +2258,10 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, .prefixlen = policy->sel.prefixlen_s, ); - if (charon->kernel->get_address_by_ts(charon->kernel, fwd->dst_ts, + if (charon->kernel->get_address_by_ts(charon->kernel, in->dst_ts, &route->src_ip, NULL) == SUCCESS) { - /* get the nexthop to src (src as we are in POLICY_FWD) */ + /* get the nexthop to src (src as we are in POLICY_IN) */ if (!ipsec->src->is_anyaddr(ipsec->src)) { route->gateway = charon->kernel->get_nexthop(charon->kernel, @@ -2310,8 +2310,8 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, old->src_ip, old->if_name) != SUCCESS) { DBG1(DBG_KNL, "error uninstalling route installed with " - "policy %R === %R %N", fwd->src_ts, - fwd->dst_ts, policy_dir_names, + "policy %R === %R %N", in->src_ts, + in->dst_ts, policy_dir_names, policy->direction); } route_entry_destroy(old); @@ -2319,7 +2319,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, } DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s", - fwd->src_ts, route->gateway, route->src_ip, route->if_name); + in->src_ts, route->gateway, route->src_ip, route->if_name); switch (charon->kernel->add_route(charon->kernel, route->dst_net, route->prefixlen, route->gateway, route->src_ip, route->if_name)) From 9c12635252080af3fad7d4d8e02813d479b6ffdf Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 1 Apr 2016 16:41:05 +0200 Subject: [PATCH 03/16] child-sa: Install "outbound" FWD policy If there is a DROP shunt that matches outbound forwarded traffic it would get dropped as the FWD policy we install only matches decrypted inbound traffic. That's because the Linux kernel first checks the FWD policies before looking up the OUT policy and SA to encrypt the packets. --- src/libcharon/sa/child_sa.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 9c1808b95..05d42ba1d 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -915,6 +915,17 @@ static status_t install_policies_internal(private_child_sa_t *this, { in_id.dir = POLICY_FWD; status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy); + + /* install an "outbound" FWD policy in case there is a drop policy + * matching outbound forwarded traffic, to allow another tunnel to use + * the reversed subnets and do the same we don't set a reqid (this also + * allows the kernel backend to distinguish between the two types of + * FWD policies) */ + out_id.dir = POLICY_FWD; + other_sa->reqid = 0; + status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy); + /* reset the reqid for any other further policies */ + other_sa->reqid = this->reqid; } return status; } @@ -958,6 +969,11 @@ static void del_policies_internal(private_child_sa_t *this, { in_id.dir = POLICY_FWD; charon->kernel->del_policy(charon->kernel, &in_id, &in_policy); + + out_id.dir = POLICY_FWD; + other_sa->reqid = 0; + charon->kernel->del_policy(charon->kernel, &out_id, &out_policy); + other_sa->reqid = this->reqid; } } From f7e9e6a3fdda8c714eddf70015f998bb9c370904 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 1 Apr 2016 16:51:51 +0200 Subject: [PATCH 04/16] kernel-netlink: Only associate templates with inbound FWD policies We can't set a template on the outbound FWD policy (or we'd have to make it optional). Because if the traffic does not come from another (matching) IPsec tunnel it would get dropped due to the template mismatch. --- src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index df79f86fc..22afc6352 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -2156,7 +2156,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, policy_info->lft.soft_use_expires_seconds = 0; policy_info->lft.hard_use_expires_seconds = 0; - if (mapping->type == POLICY_IPSEC) + if (mapping->type == POLICY_IPSEC && ipsec->cfg.reqid) { struct xfrm_user_tmpl *tmpl; struct { From 83312ee5e4eb8f17d7213206eb4a34df2b75c524 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 1 Apr 2016 17:06:10 +0200 Subject: [PATCH 05/16] kernel-netlink: Prefer policies with reqid over those without This allows two CHILD_SAs with reversed subnets to install two FWD policies each. Since the outbound policy won't have a reqid set we will end up with the two inbound FWD policies installed in the kernel, with the correct templates to allow decrypted traffic. --- .../plugins/kernel_netlink/kernel_netlink_ipsec.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 22afc6352..b147590e3 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -2403,7 +2403,13 @@ METHOD(kernel_ipsec_t, add_policy, status_t, enumerator = policy->used_by->create_enumerator(policy->used_by); while (enumerator->enumerate(enumerator, (void**)¤t_sa)) { - if (current_sa->priority >= assigned_sa->priority) + if (current_sa->priority > assigned_sa->priority) + { + break; + } + /* prefer SAs with a reqid over those without */ + if (current_sa->priority == assigned_sa->priority && + (!current_sa->sa->cfg.reqid || assigned_sa->sa->cfg.reqid)) { break; } From 23f25f96475c9125e4f96e7dacfa5d9b1b4f0780 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 4 Apr 2016 10:49:35 +0200 Subject: [PATCH 06/16] shunt-manager: Install "outbound" FWD policy If there is a default drop policy forwarded traffic might otherwise not be allowed by a specific passthrough policy (while local traffic is allowed). --- src/libcharon/sa/shunt_manager.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c index 13c8b5e3d..36af86bae 100644 --- a/src/libcharon/sa/shunt_manager.c +++ b/src/libcharon/sa/shunt_manager.c @@ -124,6 +124,9 @@ static bool install_shunt_policy(child_cfg_t *child) .sa = &sa, }; status |= charon->kernel->add_policy(charon->kernel, &id, &policy); + /* install "outbound" forward policy */ + id.dir = POLICY_FWD; + status |= charon->kernel->add_policy(charon->kernel, &id, &policy); /* install in policy */ id = (kernel_ipsec_policy_id_t){ .dir = POLICY_IN, @@ -132,7 +135,7 @@ static bool install_shunt_policy(child_cfg_t *child) .mark = child->get_mark(child, TRUE), }; status |= charon->kernel->add_policy(charon->kernel, &id, &policy); - /* install forward policy */ + /* install "inbound" forward policy */ id.dir = POLICY_FWD; status |= charon->kernel->add_policy(charon->kernel, &id, &policy); } @@ -267,6 +270,9 @@ static void uninstall_shunt_policy(child_cfg_t *child) .sa = &sa, }; status |= charon->kernel->del_policy(charon->kernel, &id, &policy); + /* uninstall "outbound" forward policy */ + id.dir = POLICY_FWD; + status |= charon->kernel->del_policy(charon->kernel, &id, &policy); /* uninstall in policy */ id = (kernel_ipsec_policy_id_t){ .dir = POLICY_IN, @@ -275,7 +281,7 @@ static void uninstall_shunt_policy(child_cfg_t *child) .mark = child->get_mark(child, TRUE), }; status |= charon->kernel->del_policy(charon->kernel, &id, &policy); - /* uninstall forward policy */ + /* uninstall "inbound" forward policy */ id.dir = POLICY_FWD; status |= charon->kernel->del_policy(charon->kernel, &id, &policy); } From 638b4638e3ead81822ef693612da6bffd04fcfe6 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 1 Apr 2016 19:05:02 +0200 Subject: [PATCH 07/16] testing: Add swanctl/net2net-gw scenario --- .../tests/swanctl/net2net-gw/description.txt | 7 +++ testing/tests/swanctl/net2net-gw/evaltest.dat | 5 ++ .../hosts/carol/etc/strongswan.conf | 14 ++++++ .../hosts/carol/etc/swanctl/swanctl.conf | 49 +++++++++++++++++++ .../net2net-gw/hosts/moon/etc/strongswan.conf | 14 ++++++ .../hosts/moon/etc/swanctl/swanctl.conf | 28 +++++++++++ .../net2net-gw/hosts/sun/etc/strongswan.conf | 14 ++++++ .../hosts/sun/etc/swanctl/swanctl.conf | 28 +++++++++++ testing/tests/swanctl/net2net-gw/posttest.dat | 8 +++ testing/tests/swanctl/net2net-gw/pretest.dat | 12 +++++ testing/tests/swanctl/net2net-gw/test.conf | 25 ++++++++++ 11 files changed, 204 insertions(+) create mode 100755 testing/tests/swanctl/net2net-gw/description.txt create mode 100755 testing/tests/swanctl/net2net-gw/evaltest.dat create mode 100755 testing/tests/swanctl/net2net-gw/hosts/carol/etc/strongswan.conf create mode 100755 testing/tests/swanctl/net2net-gw/hosts/carol/etc/swanctl/swanctl.conf create mode 100755 testing/tests/swanctl/net2net-gw/hosts/moon/etc/strongswan.conf create mode 100755 testing/tests/swanctl/net2net-gw/hosts/moon/etc/swanctl/swanctl.conf create mode 100755 testing/tests/swanctl/net2net-gw/hosts/sun/etc/strongswan.conf create mode 100755 testing/tests/swanctl/net2net-gw/hosts/sun/etc/swanctl/swanctl.conf create mode 100755 testing/tests/swanctl/net2net-gw/posttest.dat create mode 100755 testing/tests/swanctl/net2net-gw/pretest.dat create mode 100755 testing/tests/swanctl/net2net-gw/test.conf diff --git a/testing/tests/swanctl/net2net-gw/description.txt b/testing/tests/swanctl/net2net-gw/description.txt new file mode 100755 index 000000000..00c9f1030 --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/description.txt @@ -0,0 +1,7 @@ +A connection between the subnets behind the gateways moon and sun is set up +via the gateway carol. +The authentication is based on X.509 certificates. Upon the successful +establishment of the IPsec tunnels, the updown script automatically +inserts iptables-based firewall rules that let pass the tunneled traffic. +In order to test tunnels and firewall, client alice behind gateway moon +pings client bob located behind gateway sun. diff --git a/testing/tests/swanctl/net2net-gw/evaltest.dat b/testing/tests/swanctl/net2net-gw/evaltest.dat new file mode 100755 index 000000000..f8f248618 --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/evaltest.dat @@ -0,0 +1,5 @@ +moon::swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=500 remote-id=carol@strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*net-net.*state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.0/16] remote-ts=\[10.2.0.0/16]::YES +sun:: swanctl --list-sas --raw 2> /dev/null::gw-gw.*version=2 state=ESTABLISHED local-host=192.168.0.2 local-port=500 local-id=sun.strongswan.org remote-host=192.168.0.100 remote-port=500 remote-id=carol@strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*net-net.*state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.2.0.0/16] remote-ts=\[10.1.0.0/16]::YES +alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_req=1::YES +sun::tcpdump::IP carol.strongswan.org > sun.strongswan.org: ESP::YES +sun::tcpdump::IP sun.strongswan.org > carol.strongswan.org: ESP::YES diff --git a/testing/tests/swanctl/net2net-gw/hosts/carol/etc/strongswan.conf b/testing/tests/swanctl/net2net-gw/hosts/carol/etc/strongswan.conf new file mode 100755 index 000000000..febe9faba --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/hosts/carol/etc/strongswan.conf @@ -0,0 +1,14 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon { + load = sha1 sha2 md5 aes des hmac pem pkcs1 x509 revocation constraints pubkey gmp random nonce curl kernel-netlink socket-default updown vici + + start-scripts { + creds = /usr/local/sbin/swanctl --load-creds + conns = /usr/local/sbin/swanctl --load-conns + } +} diff --git a/testing/tests/swanctl/net2net-gw/hosts/carol/etc/swanctl/swanctl.conf b/testing/tests/swanctl/net2net-gw/hosts/carol/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..d450053e5 --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/hosts/carol/etc/swanctl/swanctl.conf @@ -0,0 +1,49 @@ +connections { + + gw-moon { + local { + auth = pubkey + certs = carolCert.pem + id = carol@strongswan.org + } + remote { + auth = pubkey + id = moon.strongswan.org + } + children { + net-moon { + local_ts = 10.2.0.0/16 + remote_ts = 10.1.0.0/16 + + updown = /usr/local/libexec/ipsec/_updown iptables + esp_proposals = aes128gcm128-modp3072 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-modp3072 + } + gw-sun { + local { + auth = pubkey + certs = carolCert.pem + id = carol@strongswan.org + } + remote { + auth = pubkey + id = sun.strongswan.org + } + children { + net-sun { + local_ts = 10.1.0.0/16 + remote_ts = 10.2.0.0/16 + + updown = /usr/local/libexec/ipsec/_updown iptables + esp_proposals = aes128gcm128-modp3072 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-modp3072 + } +} diff --git a/testing/tests/swanctl/net2net-gw/hosts/moon/etc/strongswan.conf b/testing/tests/swanctl/net2net-gw/hosts/moon/etc/strongswan.conf new file mode 100755 index 000000000..febe9faba --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/hosts/moon/etc/strongswan.conf @@ -0,0 +1,14 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon { + load = sha1 sha2 md5 aes des hmac pem pkcs1 x509 revocation constraints pubkey gmp random nonce curl kernel-netlink socket-default updown vici + + start-scripts { + creds = /usr/local/sbin/swanctl --load-creds + conns = /usr/local/sbin/swanctl --load-conns + } +} diff --git a/testing/tests/swanctl/net2net-gw/hosts/moon/etc/swanctl/swanctl.conf b/testing/tests/swanctl/net2net-gw/hosts/moon/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..348e5329f --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/hosts/moon/etc/swanctl/swanctl.conf @@ -0,0 +1,28 @@ +connections { + + gw-gw { + remote_addrs = 192.168.0.100 + + local { + auth = pubkey + certs = moonCert.pem + id = moon.strongswan.org + } + remote { + auth = pubkey + id = carol@strongswan.org + } + children { + net-net { + local_ts = 10.1.0.0/16 + remote_ts = 10.2.0.0/16 + + updown = /usr/local/libexec/ipsec/_updown iptables + esp_proposals = aes128gcm128-modp3072 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-modp3072 + } +} diff --git a/testing/tests/swanctl/net2net-gw/hosts/sun/etc/strongswan.conf b/testing/tests/swanctl/net2net-gw/hosts/sun/etc/strongswan.conf new file mode 100755 index 000000000..febe9faba --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/hosts/sun/etc/strongswan.conf @@ -0,0 +1,14 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon { + load = sha1 sha2 md5 aes des hmac pem pkcs1 x509 revocation constraints pubkey gmp random nonce curl kernel-netlink socket-default updown vici + + start-scripts { + creds = /usr/local/sbin/swanctl --load-creds + conns = /usr/local/sbin/swanctl --load-conns + } +} diff --git a/testing/tests/swanctl/net2net-gw/hosts/sun/etc/swanctl/swanctl.conf b/testing/tests/swanctl/net2net-gw/hosts/sun/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..68e70be81 --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/hosts/sun/etc/swanctl/swanctl.conf @@ -0,0 +1,28 @@ +connections { + + gw-gw { + remote_addrs = 192.168.0.100 + + local { + auth = pubkey + certs = sunCert.pem + id = sun.strongswan.org + } + remote { + auth = pubkey + id = carol@strongswan.org + } + children { + net-net { + local_ts = 10.2.0.0/16 + remote_ts = 10.1.0.0/16 + + updown = /usr/local/libexec/ipsec/_updown iptables + esp_proposals = aes128gcm128-modp3072 + } + } + version = 2 + mobike = no + proposals = aes128-sha256-modp3072 + } +} diff --git a/testing/tests/swanctl/net2net-gw/posttest.dat b/testing/tests/swanctl/net2net-gw/posttest.dat new file mode 100755 index 000000000..94914f832 --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/posttest.dat @@ -0,0 +1,8 @@ +moon::swanctl --terminate --ike gw-gw 2> /dev/null +sun::swanctl --terminate --ike gw-gw 2> /dev/null +moon::service charon stop 2> /dev/null +sun::service charon stop 2> /dev/null +carol::service charon stop 2> /dev/null +moon::iptables-restore < /etc/iptables.flush +sun::iptables-restore < /etc/iptables.flush +carol::iptables-restore < /etc/iptables.flush diff --git a/testing/tests/swanctl/net2net-gw/pretest.dat b/testing/tests/swanctl/net2net-gw/pretest.dat new file mode 100755 index 000000000..e3136491c --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/pretest.dat @@ -0,0 +1,12 @@ +moon::iptables-restore < /etc/iptables.rules +sun::iptables-restore < /etc/iptables.rules +carol::iptables-restore < /etc/iptables.rules +moon::service charon start 2> /dev/null +sun::service charon start 2> /dev/null +carol::service charon start 2> /dev/null +carol::expect-connection gw-moon +carol::expect-connection gw-sun +moon::expect-connection gw-gw +moon::swanctl --initiate --child net-net 2> /dev/null +sun::expect-connection gw-gw +sun::swanctl --initiate --child net-net 2> /dev/null diff --git a/testing/tests/swanctl/net2net-gw/test.conf b/testing/tests/swanctl/net2net-gw/test.conf new file mode 100755 index 000000000..6eafdf20f --- /dev/null +++ b/testing/tests/swanctl/net2net-gw/test.conf @@ -0,0 +1,25 @@ +#!/bin/bash +# +# This configuration file provides information on the +# guest instances used for this test + +# All guest instances that are required for this test +# +VIRTHOSTS="alice moon carol winnetou sun bob" + +# Corresponding block diagram +# +DIAGRAM="a-m-c-w-s-b-med.png" + +# Guest instances on which tcpdump is to be started +# +TCPDUMPHOSTS="sun" + +# Guest instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon sun carol" + +# charon controlled by swanctl +# +SWANCTL=1 From 0ff8ce9452be4b1ac77fa9bd697e28f2ffe693e5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 4 Apr 2016 15:06:11 +0200 Subject: [PATCH 08/16] kernel-pfkey: Only install templates for regular IPsec policies with reqid --- .../plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 4c7dc8011..0e2e7df48 100644 --- a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -2428,53 +2428,56 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, pol->sadb_x_policy_priority = mapping->priority; #endif - /* 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) + if (mapping->type == POLICY_IPSEC && ipsec->cfg.reqid) { - req->sadb_x_ipsecrequest_proto = IPPROTO_COMP; + /* 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 = (policy->direction == POLICY_OUT) ? - IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_USE; - if (ipsec->cfg.mode == MODE_TUNNEL) + req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE; + if (proto_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(proto_mode); - req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid; - req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE; - if (proto_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; - } - - pol->sadb_x_policy_len += PFKEY_LEN(req->sadb_x_ipsecrequest_len); PFKEY_EXT_ADD(msg, pol); add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto, From fd8f1194f3f14ff94c02e2218dd01b3aaf14c414 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 4 Apr 2016 15:06:44 +0200 Subject: [PATCH 09/16] kernel-pfkey: Prefer policies with reqid over those without --- src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 0e2e7df48..7eb6c5808 100644 --- a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -2598,7 +2598,13 @@ METHOD(kernel_ipsec_t, add_policy, status_t, enumerator = policy->used_by->create_enumerator(policy->used_by); while (enumerator->enumerate(enumerator, (void**)¤t_sa)) { - if (current_sa->priority >= assigned_sa->priority) + if (current_sa->priority > assigned_sa->priority) + { + break; + } + /* prefer SAs with a reqid over those without */ + if (current_sa->priority == assigned_sa->priority && + (!current_sa->sa->cfg.reqid || assigned_sa->sa->cfg.reqid)) { break; } From 8a00a8452ddb36ec07038242c029a214b0417ae8 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 4 Apr 2016 16:09:23 +0200 Subject: [PATCH 10/16] child-cfg: Use struct to pass data to constructor --- src/charon-cmd/cmd/cmd_connection.c | 20 +- src/charon-nm/nm/nm_service.c | 63 +++-- src/conftest/config.c | 16 +- .../backend/android_service.c | 21 +- src/frontends/osx/charon-xpc/xpc_dispatch.c | 20 +- src/libcharon/config/child_cfg.c | 58 ++--- src/libcharon/config/child_cfg.h | 80 +++--- src/libcharon/plugins/ha/ha_tunnel.c | 13 +- .../plugins/load_tester/load_tester_config.c | 24 +- src/libcharon/plugins/maemo/maemo_service.c | 19 +- src/libcharon/plugins/medcli/medcli_config.c | 38 +-- src/libcharon/plugins/sql/sql_config.c | 20 +- src/libcharon/plugins/stroke/stroke_config.c | 67 ++--- src/libcharon/plugins/uci/uci_config.c | 19 +- src/libcharon/plugins/unity/unity_handler.c | 8 +- src/libcharon/plugins/vici/vici_config.c | 242 +++++++++--------- 16 files changed, 362 insertions(+), 366 deletions(-) diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c index 23e2b09fa..48e7dd309 100644 --- a/src/charon-cmd/cmd/cmd_connection.c +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -335,18 +335,18 @@ static child_cfg_t* create_child_cfg(private_cmd_connection_t *this, traffic_selector_t *ts; proposal_t *proposal; bool has_v4 = FALSE, has_v6 = FALSE; - lifetime_cfg_t lifetime = { - .time = { - .life = 10800 /* 3h */, - .rekey = 10200 /* 2h50min */, - .jitter = 300 /* 5min */ - } + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = 10800 /* 3h */, + .rekey = 10200 /* 2h50min */, + .jitter = 300 /* 5min */ + } + }, + .mode = MODE_TUNNEL, }; - child_cfg = child_cfg_create("cmd", &lifetime, - NULL, FALSE, MODE_TUNNEL, /* updown, hostaccess */ - ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, - 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create("cmd", &child); if (this->child_proposals->get_count(this->child_proposals)) { while (this->child_proposals->remove_first(this->child_proposals, diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c index 4cbf8d05b..f6ef9ecaf 100644 --- a/src/charon-nm/nm/nm_service.c +++ b/src/charon-nm/nm/nm_service.c @@ -289,7 +289,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, NMSettingVPN *vpn; identification_t *user = NULL, *gateway = NULL; const char *address, *str; - bool virtual, encap, ipcomp; + bool virtual, encap; ike_cfg_t *ike_cfg; peer_cfg_t *peer_cfg; child_cfg_t *child_cfg; @@ -300,12 +300,15 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, certificate_t *cert = NULL; x509_t *x509; bool agent = FALSE, smartcard = FALSE, loose_gateway_id = FALSE; - lifetime_cfg_t lifetime = { - .time = { - .life = 10800 /* 3h */, - .rekey = 10200 /* 2h50min */, - .jitter = 300 /* 5min */ - } + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = 10800 /* 3h */, + .rekey = 10200 /* 2h50min */, + .jitter = 300 /* 5min */ + }, + }, + .mode = MODE_TUNNEL, }; /** @@ -339,32 +342,29 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, return FALSE; } str = nm_setting_vpn_get_data_item(vpn, "virtual"); - virtual = str && streq(str, "yes"); + virtual = streq(str, "yes"); str = nm_setting_vpn_get_data_item(vpn, "encap"); - encap = str && streq(str, "yes"); + encap = streq(str, "yes"); str = nm_setting_vpn_get_data_item(vpn, "ipcomp"); - ipcomp = str && streq(str, "yes"); + child.ipcomp = streq(str, "yes"); str = nm_setting_vpn_get_data_item(vpn, "method"); - if (str) + if (streq(str, "psk")) { - if (streq(str, "psk")) - { - auth_class = AUTH_CLASS_PSK; - } - else if (streq(str, "agent")) - { - auth_class = AUTH_CLASS_PUBKEY; - agent = TRUE; - } - else if (streq(str, "key")) - { - auth_class = AUTH_CLASS_PUBKEY; - } - else if (streq(str, "smartcard")) - { - auth_class = AUTH_CLASS_PUBKEY; - smartcard = TRUE; - } + auth_class = AUTH_CLASS_PSK; + } + else if (streq(str, "agent")) + { + auth_class = AUTH_CLASS_PUBKEY; + agent = TRUE; + } + else if (streq(str, "key")) + { + auth_class = AUTH_CLASS_PUBKEY; + } + else if (streq(str, "smartcard")) + { + auth_class = AUTH_CLASS_PUBKEY; + smartcard = TRUE; } /** @@ -561,10 +561,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id); peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); - child_cfg = child_cfg_create(priv->name, &lifetime, - NULL, TRUE, MODE_TUNNEL, /* updown, hostaccess */ - ACTION_NONE, ACTION_NONE, ACTION_NONE, ipcomp, - 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create(priv->name, &child); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP)); ts = traffic_selector_create_dynamic(0, 0, 65535); diff --git a/src/conftest/config.c b/src/conftest/config.c index 907bed9b3..46a21b3ab 100644 --- a/src/conftest/config.c +++ b/src/conftest/config.c @@ -139,25 +139,23 @@ static ike_cfg_t *load_ike_config(private_config_t *this, static child_cfg_t *load_child_config(private_config_t *this, settings_t *settings, char *config, char *child) { + child_cfg_create_t data = { + .mode = MODE_TUNNEL, + }; child_cfg_t *child_cfg; - lifetime_cfg_t lifetime = {}; enumerator_t *enumerator; proposal_t *proposal; traffic_selector_t *ts; - ipsec_mode_t mode = MODE_TUNNEL; char *token; - uint32_t tfc; if (settings->get_bool(settings, "configs.%s.%s.transport", FALSE, config, child)) { - mode = MODE_TRANSPORT; + data.mode = MODE_TRANSPORT; } - tfc = settings->get_int(settings, "configs.%s.%s.tfc_padding", - 0, config, child); - child_cfg = child_cfg_create(child, &lifetime, NULL, FALSE, mode, - ACTION_NONE, ACTION_NONE, ACTION_NONE, - FALSE, 0, 0, NULL, NULL, tfc); + data.tfc = settings->get_int(settings, "configs.%s.%s.tfc_padding", + 0, config, child); + child_cfg = child_cfg_create(child, &data); token = settings->get_str(settings, "configs.%s.%s.proposal", NULL, config, child); diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c index eb3758d2e..ba5c9e28e 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c @@ -673,12 +673,17 @@ static job_requeue_t initiate(private_android_service_t *this) traffic_selector_t *ts; ike_sa_t *ike_sa; auth_cfg_t *auth; - lifetime_cfg_t lifetime = { - .time = { - .life = 3600, /* 1h */ - .rekey = 3000, /* 50min */ - .jitter = 300 /* 5min */ - } + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = 3600, /* 1h */ + .rekey = 3000, /* 50min */ + .jitter = 300 /* 5min */ + }, + }, + .mode = MODE_TUNNEL, + .dpd_action = ACTION_RESTART, + .close_action = ACTION_RESTART, }; char *type, *server; int port; @@ -731,9 +736,7 @@ static job_requeue_t initiate(private_android_service_t *this) auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); - child_cfg = child_cfg_create("android", &lifetime, NULL, TRUE, MODE_TUNNEL, - ACTION_NONE, ACTION_RESTART, ACTION_RESTART, - FALSE, 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create("android", &child); /* create ESP proposals with and without DH groups, let responder decide * if PFS is used */ child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP, diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index 2e84b0e7a..c8079cce8 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -125,18 +125,18 @@ static child_cfg_t* create_child_cfg(char *name) { child_cfg_t *child_cfg; traffic_selector_t *ts; - lifetime_cfg_t lifetime = { - .time = { - .life = 10800 /* 3h */, - .rekey = 10200 /* 2h50min */, - .jitter = 300 /* 5min */ - } + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = 10800 /* 3h */, + .rekey = 10200 /* 2h50min */, + .jitter = 300 /* 5min */ + }, + }, + .mode = MODE_TUNNEL, }; - child_cfg = child_cfg_create(name, &lifetime, - NULL, FALSE, MODE_TUNNEL, /* updown, hostaccess */ - ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, - 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create(name, &child); child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP, "aes128gcm8-aes128gcm12-aes128gcm16-" "aes256gcm8-aes256gcm12-aes256gcm16")); diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 8e5c522d2..1a84d30d2 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner + * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -512,13 +512,6 @@ METHOD(child_cfg_t, set_replay_window, void, this->replay_window = replay_window; } -METHOD(child_cfg_t, set_mipv6_options, void, - private_child_cfg_t *this, bool proxy_mode, bool install_policy) -{ - this->proxy_mode = proxy_mode; - this->install_policy = install_policy; -} - METHOD(child_cfg_t, use_proxy_mode, bool, private_child_cfg_t *this) { @@ -609,12 +602,7 @@ METHOD(child_cfg_t, destroy, void, /* * Described in header-file */ -child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime, - char *updown, bool hostaccess, - ipsec_mode_t mode, action_t start_action, - action_t dpd_action, action_t close_action, - bool ipcomp, uint32_t inactivity, uint32_t reqid, - mark_t *mark_in, mark_t *mark_out, uint32_t tfc) +child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) { private_child_cfg_t *this; @@ -634,7 +622,6 @@ child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime, .get_close_action = _get_close_action, .get_lifetime = _get_lifetime, .get_dh_group = _get_dh_group, - .set_mipv6_options = _set_mipv6_options, .use_ipcomp = _use_ipcomp, .get_inactivity = _get_inactivity, .get_reqid = _get_reqid, @@ -649,35 +636,28 @@ child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime, .destroy = _destroy, }, .name = strdup(name), - .updown = strdupnull(updown), - .hostaccess = hostaccess, - .mode = mode, - .start_action = start_action, - .dpd_action = dpd_action, - .close_action = close_action, - .use_ipcomp = ipcomp, - .inactivity = inactivity, - .reqid = reqid, - .proxy_mode = FALSE, - .install_policy = TRUE, + .updown = strdupnull(data->updown), + .hostaccess = data->hostaccess, + .reqid = data->reqid, + .mode = data->mode, + .proxy_mode = data->proxy_mode, + .start_action = data->start_action, + .dpd_action = data->dpd_action, + .close_action = data->close_action, + .mark_in = data->mark_in, + .mark_out = data->mark_out, + .lifetime = data->lifetime, + .inactivity = data->inactivity, + .use_ipcomp = data->ipcomp, + .tfc = data->tfc, + .install_policy = !data->suppress_policies, .refcount = 1, .proposals = linked_list_create(), .my_ts = linked_list_create(), .other_ts = linked_list_create(), - .tfc = tfc, .replay_window = lib->settings->get_int(lib->settings, - "%s.replay_window", DEFAULT_REPLAY_WINDOW, lib->ns), + "%s.replay_window", DEFAULT_REPLAY_WINDOW, lib->ns), ); - if (mark_in) - { - this->mark_in = *mark_in; - } - if (mark_out) - { - this->mark_out = *mark_out; - } - memcpy(&this->lifetime, lifetime, sizeof(lifetime_cfg_t)); - return &this->public; } diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index 0281f5a5c..4eecbf103 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner + * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -25,6 +25,7 @@ typedef enum action_t action_t; typedef struct child_cfg_t child_cfg_t; +typedef struct child_cfg_create_t child_cfg_create_t; #include #include @@ -248,15 +249,6 @@ struct child_cfg_t { */ void (*set_replay_window)(child_cfg_t *this, uint32_t window); - /** - * Sets two options needed for Mobile IPv6 interoperability. - * - * @param proxy_mode use IPsec transport proxy mode (default FALSE) - * @param install_policy install IPsec kernel policies (default TRUE) - */ - void (*set_mipv6_options)(child_cfg_t *this, bool proxy_mode, - bool install_policy); - /** * Check whether IPsec transport SA should be set up in proxy mode. * @@ -297,38 +289,52 @@ struct child_cfg_t { void (*destroy) (child_cfg_t *this); }; + +/** + * Data passed to the constructor of a child_cfg_t object. + */ +struct child_cfg_create_t { + /** Specific reqid to use for CHILD_SA, 0 for auto assignment */ + uint32_t reqid; + /** Optional inbound mark */ + mark_t mark_in; + /** Optional outbound mark */ + mark_t mark_out; + /** Mode to propose for CHILD_SA */ + ipsec_mode_t mode; + /** Use IPsec transport proxy mode */ + bool proxy_mode; + /** Use IPComp, if peer supports it */ + bool ipcomp; + /** TFC padding size, 0 to disable, -1 to pad to PMTU */ + uint32_t tfc; + /** lifetime_cfg_t for this child_cfg */ + lifetime_cfg_t lifetime; + /** Inactivity timeout in s before closing a CHILD_SA */ + uint32_t inactivity; + /** Start action */ + action_t start_action; + /** DPD action */ + action_t dpd_action; + /** Close action */ + action_t close_action; + /** updown script to execute on up/down event (cloned) */ + char *updown; + /** TRUE to allow access to the local host */ + bool hostaccess; + /** Don't install IPsec policies */ + bool suppress_policies; +}; + /** * Create a configuration template for CHILD_SA setup. * - * The "name" string gets cloned. - * - * The lifetime_cfg_t object gets cloned. - * To prevent two peers to start rekeying at the same time, a jitter may be - * specified. Rekeying of an SA starts at (x.rekey - random(0, x.jitter)). - * * After a call to create, a reference is obtained (refcount = 1). * - * @param name name of the child_cfg - * @param lifetime lifetime_cfg_t for this child_cfg - * @param updown updown script to execute on up/down event - * @param hostaccess TRUE to allow access to the local host - * @param mode mode to propose for CHILD_SA, transport, tunnel or BEET - * @param start_action start action - * @param dpd_action DPD action - * @param close_action close action - * @param ipcomp use IPComp, if peer supports it - * @param inactivity inactivity timeout in s before closing a CHILD_SA - * @param reqid specific reqid to use for CHILD_SA, 0 for auto assign - * @param mark_in optional inbound mark (can be NULL) - * @param mark_out optional outbound mark (can be NULL) - * @param tfc TFC padding size, 0 to disable, -1 to pad to PMTU + * @param name name of the child_cfg (cloned) + * @param data data for this child_cfg * @return child_cfg_t object */ -child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime, - char *updown, bool hostaccess, - ipsec_mode_t mode, action_t start_action, - action_t dpd_action, action_t close_action, - bool ipcomp, uint32_t inactivity, uint32_t reqid, - mark_t *mark_in, mark_t *mark_out, uint32_t tfc); +child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data); #endif /** CHILD_CFG_H_ @}*/ diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index fd8e6466a..fc956ac94 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -183,10 +183,13 @@ static void setup_tunnel(private_ha_tunnel_t *this, auth_cfg_t *auth_cfg; child_cfg_t *child_cfg; traffic_selector_t *ts; - lifetime_cfg_t lifetime = { - .time = { - .life = 21600, .rekey = 20400, .jitter = 400, + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = 21600, .rekey = 20400, .jitter = 400, + }, }, + .mode = MODE_TRANSPORT, }; /* setup credentials */ @@ -224,9 +227,7 @@ static void setup_tunnel(private_ha_tunnel_t *this, identification_create_from_string(remote)); peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE); - child_cfg = child_cfg_create("ha", &lifetime, NULL, TRUE, MODE_TRANSPORT, - ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, - 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create("ha", &child); ts = traffic_selector_create_dynamic(IPPROTO_UDP, HA_PORT, HA_PORT); child_cfg->add_traffic_selector(child_cfg, TRUE, ts); ts = traffic_selector_create_dynamic(IPPROTO_ICMP, 0, 65535); diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c index 9366556fc..efef3fbde 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -688,13 +688,15 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) peer_cfg_t *peer_cfg; char local[32], *remote; host_t *addr; - ipsec_mode_t mode = MODE_TUNNEL; - lifetime_cfg_t lifetime = { - .time = { - .life = this->child_rekey * 2, - .rekey = this->child_rekey, - .jitter = 0 - } + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = this->child_rekey * 2, + .rekey = this->child_rekey, + .jitter = 0 + }, + }, + .mode = MODE_TUNNEL, }; if (num) @@ -768,17 +770,15 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) { if (streq(this->mode, "transport")) { - mode = MODE_TRANSPORT; + child.mode = MODE_TRANSPORT; } else if (streq(this->mode, "beet")) { - mode = MODE_BEET; + child.mode = MODE_BEET; } } - child_cfg = child_cfg_create("load-test", &lifetime, NULL, TRUE, mode, - ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, - 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create("load-test", &child); child_cfg->add_proposal(child_cfg, this->esp->clone(this->esp)); if (num) diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index 2e96f8fb4..db0ce2cf7 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -236,12 +236,15 @@ static gboolean initiate_connection(private_maemo_service_t *this, traffic_selector_t *ts; auth_cfg_t *auth; certificate_t *cert; - lifetime_cfg_t lifetime = { - .time = { - .life = 10800, /* 3h */ - .rekey = 10200, /* 2h50min */ - .jitter = 300 /* 5min */ - } + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = 10800, /* 3h */ + .rekey = 10200, /* 2h50min */ + .jitter = 300 /* 5min */ + }, + }, + .mode = MODE_TUNNEL, }; if (this->status == VPN_STATUS_CONNECTED || @@ -348,9 +351,7 @@ static gboolean initiate_connection(private_maemo_service_t *this, auth->add(auth, AUTH_RULE_IDENTITY, gateway); peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); - child_cfg = child_cfg_create(this->current, &lifetime, NULL /* updown */, - TRUE, MODE_TUNNEL, ACTION_NONE, ACTION_NONE, - ACTION_NONE, FALSE, 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create(this->current, &child); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP)); ts = traffic_selector_create_dynamic(0, 0, 65535); diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index 25b138387..d3476e90f 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -82,12 +82,15 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, child_cfg_t *child_cfg; chunk_t me, other; char *address, *local_net, *remote_net; - lifetime_cfg_t lifetime = { - .time = { - .life = this->rekey * 60 + this->rekey, - .rekey = this->rekey, - .jitter = this->rekey - } + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = this->rekey * 60 + this->rekey, + .rekey = this->rekey, + .jitter = this->rekey + }, + }, + .mode = MODE_TUNNEL, }; /* query mediation server config: @@ -165,9 +168,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, identification_create_from_encoding(ID_KEY_ID, other)); peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); - child_cfg = child_cfg_create(name, &lifetime, NULL, TRUE, MODE_TUNNEL, - ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, - 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create(name, &child); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP)); child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net)); @@ -205,12 +206,15 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, chunk_t me, other; child_cfg_t *child_cfg; auth_cfg_t *auth; - lifetime_cfg_t lifetime = { - .time = { - .life = this->rekey * 60 + this->rekey, - .rekey = this->rekey, - .jitter = this->rekey - } + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = this->rekey * 60 + this->rekey, + .rekey = this->rekey, + .jitter = this->rekey + }, + }, + .mode = MODE_TUNNEL, }; DESTROY_IF(this->current); @@ -240,9 +244,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, identification_create_from_encoding(ID_KEY_ID, other)); this->current->add_auth_cfg(this->current, auth, FALSE); - child_cfg = child_cfg_create(name, &lifetime, NULL, TRUE, MODE_TUNNEL, - ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, - 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create(name, &child); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP)); child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net)); diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index ce24d180a..25704b0de 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -170,12 +170,22 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e) if (e->enumerate(e, &id, &name, &lifetime, &rekeytime, &jitter, &updown, &hostaccess, &mode, &start, &dpd, &close, &ipcomp, &reqid)) { - lifetime_cfg_t lft = { - .time = { .life = lifetime, .rekey = rekeytime, .jitter = jitter } + child_cfg_create_t child = { + .mode = mode, + .reqid = reqid, + .ipcomp = ipcomp, + .lifetime = { + .time = { + .life = lifetime, .rekey = rekeytime, .jitter = jitter + }, + }, + .start_action = start, + .dpd_action = dpd, + .close_action = close, + .updown = updown, + .hostaccess = hostaccess, }; - child_cfg = child_cfg_create(name, &lft, updown, hostaccess, mode, - start, dpd, close, ipcomp, 0, reqid, - NULL, NULL, 0); + child_cfg = child_cfg_create(name, &child); add_esp_proposals(this, child_cfg, id); add_traffic_selectors(this, child_cfg, id); return child_cfg; diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 0e6aee1b0..9789163b7 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -1070,45 +1070,50 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this, stroke_msg_t *msg) { child_cfg_t *child_cfg; - lifetime_cfg_t lifetime = { - .time = { - .life = msg->add_conn.rekey.ipsec_lifetime, - .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, - .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100 + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = msg->add_conn.rekey.ipsec_lifetime, + .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, + .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100 + }, + .bytes = { + .life = msg->add_conn.rekey.life_bytes, + .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes, + .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100 + }, + .packets = { + .life = msg->add_conn.rekey.life_packets, + .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets, + .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100 + }, }, - .bytes = { - .life = msg->add_conn.rekey.life_bytes, - .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes, - .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100 + .mark_in = { + .value = msg->add_conn.mark_in.value, + .mask = msg->add_conn.mark_in.mask }, - .packets = { - .life = msg->add_conn.rekey.life_packets, - .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets, - .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100 - } - }; - mark_t mark_in = { - .value = msg->add_conn.mark_in.value, - .mask = msg->add_conn.mark_in.mask - }; - mark_t mark_out = { - .value = msg->add_conn.mark_out.value, - .mask = msg->add_conn.mark_out.mask + .mark_out = { + .value = msg->add_conn.mark_out.value, + .mask = msg->add_conn.mark_out.mask + }, + .reqid = msg->add_conn.reqid, + .mode = msg->add_conn.mode, + .proxy_mode = msg->add_conn.proxy_mode, + .ipcomp = msg->add_conn.ipcomp, + .tfc = msg->add_conn.tfc, + .inactivity = msg->add_conn.inactivity, + .dpd_action = map_action(msg->add_conn.dpd.action), + .close_action = map_action(msg->add_conn.close_action), + .updown = msg->add_conn.me.updown, + .hostaccess = msg->add_conn.me.hostaccess, + .suppress_policies = !msg->add_conn.install_policy, }; - child_cfg = child_cfg_create( - msg->add_conn.name, &lifetime, msg->add_conn.me.updown, - msg->add_conn.me.hostaccess, msg->add_conn.mode, ACTION_NONE, - map_action(msg->add_conn.dpd.action), - map_action(msg->add_conn.close_action), msg->add_conn.ipcomp, - msg->add_conn.inactivity, msg->add_conn.reqid, - &mark_in, &mark_out, msg->add_conn.tfc); + child_cfg = child_cfg_create(msg->add_conn.name, &child); if (msg->add_conn.replay_window != -1) { child_cfg->set_replay_window(child_cfg, msg->add_conn.replay_window); } - child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode, - msg->add_conn.install_policy); add_ts(this, &msg->add_conn.me, child_cfg, TRUE); add_ts(this, &msg->add_conn.other, child_cfg, FALSE); diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c index 2a8e40380..8d76bb454 100644 --- a/src/libcharon/plugins/uci/uci_config.c +++ b/src/libcharon/plugins/uci/uci_config.c @@ -126,12 +126,15 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, child_cfg_t *child_cfg; ike_cfg_t *ike_cfg; auth_cfg_t *auth; - lifetime_cfg_t lifetime = { - .time = { - .life = create_rekey(esp_rekey) + 300, - .rekey = create_rekey(esp_rekey), - .jitter = 300 - } + child_cfg_create_t child = { + .lifetime = { + .time = { + .life = create_rekey(esp_rekey) + 300, + .rekey = create_rekey(esp_rekey), + .jitter = 300 + }, + }, + .mode = MODE_TUNNEL, }; /* defaults */ @@ -179,9 +182,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, } this->peer_cfg->add_auth_cfg(this->peer_cfg, auth, FALSE); - child_cfg = child_cfg_create(name, &lifetime, NULL, TRUE, MODE_TUNNEL, - ACTION_NONE, ACTION_NONE, ACTION_NONE, - FALSE, 0, 0, NULL, NULL, 0); + child_cfg = child_cfg_create(name, &child); child_cfg->add_proposal(child_cfg, create_proposal(esp_proposal, PROTO_ESP)); child_cfg->add_traffic_selector(child_cfg, TRUE, create_ts(local_net)); child_cfg->add_traffic_selector(child_cfg, FALSE, create_ts(remote_net)); diff --git a/src/libcharon/plugins/unity/unity_handler.c b/src/libcharon/plugins/unity/unity_handler.c index 9fc9be61a..570727823 100644 --- a/src/libcharon/plugins/unity/unity_handler.c +++ b/src/libcharon/plugins/unity/unity_handler.c @@ -206,7 +206,9 @@ static job_requeue_t add_exclude_async(entry_t *entry) { enumerator_t *enumerator; child_cfg_t *child_cfg; - lifetime_cfg_t lft = { .time = { .life = 0 } }; + child_cfg_create_t child = { + .mode = MODE_PASS, + }; ike_sa_t *ike_sa; char name[128]; host_t *host; @@ -216,9 +218,7 @@ static job_requeue_t add_exclude_async(entry_t *entry) { create_shunt_name(ike_sa, entry->ts, name, sizeof(name)); - child_cfg = child_cfg_create(name, &lft, NULL, TRUE, MODE_PASS, - ACTION_NONE, ACTION_NONE, ACTION_NONE, - FALSE, 0, 0, NULL, NULL, FALSE); + child_cfg = child_cfg_create(name, &child); child_cfg->add_traffic_selector(child_cfg, FALSE, entry->ts->clone(entry->ts)); host = ike_sa->get_my_host(ike_sa); diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index f95d1571b..f1c2fa860 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -422,24 +422,12 @@ static void free_peer_data(peer_data_t *data) */ typedef struct { request_data_t *request; - lifetime_cfg_t lft; - char* updown; - bool hostaccess; - bool ipcomp; - bool policies; - ipsec_mode_t mode; - uint32_t replay_window; - action_t dpd_action; - action_t start_action; - action_t close_action; - uint32_t reqid; - uint32_t tfc; - mark_t mark_in; - mark_t mark_out; - uint64_t inactivity; linked_list_t *proposals; linked_list_t *local_ts; linked_list_t *remote_ts; + uint32_t replay_window; + bool policies; + child_cfg_create_t cfg; } child_data_t; /** @@ -447,35 +435,37 @@ typedef struct { */ static void log_child_data(child_data_t *data, char *name) { + child_cfg_create_t *cfg = &data->cfg; + DBG2(DBG_CFG, " child %s:", name); - DBG2(DBG_CFG, " rekey_time = %llu", data->lft.time.rekey); - DBG2(DBG_CFG, " life_time = %llu", data->lft.time.life); - DBG2(DBG_CFG, " rand_time = %llu", data->lft.time.jitter); - DBG2(DBG_CFG, " rekey_bytes = %llu", data->lft.bytes.rekey); - DBG2(DBG_CFG, " life_bytes = %llu", data->lft.bytes.life); - DBG2(DBG_CFG, " rand_bytes = %llu", data->lft.bytes.jitter); - DBG2(DBG_CFG, " rekey_packets = %llu", data->lft.packets.rekey); - DBG2(DBG_CFG, " life_packets = %llu", data->lft.packets.life); - DBG2(DBG_CFG, " rand_packets = %llu", data->lft.packets.jitter); - DBG2(DBG_CFG, " updown = %s", data->updown); - DBG2(DBG_CFG, " hostaccess = %u", data->hostaccess); - DBG2(DBG_CFG, " ipcomp = %u", data->ipcomp); - DBG2(DBG_CFG, " mode = %N", ipsec_mode_names, data->mode); + DBG2(DBG_CFG, " rekey_time = %llu", cfg->lifetime.time.rekey); + DBG2(DBG_CFG, " life_time = %llu", cfg->lifetime.time.life); + DBG2(DBG_CFG, " rand_time = %llu", cfg->lifetime.time.jitter); + DBG2(DBG_CFG, " rekey_bytes = %llu", cfg->lifetime.bytes.rekey); + DBG2(DBG_CFG, " life_bytes = %llu", cfg->lifetime.bytes.life); + DBG2(DBG_CFG, " rand_bytes = %llu", cfg->lifetime.bytes.jitter); + DBG2(DBG_CFG, " rekey_packets = %llu", cfg->lifetime.packets.rekey); + DBG2(DBG_CFG, " life_packets = %llu", cfg->lifetime.packets.life); + DBG2(DBG_CFG, " rand_packets = %llu", cfg->lifetime.packets.jitter); + DBG2(DBG_CFG, " updown = %s", cfg->updown); + DBG2(DBG_CFG, " hostaccess = %u", cfg->hostaccess); + DBG2(DBG_CFG, " ipcomp = %u", cfg->ipcomp); + DBG2(DBG_CFG, " mode = %N", ipsec_mode_names, cfg->mode); DBG2(DBG_CFG, " policies = %u", data->policies); if (data->replay_window != REPLAY_UNDEFINED) { DBG2(DBG_CFG, " replay_window = %u", data->replay_window); } - DBG2(DBG_CFG, " dpd_action = %N", action_names, data->dpd_action); - DBG2(DBG_CFG, " start_action = %N", action_names, data->start_action); - DBG2(DBG_CFG, " close_action = %N", action_names, data->close_action); - DBG2(DBG_CFG, " reqid = %u", data->reqid); - DBG2(DBG_CFG, " tfc = %d", data->tfc); + DBG2(DBG_CFG, " dpd_action = %N", action_names, cfg->dpd_action); + DBG2(DBG_CFG, " start_action = %N", action_names, cfg->start_action); + DBG2(DBG_CFG, " close_action = %N", action_names, cfg->close_action); + DBG2(DBG_CFG, " reqid = %u", cfg->reqid); + DBG2(DBG_CFG, " tfc = %d", cfg->tfc); DBG2(DBG_CFG, " mark_in = %u/%u", - data->mark_in.value, data->mark_in.mask); + cfg->mark_in.value, cfg->mark_in.mask); DBG2(DBG_CFG, " mark_out = %u/%u", - data->mark_out.value, data->mark_out.mask); - DBG2(DBG_CFG, " inactivity = %llu", data->inactivity); + cfg->mark_out.value, cfg->mark_out.mask); + DBG2(DBG_CFG, " inactivity = %llu", cfg->inactivity); DBG2(DBG_CFG, " proposals = %#P", data->proposals); DBG2(DBG_CFG, " local_ts = %#R", data->local_ts); DBG2(DBG_CFG, " remote_ts = %#R", data->remote_ts); @@ -492,7 +482,7 @@ static void free_child_data(child_data_t *data) offsetof(traffic_selector_t, destroy)); data->remote_ts->destroy_offset(data->remote_ts, offsetof(traffic_selector_t, destroy)); - free(data->updown); + free(data->cfg.updown); } /** @@ -1327,29 +1317,29 @@ CALLBACK(child_kv, bool, child_data_t *child, vici_message_t *message, char *name, chunk_t value) { parse_rule_t rules[] = { - { "updown", parse_string, &child->updown }, - { "hostaccess", parse_bool, &child->hostaccess }, - { "mode", parse_mode, &child->mode }, - { "policies", parse_bool, &child->policies }, - { "replay_window", parse_uint32, &child->replay_window }, - { "rekey_time", parse_time, &child->lft.time.rekey }, - { "life_time", parse_time, &child->lft.time.life }, - { "rand_time", parse_time, &child->lft.time.jitter }, - { "rekey_bytes", parse_bytes, &child->lft.bytes.rekey }, - { "life_bytes", parse_bytes, &child->lft.bytes.life }, - { "rand_bytes", parse_bytes, &child->lft.bytes.jitter }, - { "rekey_packets", parse_uint64, &child->lft.packets.rekey }, - { "life_packets", parse_uint64, &child->lft.packets.life }, - { "rand_packets", parse_uint64, &child->lft.packets.jitter }, - { "dpd_action", parse_action, &child->dpd_action }, - { "start_action", parse_action, &child->start_action }, - { "close_action", parse_action, &child->close_action }, - { "ipcomp", parse_bool, &child->ipcomp }, - { "inactivity", parse_time, &child->inactivity }, - { "reqid", parse_uint32, &child->reqid }, - { "mark_in", parse_mark, &child->mark_in }, - { "mark_out", parse_mark, &child->mark_out }, - { "tfc_padding", parse_tfc, &child->tfc }, + { "updown", parse_string, &child->cfg.updown }, + { "hostaccess", parse_bool, &child->cfg.hostaccess }, + { "mode", parse_mode, &child->cfg.mode }, + { "policies", parse_bool, &child->policies }, + { "replay_window", parse_uint32, &child->replay_window }, + { "rekey_time", parse_time, &child->cfg.lifetime.time.rekey }, + { "life_time", parse_time, &child->cfg.lifetime.time.life }, + { "rand_time", parse_time, &child->cfg.lifetime.time.jitter }, + { "rekey_bytes", parse_bytes, &child->cfg.lifetime.bytes.rekey }, + { "life_bytes", parse_bytes, &child->cfg.lifetime.bytes.life }, + { "rand_bytes", parse_bytes, &child->cfg.lifetime.bytes.jitter }, + { "rekey_packets", parse_uint64, &child->cfg.lifetime.packets.rekey }, + { "life_packets", parse_uint64, &child->cfg.lifetime.packets.life }, + { "rand_packets", parse_uint64, &child->cfg.lifetime.packets.jitter }, + { "dpd_action", parse_action, &child->cfg.dpd_action }, + { "start_action", parse_action, &child->cfg.start_action }, + { "close_action", parse_action, &child->cfg.close_action }, + { "ipcomp", parse_bool, &child->cfg.ipcomp }, + { "inactivity", parse_time, &child->cfg.inactivity }, + { "reqid", parse_uint32, &child->cfg.reqid }, + { "mark_in", parse_mark, &child->cfg.mark_in }, + { "mark_out", parse_mark, &child->cfg.mark_out }, + { "tfc_padding", parse_tfc, &child->cfg.tfc }, }; return parse_rules(rules, countof(rules), name, value, @@ -1430,6 +1420,51 @@ CALLBACK(peer_kv, bool, &peer->request->reply); } +/** + * Check and update lifetimes + */ +static void check_lifetimes(lifetime_cfg_t *lft) +{ + /* if no hard lifetime specified, add one at soft lifetime + 10% */ + if (lft->time.life == LFT_UNDEFINED) + { + lft->time.life = lft->time.rekey * 110 / 100; + } + if (lft->bytes.life == LFT_UNDEFINED) + { + lft->bytes.life = lft->bytes.rekey * 110 / 100; + } + if (lft->packets.life == LFT_UNDEFINED) + { + lft->packets.life = lft->packets.rekey * 110 / 100; + } + /* if no soft lifetime specified, add one at hard lifetime - 10% */ + if (lft->bytes.rekey == LFT_UNDEFINED) + { + lft->bytes.rekey = lft->bytes.life * 90 / 100; + } + if (lft->packets.rekey == LFT_UNDEFINED) + { + lft->packets.rekey = lft->packets.life * 90 / 100; + } + /* if no rand time defined, use difference of hard and soft */ + if (lft->time.jitter == LFT_UNDEFINED) + { + lft->time.jitter = lft->time.life - + min(lft->time.life, lft->time.rekey); + } + if (lft->bytes.jitter == LFT_UNDEFINED) + { + lft->bytes.jitter = lft->bytes.life - + min(lft->bytes.life, lft->bytes.rekey); + } + if (lft->packets.jitter == LFT_UNDEFINED) + { + lft->packets.jitter = lft->packets.life - + min(lft->packets.life, lft->packets.rekey); + } +} + CALLBACK(children_sn, bool, peer_data_t *peer, vici_message_t *message, vici_parse_context_t *ctx, char *name) @@ -1439,29 +1474,28 @@ CALLBACK(children_sn, bool, .proposals = linked_list_create(), .local_ts = linked_list_create(), .remote_ts = linked_list_create(), - .mode = MODE_TUNNEL, .policies = TRUE, .replay_window = REPLAY_UNDEFINED, - .dpd_action = ACTION_NONE, - .start_action = ACTION_NONE, - .close_action = ACTION_NONE, - .lft = { - .time = { - .rekey = LFT_DEFAULT_CHILD_REKEY, - .life = LFT_UNDEFINED, - .jitter = LFT_UNDEFINED, + .cfg = { + .mode = MODE_TUNNEL, + .lifetime = { + .time = { + .rekey = LFT_DEFAULT_CHILD_REKEY, + .life = LFT_UNDEFINED, + .jitter = LFT_UNDEFINED, + }, + .bytes = { + .rekey = LFT_UNDEFINED, + .life = LFT_UNDEFINED, + .jitter = LFT_UNDEFINED, + }, + .packets = { + .rekey = LFT_UNDEFINED, + .life = LFT_UNDEFINED, + .jitter = LFT_UNDEFINED, + }, }, - .bytes = { - .rekey = LFT_UNDEFINED, - .life = LFT_UNDEFINED, - .jitter = LFT_UNDEFINED, - }, - .packets = { - .rekey = LFT_UNDEFINED, - .life = LFT_UNDEFINED, - .jitter = LFT_UNDEFINED, - }, - } + }, }; child_cfg_t *cfg; proposal_t *proposal; @@ -1496,55 +1530,13 @@ CALLBACK(children_sn, bool, child.proposals->insert_last(child.proposals, proposal); } } + child.cfg.suppress_policies = !child.policies; - /* if no hard lifetime specified, add one at soft lifetime + 10% */ - if (child.lft.time.life == LFT_UNDEFINED) - { - child.lft.time.life = child.lft.time.rekey * 110 / 100; - } - if (child.lft.bytes.life == LFT_UNDEFINED) - { - child.lft.bytes.life = child.lft.bytes.rekey * 110 / 100; - } - if (child.lft.packets.life == LFT_UNDEFINED) - { - child.lft.packets.life = child.lft.packets.rekey * 110 / 100; - } - /* if no soft lifetime specified, add one at hard lifetime - 10% */ - if (child.lft.bytes.rekey == LFT_UNDEFINED) - { - child.lft.bytes.rekey = child.lft.bytes.life * 90 / 100; - } - if (child.lft.packets.rekey == LFT_UNDEFINED) - { - child.lft.packets.rekey = child.lft.packets.life * 90 / 100; - } - /* if no rand time defined, use difference of hard and soft */ - if (child.lft.time.jitter == LFT_UNDEFINED) - { - child.lft.time.jitter = child.lft.time.life - - min(child.lft.time.life, child.lft.time.rekey); - } - if (child.lft.bytes.jitter == LFT_UNDEFINED) - { - child.lft.bytes.jitter = child.lft.bytes.life - - min(child.lft.bytes.life, child.lft.bytes.rekey); - } - if (child.lft.packets.jitter == LFT_UNDEFINED) - { - child.lft.packets.jitter = child.lft.packets.life - - min(child.lft.packets.life, child.lft.packets.rekey); - } + check_lifetimes(&child.cfg.lifetime); log_child_data(&child, name); - cfg = child_cfg_create(name, &child.lft, child.updown, - child.hostaccess, child.mode, child.start_action, - child.dpd_action, child.close_action, child.ipcomp, - child.inactivity, child.reqid, &child.mark_in, - &child.mark_out, child.tfc); - - cfg->set_mipv6_options(cfg, FALSE, child.policies); + cfg = child_cfg_create(name, &child.cfg); if (child.replay_window != REPLAY_UNDEFINED) { From 2ba5dadb12dd95c9ba5ff99e619fb33388582661 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 4 Apr 2016 18:41:17 +0200 Subject: [PATCH 11/16] peer-cfg: Use struct to pass data to constructor --- src/charon-cmd/cmd/cmd_connection.c | 20 ++--- src/charon-nm/nm/nm_service.c | 17 ++-- src/conftest/config.c | 10 ++- .../backend/android_service.c | 15 ++-- src/frontends/osx/charon-xpc/xpc_dispatch.c | 17 ++-- src/libcharon/config/peer_cfg.c | 63 ++++++--------- src/libcharon/config/peer_cfg.h | 81 +++++++++++-------- src/libcharon/plugins/ha/ha_tunnel.c | 13 ++- .../plugins/load_tester/load_tester_config.c | 20 +++-- src/libcharon/plugins/maemo/maemo_service.c | 17 ++-- src/libcharon/plugins/medcli/medcli_config.c | 50 ++++++------ src/libcharon/plugins/medsrv/medsrv_config.c | 20 +++-- src/libcharon/plugins/sql/sql_config.c | 30 +++++-- src/libcharon/plugins/stroke/stroke_config.c | 53 ++++++------ src/libcharon/plugins/uci/uci_config.c | 17 ++-- src/libcharon/plugins/vici/vici_config.c | 23 ++++-- 16 files changed, 266 insertions(+), 200 deletions(-) diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c index 48e7dd309..71df92f7e 100644 --- a/src/charon-cmd/cmd/cmd_connection.c +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -144,8 +144,16 @@ static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) peer_cfg_t *peer_cfg; uint16_t local_port, remote_port = IKEV2_UDP_PORT; ike_version_t version = IKE_ANY; - bool aggressive = FALSE; proposal_t *proposal; + peer_cfg_create_t peer = { + .cert_policy = CERT_SEND_IF_ASKED, + .unique = UNIQUE_REPLACE, + .keyingtries = 1, + .rekey_time = 36000, /* 10h */ + .jitter_time = 600, /* 10min */ + .over_time = 600, /* 10min */ + .dpd = 30, + }; switch (this->profile) { @@ -159,7 +167,7 @@ static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) case PROF_V1_XAUTH_AM: case PROF_V1_XAUTH_PSK_AM: case PROF_V1_HYBRID_AM: - aggressive = TRUE; + peer.aggressive = TRUE; /* FALL */ case PROF_V1_PUB: case PROF_V1_XAUTH: @@ -189,13 +197,7 @@ static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); } - peer_cfg = peer_cfg_create("cmd", ike_cfg, - CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ - 36000, 0, /* rekey 10h, reauth none */ - 600, 600, /* jitter, over 10min */ - TRUE, aggressive, TRUE, /* mobike, aggressive, pull */ - 30, 0, /* DPD delay, timeout */ - FALSE, NULL, NULL); /* mediation */ + peer_cfg = peer_cfg_create("cmd", ike_cfg, &peer); return peer_cfg; } diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c index f6ef9ecaf..5991c2465 100644 --- a/src/charon-nm/nm/nm_service.c +++ b/src/charon-nm/nm/nm_service.c @@ -300,6 +300,14 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, certificate_t *cert = NULL; x509_t *x509; bool agent = FALSE, smartcard = FALSE, loose_gateway_id = FALSE; + peer_cfg_create_t peer = { + .cert_policy = CERT_SEND_IF_ASKED, + .unique = UNIQUE_REPLACE, + .keyingtries = 1, + .rekey_time = 36000, /* 10h */ + .jitter_time = 600, /* 10min */ + .over_time = 600, /* 10min */ + }; child_cfg_create_t child = { .lifetime = { .time = { @@ -533,13 +541,8 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); - peer_cfg = peer_cfg_create(priv->name, ike_cfg, - CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ - 36000, 0, /* rekey 10h, reauth none */ - 600, 600, /* jitter, over 10min */ - TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ - 0, 0, /* DPD delay, timeout */ - FALSE, NULL, NULL); /* mediation */ + + peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer); if (virtual) { peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); diff --git a/src/conftest/config.c b/src/conftest/config.c index 46a21b3ab..06a685047 100644 --- a/src/conftest/config.c +++ b/src/conftest/config.c @@ -247,11 +247,15 @@ static peer_cfg_t *load_peer_config(private_config_t *this, identification_t *lid, *rid; char *child, *policy, *pool; uintptr_t strength; + peer_cfg_create_t peer = { + .cert_policy = CERT_ALWAYS_SEND, + .unique = UNIQUE_NO, + .keyingtries = 1, + .no_mobike = TRUE, + }; ike_cfg = load_ike_config(this, settings, config); - peer_cfg = peer_cfg_create(config, ike_cfg, CERT_ALWAYS_SEND, - UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, FALSE, TRUE, - 0, 0, FALSE, NULL, NULL); + peer_cfg = peer_cfg_create(config, ike_cfg, &peer); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c index ba5c9e28e..b3e91d808 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c @@ -673,6 +673,13 @@ static job_requeue_t initiate(private_android_service_t *this) traffic_selector_t *ts; ike_sa_t *ike_sa; auth_cfg_t *auth; + peer_cfg_create_t peer = { + .cert_policy = CERT_SEND_IF_ASKED, + .unique = UNIQUE_REPLACE, + .rekey_time = 36000, /* 10h */ + .jitter_time = 600, /* 10min */ + .over_time = 600, /* 10min */ + }; child_cfg_create_t child = { .lifetime = { .time = { @@ -697,13 +704,7 @@ static job_requeue_t initiate(private_android_service_t *this) ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); - peer_cfg = peer_cfg_create("android", ike_cfg, CERT_SEND_IF_ASKED, - UNIQUE_REPLACE, 0, /* keyingtries */ - 36000, 0, /* rekey 10h, reauth none */ - 600, 600, /* jitter, over 10min */ - TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ - 0, 0, /* DPD delay, timeout */ - FALSE, NULL, NULL); /* mediation */ + peer_cfg = peer_cfg_create("android", ike_cfg, &peer); peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET)); peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET6)); diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index c8079cce8..0483199df 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -78,6 +78,15 @@ static peer_cfg_t* create_peer_cfg(char *name, char *host) ike_cfg_t *ike_cfg; peer_cfg_t *peer_cfg; uint16_t local_port, remote_port = IKEV2_UDP_PORT; + peer_cfg_create_t peer = { + .cert_policy = CERT_SEND_IF_ASKED, + .unique = UNIQUE_REPLACE, + .keyingtries = 1, + .rekey_time = 36000, /* 10h */ + .jitter_time = 600, /* 10min */ + .over_time = 600, /* 10min */ + .dpd = 30, + }; local_port = charon->socket->get_port(charon->socket, FALSE); if (local_port != IKEV2_UDP_PORT) @@ -88,13 +97,7 @@ static peer_cfg_t* create_peer_cfg(char *name, char *host) host, remote_port, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); - peer_cfg = peer_cfg_create(name, ike_cfg, - CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ - 36000, 0, /* rekey 10h, reauth none */ - 600, 600, /* jitter, over 10min */ - TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ - 30, 0, /* DPD delay, timeout */ - FALSE, NULL, NULL); /* mediation */ + peer_cfg = peer_cfg_create(name, ike_cfg, &peer); peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); return peer_cfg; diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index 4eebfb09d..6463c7a36 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2007-2015 Tobias Brunner + * Copyright (C) 2007-2016 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -724,29 +724,22 @@ METHOD(peer_cfg_t, destroy, void, /* * Described in header-file */ -peer_cfg_t *peer_cfg_create(char *name, - ike_cfg_t *ike_cfg, cert_policy_t cert_policy, - unique_policy_t unique, uint32_t keyingtries, - uint32_t rekey_time, uint32_t reauth_time, - uint32_t jitter_time, uint32_t over_time, - bool mobike, bool aggressive, bool pull_mode, - uint32_t dpd, uint32_t dpd_timeout, - bool mediation, peer_cfg_t *mediated_by, - identification_t *peer_id) +peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg, + peer_cfg_create_t *data) { private_peer_cfg_t *this; - if (rekey_time && jitter_time > rekey_time) + if (data->rekey_time && data->jitter_time > data->rekey_time) { - jitter_time = rekey_time; + data->jitter_time = data->rekey_time; } - if (reauth_time && jitter_time > reauth_time) + if (data->reauth_time && data->jitter_time > data->reauth_time) { - jitter_time = reauth_time; + data->jitter_time = data->reauth_time; } - if (dpd && dpd_timeout && dpd > dpd_timeout) + if (data->dpd && data->dpd_timeout && data->dpd > data->dpd_timeout) { - dpd_timeout = dpd; + data->dpd_timeout = data->dpd; } INIT(this, @@ -789,33 +782,29 @@ peer_cfg_t *peer_cfg_create(char *name, .ike_cfg = ike_cfg, .child_cfgs = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - .cert_policy = cert_policy, - .unique = unique, - .keyingtries = keyingtries, - .rekey_time = rekey_time, - .reauth_time = reauth_time, - .jitter_time = jitter_time, - .over_time = over_time, - .use_mobike = mobike, - .aggressive = aggressive, - .pull_mode = pull_mode, - .dpd = dpd, - .dpd_timeout = dpd_timeout, + .cert_policy = data->cert_policy, + .unique = data->unique, + .keyingtries = data->keyingtries, + .rekey_time = data->rekey_time, + .reauth_time = data->reauth_time, + .jitter_time = data->jitter_time, + .over_time = data->over_time, + .use_mobike = !data->no_mobike, + .aggressive = data->aggressive, + .pull_mode = !data->push_mode, + .dpd = data->dpd, + .dpd_timeout = data->dpd_timeout, .vips = linked_list_create(), .pools = linked_list_create(), .local_auth = linked_list_create(), .remote_auth = linked_list_create(), .refcount = 1, - ); - #ifdef ME - this->mediation = mediation; - this->mediated_by = mediated_by; - this->peer_id = peer_id; -#else /* ME */ - DESTROY_IF(mediated_by); - DESTROY_IF(peer_id); + .mediation = data->mediation, + .mediated_by = data->mediated_by, + .peer_id = data->peer_id, #endif /* ME */ + ); return &this->public; } diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index a4646af87..2e7959307 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2007-2015 Tobias Brunner + * Copyright (C) 2007-2016 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -26,6 +26,7 @@ typedef enum cert_policy_t cert_policy_t; typedef enum unique_policy_t unique_policy_t; typedef struct peer_cfg_t peer_cfg_t; +typedef struct peer_cfg_create_t peer_cfg_create_t; #include #include @@ -366,43 +367,53 @@ struct peer_cfg_t { void (*destroy) (peer_cfg_t *this); }; +/** + * Data passed to the constructor of a peer_cfg_t object. + */ +struct peer_cfg_create_t { + /** Whether to send a certificate payload */ + cert_policy_t cert_policy; + /** Uniqueness of an IKE_SA */ + unique_policy_t unique; + /** How many keying tries should be done before giving up */ + uint32_t keyingtries; + /** Timeout in seconds before starting rekeying */ + uint32_t rekey_time; + /** Timeout in seconds before starting reauthentication */ + uint32_t reauth_time; + /** Time range in seconds to randomly subtract from rekey/reauth time */ + uint32_t jitter_time; + /** Maximum overtime in seconds before closing a rekeying/reauth SA */ + uint32_t over_time; + /** Disable MOBIKE (RFC4555) */ + bool no_mobike; + /** Use/accept aggressive mode with IKEv1 */ + bool aggressive; + /** TRUE to use modeconfig push, FALSE for pull */ + bool push_mode; + /** DPD check interval, 0 to disable */ + uint32_t dpd; + /** DPD timeout interval (IKEv1 only), if 0 default applies */ + uint32_t dpd_timeout; +#ifdef ME + /** TRUE if this is a mediation connection */ + bool mediation; + /** peer_cfg_t of the mediation connection to mediate through (adopted) */ + peer_cfg_t *mediated_by; + /** ID that identifies our peer at the mediation server (adopted) */ + identification_t *peer_id; +#endif /* ME */ +}; + /** * Create a configuration object for IKE_AUTH and later. * - * name-string gets cloned, ID's not. - * Virtual IPs are used if they are != NULL. A %any host means the virtual - * IP should be obtained from the other peer. - * Lifetimes are in seconds. To prevent to peers to start rekeying at the - * same time, a jitter may be specified. Rekeying of an SA starts at - * (rekeylifetime - random(0, jitter)). - * - * @param name name of the peer_cfg - * @param ike_cfg IKE config to use when acting as initiator - * @param cert_policy should we send a certificate payload? - * @param unique uniqueness of an IKE_SA - * @param keyingtries how many keying tries should be done before giving up - * @param rekey_time timeout before starting rekeying - * @param reauth_time timeout before starting reauthentication - * @param jitter_time timerange to randomly subtract from rekey/reauth time - * @param over_time maximum overtime before closing a rekeying/reauth SA - * @param mobike use MOBIKE (RFC4555) if peer supports it - * @param aggressive use/accept aggressive mode with IKEv1 - * @param pull_mode TRUE to use modeconfig pull, FALSE for push - * @param dpd DPD check interval, 0 to disable - * @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies - * @param mediation TRUE if this is a mediation connection - * @param mediated_by peer_cfg_t of the mediation connection to mediate through - * @param peer_id ID that identifies our peer at the mediation server + * @param name name of the peer_cfg (cloned) + * @param ike_cfg IKE config to use when acting as initiator (adopted) + * @param data data for this peer_cfg * @return peer_cfg_t object */ -peer_cfg_t *peer_cfg_create(char *name, - ike_cfg_t *ike_cfg, cert_policy_t cert_policy, - unique_policy_t unique, uint32_t keyingtries, - uint32_t rekey_time, uint32_t reauth_time, - uint32_t jitter_time, uint32_t over_time, - bool mobike, bool aggressive, bool pull_mode, - uint32_t dpd, uint32_t dpd_timeout, - bool mediation, peer_cfg_t *mediated_by, - identification_t *peer_id); +peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg, + peer_cfg_create_t *data); #endif /** PEER_CFG_H_ @}*/ diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index fc956ac94..a0e514614 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -183,6 +183,15 @@ static void setup_tunnel(private_ha_tunnel_t *this, auth_cfg_t *auth_cfg; child_cfg_t *child_cfg; traffic_selector_t *ts; + peer_cfg_create_t peer = { + .cert_policy = CERT_NEVER_SEND, + .unique = UNIQUE_KEEP, + .rekey_time = 86400, /* 24h */ + .jitter_time = 7200, /* 2h */ + .over_time = 3600, /* 1h */ + .no_mobike = TRUE, + .dpd = 30, + }; child_cfg_create_t child = { .lifetime = { .time = { @@ -211,9 +220,7 @@ static void setup_tunnel(private_ha_tunnel_t *this, remote, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); - peer_cfg = peer_cfg_create("ha", ike_cfg, CERT_NEVER_SEND, - UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, - TRUE, 30, 0, FALSE, NULL, NULL); + peer_cfg = peer_cfg_create("ha", ike_cfg, &peer); auth_cfg = auth_cfg_create(); auth_cfg->add(auth_cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c index efef3fbde..28421c212 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -688,6 +688,16 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) peer_cfg_t *peer_cfg; char local[32], *remote; host_t *addr; + peer_cfg_create_t peer = { + .cert_policy = CERT_SEND_IF_ASKED, + .unique = UNIQUE_NO, + .keyingtries = 1, + .rekey_time = this->ike_rekey, + .over_time = this->ike_rekey, + .no_mobike = TRUE, + .dpd = this->dpd_delay, + .dpd_timeout = this->dpd_timeout, + }; child_cfg_create_t child = { .lifetime = { .time = { @@ -739,14 +749,8 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) FRAGMENTATION_NO, 0); } ike_cfg->add_proposal(ike_cfg, this->proposal->clone(this->proposal)); - peer_cfg = peer_cfg_create("load-test", ike_cfg, - CERT_SEND_IF_ASKED, UNIQUE_NO, 1, /* keytries */ - this->ike_rekey, 0, /* rekey, reauth */ - 0, this->ike_rekey, /* jitter, overtime */ - FALSE, FALSE, TRUE, /* mobike, aggressive, pull */ - this->dpd_delay, /* dpd_delay */ - this->dpd_timeout, /* dpd_timeout */ - FALSE, NULL, NULL); + peer_cfg = peer_cfg_create("load-test", ike_cfg, &peer); + if (this->vip) { peer_cfg->add_virtual_ip(peer_cfg, this->vip->clone(this->vip)); diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index db0ce2cf7..3e5861b87 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -236,6 +236,14 @@ static gboolean initiate_connection(private_maemo_service_t *this, traffic_selector_t *ts; auth_cfg_t *auth; certificate_t *cert; + peer_cfg_create_t peer = { + .cert_policy = CERT_SEND_IF_ASKED, + .unique = UNIQUE_REPLACE, + .keyingtries = 1, + .rekey_time = 36000, /* 10h */ + .jitter_time = 600, /* 10min */ + .over_time = 600, /* 10min */ + }; child_cfg_create_t child = { .lifetime = { .time = { @@ -332,14 +340,7 @@ static gboolean initiate_connection(private_maemo_service_t *this, ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); - peer_cfg = peer_cfg_create(this->current, ike_cfg, - CERT_SEND_IF_ASKED, - UNIQUE_REPLACE, 1, /* keyingtries */ - 36000, 0, /* rekey 10h, reauth none */ - 600, 600, /* jitter, over 10min */ - TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ - 0, 0, /* DPD delay, timeout */ - FALSE, NULL, NULL); /* mediation */ + peer_cfg = peer_cfg_create(this->current, ike_cfg, &peer); peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); auth = auth_cfg_create(); diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index d3476e90f..4452739c1 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -82,6 +82,16 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, child_cfg_t *child_cfg; chunk_t me, other; char *address, *local_net, *remote_net; + peer_cfg_create_t peer = { + .cert_policy = CERT_NEVER_SEND, + .unique = UNIQUE_REPLACE, + .keyingtries = 1, + .rekey_time = this->rekey * 60, + .jitter_time = this->rekey * 5, + .over_time = this->rekey * 3, + .dpd = this->dpd, + .mediation = TRUE, + }; child_cfg_create_t child = { .lifetime = { .time = { @@ -110,14 +120,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, address, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE)); - med_cfg = peer_cfg_create( - "mediation", ike_cfg, - CERT_NEVER_SEND, UNIQUE_REPLACE, - 1, this->rekey*60, 0, /* keytries, rekey, reauth */ - this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ - this->dpd, 0, /* DPD delay, timeout */ - TRUE, NULL, NULL); /* mediation, med by, peer id */ + med_cfg = peer_cfg_create("mediation", ike_cfg, &peer); e->destroy(e); auth = auth_cfg_create(); @@ -147,15 +150,10 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, DESTROY_IF(e); return NULL; } - peer_cfg = peer_cfg_create( - name, this->ike->get_ref(this->ike), - CERT_NEVER_SEND, UNIQUE_REPLACE, - 1, this->rekey*60, 0, /* keytries, rekey, reauth */ - this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ - this->dpd, 0, /* DPD delay, timeout */ - FALSE, med_cfg, /* mediation, med by */ - identification_create_from_encoding(ID_KEY_ID, other)); + peer.mediation = FALSE; + peer.mediated_by = med_cfg; + peer.peer_id = identification_create_from_encoding(ID_KEY_ID, other); + peer_cfg = peer_cfg_create(name, this->ike->get_ref(this->ike), &peer); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); @@ -206,6 +204,15 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, chunk_t me, other; child_cfg_t *child_cfg; auth_cfg_t *auth; + peer_cfg_create_t peer = { + .cert_policy = CERT_NEVER_SEND, + .unique = UNIQUE_REPLACE, + .keyingtries = 1, + .rekey_time = this->rekey * 60, + .jitter_time = this->rekey * 5, + .over_time = this->rekey * 3, + .dpd = this->dpd, + }; child_cfg_create_t child = { .lifetime = { .time = { @@ -224,14 +231,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, this->current = NULL; return FALSE; } - this->current = peer_cfg_create( - name, this->ike->get_ref(this->ike), - CERT_NEVER_SEND, UNIQUE_REPLACE, - 1, this->rekey*60, 0, /* keytries, rekey, reauth */ - this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ - this->dpd, 0, /* DPD delay, timeout */ - FALSE, NULL, NULL); /* mediation, med by, peer id */ + this->current = peer_cfg_create(name, this->ike->get_ref(this->ike), &peer); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); diff --git a/src/libcharon/plugins/medsrv/medsrv_config.c b/src/libcharon/plugins/medsrv/medsrv_config.c index 02d805e06..be7f481b6 100644 --- a/src/libcharon/plugins/medsrv/medsrv_config.c +++ b/src/libcharon/plugins/medsrv/medsrv_config.c @@ -87,14 +87,18 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, if (e->enumerate(e, &name)) { - peer_cfg = peer_cfg_create( - name, this->ike->get_ref(this->ike), - CERT_NEVER_SEND, UNIQUE_REPLACE, - 1, this->rekey*60, 0, /* keytries, rekey, reauth */ - this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ - this->dpd, 0, /* DPD delay, timeout */ - TRUE, NULL, NULL); /* mediation, med by, peer id */ + peer_cfg_create_t peer = { + .cert_policy = CERT_NEVER_SEND, + .unique = UNIQUE_REPLACE, + .keyingtries = 1, + .rekey_time = this->rekey * 60, + .jitter_time = this->rekey * 5, + .over_time = this->rekey * 3, + .dpd = this->dpd, + .mediation = TRUE, + }; + peer_cfg = peer_cfg_create(name, this->ike->get_ref(this->ike), + &peer); e->destroy(e); auth = auth_cfg_create(); diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index 25704b0de..bbc20dca7 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -300,6 +300,7 @@ static ike_cfg_t* get_ike_cfg_by_id(private_sql_config_t *this, int id) return ike_cfg; } +#ifdef ME /** * Query a peer config by its id */ @@ -332,6 +333,7 @@ static peer_cfg_t *get_peer_cfg_by_id(private_sql_config_t *this, int id) } return peer_cfg; } +#endif /* ME */ /** * Check if the two IDs match (the first one is optional) @@ -363,7 +365,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, &mediation, &mediated_by, &p_type, &p_data)) { identification_t *local_id, *remote_id, *peer_id = NULL; - peer_cfg_t *peer_cfg, *mediated_cfg; + peer_cfg_t *peer_cfg, *mediated_cfg = NULL; ike_cfg_t *ike; host_t *vip = NULL; auth_cfg_t *auth; @@ -377,22 +379,38 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, continue; } ike = get_ike_cfg_by_id(this, ike_cfg); + +#ifdef ME mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by) : NULL; if (p_type) { peer_id = identification_create_from_encoding(p_type, p_data); } +#endif if (virtual) { vip = host_create_from_string(virtual, 0); } if (ike) { - peer_cfg = peer_cfg_create( - name, ike, cert_policy, uniqueid, - keyingtries, rekeytime, reauthtime, jitter, overtime, - mobike, FALSE, TRUE, dpd_delay, 0, - mediation, mediated_cfg, peer_id); + peer_cfg_create_t peer = { + .cert_policy = cert_policy, + .unique = uniqueid, + .keyingtries = keyingtries, + .rekey_time = rekeytime, + .reauth_time = reauthtime, + .jitter_time = jitter, + .over_time = overtime, + .no_mobike = !mobike, + .dpd = dpd_delay, +#ifdef ME + .mediation = mediation, + .mediated_by = mediated_cfg, + .peer_id = peer_id, +#endif /* ME */ + }; + + peer_cfg = peer_cfg_create(name, ike, &peer); if (vip) { peer_cfg->add_virtual_ip(peer_cfg, vip); diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 9789163b7..f2d110434 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -616,12 +616,17 @@ static mem_pool_t *create_pool_range(char *str) static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, stroke_msg_t *msg, ike_cfg_t *ike_cfg) { - identification_t *peer_id = NULL; - peer_cfg_t *mediated_by = NULL; - unique_policy_t unique; - uint32_t rekey = 0, reauth = 0, over, jitter; peer_cfg_t *peer_cfg; auth_cfg_t *auth_cfg; + peer_cfg_create_t peer = { + .cert_policy = msg->add_conn.me.sendcert, + .keyingtries = msg->add_conn.rekey.tries, + .no_mobike = !msg->add_conn.mobike, + .aggressive = msg->add_conn.aggressive, + .push_mode = msg->add_conn.pushmode, + .dpd = msg->add_conn.dpd.delay, + .dpd_timeout = msg->add_conn.dpd.timeout, + }; #ifdef ME if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by) @@ -633,14 +638,17 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, if (msg->add_conn.ikeme.mediation) { + peer.mediation = TRUE; /* force unique connections for mediation connections */ msg->add_conn.unique = 1; } if (msg->add_conn.ikeme.mediated_by) { - mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends, - msg->add_conn.ikeme.mediated_by); + peer_cfg_t *mediated_by; + + mediated_by = charon->backends->get_peer_cfg_by_name( + charon->backends, msg->add_conn.ikeme.mediated_by); if (!mediated_by) { DBG1(DBG_CFG, "mediation connection '%s' not found, aborting", @@ -655,58 +663,55 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, mediated_by->destroy(mediated_by); return NULL; } + peer.mediated_by = mediated_by; if (msg->add_conn.ikeme.peerid) { - peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid); + peer.peer_id = identification_create_from_string( + msg->add_conn.ikeme.peerid); } else if (msg->add_conn.other.id) { - peer_id = identification_create_from_string(msg->add_conn.other.id); + peer.peer_id = identification_create_from_string( + msg->add_conn.other.id); } } #endif /* ME */ - jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100; - over = msg->add_conn.rekey.margin; + peer.jitter_time = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100; + peer.over_time = msg->add_conn.rekey.margin; if (msg->add_conn.rekey.reauth) { - reauth = msg->add_conn.rekey.ike_lifetime - over; + peer.reauth_time = msg->add_conn.rekey.ike_lifetime - peer.over_time; } else { - rekey = msg->add_conn.rekey.ike_lifetime - over; + peer.rekey_time = msg->add_conn.rekey.ike_lifetime - peer.over_time; } switch (msg->add_conn.unique) { case 1: /* yes */ case 2: /* replace */ - unique = UNIQUE_REPLACE; + peer.unique = UNIQUE_REPLACE; break; case 3: /* keep */ - unique = UNIQUE_KEEP; + peer.unique = UNIQUE_KEEP; break; case 4: /* never */ - unique = UNIQUE_NEVER; + peer.unique = UNIQUE_NEVER; break; default: /* no */ - unique = UNIQUE_NO; + peer.unique = UNIQUE_NO; break; } if (msg->add_conn.dpd.action == 0) { /* dpdaction=none disables DPD */ - msg->add_conn.dpd.delay = 0; + peer.dpd = 0; } /* other.sourceip is managed in stroke_attributes. If it is set, we define * the pool name as the connection name, which the attribute provider * uses to serve pool addresses. */ - peer_cfg = peer_cfg_create(msg->add_conn.name, ike_cfg, - msg->add_conn.me.sendcert, unique, - msg->add_conn.rekey.tries, rekey, reauth, jitter, over, - msg->add_conn.mobike, msg->add_conn.aggressive, - msg->add_conn.pushmode == 0, - msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout, - msg->add_conn.ikeme.mediation, mediated_by, peer_id); + peer_cfg = peer_cfg_create(msg->add_conn.name, ike_cfg, &peer); if (msg->add_conn.other.sourceip) { diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c index 8d76bb454..e0578fe9b 100644 --- a/src/libcharon/plugins/uci/uci_config.c +++ b/src/libcharon/plugins/uci/uci_config.c @@ -126,6 +126,14 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, child_cfg_t *child_cfg; ike_cfg_t *ike_cfg; auth_cfg_t *auth; + peer_cfg_create_t peer = { + .cert_policy = CERT_SEND_IF_ASKED, + .unique = UNIQUE_NO, + .keyingtries = 1, + .jitter_time = 1800, + .over_time = 900, + .dpd = 60, + }; child_cfg_create_t child = { .lifetime = { .time = { @@ -160,13 +168,8 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, remote_addr, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, create_proposal(ike_proposal, PROTO_IKE)); - this->peer_cfg = peer_cfg_create( - name, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, - 1, create_rekey(ike_rekey), 0, /* keytries, rekey, reauth */ - 1800, 900, /* jitter, overtime */ - TRUE, FALSE, TRUE, /* mobike, aggressive, pull */ - 60, 0, /* DPD delay, timeout */ - FALSE, NULL, NULL); /* mediation, med by, peer id */ + peer.rekey_time = create_rekey(ike_rekey); + this->peer_cfg = peer_cfg_create(name, ike_cfg, &peer); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); auth->add(auth, AUTH_RULE_IDENTITY, diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index f1c2fa860..e3fd9e9e3 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -1979,6 +1979,7 @@ CALLBACK(config_sn, bool, .rand_time = LFT_UNDEFINED, }; enumerator_t *enumerator; + peer_cfg_create_t cfg; peer_cfg_t *peer_cfg; ike_cfg_t *ike_cfg; child_cfg_t *child_cfg; @@ -2075,12 +2076,22 @@ CALLBACK(config_sn, bool, peer.local_addrs, peer.local_port, peer.remote_addrs, peer.remote_port, peer.fragmentation, 0); - peer_cfg = peer_cfg_create(name, ike_cfg, peer.send_cert, peer.unique, - peer.keyingtries, peer.rekey_time, peer.reauth_time, - peer.rand_time, peer.over_time, peer.mobike, - peer.aggressive, peer.pull, - peer.dpd_delay, peer.dpd_timeout, - FALSE, NULL, NULL); + + cfg = (peer_cfg_create_t){ + .cert_policy = peer.send_cert, + .unique = peer.unique, + .keyingtries = peer.keyingtries, + .rekey_time = peer.rekey_time, + .reauth_time = peer.reauth_time, + .jitter_time = peer.rand_time, + .over_time = peer.over_time, + .no_mobike = !peer.mobike, + .aggressive = peer.aggressive, + .push_mode = !peer.pull, + .dpd = peer.dpd_delay, + .dpd_timeout = peer.dpd_timeout, + }; + peer_cfg = peer_cfg_create(name, ike_cfg, &cfg); while (peer.local->remove_first(peer.local, (void**)&auth) == SUCCESS) From 7f57c4f9fbf3bdd559af054795bdbf2dfaa9b810 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Thu, 24 Mar 2016 18:35:27 +0100 Subject: [PATCH 12/16] Support manually-set IPsec policy priorities --- src/libcharon/config/child_cfg.c | 15 +++++ src/libcharon/config/child_cfg.h | 10 ++++ src/libcharon/kernel/kernel_ipsec.h | 3 + .../kernel_netlink/kernel_netlink_ipsec.c | 6 +- src/libcharon/plugins/vici/vici_config.c | 2 + src/libcharon/sa/child_sa.c | 59 +++++++++++++------ src/libcharon/sa/shunt_manager.c | 4 +- src/swanctl/swanctl.opt | 7 +++ 8 files changed, 84 insertions(+), 22 deletions(-) diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 1a84d30d2..a7ec167a4 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2016 Andreas Steffen * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -132,6 +133,11 @@ struct private_child_cfg_t { */ uint32_t tfc; + /** + * Optional manually-set IPsec policy priorities + */ + uint32_t manual_prio; + /** * set up IPsec transport SA in MIPv6 proxy mode */ @@ -500,6 +506,12 @@ METHOD(child_cfg_t, get_tfc, uint32_t, return this->tfc; } +METHOD(child_cfg_t, get_manual_prio, uint32_t, + private_child_cfg_t *this) +{ + return this->manual_prio; +} + METHOD(child_cfg_t, get_replay_window, uint32_t, private_child_cfg_t *this) { @@ -569,6 +581,7 @@ METHOD(child_cfg_t, equals, bool, this->mark_out.value == other->mark_out.value && this->mark_out.mask == other->mark_out.mask && this->tfc == other->tfc && + this->manual_prio == other->manual_prio && this->replay_window == other->replay_window && this->proxy_mode == other->proxy_mode && this->install_policy == other->install_policy && @@ -627,6 +640,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .get_reqid = _get_reqid, .get_mark = _get_mark, .get_tfc = _get_tfc, + .get_manual_prio = _get_manual_prio, .get_replay_window = _get_replay_window, .set_replay_window = _set_replay_window, .use_proxy_mode = _use_proxy_mode, @@ -650,6 +664,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .inactivity = data->inactivity, .use_ipcomp = data->ipcomp, .tfc = data->tfc, + .manual_prio = data->priority, .install_policy = !data->suppress_policies, .refcount = 1, .proposals = linked_list_create(), diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index 4eecbf103..8ac9c30ca 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2016 Andreas Steffen * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -235,6 +236,13 @@ struct child_cfg_t { */ uint32_t (*get_tfc)(child_cfg_t *this); + /** + * Get optional manually-set IPsec policy priority + * + * @return manually-set IPsec policy priority (automatic if 0) + */ + uint32_t (*get_manual_prio)(child_cfg_t *this); + /** * Get anti-replay window size * @@ -308,6 +316,8 @@ struct child_cfg_create_t { bool ipcomp; /** TFC padding size, 0 to disable, -1 to pad to PMTU */ uint32_t tfc; + /** Optional manually-set IPsec policy priority */ + uint32_t priority; /** lifetime_cfg_t for this child_cfg */ lifetime_cfg_t lifetime; /** Inactivity timeout in s before closing a CHILD_SA */ diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h index a823814f3..3a06ce66b 100644 --- a/src/libcharon/kernel/kernel_ipsec.h +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2016 Andreas Steffen * Copyright (C) 2006-2016 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi @@ -151,6 +152,8 @@ struct kernel_ipsec_manage_policy_t { policy_type_t type; /** Priority class */ policy_priority_t prio; + /** Manually-set priority (automatic if set to 0) */ + uint32_t manual_prio; /** Source address of the SA(s) tied to this policy */ host_t *src; /** Destination address of the SA(s) tied to this policy */ diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index b147590e3..bad343eba 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -2397,7 +2397,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t, /* cache the assigned IPsec SA */ assigned_sa = policy_sa_create(this, id->dir, data->type, data->src, data->dst, id->src_ts, id->dst_ts, id->mark, data->sa); - assigned_sa->priority = get_priority(policy, data->prio); + assigned_sa->priority = data->manual_prio ? data->manual_prio : + get_priority(policy, data->prio); /* insert the SA according to its priority */ enumerator = policy->used_by->create_enumerator(policy->used_by); @@ -2576,7 +2577,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t, } /* remove mapping to SA by reqid and priority */ - priority = get_priority(current, data->prio); + priority = data->manual_prio ? data->manual_prio : + get_priority(current, data->prio); enumerator = current->used_by->create_enumerator(current->used_by); while (enumerator->enumerate(enumerator, (void**)&mapping)) { diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index e3fd9e9e3..8358336af 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -461,6 +461,7 @@ static void log_child_data(child_data_t *data, char *name) DBG2(DBG_CFG, " close_action = %N", action_names, cfg->close_action); DBG2(DBG_CFG, " reqid = %u", cfg->reqid); DBG2(DBG_CFG, " tfc = %d", cfg->tfc); + DBG2(DBG_CFG, " priority = %d", cfg->priority); DBG2(DBG_CFG, " mark_in = %u/%u", cfg->mark_in.value, cfg->mark_in.mask); DBG2(DBG_CFG, " mark_out = %u/%u", @@ -1340,6 +1341,7 @@ CALLBACK(child_kv, bool, { "mark_in", parse_mark, &child->cfg.mark_in }, { "mark_out", parse_mark, &child->cfg.mark_out }, { "tfc_padding", parse_tfc, &child->cfg.tfc }, + { "priority", parse_uint32, &child->cfg.priority }, }; return parse_rules(rules, countof(rules), name, value, diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 05d42ba1d..a1e47a2a4 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -1,4 +1,5 @@ /* + * Coypright (C) 2016 Andreas Steffen * Copyright (C) 2006-2016 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger @@ -881,7 +882,8 @@ static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa, static status_t install_policies_internal(private_child_sa_t *this, host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts, traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, - ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority) + ipsec_sa_cfg_t *other_sa, policy_type_t type, + policy_priority_t priority, uint32_t manual_prio) { kernel_ipsec_policy_id_t out_id = { .dir = POLICY_OUT, @@ -897,12 +899,14 @@ static status_t install_policies_internal(private_child_sa_t *this, kernel_ipsec_manage_policy_t out_policy = { .type = type, .prio = priority, + .manual_prio = manual_prio, .src = my_addr, .dst = other_addr, .sa = other_sa, }, in_policy = { .type = type, .prio = priority, + .manual_prio = manual_prio, .src = other_addr, .dst = my_addr, .sa = my_sa, @@ -936,7 +940,8 @@ static status_t install_policies_internal(private_child_sa_t *this, static void del_policies_internal(private_child_sa_t *this, host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts, traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, - ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority) + ipsec_sa_cfg_t *other_sa, policy_type_t type, + policy_priority_t priority, uint32_t manual_prio) { kernel_ipsec_policy_id_t out_id = { .dir = POLICY_OUT, @@ -952,12 +957,14 @@ static void del_policies_internal(private_child_sa_t *this, kernel_ipsec_manage_policy_t out_policy = { .type = type, .prio = priority, + .manual_prio = manual_prio, .src = my_addr, .dst = other_addr, .sa = other_sa, }, in_policy = { .type = type, .prio = priority, + .manual_prio = manual_prio, .src = other_addr, .dst = my_addr, .sa = my_sa, @@ -1019,8 +1026,10 @@ METHOD(child_sa_t, add_policies, status_t, { policy_priority_t priority; ipsec_sa_cfg_t my_sa, other_sa; + uint32_t manual_prio; prepare_sa_cfg(this, &my_sa, &other_sa); + manual_prio = this->config->get_manual_prio(this->config); /* if we're not in state CHILD_INSTALLING (i.e. if there is no SAD * entry) we install a trap policy */ @@ -1034,18 +1043,20 @@ METHOD(child_sa_t, add_policies, status_t, { /* install outbound drop policy to avoid packets leaving unencrypted * when updating policies */ - if (priority == POLICY_PRIORITY_DEFAULT && require_policy_update()) + if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 && + require_policy_update()) { status |= install_policies_internal(this, this->my_addr, this->other_addr, my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP, - POLICY_PRIORITY_FALLBACK); + POLICY_PRIORITY_FALLBACK, 0); } /* install policies */ status |= install_policies_internal(this, this->my_addr, this->other_addr, my_ts, other_ts, - &my_sa, &other_sa, POLICY_IPSEC, priority); + &my_sa, &other_sa, POLICY_IPSEC, + priority, manual_prio); if (status != SUCCESS) { @@ -1157,18 +1168,21 @@ METHOD(child_sa_t, update, status_t, ipsec_sa_cfg_t my_sa, other_sa; enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; + uint32_t manual_prio; prepare_sa_cfg(this, &my_sa, &other_sa); + manual_prio = this->config->get_manual_prio(this->config); /* always use high priorities, as hosts getting updated are INSTALLED */ enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { traffic_selector_t *old_my_ts = NULL, *old_other_ts = NULL; + /* remove old policies first */ del_policies_internal(this, this->my_addr, this->other_addr, - my_ts, other_ts, &my_sa, &other_sa, - POLICY_IPSEC, POLICY_PRIORITY_DEFAULT); + my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC, + POLICY_PRIORITY_DEFAULT, manual_prio); /* check if we have to update a "dynamic" traffic selector */ if (!me->ip_equals(me, this->my_addr) && @@ -1191,17 +1205,20 @@ METHOD(child_sa_t, update, status_t, /* reinstall updated policies */ install_policies_internal(this, me, other, my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC, - POLICY_PRIORITY_DEFAULT); + POLICY_PRIORITY_DEFAULT, manual_prio); /* update fallback policies after the new policy is in place */ - del_policies_internal(this, this->my_addr, this->other_addr, - old_my_ts ?: my_ts, - old_other_ts ?: other_ts, - &my_sa, &other_sa, POLICY_DROP, - POLICY_PRIORITY_FALLBACK); - install_policies_internal(this, me, other, my_ts, other_ts, + if (manual_prio == 0) + { + del_policies_internal(this, this->my_addr, this->other_addr, + old_my_ts ?: my_ts, + old_other_ts ?: other_ts, &my_sa, &other_sa, POLICY_DROP, - POLICY_PRIORITY_FALLBACK); + POLICY_PRIORITY_FALLBACK, 0); + install_policies_internal(this, me, other, my_ts, other_ts, + &my_sa, &other_sa, POLICY_DROP, + POLICY_PRIORITY_FALLBACK, 0); + } DESTROY_IF(old_my_ts); DESTROY_IF(old_other_ts); } @@ -1244,20 +1261,24 @@ METHOD(child_sa_t, destroy, void, if (this->config->install_policy(this->config)) { ipsec_sa_cfg_t my_sa, other_sa; + uint32_t manual_prio; prepare_sa_cfg(this, &my_sa, &other_sa); + manual_prio = this->config->get_manual_prio(this->config); /* delete all policies in the kernel */ enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { del_policies_internal(this, this->my_addr, this->other_addr, - my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC, priority); - if (priority == POLICY_PRIORITY_DEFAULT && require_policy_update()) + my_ts, other_ts, &my_sa, &other_sa, + POLICY_IPSEC, priority, manual_prio); + if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 && + require_policy_update()) { del_policies_internal(this, this->my_addr, this->other_addr, - my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP, - POLICY_PRIORITY_FALLBACK); + my_ts, other_ts, &my_sa, &other_sa, + POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0); } } enumerator->destroy(enumerator); diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c index 36af86bae..b74b454ea 100644 --- a/src/libcharon/sa/shunt_manager.c +++ b/src/libcharon/sa/shunt_manager.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2015-2016 Tobias Brunner - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2016 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -119,6 +119,7 @@ static bool install_shunt_policy(child_cfg_t *child) kernel_ipsec_manage_policy_t policy = { .type = policy_type, .prio = policy_prio, + .manual_prio = child->get_manual_prio(child), .src = host_any, .dst = host_any, .sa = &sa, @@ -265,6 +266,7 @@ static void uninstall_shunt_policy(child_cfg_t *child) kernel_ipsec_manage_policy_t policy = { .type = policy_type, .prio = policy_prio, + .manual_prio = child->get_manual_prio(child), .src = host_any, .dst = host_any, .sa = &sa, diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt index d69daeaad..08d3cf1c9 100644 --- a/src/swanctl/swanctl.opt +++ b/src/swanctl/swanctl.opt @@ -684,6 +684,13 @@ connections..children..reqid = 0 not more than once. The default of _0_ uses dynamic reqids, allocated incrementally. +connections..children..priority = 0 + Optional fixed priority for IPsec policies. + + Optional fixed priority for IPsec policies. This could be useful to install + high-priority drop policies. The default of _0_ uses dynamically calculated + priorities based on the size of the traffic selectors. + connections..children..mark_in = 0/0x00000000 Netfilter mark and mask for input traffic. From c26e4330e75688415e1b1a1499851b16d2a8a8e7 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Sun, 27 Mar 2016 10:18:19 +0200 Subject: [PATCH 13/16] Implemented IPsec policies restricted to given network interface --- src/libcharon/config/child_cfg.c | 24 ++++++++++++++----- src/libcharon/config/child_cfg.h | 9 +++++++ src/libcharon/kernel/kernel_ipsec.h | 4 ++++ .../kernel_netlink/kernel_netlink_ipsec.c | 15 +++++++----- src/libcharon/plugins/vici/vici_config.c | 3 +++ src/libcharon/sa/child_sa.c | 4 ++++ src/libcharon/sa/shunt_manager.c | 18 ++++++++++++-- src/swanctl/swanctl.opt | 3 +++ 8 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index a7ec167a4..be84621d4 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -138,6 +138,11 @@ struct private_child_cfg_t { */ uint32_t manual_prio; + /** + * Optional restriction of IPsec policy to a given network interface + */ + char *interface; + /** * set up IPsec transport SA in MIPv6 proxy mode */ @@ -512,6 +517,12 @@ METHOD(child_cfg_t, get_manual_prio, uint32_t, return this->manual_prio; } +METHOD(child_cfg_t, get_interface, char*, + private_child_cfg_t *this) +{ + return this->interface; +} + METHOD(child_cfg_t, get_replay_window, uint32_t, private_child_cfg_t *this) { @@ -537,7 +548,7 @@ METHOD(child_cfg_t, install_policy, bool, } #define LT_PART_EQUALS(a, b) ({ a.life == b.life && a.rekey == b.rekey && a.jitter == b.jitter; }) -#define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); }) +#define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); }) METHOD(child_cfg_t, equals, bool, private_child_cfg_t *this, child_cfg_t *other_pub) @@ -585,7 +596,8 @@ METHOD(child_cfg_t, equals, bool, this->replay_window == other->replay_window && this->proxy_mode == other->proxy_mode && this->install_policy == other->install_policy && - streq(this->updown, other->updown); + streq(this->updown, other->updown) && + streq(this->interface, other->interface); } METHOD(child_cfg_t, get_ref, child_cfg_t*, @@ -603,10 +615,8 @@ METHOD(child_cfg_t, destroy, void, this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy)); this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy)); - if (this->updown) - { - free(this->updown); - } + free(this->updown); + free(this->interface); free(this->name); free(this); } @@ -641,6 +651,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .get_mark = _get_mark, .get_tfc = _get_tfc, .get_manual_prio = _get_manual_prio, + .get_interface = _get_interface, .get_replay_window = _get_replay_window, .set_replay_window = _set_replay_window, .use_proxy_mode = _use_proxy_mode, @@ -665,6 +676,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .use_ipcomp = data->ipcomp, .tfc = data->tfc, .manual_prio = data->priority, + .interface = strdupnull(data->interface), .install_policy = !data->suppress_policies, .refcount = 1, .proposals = linked_list_create(), diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index 8ac9c30ca..7d348fd6c 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -243,6 +243,13 @@ struct child_cfg_t { */ uint32_t (*get_manual_prio)(child_cfg_t *this); + /** + * Get optional network interface restricting IPsec policy + * + * @return network interface) + */ + char* (*get_interface)(child_cfg_t *this); + /** * Get anti-replay window size * @@ -318,6 +325,8 @@ struct child_cfg_create_t { uint32_t tfc; /** Optional manually-set IPsec policy priority */ uint32_t priority; + /** Optional network interface restricting IPsec policy (cloned) */ + char *interface; /** lifetime_cfg_t for this child_cfg */ lifetime_cfg_t lifetime; /** Inactivity timeout in s before closing a CHILD_SA */ diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h index 3a06ce66b..0ad566068 100644 --- a/src/libcharon/kernel/kernel_ipsec.h +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -69,6 +69,8 @@ struct kernel_ipsec_add_sa_t { linked_list_t *src_ts; /** List of destination traffic selectors */ linked_list_t *dst_ts; + /** Network interface restricting policy */ + char *interface; /** Lifetime configuration */ lifetime_cfg_t *lifetime; /** Encryption algorithm */ @@ -142,6 +144,8 @@ struct kernel_ipsec_policy_id_t { traffic_selector_t *dst_ts; /** Optional mark */ mark_t mark; + /** Network interface restricting policy */ + char *interface; }; /** diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index bad343eba..95c0e3ce0 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -739,7 +740,8 @@ static void ts2ports(traffic_selector_t* ts, * Convert a pair of traffic_selectors to an xfrm_selector */ static struct xfrm_selector ts2selector(traffic_selector_t *src, - traffic_selector_t *dst) + traffic_selector_t *dst, + char *interface) { struct xfrm_selector sel; uint16_t port; @@ -763,7 +765,7 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src, sel.dport = htons(traffic_selector_icmp_code(port)); sel.dport_mask = sel.dport ? ~0 : 0; } - sel.ifindex = 0; + sel.ifindex = interface ? if_nametoindex(interface) : 0; sel.user = 0; return sel; @@ -1279,7 +1281,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, data->dst_ts->get_first(data->dst_ts, (void**)&first_dst_ts) == SUCCESS) { - sa->sel = ts2selector(first_src_ts, first_dst_ts); + sa->sel = ts2selector(first_src_ts, first_dst_ts, + data->interface); if (!this->proto_port_transport) { /* don't install proto/port on SA. This would break @@ -2358,7 +2361,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, /* create a policy */ INIT(policy, - .sel = ts2selector(id->src_ts, id->dst_ts), + .sel = ts2selector(id->src_ts, id->dst_ts, id->interface), .mark = id->mark.value & id->mark.mask, .direction = id->dir, .reqid = data->sa->reqid, @@ -2468,7 +2471,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)); policy_id = NLMSG_DATA(hdr); - policy_id->sel = ts2selector(id->src_ts, id->dst_ts); + policy_id->sel = ts2selector(id->src_ts, id->dst_ts, id->interface); policy_id->dir = id->dir; if (!add_mark(hdr, sizeof(request), id->mark)) @@ -2552,7 +2555,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, /* create a policy */ memset(&policy, 0, sizeof(policy_entry_t)); - policy.sel = ts2selector(id->src_ts, id->dst_ts); + policy.sel = ts2selector(id->src_ts, id->dst_ts, id->interface); policy.mark = id->mark.value & id->mark.mask; policy.direction = id->dir; diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 8358336af..a1ab56df9 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -462,6 +462,7 @@ static void log_child_data(child_data_t *data, char *name) DBG2(DBG_CFG, " reqid = %u", cfg->reqid); DBG2(DBG_CFG, " tfc = %d", cfg->tfc); DBG2(DBG_CFG, " priority = %d", cfg->priority); + DBG2(DBG_CFG, " interface = %s", cfg->interface); DBG2(DBG_CFG, " mark_in = %u/%u", cfg->mark_in.value, cfg->mark_in.mask); DBG2(DBG_CFG, " mark_out = %u/%u", @@ -484,6 +485,7 @@ static void free_child_data(child_data_t *data) data->remote_ts->destroy_offset(data->remote_ts, offsetof(traffic_selector_t, destroy)); free(data->cfg.updown); + free(data->cfg.interface); } /** @@ -1342,6 +1344,7 @@ CALLBACK(child_kv, bool, { "mark_out", parse_mark, &child->cfg.mark_out }, { "tfc_padding", parse_tfc, &child->cfg.tfc }, { "priority", parse_uint32, &child->cfg.priority }, + { "interface", parse_string, &child->cfg.interface }, }; return parse_rules(rules, countof(rules), name, value, diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index a1e47a2a4..6e0113ee7 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -576,6 +576,7 @@ static bool update_usetime(private_child_sa_t *this, bool inbound) .src_ts = my_ts, .dst_ts = other_ts, .mark = this->mark_out, + .interface = this->config->get_interface(this->config), }; kernel_ipsec_query_policy_t query = {}; @@ -798,6 +799,7 @@ METHOD(child_sa_t, install, status_t, .mode = this->mode, .src_ts = src_ts, .dst_ts = dst_ts, + .interface = inbound ? NULL : this->config->get_interface(this->config), .lifetime = lifetime, .enc_alg = enc_alg, .enc_key = encr, @@ -890,6 +892,7 @@ static status_t install_policies_internal(private_child_sa_t *this, .src_ts = my_ts, .dst_ts = other_ts, .mark = this->mark_out, + .interface = this->config->get_interface(this->config), }, in_id = { .dir = POLICY_IN, .src_ts = other_ts, @@ -948,6 +951,7 @@ static void del_policies_internal(private_child_sa_t *this, .src_ts = my_ts, .dst_ts = other_ts, .mark = this->mark_out, + .interface = this->config->get_interface(this->config), }, in_id = { .dir = POLICY_IN, .src_ts = other_ts, diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c index b74b454ea..40e291be5 100644 --- a/src/libcharon/sa/shunt_manager.c +++ b/src/libcharon/sa/shunt_manager.c @@ -68,6 +68,8 @@ static bool install_shunt_policy(child_cfg_t *child) policy_type_t policy_type; policy_priority_t policy_prio; status_t status = SUCCESS; + uint32_t manual_prio; + char *interface; ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT }; switch (child->get_mode(child)) @@ -92,6 +94,9 @@ static bool install_shunt_policy(child_cfg_t *child) other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts); hosts->destroy(hosts); + manual_prio = child->get_manual_prio(child); + interface = child->get_interface(child); + /* enumerate pairs of traffic selectors */ e_my_ts = my_ts_list->create_enumerator(my_ts_list); while (e_my_ts->enumerate(e_my_ts, &my_ts)) @@ -115,11 +120,12 @@ static bool install_shunt_policy(child_cfg_t *child) .src_ts = my_ts, .dst_ts = other_ts, .mark = child->get_mark(child, FALSE), + .interface = interface, }; kernel_ipsec_manage_policy_t policy = { .type = policy_type, .prio = policy_prio, - .manual_prio = child->get_manual_prio(child), + .manual_prio = manual_prio, .src = host_any, .dst = host_any, .sa = &sa, @@ -134,6 +140,7 @@ static bool install_shunt_policy(child_cfg_t *child) .src_ts = other_ts, .dst_ts = my_ts, .mark = child->get_mark(child, TRUE), + .interface = interface, }; status |= charon->kernel->add_policy(charon->kernel, &id, &policy); /* install "inbound" forward policy */ @@ -215,6 +222,8 @@ static void uninstall_shunt_policy(child_cfg_t *child) policy_type_t policy_type; policy_priority_t policy_prio; status_t status = SUCCESS; + uint32_t manual_prio; + char *interface; ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT }; switch (child->get_mode(child)) @@ -239,6 +248,9 @@ static void uninstall_shunt_policy(child_cfg_t *child) other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts); hosts->destroy(hosts); + manual_prio = child->get_manual_prio(child); + interface = child->get_interface(child); + /* enumerate pairs of traffic selectors */ e_my_ts = my_ts_list->create_enumerator(my_ts_list); while (e_my_ts->enumerate(e_my_ts, &my_ts)) @@ -262,11 +274,12 @@ static void uninstall_shunt_policy(child_cfg_t *child) .src_ts = my_ts, .dst_ts = other_ts, .mark = child->get_mark(child, FALSE), + .interface = interface, }; kernel_ipsec_manage_policy_t policy = { .type = policy_type, .prio = policy_prio, - .manual_prio = child->get_manual_prio(child), + .manual_prio = manual_prio, .src = host_any, .dst = host_any, .sa = &sa, @@ -281,6 +294,7 @@ static void uninstall_shunt_policy(child_cfg_t *child) .src_ts = other_ts, .dst_ts = my_ts, .mark = child->get_mark(child, TRUE), + .interface = interface, }; status |= charon->kernel->del_policy(charon->kernel, &id, &policy); /* uninstall "inbound" forward policy */ diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt index 08d3cf1c9..fe5b293fb 100644 --- a/src/swanctl/swanctl.opt +++ b/src/swanctl/swanctl.opt @@ -691,6 +691,9 @@ connections..children..priority = 0 high-priority drop policies. The default of _0_ uses dynamically calculated priorities based on the size of the traffic selectors. +connections..children..interface = + Optional interface name to restrict IPsec policies. + connections..children..mark_in = 0/0x00000000 Netfilter mark and mask for input traffic. From e9704e90cf506febf7f0806482eec607c813210b Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Mon, 28 Mar 2016 09:03:21 +0200 Subject: [PATCH 14/16] Include manual policy priorities and restriction to interfaces in vici list-conn command --- src/libcharon/plugins/vici/vici_query.c | 15 ++++++++++++++- src/swanctl/commands/list_conns.c | 13 +++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c index 3a005ea57..4bad88984 100644 --- a/src/libcharon/plugins/vici/vici_query.c +++ b/src/libcharon/plugins/vici/vici_query.c @@ -682,7 +682,8 @@ CALLBACK(list_conns, vici_message_t*, peer_cfg_t *peer_cfg; ike_cfg_t *ike_cfg; child_cfg_t *child_cfg; - char *ike, *str; + char *ike, *str, *interface; + uint32_t manual_prio; linked_list_t *list; traffic_selector_t *ts; vici_builder_t *b; @@ -761,6 +762,18 @@ CALLBACK(list_conns, vici_message_t*, list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); b->end_list(b /* remote-ts */); + interface = child_cfg->get_interface(child_cfg); + if (interface) + { + b->add_kv(b, "interface", "%s", interface); + } + + manual_prio = child_cfg->get_manual_prio(child_cfg); + if (manual_prio) + { + b->add_kv(b, "priority", "%u", manual_prio); + } + b->end_section(b); } children->destroy(children); diff --git a/src/swanctl/commands/list_conns.c b/src/swanctl/commands/list_conns.c index 019c88888..22a5633d5 100644 --- a/src/swanctl/commands/list_conns.c +++ b/src/swanctl/commands/list_conns.c @@ -80,6 +80,7 @@ CALLBACK(children_sn, int, hashtable_t *ike, vici_res_t *res, char *name) { hashtable_t *child; + char *interface, *priority; int ret; child = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1); @@ -89,6 +90,18 @@ CALLBACK(children_sn, int, printf(" %s: %s\n", name, child->get(child, "mode")); printf(" local: %s\n", child->get(child, "local-ts")); printf(" remote: %s\n", child->get(child, "remote-ts")); + + interface = child->get(child, "interface"); + if (interface) + { + printf(" interface: %s\n", interface); + } + + priority = child->get(child, "priority"); + if (priority) + { + printf(" priority: %s\n", priority); + } } free_hashtable(child); return ret; From d3edc8aa0f3a793a722825ab09a4a7142c6c83f2 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Wed, 6 Apr 2016 16:08:38 +0200 Subject: [PATCH 15/16] testing: Added swanctl/manual_prio scenario --- .../tests/swanctl/manual-prio/description.txt | 4 ++ .../tests/swanctl/manual-prio/evaltest.dat | 24 +++++++ .../hosts/carol/etc/strongswan.conf | 14 ++++ .../hosts/carol/etc/swanctl/swanctl.conf | 49 ++++++++++++++ .../hosts/dave/etc/strongswan.conf | 14 ++++ .../hosts/dave/etc/swanctl/swanctl.conf | 49 ++++++++++++++ .../hosts/moon/etc/strongswan.conf | 14 ++++ .../hosts/moon/etc/swanctl/swanctl.conf | 65 +++++++++++++++++++ .../tests/swanctl/manual-prio/posttest.dat | 8 +++ testing/tests/swanctl/manual-prio/pretest.dat | 11 ++++ testing/tests/swanctl/manual-prio/test.conf | 25 +++++++ 11 files changed, 277 insertions(+) create mode 100755 testing/tests/swanctl/manual-prio/description.txt create mode 100755 testing/tests/swanctl/manual-prio/evaltest.dat create mode 100755 testing/tests/swanctl/manual-prio/hosts/carol/etc/strongswan.conf create mode 100755 testing/tests/swanctl/manual-prio/hosts/carol/etc/swanctl/swanctl.conf create mode 100755 testing/tests/swanctl/manual-prio/hosts/dave/etc/strongswan.conf create mode 100755 testing/tests/swanctl/manual-prio/hosts/dave/etc/swanctl/swanctl.conf create mode 100755 testing/tests/swanctl/manual-prio/hosts/moon/etc/strongswan.conf create mode 100755 testing/tests/swanctl/manual-prio/hosts/moon/etc/swanctl/swanctl.conf create mode 100755 testing/tests/swanctl/manual-prio/posttest.dat create mode 100755 testing/tests/swanctl/manual-prio/pretest.dat create mode 100755 testing/tests/swanctl/manual-prio/test.conf diff --git a/testing/tests/swanctl/manual-prio/description.txt b/testing/tests/swanctl/manual-prio/description.txt new file mode 100755 index 000000000..120fa396e --- /dev/null +++ b/testing/tests/swanctl/manual-prio/description.txt @@ -0,0 +1,4 @@ +The roadwarriors carol and dave set up a connection each +to gateway moon. The authentication is based on X.509 certificates. +High priority passthrough rules cause ssh connections to be exempted from both +ESP encryption and a general drop rule for moon's external eth0 interface. diff --git a/testing/tests/swanctl/manual-prio/evaltest.dat b/testing/tests/swanctl/manual-prio/evaltest.dat new file mode 100755 index 000000000..2645fee0e --- /dev/null +++ b/testing/tests/swanctl/manual-prio/evaltest.dat @@ -0,0 +1,24 @@ +carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.100 local-port=4500 local-id=carol@strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*home.*state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[192.168.0.100/32] remote-ts=\[10.1.0.0/16]::YES +dave:: swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.200 local-port=4500 local-id=dave@strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*home.*state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[192.168.0.200/32] remote-ts=\[10.1.0.0/16]::YES +moon:: swanctl --list-sas --ike-id 1 --raw 2> /dev/null::rw.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=4500 remote-id=carol@strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.0/16] remote-ts=\[192.168.0.100/32]::YES +moon:: swanctl --list-sas --ike-id 2 --raw 2> /dev/null::rw.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.200 remote-port=4500 remote-id=dave@strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*net.*reqid=2 state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.0/16] remote-ts=\[192.168.0.200/32]::YES +carol::ping -c 1 10.1.0.1::64 bytes from 10.1.0.1: icmp_req=1::YES +carol::ping -c 1 10.1.0.10::64 bytes from 10.1.0.10: icmp_req=1::YES +dave:: ping -c 1 10.1.0.1::64 bytes from 10.1.0.1: icmp_req=1::YES +dave:: ping -c 1 10.1.0.20::64 bytes from 10.1.0.20: icmp_req=1::YES +moon:: ping -c 1 10.1.0.10::64 bytes from 10.1.0.10: icmp_req=1::YES +moon:: ping -c 1 10.1.0.20::64 bytes from 10.1.0.20: icmp_req=1::YES +alice::ping -c 1 -W 1 192.168.0.150::64 bytes from 192.168.0.150: icmp_req=1::NO +moon:: ping -c 1 -W 1 192.168.0.150::64 bytes from 192.168.0.150: icmp_req=1::NO +winnetou::ping -c 1 -W 1 192.168.0.1::64 bytes from 192.168.0.1: icmp_req=1::NO +carol::ssh -o ConnectTimeout=5 192.168.0.1 hostname 2> /dev/null::moon::YES +carol::ssh -o ConnectTimeout=5 10.1.0.1 hostname 2> /dev/null::moon::YES +carol::ssh -o ConnectTimeout=5 10.1.0.10 hostname 2> /dev/null::alice::YES +dave:: ssh -o ConnectTimeout=5 192.168.0.1 hostname 2> /dev/null::moon::YES +dave ::ssh -o ConnectTimeout=5 10.1.0.1 hostname 2> /dev/null::moon::YES +dave ::ssh -o ConnectTimeout=5 10.1.0.20 hostname 2> /dev/null::venus::YES +moon ::ssh -o ConnectTimeout=5 192.168.0.150 hostname 2> /dev/null::winnetou::YES +moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES +moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES +moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES +moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES diff --git a/testing/tests/swanctl/manual-prio/hosts/carol/etc/strongswan.conf b/testing/tests/swanctl/manual-prio/hosts/carol/etc/strongswan.conf new file mode 100755 index 000000000..7d7e5f9f5 --- /dev/null +++ b/testing/tests/swanctl/manual-prio/hosts/carol/etc/strongswan.conf @@ -0,0 +1,14 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon { + load = sha1 sha2 md5 aes des hmac pem pkcs1 x509 revocation constraints pubkey gmp random nonce curl kernel-netlink socket-default updown vici + + start-scripts { + creds = /usr/local/sbin/swanctl --load-creds + conns = /usr/local/sbin/swanctl --load-conns + } +} diff --git a/testing/tests/swanctl/manual-prio/hosts/carol/etc/swanctl/swanctl.conf b/testing/tests/swanctl/manual-prio/hosts/carol/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..1821c1ca2 --- /dev/null +++ b/testing/tests/swanctl/manual-prio/hosts/carol/etc/swanctl/swanctl.conf @@ -0,0 +1,49 @@ +connections { + + home { + local_addrs = 192.168.0.100 + remote_addrs = 192.168.0.1 + + local { + auth = pubkey + certs = carolCert.pem + id = carol@strongswan.org + } + remote { + auth = pubkey + id = moon.strongswan.org + } + children { + home { + remote_ts = 10.1.0.0/16 + priority = 2 + + esp_proposals = aes128gcm128-modp3072 + } + } + version = 2 + proposals = aes128-sha256-modp3072 + } + + shunts { + + children { + pass-ssh-in { + local_ts = 0.0.0.0/0[tcp/ssh] + remote_ts = 0.0.0.0/0[tcp] + priority = 1 + + mode = pass + start_action = trap + } + pass-ssh-out { + local_ts = 0.0.0.0/0[tcp] + remote_ts = 0.0.0.0/0[tcp/ssh] + priority = 1 + + mode = pass + start_action = trap + } + } + } +} diff --git a/testing/tests/swanctl/manual-prio/hosts/dave/etc/strongswan.conf b/testing/tests/swanctl/manual-prio/hosts/dave/etc/strongswan.conf new file mode 100755 index 000000000..7d7e5f9f5 --- /dev/null +++ b/testing/tests/swanctl/manual-prio/hosts/dave/etc/strongswan.conf @@ -0,0 +1,14 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon { + load = sha1 sha2 md5 aes des hmac pem pkcs1 x509 revocation constraints pubkey gmp random nonce curl kernel-netlink socket-default updown vici + + start-scripts { + creds = /usr/local/sbin/swanctl --load-creds + conns = /usr/local/sbin/swanctl --load-conns + } +} diff --git a/testing/tests/swanctl/manual-prio/hosts/dave/etc/swanctl/swanctl.conf b/testing/tests/swanctl/manual-prio/hosts/dave/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..ecdd58591 --- /dev/null +++ b/testing/tests/swanctl/manual-prio/hosts/dave/etc/swanctl/swanctl.conf @@ -0,0 +1,49 @@ +connections { + + home { + local_addrs = 192.168.0.200 + remote_addrs = 192.168.0.1 + + local { + auth = pubkey + certs = daveCert.pem + id = dave@strongswan.org + } + remote { + auth = pubkey + id = moon.strongswan.org + } + children { + home { + remote_ts = 10.1.0.0/16 + + updown = /usr/local/libexec/ipsec/_updown iptables + esp_proposals = aes128gcm128-modp3072 + } + } + version = 2 + proposals = aes128-sha256-modp3072 + } + + shunts { + + children { + pass-ssh-in { + local_ts = 0.0.0.0/0[tcp/ssh] + remote_ts = 0.0.0.0/0[tcp] + priority = 1 + + mode = pass + start_action = trap + } + pass-ssh-out { + local_ts = 0.0.0.0/0[tcp] + remote_ts = 0.0.0.0/0[tcp/ssh] + priority = 1 + + mode = pass + start_action = trap + } + } + } +} diff --git a/testing/tests/swanctl/manual-prio/hosts/moon/etc/strongswan.conf b/testing/tests/swanctl/manual-prio/hosts/moon/etc/strongswan.conf new file mode 100755 index 000000000..7d7e5f9f5 --- /dev/null +++ b/testing/tests/swanctl/manual-prio/hosts/moon/etc/strongswan.conf @@ -0,0 +1,14 @@ +# /etc/strongswan.conf - strongSwan configuration file + +swanctl { + load = pem pkcs1 x509 revocation constraints pubkey openssl random +} + +charon { + load = sha1 sha2 md5 aes des hmac pem pkcs1 x509 revocation constraints pubkey gmp random nonce curl kernel-netlink socket-default updown vici + + start-scripts { + creds = /usr/local/sbin/swanctl --load-creds + conns = /usr/local/sbin/swanctl --load-conns + } +} diff --git a/testing/tests/swanctl/manual-prio/hosts/moon/etc/swanctl/swanctl.conf b/testing/tests/swanctl/manual-prio/hosts/moon/etc/swanctl/swanctl.conf new file mode 100755 index 000000000..3e8464cb9 --- /dev/null +++ b/testing/tests/swanctl/manual-prio/hosts/moon/etc/swanctl/swanctl.conf @@ -0,0 +1,65 @@ +connections { + + rw { + local_addrs = 192.168.0.1 + + local { + auth = pubkey + certs = moonCert.pem + id = moon.strongswan.org + } + remote { + auth = pubkey + } + children { + net { + local_ts = 10.1.0.0/16 + priority = 2 + interface = eth0 + + esp_proposals = aes128gcm128-modp3072 + } + } + version = 2 + proposals = aes128-sha256-modp3072 + } + + shunts { + + children { + drop-eth0-default { + local_ts = 0.0.0.0/0 + remote_ts = 0.0.0.0/0 + interface = eth0 + priority = 4 + + mode = drop + start_action = trap + } + pass-ssh-in { + local_ts = 0.0.0.0/0[tcp/ssh] + remote_ts = 0.0.0.0/0[tcp] + priority = 1 + + mode = pass + start_action = trap + } + pass-ssh-out { + local_ts = 0.0.0.0/0[tcp] + remote_ts = 0.0.0.0/0[tcp/ssh] + priority = 1 + + mode = pass + start_action = trap + } + pass-http-out { + local_ts = 0.0.0.0/0[tcp] + remote_ts = 192.168.0.150[tcp/http] + priority = 1 + + mode = pass + start_action = trap + } + } + } +} diff --git a/testing/tests/swanctl/manual-prio/posttest.dat b/testing/tests/swanctl/manual-prio/posttest.dat new file mode 100755 index 000000000..fd9726374 --- /dev/null +++ b/testing/tests/swanctl/manual-prio/posttest.dat @@ -0,0 +1,8 @@ +carol::swanctl --terminate --ike home +dave::swanctl --terminate --ike home +carol::service charon stop 2> /dev/null +dave::service charon stop 2> /dev/null +moon::service charon stop 2> /dev/null +winnetou::ip route del 10.1.0.0/16 via 192.168.0.1 +carol::ip route del 10.1.0.0/16 via 192.168.0.1 +dave::ip route del 10.1.0.0/16 via 192.168.0.1 diff --git a/testing/tests/swanctl/manual-prio/pretest.dat b/testing/tests/swanctl/manual-prio/pretest.dat new file mode 100755 index 000000000..8613a0189 --- /dev/null +++ b/testing/tests/swanctl/manual-prio/pretest.dat @@ -0,0 +1,11 @@ +winnetou::ip route add 10.1.0.0/16 via 192.168.0.1 +carol::ip route add 10.1.0.0/16 via 192.168.0.1 +dave::ip route add 10.1.0.0/16 via 192.168.0.1 +moon::service charon start 2> /dev/null +carol::service charon start 2> /dev/null +dave::service charon start 2> /dev/null +moon::expect-connection rw +carol::expect-connection home +carol::swanctl --initiate --child home 2> /dev/null +dave::expect-connection home +dave::swanctl --initiate --child home 2> /dev/null diff --git a/testing/tests/swanctl/manual-prio/test.conf b/testing/tests/swanctl/manual-prio/test.conf new file mode 100755 index 000000000..b8048b4a0 --- /dev/null +++ b/testing/tests/swanctl/manual-prio/test.conf @@ -0,0 +1,25 @@ +#!/bin/bash +# +# This configuration file provides information on the +# guest instances used for this test + +# All guest instances that are required for this test +# +VIRTHOSTS="alice venus moon carol winnetou dave" + +# Corresponding block diagram +# +DIAGRAM="a-v-m-c-w-d.png" + +# Guest instances on which tcpdump is to be started +# +TCPDUMPHOSTS="moon" + +# Guest instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon carol dave" + +# charon controlled by swanctl +# +SWANCTL=1 From d3af3b799fd6dd872e305e3a7db5719e1024b9d1 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Sat, 9 Apr 2016 16:46:37 +0200 Subject: [PATCH 16/16] Extended IPsec kernel policy scheme The kernel policy now considers src and dst port masks as well as restictions to a given network interface. The base priority is 100'000 for passthrough shunts, 200'000 for IPsec policies, 300'000 for IPsec policy traps and 400'000 for fallback drop shunts. The values 1..30'000 can be used for manually set priorities. --- .../kernel_netlink/kernel_netlink_ipsec.c | 73 ++++++++++++++----- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 95c0e3ce0..b21485e62 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -73,7 +73,7 @@ #endif /** Base priority for installed policies */ -#define PRIO_BASE 384 +#define PRIO_BASE 100000 /** Default lifetime of an acquire XFRM state (in seconds) */ #define DEFAULT_ACQUIRE_LIFETIME 165 @@ -605,32 +605,66 @@ static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key) } /** - * Calculate the priority of a policy + * Determine number of set bits in 16 bit port mask */ -static inline uint32_t get_priority(policy_entry_t *policy, - policy_priority_t prio) +static inline uint32_t port_mask_bits(uint16_t port_mask) { - uint32_t priority = PRIO_BASE; + uint32_t bits; + uint16_t bit_mask = 0x8000; + + port_mask = ntohs(port_mask); + + for (bits = 0; bits < 16; bits++) + { + if (!(port_mask & bit_mask)) + { + break; + } + bit_mask >>= 1; + } + return bits; +} + +/** + * Calculate the priority of a policy + * + * bits 0-0: restriction to network interface (0..1) 1 bit + * bits 1-6: src + dst port mask bits (2 * 0..16) 6 bits + * bits 7-7: restriction to protocol (0..1) 1 bit + * bits 8-16: src + dst network mask bits (2 * 0..128) 9 bits + * 17 bits + * + * smallest value: 000000000 0 000000 0: 0, lowest priority = 100'000 + * largest value : 100000000 1 100000 1: 65'729, highst priority = 34'271 + */ +static uint32_t get_priority(policy_entry_t *policy, policy_priority_t prio, + char *interface) +{ + uint32_t priority = PRIO_BASE, sport_mask_bits, dport_mask_bits; + switch (prio) { case POLICY_PRIORITY_FALLBACK: - priority <<= 1; - /* fall-through */ + priority += PRIO_BASE; + /* fall-through to next case */ case POLICY_PRIORITY_ROUTED: - priority <<= 1; - /* fall-through */ + priority += PRIO_BASE; + /* fall-through to next case */ case POLICY_PRIORITY_DEFAULT: - priority <<= 1; - /* fall-through */ + priority += PRIO_BASE; + /* fall-through to next case */ case POLICY_PRIORITY_PASS: break; } - /* calculate priority based on selector size, small size = high prio */ - priority -= policy->sel.prefixlen_s; - priority -= policy->sel.prefixlen_d; - priority <<= 2; /* make some room for the two flags */ - priority += policy->sel.sport_mask || policy->sel.dport_mask ? 0 : 2; - priority += policy->sel.proto ? 0 : 1; + sport_mask_bits = port_mask_bits(policy->sel.sport_mask); + dport_mask_bits = port_mask_bits(policy->sel.dport_mask); + + /* calculate priority */ + priority -= (policy->sel.prefixlen_s + policy->sel.prefixlen_d) * 256; + priority -= policy->sel.proto ? 128 : 0; + priority -= (sport_mask_bits + dport_mask_bits) * 2; + priority -= (interface != NULL); + return priority; } @@ -2401,7 +2435,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, assigned_sa = policy_sa_create(this, id->dir, data->type, data->src, data->dst, id->src_ts, id->dst_ts, id->mark, data->sa); assigned_sa->priority = data->manual_prio ? data->manual_prio : - get_priority(policy, data->prio); + get_priority(policy, data->prio, id->interface); /* insert the SA according to its priority */ enumerator = policy->used_by->create_enumerator(policy->used_by); @@ -2581,7 +2615,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t, /* remove mapping to SA by reqid and priority */ priority = data->manual_prio ? data->manual_prio : - get_priority(current, data->prio); + get_priority(current, data->prio,id->interface); + enumerator = current->used_by->create_enumerator(current->used_by); while (enumerator->enumerate(enumerator, (void**)&mapping)) {