kernel: Use structs to pass information to the kernel-ipsec interface

This commit is contained in:
Tobias Brunner
2016-04-09 16:50:59 +02:00
committed by Andreas Steffen
parent ea3a4d3f72
commit 89da06ace9
12 changed files with 1135 additions and 978 deletions
+39 -48
View File
@@ -81,13 +81,8 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,
} }
METHOD(kernel_ipsec_t, add_sa, status_t, METHOD(kernel_ipsec_t, add_sa, status_t,
private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, kernel_ipsec_add_sa_t *data)
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)
{ {
esa_info_t esa; esa_info_t esa;
esp_spi_type spi_loc, spi_rem; esp_spi_type spi_loc, spi_rem;
@@ -97,43 +92,43 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
esa_id_type esa_id; esa_id_type esa_id;
nonce_type nc_rem; nonce_type nc_rem;
if (enc_key.ptr == NULL) if (data->enc_key.ptr == NULL)
{ {
DBG1(DBG_KNL, "Unable to get ESA information"); DBG1(DBG_KNL, "Unable to get ESA information");
return FAILED; 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 */ /* 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_i);
chunk_free(&esa.nonce_r); chunk_free(&esa.nonce_r);
return SUCCESS; return SUCCESS;
} }
if (initiator) if (data->initiator)
{ {
spi_loc = spi; spi_loc = id->spi;
spi_rem = esa.spi_r; spi_rem = esa.spi_r;
local = dst; local = id->dst;
peer = src; peer = id->src;
nonce_loc = &esa.nonce_i; nonce_loc = &esa.nonce_i;
nonce_rem = &esa.nonce_r; nonce_rem = &esa.nonce_r;
} }
else else
{ {
spi_loc = esa.spi_r; spi_loc = esa.spi_r;
spi_rem = spi; spi_rem = id->spi;
local = src; local = id->src;
peer = dst; peer = id->dst;
nonce_loc = &esa.nonce_r; nonce_loc = &esa.nonce_r;
nonce_rem = &esa.nonce_i; nonce_rem = &esa.nonce_i;
} }
esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA); 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, if (!tkm->sad->insert(tkm->sad, esa_id, data->reqid, local, peer,
protocol)) spi_loc, spi_rem, id->proto))
{ {
DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id); DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id);
goto sad_failure; 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); nonce_loc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce_loc);
if (nonce_loc_id == 0 && esa.dh_id == 0) 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) if (ike_esa_create_first(esa_id, esa.isa_id, data->reqid, 1, spi_loc,
!= TKM_OK) spi_rem) != TKM_OK)
{ {
DBG1(DBG_KNL, "child SA (%llu, first) creation failed", esa_id); DBG1(DBG_KNL, "child SA (%llu, first) creation failed", esa_id);
goto failure; goto failure;
@@ -157,9 +152,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
else if (nonce_loc_id != 0 && esa.dh_id == 0) else if (nonce_loc_id != 0 && esa.dh_id == 0)
{ {
chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type)); 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, if (ike_esa_create_no_pfs(esa_id, esa.isa_id, data->reqid, 1,
nc_rem, initiator, spi_loc, spi_rem) nonce_loc_id, nc_rem, data->initiator,
!= TKM_OK) spi_loc, spi_rem) != TKM_OK)
{ {
DBG1(DBG_KNL, "child SA (%llu, no PFS) creation failed", esa_id); DBG1(DBG_KNL, "child SA (%llu, no PFS) creation failed", esa_id);
goto failure; goto failure;
@@ -171,8 +166,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
else else
{ {
chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type)); 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, if (ike_esa_create(esa_id, esa.isa_id, data->reqid, 1, esa.dh_id,
nc_rem, initiator, spi_loc, spi_rem) != TKM_OK) nonce_loc_id, nc_rem, data->initiator, spi_loc,
spi_rem) != TKM_OK)
{ {
DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id); DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id);
goto failure; 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, " 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), "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_i);
chunk_free(&esa.nonce_r); chunk_free(&esa.nonce_r);
@@ -208,20 +204,21 @@ sad_failure:
} }
METHOD(kernel_ipsec_t, query_sa, status_t, METHOD(kernel_ipsec_t, query_sa, status_t,
private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, uint64_t *bytes, kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
uint64_t *packets, time_t *time) time_t *time)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
METHOD(kernel_ipsec_t, del_sa, status_t, METHOD(kernel_ipsec_t, del_sa, status_t,
private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) kernel_ipsec_del_sa_t *data)
{ {
esa_id_type esa_id, other_esa_id; 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) if (esa_id)
{ {
other_esa_id = tkm->sad->get_other_esa_id(tkm->sad, 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, 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) if (ike_esa_reset(esa_id) != TKM_OK)
{ {
DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id); 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, METHOD(kernel_ipsec_t, update_sa, status_t,
private_tkm_kernel_ipsec_t *this, uint32_t spi, uint8_t protocol, private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, kernel_ipsec_update_sa_t *data)
bool old_encap, bool new_encap, mark_t mark)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
@@ -264,27 +260,22 @@ METHOD(kernel_ipsec_t, flush_sas, status_t,
} }
METHOD(kernel_ipsec_t, add_policy, status_t, METHOD(kernel_ipsec_t, add_policy, status_t,
private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
return SUCCESS; return SUCCESS;
} }
METHOD(kernel_ipsec_t, query_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t,
private_tkm_kernel_ipsec_t *this, traffic_selector_t *src_ts, private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, kernel_ipsec_query_policy_t *data, time_t *use_time)
time_t *use_time)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
return SUCCESS; return SUCCESS;
} }
@@ -60,43 +60,40 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,
} }
METHOD(kernel_ipsec_t, add_sa, status_t, METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, kernel_ipsec_add_sa_t *data)
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)
{ {
return ipsec->sas->add_sa(ipsec->sas, src, dst, spi, protocol, reqid, mark, return ipsec->sas->add_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto,
tfc, lifetime, enc_alg, enc_key, int_alg, int_key, data->reqid, id->mark, data->tfc, data->lifetime,
mode, ipcomp, cpi, initiator, encap, esn, data->enc_alg, data->enc_key, data->int_alg, data->int_key,
inbound, update); data->mode, data->ipcomp, data->cpi, data->initiator,
data->encap, data->esn, data->inbound, data->update);
} }
METHOD(kernel_ipsec_t, update_sa, status_t, METHOD(kernel_ipsec_t, update_sa, status_t,
private_kernel_android_ipsec_t *this, uint32_t spi, uint8_t protocol, private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, kernel_ipsec_update_sa_t *data)
bool encap, bool new_encap, mark_t mark)
{ {
return ipsec->sas->update_sa(ipsec->sas, spi, protocol, cpi, src, dst, return ipsec->sas->update_sa(ipsec->sas, id->spi, id->proto, data->cpi,
new_src, new_dst, encap, new_encap, mark); 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, METHOD(kernel_ipsec_t, query_sa, status_t,
private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
uint64_t *bytes, uint64_t *packets, time_t *time) time_t *time)
{ {
return ipsec->sas->query_sa(ipsec->sas, src, dst, spi, protocol, mark, return ipsec->sas->query_sa(ipsec->sas, id->src, id->dst, id->spi,
bytes, packets, time); id->proto, id->mark, bytes, packets, time);
} }
METHOD(kernel_ipsec_t, del_sa, status_t, METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, private_kernel_android_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) 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, 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, METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, private_kernel_android_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
policy_priority_t priority)
{ {
return ipsec->policies->add_policy(ipsec->policies, src, dst, src_ts, return ipsec->policies->add_policy(ipsec->policies, data->src, data->dst,
dst_ts, direction, type, sa, mark, id->src_ts, id->dst_ts, id->dir,
priority); data->type, data->sa, id->mark,
data->prio);
} }
METHOD(kernel_ipsec_t, query_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t,
private_kernel_android_ipsec_t *this, traffic_selector_t *src_ts, private_kernel_android_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, kernel_ipsec_query_policy_t *data, time_t *use_time)
time_t *use_time)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_android_ipsec_t *this, host_t *src, host_t *dst, private_kernel_android_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
return ipsec->policies->del_policy(ipsec->policies, src, dst, src_ts, return ipsec->policies->del_policy(ipsec->policies, data->src, data->dst,
dst_ts, direction, type, sa, mark, id->src_ts, id->dst_ts, id->dir,
priority); data->type, data->sa, id->mark,
data->prio);
} }
METHOD(kernel_ipsec_t, flush_policies, status_t, METHOD(kernel_ipsec_t, flush_policies, status_t,
+25 -43
View File
@@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2008-2015 Tobias Brunner * Copyright (C) 2008-2016 Tobias Brunner
* Hochschule fuer Technik Rapperswil * HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2010 Martin Willi * Copyright (C) 2010 Martin Willi
* Copyright (C) 2010 revosec AG * 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, METHOD(kernel_interface_t, add_sa, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst, private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, kernel_ipsec_add_sa_t *data)
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)
{ {
if (!this->ipsec) if (!this->ipsec)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid, return this->ipsec->add_sa(this->ipsec, id, data);
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);
} }
METHOD(kernel_interface_t, update_sa, status_t, METHOD(kernel_interface_t, update_sa, status_t,
private_kernel_interface_t *this, uint32_t spi, uint8_t protocol, private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, kernel_ipsec_update_sa_t *data)
bool encap, bool new_encap, mark_t mark)
{ {
if (!this->ipsec) if (!this->ipsec)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
return this->ipsec->update_sa(this->ipsec, spi, protocol, cpi, src, dst, return this->ipsec->update_sa(this->ipsec, id, data);
new_src, new_dst, encap, new_encap, mark);
} }
METHOD(kernel_interface_t, query_sa, status_t, METHOD(kernel_interface_t, query_sa, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst, private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
uint64_t *bytes, uint64_t *packets, time_t *time) time_t *time)
{ {
if (!this->ipsec) if (!this->ipsec)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, mark, return this->ipsec->query_sa(this->ipsec, id, data, bytes, packets, time);
bytes, packets, time);
} }
METHOD(kernel_interface_t, del_sa, status_t, METHOD(kernel_interface_t, del_sa, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst, uint32_t spi, private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
uint8_t protocol, uint16_t cpi, mark_t mark) kernel_ipsec_del_sa_t *data)
{ {
if (!this->ipsec) if (!this->ipsec)
{ {
return NOT_SUPPORTED; 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, 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, METHOD(kernel_interface_t, add_policy, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst, private_kernel_interface_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
if (!this->ipsec) if (!this->ipsec)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts, return this->ipsec->add_policy(this->ipsec, id, data);
direction, type, sa, mark, priority);
} }
METHOD(kernel_interface_t, query_policy, status_t, METHOD(kernel_interface_t, query_policy, status_t,
private_kernel_interface_t *this, traffic_selector_t *src_ts, private_kernel_interface_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, kernel_ipsec_query_policy_t *data, time_t *use_time)
time_t *use_time)
{ {
if (!this->ipsec) if (!this->ipsec)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts, return this->ipsec->query_policy(this->ipsec, id, data, use_time);
direction, mark, use_time);
} }
METHOD(kernel_interface_t, del_policy, status_t, METHOD(kernel_interface_t, del_policy, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst, private_kernel_interface_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
if (!this->ipsec) if (!this->ipsec)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
return this->ipsec->del_policy(this->ipsec, src, dst, src_ts, dst_ts, return this->ipsec->del_policy(this->ipsec, id, data);
direction, type, sa, mark, priority);
} }
METHOD(kernel_interface_t, flush_policies, status_t, METHOD(kernel_interface_t, flush_policies, status_t,
+32 -105
View File
@@ -1,9 +1,9 @@
/* /*
* Copyright (C) 2006-2015 Tobias Brunner * Copyright (C) 2006-2016 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter * 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 * 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 * 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 * This function does install a single SA for a single protocol in one
* direction. * direction.
* *
* @param src source address for this SA * @param id data identifying this SA
* @param dst destination address for this SA * @param data data 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
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*add_sa) (kernel_interface_t *this, status_t (*add_sa)(kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
host_t *src, host_t *dst, uint32_t spi, kernel_ipsec_add_sa_t *data);
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);
/** /**
* Update the hosts on an installed SA. * Update the hosts on an installed SA.
@@ -204,56 +175,37 @@ struct kernel_interface_t {
* to identify SAs. Therefore if the destination address changed we * to identify SAs. Therefore if the destination address changed we
* create a new SA and delete the old one. * create a new SA and delete the old one.
* *
* @param spi SPI of the SA * @param id data identifying this SA
* @param protocol protocol for this SA (ESP/AH) * @param data updated data for this SA
* @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
* @return SUCCESS if operation completed, NOT_SUPPORTED if * @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, status_t (*update_sa)(kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, kernel_ipsec_update_sa_t *data);
host_t *src, host_t *dst,
host_t *new_src, host_t *new_dst,
bool encap, bool new_encap, mark_t mark);
/** /**
* Query the number of bytes processed by an SA from the SAD. * Query the number of bytes processed by an SA from the SAD.
* *
* @param src source address for this SA * @param id data identifying this SA
* @param dst destination address for this SA * @param data data to query the 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[out] bytes the number of bytes processed by SA * @param[out] bytes the number of bytes processed by SA
* @param[out] packets number of packets processed by SA * @param[out] packets number of packets processed by SA
* @param[out] time last (monotonic) time of SA use * @param[out] time last (monotonic) time of SA use
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*query_sa) (kernel_interface_t *this, host_t *src, host_t *dst, status_t (*query_sa)(kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, kernel_ipsec_query_sa_t *data, uint64_t *bytes,
uint64_t *bytes, uint64_t *packets, time_t *time); uint64_t *packets, time_t *time);
/** /**
* Delete a previously installed SA from the SAD. * Delete a previously installed SA from the SAD.
* *
* @param src source address for this SA * @param id data identifying this SA
* @param dst destination address for this SA * @param data data to delete the 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
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*del_sa) (kernel_interface_t *this, host_t *src, host_t *dst, status_t (*del_sa)(kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, kernel_ipsec_del_sa_t *data);
mark_t mark);
/** /**
* Flush all SAs from the SAD. * Flush all SAs from the SAD.
@@ -265,24 +217,13 @@ struct kernel_interface_t {
/** /**
* Add a policy to the SPD. * Add a policy to the SPD.
* *
* @param src source address of SA * @param id data identifying this policy
* @param dst dest address of SA * @param data data for this policy
* @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
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*add_policy)(kernel_interface_t *this, status_t (*add_policy)(kernel_interface_t *this,
host_t *src, host_t *dst, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, kernel_ipsec_manage_policy_t *data);
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);
/** /**
* Query the use time of a policy. * Query the use time of a policy.
@@ -290,40 +231,26 @@ struct kernel_interface_t {
* The use time of a policy is the time the policy was used * The use time of a policy is the time the policy was used
* for the last time. * for the last time.
* *
* @param src_ts traffic selector to match traffic source * @param id data identifying this policy
* @param dst_ts traffic selector to match traffic dest * @param data data to query the policy
* @param direction direction of traffic, POLICY_(IN|OUT|FWD) * @param[out] use_time the monotonic timestamp of this SA's last use
* @param mark optional mark
* @param[out] use_time the (monotonic) time of this SA's last use
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*query_policy)(kernel_interface_t *this, status_t (*query_policy)(kernel_interface_t *this,
traffic_selector_t *src_ts, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, kernel_ipsec_query_policy_t *data,
policy_dir_t direction, mark_t mark,
time_t *use_time); time_t *use_time);
/** /**
* Remove a policy from the SPD. * Remove a policy from the SPD.
* *
* @param src source address of SA * @param id data identifying this policy
* @param dst dest address of SA * @param data data for this policy
* @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
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*del_policy)(kernel_interface_t *this, status_t (*del_policy)(kernel_interface_t *this,
host_t *src, host_t *dst, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, kernel_ipsec_manage_policy_t *data);
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);
/** /**
* Flush all policies from the SPD. * Flush all policies from the SPD.
+165 -105
View File
@@ -1,9 +1,9 @@
/* /*
* Copyright (C) 2006-2015 Tobias Brunner * Copyright (C) 2006-2016 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter * 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 * 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 * under the terms of the GNU General Public License as published by the
@@ -25,6 +25,14 @@
#define KERNEL_IPSEC_H_ #define KERNEL_IPSEC_H_
typedef struct kernel_ipsec_t kernel_ipsec_t; 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 <networking/host.h> #include <networking/host.h>
#include <ipsec/ipsec_types.h> #include <ipsec/ipsec_types.h>
@@ -32,6 +40,131 @@ typedef struct kernel_ipsec_t kernel_ipsec_t;
#include <plugins/plugin.h> #include <plugins/plugin.h>
#include <kernel/kernel_interface.h> #include <kernel/kernel_interface.h>
/**
* 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. * 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 * This function does install a single SA for a single protocol in one
* direction. * direction.
* *
* @param src source address for this SA * @param id data identifying this SA
* @param dst destination address for this SA * @param data data 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
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*add_sa) (kernel_ipsec_t *this, status_t (*add_sa)(kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
host_t *src, host_t *dst, uint32_t spi, kernel_ipsec_add_sa_t *data);
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);
/** /**
* Update the hosts on an installed SA. * Update the hosts on an installed SA.
@@ -125,56 +229,37 @@ struct kernel_ipsec_t {
* to identify SAs. Therefore if the destination address changed we * to identify SAs. Therefore if the destination address changed we
* create a new SA and delete the old one. * create a new SA and delete the old one.
* *
* @param spi SPI of the SA * @param id data identifying this SA
* @param protocol protocol for this SA (ESP/AH) * @param data updated data for this SA
* @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
* @return SUCCESS if operation completed, NOT_SUPPORTED if * @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, status_t (*update_sa)(kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, kernel_ipsec_update_sa_t *data);
host_t *src, host_t *dst,
host_t *new_src, host_t *new_dst,
bool encap, bool new_encap, mark_t mark);
/** /**
* Query the number of bytes processed by an SA from the SAD. * Query the number of bytes processed by an SA from the SAD.
* *
* @param src source address for this SA * @param id data identifying this SA
* @param dst destination address for this SA * @param data data to query the 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[out] bytes the number of bytes processed by SA * @param[out] bytes the number of bytes processed by SA
* @param[out] packets number of packets processed by SA * @param[out] packets number of packets processed by SA
* @param[out] time last (monotonic) time of SA use * @param[out] time last (monotonic) time of SA use
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*query_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst, status_t (*query_sa)(kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, kernel_ipsec_query_sa_t *data, uint64_t *bytes,
uint64_t *bytes, uint64_t *packets, time_t *time); 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 id data identifying this SA
* @param dst destination address for this SA * @param data data to delete the 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
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*del_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst, status_t (*del_sa)(kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, kernel_ipsec_del_sa_t *data);
mark_t mark);
/** /**
* Flush all SAs from the SAD. * Flush all SAs from the SAD.
@@ -186,24 +271,13 @@ struct kernel_ipsec_t {
/** /**
* Add a policy to the SPD. * Add a policy to the SPD.
* *
* @param src source address of SA * @param id data identifying this policy
* @param dst dest address of SA * @param data data for this policy
* @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
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*add_policy)(kernel_ipsec_t *this, status_t (*add_policy)(kernel_ipsec_t *this,
host_t *src, host_t *dst, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, kernel_ipsec_manage_policy_t *data);
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);
/** /**
* Query the use time of a policy. * Query the use time of a policy.
@@ -212,40 +286,26 @@ struct kernel_ipsec_t {
* time. It is not the system time, but a monotonic timestamp as returned * time. It is not the system time, but a monotonic timestamp as returned
* by time_monotonic. * by time_monotonic.
* *
* @param src_ts traffic selector to match traffic source * @param id data identifying this policy
* @param dst_ts traffic selector to match traffic dest * @param data data to query the policy
* @param direction direction of traffic, POLICY_(IN|OUT|FWD)
* @param mark optional mark
* @param[out] use_time the monotonic timestamp of this SA's last use * @param[out] use_time the monotonic timestamp of this SA's last use
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*query_policy)(kernel_ipsec_t *this, status_t (*query_policy)(kernel_ipsec_t *this,
traffic_selector_t *src_ts, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, kernel_ipsec_query_policy_t *data,
policy_dir_t direction, mark_t mark,
time_t *use_time); time_t *use_time);
/** /**
* Remove a policy from the SPD. * Remove a policy from the SPD.
* *
* @param src source address of SA * @param id data identifying this policy
* @param dst dest address of SA * @param data data for this policy
* @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
* @return SUCCESS if operation completed * @return SUCCESS if operation completed
*/ */
status_t (*del_policy)(kernel_ipsec_t *this, status_t (*del_policy)(kernel_ipsec_t *this,
host_t *src, host_t *dst, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, kernel_ipsec_manage_policy_t *data);
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);
/** /**
* Flush all policies from the SPD. * Flush all policies from the SPD.
@@ -248,42 +248,38 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,
} }
METHOD(kernel_ipsec_t, add_sa, status_t, METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, kernel_ipsec_add_sa_t *data)
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)
{ {
return ipsec->sas->add_sa(ipsec->sas, src, dst, spi, protocol, reqid, mark, return ipsec->sas->add_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto,
tfc, lifetime, enc_alg, enc_key, int_alg, int_key, data->reqid, id->mark, data->tfc, data->lifetime,
mode, ipcomp, cpi, initiator, encap, esn, data->enc_alg, data->enc_key, data->int_alg, data->int_key,
inbound, update); data->mode, data->ipcomp, data->cpi, data->initiator,
data->encap, data->esn, data->inbound, data->update);
} }
METHOD(kernel_ipsec_t, update_sa, status_t, METHOD(kernel_ipsec_t, update_sa, status_t,
private_kernel_libipsec_ipsec_t *this, uint32_t spi, uint8_t protocol, private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, kernel_ipsec_update_sa_t *data)
bool encap, bool new_encap, mark_t mark)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
METHOD(kernel_ipsec_t, query_sa, status_t, METHOD(kernel_ipsec_t, query_sa, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, uint64_t *bytes, kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
uint64_t *packets, time_t *time) time_t *time)
{ {
return ipsec->sas->query_sa(ipsec->sas, src, dst, spi, protocol, mark, return ipsec->sas->query_sa(ipsec->sas, id->src, id->dst, id->spi,
bytes, packets, time); id->proto, id->mark, bytes, packets, time);
} }
METHOD(kernel_ipsec_t, del_sa, status_t, METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) 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, 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, METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, private_kernel_libipsec_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
policy_priority_t priority)
{ {
policy_entry_t *policy, *found = NULL; policy_entry_t *policy, *found = NULL;
status_t status; status_t status;
status = ipsec->policies->add_policy(ipsec->policies, src, dst, src_ts, status = ipsec->policies->add_policy(ipsec->policies, data->src, data->dst,
dst_ts, direction, type, sa, mark, priority); id->src_ts, id->dst_ts, id->dir,
data->type, data->sa, id->mark,
data->prio);
if (status != SUCCESS) if (status != SUCCESS)
{ {
return status; return status;
} }
/* we track policies in order to install routes */ /* 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); this->mutex->lock(this->mutex);
if (this->policies->find_first(this->policies, if (this->policies->find_first(this->policies,
@@ -540,7 +536,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
} }
policy->refs++; 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; return FAILED;
} }
@@ -548,26 +545,25 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
} }
METHOD(kernel_ipsec_t, query_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t,
private_kernel_libipsec_ipsec_t *this, traffic_selector_t *src_ts, private_kernel_libipsec_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, kernel_ipsec_query_policy_t *data, time_t *use_time)
time_t *use_time)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst, private_kernel_libipsec_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
policy_entry_t *policy, *found = NULL; policy_entry_t *policy, *found = NULL;
status_t status; status_t status;
status = ipsec->policies->del_policy(ipsec->policies, src, dst, src_ts, status = ipsec->policies->del_policy(ipsec->policies, data->src, data->dst,
dst_ts, direction, type, sa, mark, priority); 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); this->mutex->lock(this->mutex);
if (this->policies->find_first(this->policies, 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) route->src_ip, route->if_name) != SUCCESS)
{ {
DBG1(DBG_KNL, "error uninstalling route installed with " DBG1(DBG_KNL, "error uninstalling route installed with "
"policy %R === %R %N", src_ts, dst_ts, "policy %R === %R %N", id->src_ts, id->dst_ts,
policy_dir_names, direction); policy_dir_names, id->dir);
} }
remove_exclude_route(this, route); remove_exclude_route(this, route);
} }
@@ -1,11 +1,11 @@
/* /*
* Copyright (C) 2006-2015 Tobias Brunner * Copyright (C) 2006-2016 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2008-2016 Andreas Steffen * Copyright (C) 2008-2016 Andreas Steffen
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
* Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter * 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 * 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 * 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, METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, kernel_ipsec_add_sa_t *data)
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)
{ {
netlink_buf_t request; netlink_buf_t request;
char *alg_name; char *alg_name;
struct nlmsghdr *hdr; struct nlmsghdr *hdr;
struct xfrm_usersa_info *sa; struct xfrm_usersa_info *sa;
uint16_t icv_size = 64; uint16_t icv_size = 64, ipcomp = data->ipcomp;
ipsec_mode_t original_mode = mode; ipsec_mode_t mode = data->mode, original_mode = data->mode;
traffic_selector_t *first_src_ts, *first_dst_ts; traffic_selector_t *first_src_ts, *first_dst_ts;
status_t status = FAILED; status_t status = FAILED;
/* if IPComp is used, we install an additional IPComp SA. if the cpi is 0 /* if IPComp is used, we install an additional IPComp SA. if the cpi is 0
* we are in the recursive call below */ * 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}}; 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, kernel_ipsec_sa_id_t ipcomp_id = {
tfc, &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, .src = id->src,
chunk_empty, mode, ipcomp, 0, 0, initiator, FALSE, FALSE, .dst = id->dst,
inbound, update, src_ts, dst_ts); .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; ipcomp = IPCOMP_NONE;
/* use transport mode ESP SA, IPComp uses tunnel mode */ /* use transport mode ESP SA, IPComp uses tunnel mode */
mode = MODE_TRANSPORT; mode = MODE_TRANSPORT;
@@ -1234,19 +1247,20 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
memset(&request, 0, sizeof(request)); memset(&request, 0, sizeof(request));
DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u} (mark " 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 = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 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)); hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
sa = NLMSG_DATA(hdr); sa = NLMSG_DATA(hdr);
host2xfrm(src, &sa->saddr); host2xfrm(id->src, &sa->saddr);
host2xfrm(dst, &sa->id.daddr); host2xfrm(id->dst, &sa->id.daddr);
sa->id.spi = spi; sa->id.spi = id->spi;
sa->id.proto = protocol; sa->id.proto = id->proto;
sa->family = src->get_family(src); sa->family = id->src->get_family(id->src);
sa->mode = mode2kernel(mode); sa->mode = mode2kernel(mode);
switch (mode) switch (mode)
{ {
@@ -1260,8 +1274,10 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
* selector can be installed other traffic would get dropped */ * selector can be installed other traffic would get dropped */
break; break;
} }
if (src_ts->get_first(src_ts, (void**)&first_src_ts) == SUCCESS && if (data->src_ts->get_first(data->src_ts,
dst_ts->get_first(dst_ts, (void**)&first_dst_ts) == SUCCESS) (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); sa->sel = ts2selector(first_src_ts, first_dst_ts);
if (!this->proto_port_transport) if (!this->proto_port_transport)
@@ -1279,18 +1295,18 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
break; break;
} }
sa->reqid = reqid; sa->reqid = data->reqid;
sa->lft.soft_byte_limit = XFRM_LIMIT(lifetime->bytes.rekey); sa->lft.soft_byte_limit = XFRM_LIMIT(data->lifetime->bytes.rekey);
sa->lft.hard_byte_limit = XFRM_LIMIT(lifetime->bytes.life); sa->lft.hard_byte_limit = XFRM_LIMIT(data->lifetime->bytes.life);
sa->lft.soft_packet_limit = XFRM_LIMIT(lifetime->packets.rekey); sa->lft.soft_packet_limit = XFRM_LIMIT(data->lifetime->packets.rekey);
sa->lft.hard_packet_limit = XFRM_LIMIT(lifetime->packets.life); sa->lft.hard_packet_limit = XFRM_LIMIT(data->lifetime->packets.life);
/* we use lifetimes since added, not since used */ /* we use lifetimes since added, not since used */
sa->lft.soft_add_expires_seconds = lifetime->time.rekey; sa->lft.soft_add_expires_seconds = data->lifetime->time.rekey;
sa->lft.hard_add_expires_seconds = lifetime->time.life; sa->lft.hard_add_expires_seconds = data->lifetime->time.life;
sa->lft.soft_use_expires_seconds = 0; sa->lft.soft_use_expires_seconds = 0;
sa->lft.hard_use_expires_seconds = 0; sa->lft.hard_use_expires_seconds = 0;
switch (enc_alg) switch (data->enc_alg)
{ {
case ENCR_UNDEFINED: case ENCR_UNDEFINED:
/* no encryption */ /* no encryption */
@@ -1313,71 +1329,73 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
{ {
struct xfrm_algo_aead *algo; 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) if (alg_name == NULL)
{ {
DBG1(DBG_KNL, "algorithm %N not supported by kernel!", DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
encryption_algorithm_names, enc_alg); encryption_algorithm_names, data->enc_alg);
goto failed; goto failed;
} }
DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", 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, algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AEAD,
sizeof(*algo) + enc_key.len); sizeof(*algo) + data->enc_key.len);
if (!algo) if (!algo)
{ {
goto failed; 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; algo->alg_icv_len = icv_size;
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; 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; break;
} }
default: default:
{ {
struct xfrm_algo *algo; 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) if (alg_name == NULL)
{ {
DBG1(DBG_KNL, "algorithm %N not supported by kernel!", DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
encryption_algorithm_names, enc_alg); encryption_algorithm_names, data->enc_alg);
goto failed; goto failed;
} }
DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", 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, algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_CRYPT,
sizeof(*algo) + enc_key.len); sizeof(*algo) + data->enc_key.len);
if (!algo) if (!algo)
{ {
goto failed; 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)); strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; 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; 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) if (alg_name == NULL)
{ {
DBG1(DBG_KNL, "algorithm %N not supported by kernel!", DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
integrity_algorithm_names, int_alg); integrity_algorithm_names, data->int_alg);
goto failed; goto failed;
} }
DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", 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_MD5_128:
case AUTH_HMAC_SHA2_256_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. * use specified truncation size supported by newer kernels.
* also use this for untruncated MD5 and SHA1. */ * also use this for untruncated MD5 and SHA1. */
algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH_TRUNC, algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH_TRUNC,
sizeof(*algo) + int_key.len); sizeof(*algo) + data->int_key.len);
if (!algo) if (!algo)
{ {
goto failed; 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; algo->alg_trunc_len = trunc_len;
strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; 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 else
{ {
struct xfrm_algo* algo; struct xfrm_algo* algo;
algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH, algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH,
sizeof(*algo) + int_key.len); sizeof(*algo) + data->int_key.len);
if (!algo) if (!algo)
{ {
goto failed; 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)); strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; 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'; algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
} }
if (encap) if (data->encap)
{ {
struct xfrm_encap_tmpl *tmpl; struct xfrm_encap_tmpl *tmpl;
@@ -1461,8 +1479,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
goto failed; goto failed;
} }
tmpl->encap_type = UDP_ENCAP_ESPINUDP; tmpl->encap_type = UDP_ENCAP_ESPINUDP;
tmpl->encap_sport = htons(src->get_port(src)); tmpl->encap_sport = htons(id->src->get_port(id->src));
tmpl->encap_dport = htons(dst->get_port(dst)); tmpl->encap_dport = htons(id->dst->get_port(id->dst));
memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
/* encap_oa could probably be derived from the /* encap_oa could probably be derived from the
* traffic selectors [rfc4306, p39]. In the netlink kernel * 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. */ * 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; 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 */ { /* the kernel supports TFC padding only for tunnel mode ESP SAs */
uint32_t *tfcpad; uint32_t *tfcpad;
@@ -1491,19 +1509,19 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
{ {
goto failed; 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 /* for ESN or larger replay windows we need the new
* XFRMA_REPLAY_ESN_VAL attribute to configure a bitmap */ * XFRMA_REPLAY_ESN_VAL attribute to configure a bitmap */
struct xfrm_replay_state_esn *replay; struct xfrm_replay_state_esn *replay;
uint32_t bmp_size; 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, replay = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL,
sizeof(*replay) + bmp_size); sizeof(*replay) + bmp_size);
if (!replay) if (!replay)
@@ -1512,10 +1530,11 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
} }
/* bmp_len contains number uf __u32's */ /* bmp_len contains number uf __u32's */
replay->bmp_len = bmp_size / sizeof(uint32_t); replay->bmp_len = bmp_size / sizeof(uint32_t);
replay->replay_window = replay_window; replay->replay_window = data->replay_window;
DBG2(DBG_KNL, " using replay window of %u packets", 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)"); DBG2(DBG_KNL, " using extended sequence numbers (ESN)");
sa->flags |= XFRM_STATE_ESN; sa->flags |= XFRM_STATE_ESN;
@@ -1523,21 +1542,24 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
} }
else else
{ {
DBG2(DBG_KNL, " using replay window of %u packets", replay_window); DBG2(DBG_KNL, " using replay window of %u packets",
sa->replay_window = replay_window; data->replay_window);
sa->replay_window = data->replay_window;
} }
} }
if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) 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 " DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x (mark "
"(mark %u/0x%08x)", ntohl(spi), mark.value, mark.mask); "%u/0x%08x)", ntohl(id->spi), id->mark.value,
id->mark.mask);
} }
else 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; goto failed;
} }
@@ -1555,8 +1577,7 @@ failed:
* Allocates into one the replay state structure we get from the kernel. * Allocates into one the replay state structure we get from the kernel.
*/ */
static void get_replay_state(private_kernel_netlink_ipsec_t *this, static void get_replay_state(private_kernel_netlink_ipsec_t *this,
uint32_t spi, uint8_t protocol, kernel_ipsec_sa_id_t *sa,
host_t *dst, mark_t mark,
struct xfrm_replay_state_esn **replay_esn, struct xfrm_replay_state_esn **replay_esn,
uint32_t *replay_esn_len, uint32_t *replay_esn_len,
struct xfrm_replay_state **replay, 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)); memset(&request, 0, sizeof(request));
DBG2(DBG_KNL, "querying replay state from SAD entry with SPI %.8x", DBG2(DBG_KNL, "querying replay state from SAD entry with SPI %.8x",
ntohl(spi)); ntohl(sa->spi));
hdr = &request.hdr; hdr = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST; 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 = NLMSG_DATA(hdr);
aevent_id->flags = XFRM_AE_RVAL; aevent_id->flags = XFRM_AE_RVAL;
host2xfrm(dst, &aevent_id->sa_id.daddr); host2xfrm(sa->dst, &aevent_id->sa_id.daddr);
aevent_id->sa_id.spi = spi; aevent_id->sa_id.spi = sa->spi;
aevent_id->sa_id.proto = protocol; aevent_id->sa_id.proto = sa->proto;
aevent_id->sa_id.family = dst->get_family(dst); 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; return;
} }
@@ -1657,9 +1678,9 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this,
} }
METHOD(kernel_ipsec_t, query_sa, status_t, METHOD(kernel_ipsec_t, query_sa, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
uint64_t *bytes, uint64_t *packets, time_t *time) time_t *time)
{ {
netlink_buf_t request; netlink_buf_t request;
struct nlmsghdr *out = NULL, *hdr; struct nlmsghdr *out = NULL, *hdr;
@@ -1671,7 +1692,7 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
memset(&request, 0, sizeof(request)); memset(&request, 0, sizeof(request));
DBG2(DBG_KNL, "querying SAD entry with SPI %.8x (mark %u/0x%08x)", 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 = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST; 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)); hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
sa_id = NLMSG_DATA(hdr); sa_id = NLMSG_DATA(hdr);
host2xfrm(dst, &sa_id->daddr); host2xfrm(id->dst, &sa_id->daddr);
sa_id->spi = spi; sa_id->spi = id->spi;
sa_id->proto = protocol; sa_id->proto = id->proto;
sa_id->family = dst->get_family(dst); 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; return FAILED;
} }
@@ -1705,17 +1726,17 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
{ {
struct nlmsgerr *err = NLMSG_DATA(hdr); struct nlmsgerr *err = NLMSG_DATA(hdr);
if (mark.value) if (id->mark.value)
{ {
DBG1(DBG_KNL, "querying SAD entry with SPI %.8x " DBG1(DBG_KNL, "querying SAD entry with SPI %.8x (mark "
"(mark %u/0x%08x) failed: %s (%d)", "%u/0x%08x) failed: %s (%d)", ntohl(id->spi),
ntohl(spi), mark.value, mark.mask, id->mark.value, id->mark.mask,
strerror(-err->error), -err->error); strerror(-err->error), -err->error);
} }
else else
{ {
DBG1(DBG_KNL, "querying SAD entry with SPI %.8x " DBG1(DBG_KNL, "querying SAD entry with SPI %.8x "
"failed: %s (%d)", ntohl(spi), "failed: %s (%d)", ntohl(id->spi),
strerror(-err->error), -err->error); strerror(-err->error), -err->error);
} }
break; break;
@@ -1732,7 +1753,8 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
if (sa == NULL) 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 else
{ {
@@ -1758,23 +1780,31 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
} }
METHOD(kernel_ipsec_t, del_sa, status_t, METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) kernel_ipsec_del_sa_t *data)
{ {
netlink_buf_t request; netlink_buf_t request;
struct nlmsghdr *hdr; struct nlmsghdr *hdr;
struct xfrm_usersa_id *sa_id; struct xfrm_usersa_id *sa_id;
/* if IPComp was used, we first delete the additional IPComp SA */ /* 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)); memset(&request, 0, sizeof(request));
DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x (mark %u/0x%08x)", 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 = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 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)); hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
sa_id = NLMSG_DATA(hdr); sa_id = NLMSG_DATA(hdr);
host2xfrm(dst, &sa_id->daddr); host2xfrm(id->dst, &sa_id->daddr);
sa_id->spi = spi; sa_id->spi = id->spi;
sa_id->proto = protocol; sa_id->proto = id->proto;
sa_id->family = dst->get_family(dst); 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; return FAILED;
} }
@@ -1796,29 +1826,29 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
{ {
case SUCCESS: case SUCCESS:
DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x (mark %u/0x%08x)", DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x (mark %u/0x%08x)",
ntohl(spi), mark.value, mark.mask); ntohl(id->spi), id->mark.value, id->mark.mask);
return SUCCESS; return SUCCESS;
case NOT_FOUND: case NOT_FOUND:
return NOT_FOUND; return NOT_FOUND;
default: default:
if (mark.value) if (id->mark.value)
{ {
DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x " DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x (mark "
"(mark %u/0x%08x)", ntohl(spi), mark.value, mark.mask); "%u/0x%08x)", ntohl(id->spi), id->mark.value,
id->mark.mask);
} }
else else
{ {
DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x",
ntohl(spi)); ntohl(id->spi));
} }
return FAILED; return FAILED;
} }
} }
METHOD(kernel_ipsec_t, update_sa, status_t, METHOD(kernel_ipsec_t, update_sa, status_t,
private_kernel_netlink_ipsec_t *this, uint32_t spi, uint8_t protocol, private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, kernel_ipsec_update_sa_t *data)
bool old_encap, bool new_encap, mark_t mark)
{ {
netlink_buf_t request; netlink_buf_t request;
struct nlmsghdr *hdr, *out = NULL; 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_replay_state_esn *replay_esn = NULL;
struct xfrm_lifetime_cur *lifetime = NULL; struct xfrm_lifetime_cur *lifetime = NULL;
uint32_t replay_esn_len = 0; uint32_t replay_esn_len = 0;
kernel_ipsec_del_sa_t del = { 0 };
status_t status = FAILED; status_t status = FAILED;
/* if IPComp is used, we first update the IPComp SA */ /* if IPComp is used, we first update the IPComp SA */
if (cpi) if (data->cpi)
{ {
update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0, kernel_ipsec_sa_id_t ipcomp_id = {
src, dst, new_src, new_dst, FALSE, FALSE, mark); .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)); 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 */ /* query the existing SA first */
hdr = &request.hdr; 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)); hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
sa_id = NLMSG_DATA(hdr); sa_id = NLMSG_DATA(hdr);
host2xfrm(dst, &sa_id->daddr); host2xfrm(id->dst, &sa_id->daddr);
sa_id->spi = spi; sa_id->spi = id->spi;
sa_id->proto = protocol; sa_id->proto = id->proto;
sa_id->family = dst->get_family(dst); 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; return FAILED;
} }
@@ -1892,23 +1934,25 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
} }
if (out_sa == NULL) 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; goto failed;
} }
get_replay_state(this, spi, protocol, dst, mark, &replay_esn, get_replay_state(this, id, &replay_esn, &replay_esn_len, &replay,
&replay_esn_len, &replay, &lifetime); &lifetime);
/* delete the old SA (without affecting the IPComp SA) */ /* 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", DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x",
ntohl(spi)); ntohl(id->spi));
goto failed; goto failed;
} }
DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H", 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 */ /* copy over the SA from out to request */
hdr = &request.hdr; hdr = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 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)); hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
sa = NLMSG_DATA(hdr); sa = NLMSG_DATA(hdr);
memcpy(sa, NLMSG_DATA(out), sizeof(struct xfrm_usersa_info)); 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); 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)) while (RTA_OK(rta, rtasize))
{ {
/* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ /* 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) if (rta->rta_type == XFRMA_ENCAP)
{ /* update encap tmpl */ { /* update encap tmpl */
tmpl = RTA_DATA(rta); tmpl = RTA_DATA(rta);
tmpl->encap_sport = ntohs(new_src->get_port(new_src)); tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src));
tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
} }
netlink_add_attribute(hdr, rta->rta_type, netlink_add_attribute(hdr, rta->rta_type,
chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)), 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); rta = RTA_NEXT(rta, rtasize);
} }
if (tmpl == NULL && new_encap) if (tmpl == NULL && data->new_encap)
{ /* add tmpl if we are enabling it */ { /* add tmpl if we are enabling it */
tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl)); tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl));
if (!tmpl) if (!tmpl)
@@ -1955,8 +1999,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
goto failed; goto failed;
} }
tmpl->encap_type = UDP_ENCAP_ESPINUDP; tmpl->encap_type = UDP_ENCAP_ESPINUDP;
tmpl->encap_sport = ntohs(new_src->get_port(new_src)); tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src));
tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
} }
@@ -1987,7 +2031,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
else else
{ {
DBG1(DBG_KNL, "unable to copy replay state from old SAD entry with " DBG1(DBG_KNL, "unable to copy replay state from old SAD entry with "
"SPI %.8x", ntohl(spi)); "SPI %.8x", ntohl(id->spi));
} }
if (lifetime) if (lifetime)
{ {
@@ -2004,12 +2048,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
else else
{ {
DBG1(DBG_KNL, "unable to copy usage stats from old SAD entry with " 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) 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; 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, METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, private_kernel_netlink_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
policy_entry_t *policy, *current; policy_entry_t *policy, *current;
policy_sa_t *assigned_sa, *current_sa; policy_sa_t *assigned_sa, *current_sa;
@@ -2315,10 +2358,10 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
/* create a policy */ /* create a policy */
INIT(policy, INIT(policy,
.sel = ts2selector(src_ts, dst_ts), .sel = ts2selector(id->src_ts, id->dst_ts),
.mark = mark.value & mark.mask, .mark = id->mark.value & id->mark.mask,
.direction = direction, .direction = id->dir,
.reqid = sa->reqid, .reqid = data->sa->reqid,
); );
/* find the policy, which matches EXACTLY */ /* 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); current = this->policies->get(this->policies, policy);
if (current) 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 " DBG1(DBG_CFG, "unable to install policy %R === %R %N (mark "
"%u/0x%08x) for reqid %u, the same policy for reqid %u exists", "%u/0x%08x) for reqid %u, the same policy for reqid %u exists",
src_ts, dst_ts, policy_dir_names, direction, id->src_ts, id->dst_ts, policy_dir_names, id->dir,
mark.value, mark.mask, sa->reqid, current->reqid); id->mark.value, id->mark.mask, data->sa->reqid, current->reqid);
policy_entry_destroy(this, policy); policy_entry_destroy(this, policy);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
return INVALID_STATE; return INVALID_STATE;
} }
/* use existing policy */ /* use existing policy */
DBG2(DBG_KNL, "policy %R === %R %N (mark %u/0x%08x) " DBG2(DBG_KNL, "policy %R === %R %N (mark %u/0x%08x) already exists, "
"already exists, increasing refcount", "increasing refcount", id->src_ts, id->dst_ts, policy_dir_names,
src_ts, dst_ts, policy_dir_names, direction, id->dir, id->mark.value, id->mark.mask);
mark.value, mark.mask);
policy_entry_destroy(this, policy); policy_entry_destroy(this, policy);
policy = current; policy = current;
found = TRUE; found = TRUE;
@@ -2352,9 +2395,9 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
} }
/* cache the assigned IPsec SA */ /* cache the assigned IPsec SA */
assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts, assigned_sa = policy_sa_create(this, id->dir, data->type, data->src,
dst_ts, mark, sa); data->dst, id->src_ts, id->dst_ts, id->mark, data->sa);
assigned_sa->priority = get_priority(policy, priority); assigned_sa->priority = get_priority(policy, data->prio);
/* insert the SA according to its priority */ /* insert the SA according to its priority */
enumerator = policy->used_by->create_enumerator(policy->used_by); 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)", DBG2(DBG_KNL, "%s policy %R === %R %N (mark %u/0x%08x)",
found ? "updating" : "adding", src_ts, dst_ts, found ? "updating" : "adding", id->src_ts, id->dst_ts,
policy_dir_names, direction, mark.value, mark.mask); policy_dir_names, id->dir, id->mark.value, id->mark.mask);
if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS) if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS)
{ {
DBG1(DBG_KNL, "unable to %s policy %R === %R %N", DBG1(DBG_KNL, "unable to %s policy %R === %R %N",
found ? "update" : "add", src_ts, dst_ts, found ? "update" : "add", id->src_ts, id->dst_ts,
policy_dir_names, direction); policy_dir_names, id->dir);
return FAILED; return FAILED;
} }
return SUCCESS; return SUCCESS;
} }
METHOD(kernel_ipsec_t, query_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t,
private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts, private_kernel_netlink_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, kernel_ipsec_query_policy_t *data, time_t *use_time)
time_t *use_time)
{ {
netlink_buf_t request; netlink_buf_t request;
struct nlmsghdr *out = NULL, *hdr; struct nlmsghdr *out = NULL, *hdr;
@@ -2410,8 +2452,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
memset(&request, 0, sizeof(request)); memset(&request, 0, sizeof(request));
DBG2(DBG_KNL, "querying policy %R === %R %N (mark %u/0x%08x)", DBG2(DBG_KNL, "querying policy %R === %R %N (mark %u/0x%08x)",
src_ts, dst_ts, policy_dir_names, direction, id->src_ts, id->dst_ts, policy_dir_names, id->dir, id->mark.value,
mark.value, mark.mask); id->mark.mask);
hdr = &request.hdr; hdr = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST; 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)); hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id));
policy_id = NLMSG_DATA(hdr); policy_id = NLMSG_DATA(hdr);
policy_id->sel = ts2selector(src_ts, dst_ts); policy_id->sel = ts2selector(id->src_ts, id->dst_ts);
policy_id->dir = direction; policy_id->dir = id->dir;
if (!add_mark(hdr, sizeof(request), mark)) if (!add_mark(hdr, sizeof(request), id->mark))
{ {
return FAILED; return FAILED;
} }
@@ -2458,8 +2500,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
if (policy == NULL) if (policy == NULL)
{ {
DBG2(DBG_KNL, "unable to query policy %R === %R %N", src_ts, dst_ts, DBG2(DBG_KNL, "unable to query policy %R === %R %N", id->src_ts,
policy_dir_names, direction); id->dst_ts, policy_dir_names, id->dir);
free(out); free(out);
return FAILED; return FAILED;
} }
@@ -2479,10 +2521,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
} }
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, private_kernel_netlink_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t prio)
{ {
policy_entry_t *current, policy; policy_entry_t *current, policy;
enumerator_t *enumerator; enumerator_t *enumerator;
@@ -2493,52 +2533,52 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
bool is_installed = TRUE; bool is_installed = TRUE;
uint32_t priority; uint32_t priority;
ipsec_sa_t assigned_sa = { ipsec_sa_t assigned_sa = {
.src = src, .src = data->src,
.dst = dst, .dst = data->dst,
.mark = mark, .mark = id->mark,
.cfg = *sa, .cfg = *data->sa,
}; };
DBG2(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%08x)", DBG2(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%08x)",
src_ts, dst_ts, policy_dir_names, direction, id->src_ts, id->dst_ts, policy_dir_names, id->dir, id->mark.value,
mark.value, mark.mask); id->mark.mask);
/* create a policy */ /* create a policy */
memset(&policy, 0, sizeof(policy_entry_t)); memset(&policy, 0, sizeof(policy_entry_t));
policy.sel = ts2selector(src_ts, dst_ts); policy.sel = ts2selector(id->src_ts, id->dst_ts);
policy.mark = mark.value & mark.mask; policy.mark = id->mark.value & id->mark.mask;
policy.direction = direction; policy.direction = id->dir;
/* find the policy */ /* find the policy */
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
current = this->policies->get(this->policies, &policy); current = this->policies->get(this->policies, &policy);
if (!current) if (!current)
{ {
if (mark.value) if (id->mark.value)
{ {
DBG1(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%08x) " DBG1(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%08x) "
"failed, not found", src_ts, dst_ts, policy_dir_names, "failed, not found", id->src_ts, id->dst_ts,
direction, mark.value, mark.mask); policy_dir_names, id->dir, id->mark.value, id->mark.mask);
} }
else else
{ {
DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", 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); this->mutex->unlock(this->mutex);
return NOT_FOUND; return NOT_FOUND;
} }
/* remove mapping to SA by reqid and priority */ /* 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); enumerator = current->used_by->create_enumerator(current->used_by);
while (enumerator->enumerate(enumerator, (void**)&mapping)) 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)) ipsec_sa_equals(mapping->sa, &assigned_sa))
{ {
current->used_by->remove_at(current->used_by, enumerator); current->used_by->remove_at(current->used_by, enumerator);
policy_sa_destroy(mapping, &direction, this); policy_sa_destroy(mapping, &id->dir, this);
break; break;
} }
is_installed = FALSE; 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)", DBG2(DBG_KNL, "updating policy %R === %R %N (mark %u/0x%08x)",
src_ts, dst_ts, policy_dir_names, direction, id->src_ts, id->dst_ts, policy_dir_names, id->dir, id->mark.value,
mark.value, mark.mask); id->mark.mask);
current->used_by->get_first(current->used_by, (void**)&mapping); current->used_by->get_first(current->used_by, (void**)&mapping);
if (add_policy_internal(this, current, mapping, TRUE) != SUCCESS) if (add_policy_internal(this, current, mapping, TRUE) != SUCCESS)
{ {
DBG1(DBG_KNL, "unable to update policy %R === %R %N", 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 FAILED;
} }
return SUCCESS; return SUCCESS;
@@ -2577,9 +2617,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
policy_id = NLMSG_DATA(hdr); policy_id = NLMSG_DATA(hdr);
policy_id->sel = current->sel; 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); this->mutex->unlock(this->mutex);
return FAILED; return FAILED;
@@ -2592,9 +2632,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
route->prefixlen, route->gateway, route->prefixlen, route->gateway,
route->src_ip, route->if_name) != SUCCESS) route->src_ip, route->if_name) != SUCCESS)
{ {
DBG1(DBG_KNL, "error uninstalling route installed with " DBG1(DBG_KNL, "error uninstalling route installed with policy "
"policy %R === %R %N", src_ts, dst_ts, "%R === %R %N", id->src_ts, id->dst_ts, policy_dir_names,
policy_dir_names, direction); 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 (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 " DBG1(DBG_KNL, "unable to delete policy %R === %R %N (mark "
"(mark %u/0x%08x)", src_ts, dst_ts, policy_dir_names, "%u/0x%08x)", id->src_ts, id->dst_ts, policy_dir_names,
direction, mark.value, mark.mask); id->dir, id->mark.value, id->mark.mask);
} }
else else
{ {
DBG1(DBG_KNL, "unable to delete policy %R === %R %N", 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; return FAILED;
} }
@@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2008-2015 Tobias Brunner * Copyright (C) 2008-2016 Tobias Brunner
* Copyright (C) 2008 Andreas Steffen * 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 * 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 * 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, METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, uint32_t spi, private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint8_t protocol, uint32_t reqid, mark_t mark, uint32_t tfc, kernel_ipsec_add_sa_t *data)
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)
{ {
unsigned char request[PFKEY_BUFFER_SIZE]; unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out; struct sadb_msg *msg, *out;
@@ -1620,22 +1615,42 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
struct sadb_lifetime *lft; struct sadb_lifetime *lft;
struct sadb_key *key; struct sadb_key *key;
size_t len; 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 /* if IPComp is used, we install an additional IPComp SA. if the cpi is 0
* we are in the recursive call below */ * 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}}; 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, kernel_ipsec_sa_id_t ipcomp_id = {
tfc, &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, .src = id->src,
chunk_empty, mode, ipcomp, 0, 0, FALSE, FALSE, FALSE, inbound, .dst = id->dst,
update, NULL, NULL); .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; ipcomp = IPCOMP_NONE;
/* use transport mode ESP SA, IPComp uses tunnel mode */ /* use transport mode ESP SA, IPComp uses tunnel mode */
mode = MODE_TRANSPORT; mode = MODE_TRANSPORT;
} }
if (update) if (data->update)
{ {
/* As we didn't know the reqid during SPI allocation, we used reqid /* 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 * 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 * selector does not count for that, therefore we have to delete
* that state before installing the new SA to avoid deleting the * that state before installing the new SA to avoid deleting the
* the new state after installing it. */ * 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, if (this->public.interface.del_sa(&this->public.interface, &del_id,
src, dst, spi, protocol, 0, zeromark) != SUCCESS) &del) != SUCCESS)
{ {
DBG1(DBG_KNL, "deleting SPI allocation SA failed"); 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)); memset(&request, 0, sizeof(request));
DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}",
ntohl(spi), reqid); ntohl(id->spi), data->reqid);
msg = (struct sadb_msg*)request; msg = (struct sadb_msg*)request;
msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_version = PF_KEY_V2;
msg->sadb_msg_type = SADB_ADD; 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)); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
#ifdef __APPLE__ #ifdef __APPLE__
if (encap) if (data->encap)
{ {
struct sadb_sa_2 *sa_2; struct sadb_sa_2 *sa_2;
sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg); 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 = &sa_2->sa;
sa->sadb_sa_flags |= SADB_X_EXT_NATT; sa->sadb_sa_flags |= SADB_X_EXT_NATT;
len = sizeof(struct sadb_sa_2); 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_exttype = SADB_EXT_SA;
sa->sadb_sa_len = PFKEY_LEN(len); sa->sadb_sa_len = PFKEY_LEN(len);
sa->sadb_sa_spi = spi; sa->sadb_sa_spi = id->spi;
if (protocol == IPPROTO_COMP) if (id->proto == IPPROTO_COMP)
{ {
sa->sadb_sa_encrypt = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp); sa->sadb_sa_encrypt = lookup_algorithm(COMPRESSION_ALGORITHM,
ipcomp);
} }
else else
{ {
/* Linux interprets sadb_sa_replay as number of packets/bits in the /* 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 */ * replay window, whereas on BSD it's the size of the window in bytes */
#ifdef __linux__ #ifdef __linux__
sa->sadb_sa_replay = min(replay_window, 32); sa->sadb_sa_replay = min(data->replay_window, 32);
#else #else
sa->sadb_sa_replay = (replay_window + 7) / 8; sa->sadb_sa_replay = (data->replay_window + 7) / 8;
#endif #endif
sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, data->int_alg);
sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM,
data->enc_alg);
} }
PFKEY_EXT_ADD(msg, sa); 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_exttype = SADB_X_EXT_SA2;
sa2->sadb_x_sa2_len = PFKEY_LEN(sizeof(struct sadb_spirange)); sa2->sadb_x_sa2_len = PFKEY_LEN(sizeof(struct sadb_spirange));
sa2->sadb_x_sa2_mode = mode2kernel(mode); 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); PFKEY_EXT_ADD(msg, sa2);
add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); add_addr_ext(msg, id->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->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg); lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg);
lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime)); lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime));
lft->sadb_lifetime_allocations = lifetime->packets.rekey; lft->sadb_lifetime_allocations = data->lifetime->packets.rekey;
lft->sadb_lifetime_bytes = lifetime->bytes.rekey; lft->sadb_lifetime_bytes = data->lifetime->bytes.rekey;
lft->sadb_lifetime_addtime = lifetime->time.rekey; lft->sadb_lifetime_addtime = data->lifetime->time.rekey;
lft->sadb_lifetime_usetime = 0; /* we only use addtime */ lft->sadb_lifetime_usetime = 0; /* we only use addtime */
PFKEY_EXT_ADD(msg, lft); PFKEY_EXT_ADD(msg, lft);
lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg); lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg);
lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime)); lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime));
lft->sadb_lifetime_allocations = lifetime->packets.life; lft->sadb_lifetime_allocations = data->lifetime->packets.life;
lft->sadb_lifetime_bytes = lifetime->bytes.life; lft->sadb_lifetime_bytes = data->lifetime->bytes.life;
lft->sadb_lifetime_addtime = lifetime->time.life; lft->sadb_lifetime_addtime = data->lifetime->time.life;
lft->sadb_lifetime_usetime = 0; /* we only use addtime */ lft->sadb_lifetime_usetime = 0; /* we only use addtime */
PFKEY_EXT_ADD(msg, lft); PFKEY_EXT_ADD(msg, lft);
if (enc_alg != ENCR_UNDEFINED) if (data->enc_alg != ENCR_UNDEFINED)
{ {
if (!sa->sadb_sa_encrypt) if (!sa->sadb_sa_encrypt)
{ {
DBG1(DBG_KNL, "algorithm %N not supported by kernel!", DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
encryption_algorithm_names, enc_alg); encryption_algorithm_names, data->enc_alg);
return FAILED; return FAILED;
} }
DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", 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 = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
key->sadb_key_bits = enc_key.len * 8; key->sadb_key_bits = data->enc_key.len * 8;
key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + enc_key.len); key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + data->enc_key.len);
memcpy(key + 1, enc_key.ptr, enc_key.len); memcpy(key + 1, data->enc_key.ptr, data->enc_key.len);
PFKEY_EXT_ADD(msg, key); PFKEY_EXT_ADD(msg, key);
} }
if (int_alg != AUTH_UNDEFINED) if (data->int_alg != AUTH_UNDEFINED)
{ {
if (!sa->sadb_sa_auth) if (!sa->sadb_sa_auth)
{ {
DBG1(DBG_KNL, "algorithm %N not supported by kernel!", DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
integrity_algorithm_names, int_alg); integrity_algorithm_names, data->int_alg);
return FAILED; return FAILED;
} }
DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", 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 = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
key->sadb_key_exttype = SADB_EXT_KEY_AUTH; key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
key->sadb_key_bits = int_key.len * 8; key->sadb_key_bits = data->int_key.len * 8;
key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + int_key.len); key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + data->int_key.len);
memcpy(key + 1, int_key.ptr, int_key.len); memcpy(key + 1, data->int_key.ptr, data->int_key.len);
PFKEY_EXT_ADD(msg, key); PFKEY_EXT_ADD(msg, key);
} }
#ifdef HAVE_NATT #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*/ #endif /*HAVE_NATT*/
if (pfkey_send(this, msg, &out, &len) != SUCCESS) 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; return FAILED;
} }
else if (out->sadb_msg_errno) else if (out->sadb_msg_errno)
{ {
DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x: %s (%d)", 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); free(out);
return FAILED; return FAILED;
} }
@@ -1793,9 +1818,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
} }
METHOD(kernel_ipsec_t, update_sa, status_t, METHOD(kernel_ipsec_t, update_sa, status_t,
private_kernel_pfkey_ipsec_t *this, uint32_t spi, uint8_t protocol, private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, kernel_ipsec_update_sa_t *data)
bool encap, bool new_encap, mark_t mark)
{ {
unsigned char request[PFKEY_BUFFER_SIZE]; unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out; struct sadb_msg *msg, *out;
@@ -1806,51 +1830,63 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
/* we can't update the SA if any of the ip addresses have changed. /* 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 * that's because we can't use SADB_UPDATE and by deleting and readding the
* SA the sequence numbers would get lost */ * SA the sequence numbers would get lost */
if (!src->ip_equals(src, new_src) || if (!id->src->ip_equals(id->src, data->new_src) ||
!dst->ip_equals(dst, new_dst)) !id->dst->ip_equals(id->dst, data->new_dst))
{ {
DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: address " 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; return NOT_SUPPORTED;
} }
/* if IPComp is used, we first update the IPComp SA */ /* if IPComp is used, we first update the IPComp SA */
if (cpi) if (data->cpi)
{ {
update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0, kernel_ipsec_sa_id_t ipcomp_id = {
src, dst, new_src, new_dst, FALSE, FALSE, mark); .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)); 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 = (struct sadb_msg*)request;
msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_version = PF_KEY_V2;
msg->sadb_msg_type = SADB_GET; 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)); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_exttype = SADB_EXT_SA;
sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_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); PFKEY_EXT_ADD(msg, sa);
/* the kernel wants a SADB_EXT_ADDRESS_SRC to be present even though /* the kernel wants a SADB_EXT_ADDRESS_SRC to be present even though
* it is not used for anything. */ * it is not used for anything. */
add_anyaddr_ext(msg, dst->get_family(dst), SADB_EXT_ADDRESS_SRC); add_anyaddr_ext(msg, id->dst->get_family(id->dst), SADB_EXT_ADDRESS_SRC);
add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
if (pfkey_send(this, msg, &out, &len) != SUCCESS) 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; return FAILED;
} }
else if (out->sadb_msg_errno) else if (out->sadb_msg_errno)
{ {
DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)", DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)",
ntohl(spi), strerror(out->sadb_msg_errno), ntohl(id->spi), strerror(out->sadb_msg_errno),
out->sadb_msg_errno); out->sadb_msg_errno);
free(out); free(out);
return FAILED; return FAILED;
@@ -1858,20 +1894,20 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
else if (parse_pfkey_message(out, &response) != SUCCESS) else if (parse_pfkey_message(out, &response) != SUCCESS)
{ {
DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: parsing " 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); free(out);
return FAILED; return FAILED;
} }
DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H", 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)); memset(&request, 0, sizeof(request));
msg = (struct sadb_msg*)request; msg = (struct sadb_msg*)request;
msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_version = PF_KEY_V2;
msg->sadb_msg_type = SADB_UPDATE; 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)); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
#ifdef __APPLE__ #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 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg);
sa_2->sa.sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa_2)); sa_2->sa.sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa_2));
memcpy(&sa_2->sa, response.sa, sizeof(struct sadb_sa)); 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; 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 #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*/ #endif /*HAVE_NATT*/
@@ -1918,14 +1954,14 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
if (pfkey_send(this, msg, &out, &len) != SUCCESS) 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; return FAILED;
} }
else if (out->sadb_msg_errno) else if (out->sadb_msg_errno)
{ {
DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: %s (%d)", DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: %s (%d)",
ntohl(spi), strerror(out->sadb_msg_errno), ntohl(id->spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
out->sadb_msg_errno);
free(out); free(out);
return FAILED; return FAILED;
} }
@@ -1935,9 +1971,9 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
} }
METHOD(kernel_ipsec_t, query_sa, status_t, METHOD(kernel_ipsec_t, query_sa, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
uint64_t *bytes, uint64_t *packets, time_t *time) time_t *time)
{ {
unsigned char request[PFKEY_BUFFER_SIZE]; unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out; struct sadb_msg *msg, *out;
@@ -1947,42 +1983,44 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
memset(&request, 0, sizeof(request)); memset(&request, 0, sizeof(request));
DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi)); DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(id->spi));
msg = (struct sadb_msg*)request; msg = (struct sadb_msg*)request;
msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_version = PF_KEY_V2;
msg->sadb_msg_type = SADB_GET; 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)); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_exttype = SADB_EXT_SA;
sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_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); PFKEY_EXT_ADD(msg, sa);
/* the Linux Kernel doesn't care for the src address, but other systems do /* the Linux Kernel doesn't care for the src address, but other systems do
* (e.g. FreeBSD) * (e.g. FreeBSD)
*/ */
add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); add_addr_ext(msg, id->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->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
if (pfkey_send(this, msg, &out, &len) != SUCCESS) 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; return FAILED;
} }
else if (out->sadb_msg_errno) else if (out->sadb_msg_errno)
{ {
DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)", DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)",
ntohl(spi), strerror(out->sadb_msg_errno), ntohl(id->spi), strerror(out->sadb_msg_errno),
out->sadb_msg_errno); out->sadb_msg_errno);
free(out); free(out);
return FAILED; return FAILED;
} }
else if (parse_pfkey_message(out, &response) != SUCCESS) 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); free(out);
return FAILED; return FAILED;
} }
@@ -2013,8 +2051,8 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
} }
METHOD(kernel_ipsec_t, del_sa, status_t, METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) kernel_ipsec_del_sa_t *data)
{ {
unsigned char request[PFKEY_BUFFER_SIZE]; unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out; struct sadb_msg *msg, *out;
@@ -2022,48 +2060,57 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
size_t len; size_t len;
/* if IPComp was used, we first delete the additional IPComp SA */ /* 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)); 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 = (struct sadb_msg*)request;
msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_version = PF_KEY_V2;
msg->sadb_msg_type = SADB_DELETE; 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)); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_exttype = SADB_EXT_SA;
sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_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); PFKEY_EXT_ADD(msg, sa);
/* the Linux Kernel doesn't care for the src address, but other systems do /* the Linux Kernel doesn't care for the src address, but other systems do
* (e.g. FreeBSD) * (e.g. FreeBSD)
*/ */
add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); add_addr_ext(msg, id->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->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
if (pfkey_send(this, msg, &out, &len) != SUCCESS) 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; return FAILED;
} }
else if (out->sadb_msg_errno) else if (out->sadb_msg_errno)
{ {
DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x: %s (%d)", DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x: %s (%d)",
ntohl(spi), strerror(out->sadb_msg_errno), ntohl(id->spi), strerror(out->sadb_msg_errno),
out->sadb_msg_errno); out->sadb_msg_errno);
free(out); free(out);
return FAILED; 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); free(out);
return SUCCESS; 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, METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
policy_entry_t *policy, *found = NULL; policy_entry_t *policy, *found = NULL;
policy_sa_t *assigned_sa, *current_sa; policy_sa_t *assigned_sa, *current_sa;
enumerator_t *enumerator; enumerator_t *enumerator;
bool update = TRUE; bool update = TRUE;
if (dir2kernel(direction) == IPSEC_DIR_INVALID) if (dir2kernel(id->dir) == IPSEC_DIR_INVALID)
{ /* FWD policies are not supported on all platforms */ { /* FWD policies are not supported on all platforms */
return SUCCESS; return SUCCESS;
} }
/* create a policy */ /* 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 */ /* find a matching policy */
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
@@ -2531,7 +2576,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
(void**)&found, policy) == SUCCESS) (void**)&found, policy) == SUCCESS)
{ /* use existing policy */ { /* use existing policy */
DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing " 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_entry_destroy(policy, this);
policy = found; policy = found;
} }
@@ -2542,9 +2587,9 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
} }
/* cache the assigned IPsec SA */ /* cache the assigned IPsec SA */
assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts, assigned_sa = policy_sa_create(this, id->dir, data->type, data->src,
dst_ts, sa); data->dst, id->src_ts, id->dst_ts, data->sa);
assigned_sa->priority = get_priority(policy, priority); assigned_sa->priority = get_priority(policy, data->prio);
/* insert the SA according to its priority */ /* insert the SA according to its priority */
enumerator = policy->used_by->create_enumerator(policy->used_by); 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", DBG2(DBG_KNL, "%s policy %R === %R %N",
found ? "updating" : "adding", src_ts, dst_ts, found ? "updating" : "adding", id->src_ts, id->dst_ts,
policy_dir_names, direction); policy_dir_names, id->dir);
if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS) if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS)
{ {
DBG1(DBG_KNL, "unable to %s policy %R === %R %N", DBG1(DBG_KNL, "unable to %s policy %R === %R %N",
found ? "update" : "add", src_ts, dst_ts, found ? "update" : "add", id->src_ts, id->dst_ts,
policy_dir_names, direction); policy_dir_names, id->dir);
return FAILED; return FAILED;
} }
return SUCCESS; return SUCCESS;
} }
METHOD(kernel_ipsec_t, query_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t,
private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts, private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, kernel_ipsec_query_policy_t *data, time_t *use_time)
time_t *use_time)
{ {
unsigned char request[PFKEY_BUFFER_SIZE]; unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out; struct sadb_msg *msg, *out;
@@ -2592,16 +2636,16 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
pfkey_msg_t response; pfkey_msg_t response;
size_t len; size_t len;
if (dir2kernel(direction) == IPSEC_DIR_INVALID) if (dir2kernel(id->dir) == IPSEC_DIR_INVALID)
{ /* FWD policies are not supported on all platforms */ { /* FWD policies are not supported on all platforms */
return NOT_FOUND; return NOT_FOUND;
} }
DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts, DBG2(DBG_KNL, "querying policy %R === %R %N", id->src_ts, id->dst_ts,
policy_dir_names, direction); policy_dir_names, id->dir);
/* create a policy */ /* 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 */ /* find a matching policy */
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
@@ -2609,8 +2653,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
(linked_list_match_t)policy_entry_equals, (linked_list_match_t)policy_entry_equals,
(void**)&found, policy) != SUCCESS) (void**)&found, policy) != SUCCESS)
{ {
DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found", src_ts, DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found",
dst_ts, policy_dir_names, direction); id->src_ts, id->dst_ts, policy_dir_names, id->dir);
policy_entry_destroy(policy, this); policy_entry_destroy(policy, this);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
return NOT_FOUND; 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_exttype = SADB_X_EXT_POLICY;
pol->sadb_x_policy_id = policy->index; pol->sadb_x_policy_id = policy->index;
pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_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 = IPSEC_POLICY_IPSEC; pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
PFKEY_EXT_ADD(msg, pol); PFKEY_EXT_ADD(msg, pol);
@@ -2643,14 +2687,14 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
if (pfkey_send(this, msg, &out, &len) != SUCCESS) if (pfkey_send(this, msg, &out, &len) != SUCCESS)
{ {
DBG1(DBG_KNL, "unable to query policy %R === %R %N", src_ts, dst_ts, DBG1(DBG_KNL, "unable to query policy %R === %R %N", id->src_ts,
policy_dir_names, direction); id->dst_ts, policy_dir_names, id->dir);
return FAILED; return FAILED;
} }
else if (out->sadb_msg_errno) else if (out->sadb_msg_errno)
{ {
DBG1(DBG_KNL, "unable to query policy %R === %R %N: %s (%d)", src_ts, DBG1(DBG_KNL, "unable to query policy %R === %R %N: %s (%d)",
dst_ts, policy_dir_names, direction, id->src_ts, id->dst_ts, policy_dir_names, id->dir,
strerror(out->sadb_msg_errno), out->sadb_msg_errno); strerror(out->sadb_msg_errno), out->sadb_msg_errno);
free(out); free(out);
return FAILED; return FAILED;
@@ -2658,15 +2702,16 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
else if (parse_pfkey_message(out, &response) != SUCCESS) else if (parse_pfkey_message(out, &response) != SUCCESS)
{ {
DBG1(DBG_KNL, "unable to query policy %R === %R %N: parsing response " DBG1(DBG_KNL, "unable to query policy %R === %R %N: parsing response "
"from kernel failed", src_ts, dst_ts, policy_dir_names, "from kernel failed", id->src_ts, id->dst_ts, policy_dir_names,
direction); id->dir);
free(out); free(out);
return FAILED; return FAILED;
} }
else if (response.lft_current == NULL) else if (response.lft_current == NULL)
{ {
DBG2(DBG_KNL, "unable to query policy %R === %R %N: kernel reports no " 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); free(out);
return FAILED; return FAILED;
} }
@@ -2686,10 +2731,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
} }
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t prio)
{ {
unsigned char request[PFKEY_BUFFER_SIZE]; unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out; struct sadb_msg *msg, *out;
@@ -2701,21 +2744,21 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
uint32_t priority; uint32_t priority;
size_t len; size_t len;
ipsec_sa_t assigned_sa = { ipsec_sa_t assigned_sa = {
.src = src, .src = data->src,
.dst = dst, .dst = data->dst,
.cfg = *sa, .cfg = *data->sa,
}; };
if (dir2kernel(direction) == IPSEC_DIR_INVALID) if (dir2kernel(id->dir) == IPSEC_DIR_INVALID)
{ /* FWD policies are not supported on all platforms */ { /* FWD policies are not supported on all platforms */
return SUCCESS; return SUCCESS;
} }
DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts, DBG2(DBG_KNL, "deleting policy %R === %R %N", id->src_ts, id->dst_ts,
policy_dir_names, direction); policy_dir_names, id->dir);
/* create a policy */ /* 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 */ /* find a matching policy */
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
@@ -2723,8 +2766,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
(linked_list_match_t)policy_entry_equals, (linked_list_match_t)policy_entry_equals,
(void**)&found, policy) != SUCCESS) (void**)&found, policy) != SUCCESS)
{ {
DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts, DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found",
dst_ts, policy_dir_names, direction); id->src_ts, id->dst_ts, policy_dir_names, id->dir);
policy_entry_destroy(policy, this); policy_entry_destroy(policy, this);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
return NOT_FOUND; 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 /* remove mapping to SA by reqid and priority, if multiple match, which
* could happen when rekeying due to an address change, remove the oldest */ * 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); enumerator = policy->used_by->create_enumerator(policy->used_by);
while (enumerator->enumerate(enumerator, (void**)&mapping)) 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) if (policy->used_by->get_count(policy->used_by) > 0)
{ /* policy is used by more SAs, keep in kernel */ { /* policy is used by more SAs, keep in kernel */
DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); 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) if (!is_installed)
{ /* no need to update as the policy was not installed for this SA */ { /* 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; return SUCCESS;
} }
DBG2(DBG_KNL, "updating policy %R === %R %N", src_ts, dst_ts, DBG2(DBG_KNL, "updating policy %R === %R %N", id->src_ts, id->dst_ts,
policy_dir_names, direction); policy_dir_names, id->dir);
policy->used_by->get_first(policy->used_by, (void**)&mapping); policy->used_by->get_first(policy->used_by, (void**)&mapping);
if (add_policy_internal(this, policy, mapping, TRUE) != SUCCESS) if (add_policy_internal(this, policy, mapping, TRUE) != SUCCESS)
{ {
DBG1(DBG_KNL, "unable to update policy %R === %R %N", 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 FAILED;
} }
return SUCCESS; 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 = (struct sadb_x_policy*)PFKEY_EXT_ADD_NEXT(msg);
pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 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_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); pol->sadb_x_policy_type = type2kernel(mapping->type);
PFKEY_EXT_ADD(msg, pol); PFKEY_EXT_ADD(msg, pol);
@@ -2810,27 +2853,27 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
route->src_ip, route->if_name) != SUCCESS) route->src_ip, route->if_name) != SUCCESS)
{ {
DBG1(DBG_KNL, "error uninstalling route installed with " DBG1(DBG_KNL, "error uninstalling route installed with "
"policy %R === %R %N", src_ts, dst_ts, "policy %R === %R %N", id->src_ts, id->dst_ts,
policy_dir_names, direction); policy_dir_names, id->dir);
} }
remove_exclude_route(this, route); remove_exclude_route(this, route);
} }
this->policies->remove(this->policies, found, NULL); 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); policy_entry_destroy(policy, this);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
if (pfkey_send(this, msg, &out, &len) != SUCCESS) if (pfkey_send(this, msg, &out, &len) != SUCCESS)
{ {
DBG1(DBG_KNL, "unable to delete policy %R === %R %N", src_ts, dst_ts, DBG1(DBG_KNL, "unable to delete policy %R === %R %N", id->src_ts,
policy_dir_names, direction); id->dst_ts, policy_dir_names, id->dir);
return FAILED; return FAILED;
} }
else if (out->sadb_msg_errno) else if (out->sadb_msg_errno)
{ {
DBG1(DBG_KNL, "unable to delete policy %R === %R %N: %s (%d)", src_ts, DBG1(DBG_KNL, "unable to delete policy %R === %R %N: %s (%d)",
dst_ts, policy_dir_names, direction, id->src_ts, id->dst_ts, policy_dir_names, id->dir,
strerror(out->sadb_msg_errno), out->sadb_msg_errno); strerror(out->sadb_msg_errno), out->sadb_msg_errno);
free(out); free(out);
return FAILED; return FAILED;
@@ -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, METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, kernel_ipsec_add_sa_t *data)
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)
{ {
host_t *local, *remote; host_t *local, *remote;
entry_t *entry; entry_t *entry;
if (inbound) if (data->inbound)
{ {
/* comes first, create new entry */ /* comes first, create new entry */
local = dst->clone(dst); local = id->dst->clone(id->dst);
remote = src->clone(src); remote = id->src->clone(id->src);
INIT(entry, INIT(entry,
.reqid = reqid, .reqid = data->reqid,
.isa = { .isa = {
.spi = spi, .spi = id->spi,
.dst = local, .dst = local,
.protocol = protocol, .protocol = id->proto,
.lifetime = lifetime->time.life, .lifetime = data->lifetime->time.life,
.encr = { .encr = {
.alg = enc_alg, .alg = data->enc_alg,
.key = chunk_clone(enc_key), .key = chunk_clone(data->enc_key),
}, },
.integ = { .integ = {
.alg = int_alg, .alg = data->int_alg,
.key = chunk_clone(int_key), .key = chunk_clone(data->int_key),
}, },
}, },
.sps = array_create(0, 0), .sps = array_create(0, 0),
.local = local, .local = local,
.remote = remote, .remote = remote,
.mode = mode, .mode = data->mode,
.encap = encap, .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->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->isas->put(this->isas, &entry->isa, entry);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
} }
@@ -2151,29 +2149,29 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
{ {
/* comes after inbound, update entry */ /* comes after inbound, update entry */
this->mutex->lock(this->mutex); 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); this->mutex->unlock(this->mutex);
if (!entry) if (!entry)
{ {
DBG1(DBG_KNL, "adding outbound SA failed, no inbound SA found " DBG1(DBG_KNL, "adding outbound SA failed, no inbound SA found "
"for reqid %u ", reqid); "for reqid %u ", data->reqid);
return NOT_FOUND; return NOT_FOUND;
} }
/* TODO: should we check for local/remote, mode etc.? */ /* TODO: should we check for local/remote, mode etc.? */
entry->osa = (sa_entry_t){ entry->osa = (sa_entry_t){
.spi = spi, .spi = id->spi,
.dst = entry->remote, .dst = entry->remote,
.protocol = protocol, .protocol = id->proto,
.lifetime = lifetime->time.life, .lifetime = data->lifetime->time.life,
.encr = { .encr = {
.alg = enc_alg, .alg = data->enc_alg,
.key = chunk_clone(enc_key), .key = chunk_clone(data->enc_key),
}, },
.integ = { .integ = {
.alg = int_alg, .alg = data->int_alg,
.key = chunk_clone(int_key), .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, METHOD(kernel_ipsec_t, update_sa, status_t,
private_kernel_wfp_ipsec_t *this, uint32_t spi, uint8_t protocol, private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, kernel_ipsec_update_sa_t *data)
bool encap, bool new_encap, mark_t mark)
{ {
entry_t *entry; entry_t *entry;
sa_entry_t key = { sa_entry_t key = {
.dst = dst, .dst = id->dst,
.spi = spi, .spi = id->spi,
}; };
UINT64 sa_id = 0; UINT64 sa_id = 0;
IPSEC_SA_CONTEXT1 *ctx; 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); DBG1(DBG_KNL, "getting WFP SA context for updated failed: 0x%08x", res);
return FAILED; return FAILED;
} }
if (!hosts2traffic(this, new_dst, new_src, &ctx->inboundSa->traffic) || if (!hosts2traffic(this, data->new_dst, data->new_src, &ctx->inboundSa->traffic) ||
!hosts2traffic(this, new_dst, new_src, &ctx->outboundSa->traffic)) !hosts2traffic(this, data->new_dst, data->new_src, &ctx->outboundSa->traffic))
{ {
FwpmFreeMemory0((void**)&ctx); FwpmFreeMemory0((void**)&ctx);
return FAILED; return FAILED;
} }
if (new_encap != encap) if (data->new_encap != data->encap)
{ {
if (new_encap) if (data->new_encap)
{ {
ctx->inboundSa->udpEncapsulation = &ports; ctx->inboundSa->udpEncapsulation = &ports;
ctx->outboundSa->udpEncapsulation = &ports; ctx->outboundSa->udpEncapsulation = &ports;
@@ -2273,8 +2270,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
entry->local->destroy(entry->local); entry->local->destroy(entry->local);
entry->remote->destroy(entry->remote); entry->remote->destroy(entry->remote);
entry->local = new_dst->clone(new_dst); entry->local = data->new_dst->clone(data->new_dst);
entry->remote = new_src->clone(new_src); entry->remote = data->new_src->clone(data->new_src);
entry->isa.dst = entry->local; entry->isa.dst = entry->local;
entry->osa.dst = entry->remote; 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, METHOD(kernel_ipsec_t, query_sa, status_t,
private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, uint64_t *bytes, kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
uint64_t *packets, time_t *time) time_t *time)
{ {
/* It does not seem that WFP provides any means of getting per-SA traffic /* It does not seem that WFP provides any means of getting per-SA traffic
* statistics. IPsecGetStatistics0/1() provides global stats, and * 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, METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) kernel_ipsec_del_sa_t *data)
{ {
entry_t *entry; entry_t *entry;
sa_entry_t key = { sa_entry_t key = {
.dst = dst, .dst = id->dst,
.spi = spi, .spi = id->spi,
}; };
this->mutex->lock(this->mutex); 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, METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
policy_priority_t priority)
{ {
status_t status = SUCCESS; status_t status = SUCCESS;
entry_t *entry; entry_t *entry;
sp_entry_t *sp; sp_entry_t *sp;
sa_entry_t key = { sa_entry_t key = {
.spi = sa->esp.use ? sa->esp.spi : sa->ah.spi, .spi = data->sa->esp.use ? data->sa->esp.spi : data->sa->ah.spi,
.dst = dst, .dst = data->dst,
}; };
if (sa->esp.use && sa->ah.use) if (data->sa->esp.use && data->sa->ah.use)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
switch (type) switch (data->type)
{ {
case POLICY_IPSEC: case POLICY_IPSEC:
break; break;
@@ -2368,7 +2363,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
switch (direction) switch (id->dir)
{ {
case POLICY_OUT: case POLICY_OUT:
break; break;
@@ -2380,18 +2375,20 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
switch (priority) switch (data->prio)
{ {
case POLICY_PRIORITY_DEFAULT: case POLICY_PRIORITY_DEFAULT:
break; break;
case POLICY_PRIORITY_ROUTED: 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; 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; return FAILED;
} }
@@ -2406,14 +2403,14 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
entry = this->osas->get(this->osas, &key); entry = this->osas->get(this->osas, &key);
if (entry) 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, INIT(sp,
.src = src_ts->clone(src_ts), .src = id->src_ts->clone(id->src_ts),
.dst = dst_ts->clone(dst_ts), .dst = id->dst_ts->clone(id->dst_ts),
); );
array_insert(entry->sps, -1, sp); 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)) if (!install(this, entry))
{ {
@@ -2442,25 +2439,24 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
} }
METHOD(kernel_ipsec_t, query_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t,
private_kernel_wfp_ipsec_t *this, traffic_selector_t *src_ts, private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, kernel_ipsec_query_policy_t *data, time_t *use_time)
time_t *use_time)
{ {
/* see query_sa() for some notes */ /* see query_sa() for some notes */
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst, private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
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 SUCCESS;
} }
return NOT_FOUND; return NOT_FOUND;
@@ -50,63 +50,52 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,
} }
METHOD(kernel_ipsec_t, add_sa, status_t, METHOD(kernel_ipsec_t, add_sa, status_t,
private_load_tester_ipsec_t *this, host_t *src, host_t *dst, private_load_tester_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint32_t reqid, mark_t mark, kernel_ipsec_add_sa_t *data)
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)
{ {
return SUCCESS; return SUCCESS;
} }
METHOD(kernel_ipsec_t, update_sa, status_t, METHOD(kernel_ipsec_t, update_sa, status_t,
private_load_tester_ipsec_t *this, uint32_t spi, uint8_t protocol, private_load_tester_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, kernel_ipsec_update_sa_t *data)
host_t *new_dst, bool encap, bool new_encap, mark_t mark)
{ {
return SUCCESS; return SUCCESS;
} }
METHOD(kernel_ipsec_t, query_sa, status_t, METHOD(kernel_ipsec_t, query_sa, status_t,
private_load_tester_ipsec_t *this, host_t *src, host_t *dst, private_load_tester_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, mark_t mark, kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
uint64_t *bytes, uint64_t *packets, time_t *time) time_t *time)
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
METHOD(kernel_ipsec_t, del_sa, status_t, METHOD(kernel_ipsec_t, del_sa, status_t,
private_load_tester_ipsec_t *this, host_t *src, host_t *dst, private_load_tester_ipsec_t *this, kernel_ipsec_sa_id_t *id,
uint32_t spi, uint8_t protocol, uint16_t cpi, mark_t mark) kernel_ipsec_del_sa_t *data)
{ {
return SUCCESS; return SUCCESS;
} }
METHOD(kernel_ipsec_t, add_policy, status_t, METHOD(kernel_ipsec_t, add_policy, status_t,
private_load_tester_ipsec_t *this, host_t *src, host_t *dst, private_load_tester_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
return SUCCESS; return SUCCESS;
} }
METHOD(kernel_ipsec_t, query_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t,
private_load_tester_ipsec_t *this, traffic_selector_t *src_ts, private_load_tester_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, kernel_ipsec_query_policy_t *data, time_t *use_time)
time_t *use_time)
{ {
*use_time = 1; *use_time = 1;
return SUCCESS; return SUCCESS;
} }
METHOD(kernel_ipsec_t, del_policy, status_t, METHOD(kernel_ipsec_t, del_policy, status_t,
private_load_tester_ipsec_t *this, host_t *src, host_t *dst, private_load_tester_ipsec_t *this, kernel_ipsec_policy_id_t *id,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, kernel_ipsec_manage_policy_t *data)
policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{ {
return SUCCESS; return SUCCESS;
} }
+186 -59
View File
@@ -1,9 +1,9 @@
/* /*
* Copyright (C) 2006-2015 Tobias Brunner * Copyright (C) 2006-2016 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter * 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 * 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 * under the terms of the GNU General Public License as published by the
@@ -468,9 +468,16 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
{ {
if (this->my_spi) if (this->my_spi)
{ {
status = charon->kernel->query_sa(charon->kernel, this->other_addr, kernel_ipsec_sa_id_t id = {
this->my_addr, this->my_spi, .src = this->other_addr,
proto_ike2ip(this->protocol), this->mark_in, .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); &bytes, &packets, &time);
if (status == SUCCESS) if (status == SUCCESS)
{ {
@@ -492,9 +499,16 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
{ {
if (this->other_spi) if (this->other_spi)
{ {
status = charon->kernel->query_sa(charon->kernel, this->my_addr, kernel_ipsec_sa_id_t id = {
this->other_addr, this->other_spi, .src = this->my_addr,
proto_ike2ip(this->protocol), this->mark_out, .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); &bytes, &packets, &time);
if (status == SUCCESS) if (status == SUCCESS)
{ {
@@ -531,15 +545,24 @@ static bool update_usetime(private_child_sa_t *this, bool inbound)
if (inbound) if (inbound)
{ {
if (charon->kernel->query_policy(charon->kernel, other_ts, kernel_ipsec_policy_id_t id = {
my_ts, POLICY_IN, this->mark_in, &in) == SUCCESS) .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); last_use = max(last_use, in);
} }
if (this->mode != MODE_TRANSPORT) if (this->mode != MODE_TRANSPORT)
{ {
if (charon->kernel->query_policy(charon->kernel, other_ts, id.dir = POLICY_FWD;
my_ts, POLICY_FWD, this->mark_in, &fwd) == SUCCESS) if (charon->kernel->query_policy(charon->kernel, &id, &query,
&fwd) == SUCCESS)
{ {
last_use = max(last_use, fwd); last_use = max(last_use, fwd);
} }
@@ -547,8 +570,16 @@ static bool update_usetime(private_child_sa_t *this, bool inbound)
} }
else else
{ {
if (charon->kernel->query_policy(charon->kernel, my_ts, kernel_ipsec_policy_id_t id = {
other_ts, POLICY_OUT, this->mark_out, &out) == SUCCESS) .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); last_use = max(last_use, out);
} }
@@ -659,6 +690,8 @@ METHOD(child_sa_t, install, status_t,
uint16_t esn = NO_EXT_SEQ_NUMBERS; uint16_t esn = NO_EXT_SEQ_NUMBERS;
linked_list_t *src_ts = NULL, *dst_ts = NULL; linked_list_t *src_ts = NULL, *dst_ts = NULL;
time_t now; time_t now;
kernel_ipsec_sa_id_t id;
kernel_ipsec_add_sa_t sa;
lifetime_cfg_t *lifetime; lifetime_cfg_t *lifetime;
uint32_t tfc = 0; uint32_t tfc = 0;
host_t *src, *dst; host_t *src, *dst;
@@ -752,12 +785,35 @@ METHOD(child_sa_t, install, status_t,
dst_ts = other_ts; dst_ts = other_ts;
} }
status = charon->kernel->add_sa(charon->kernel, id = (kernel_ipsec_sa_id_t){
src, dst, spi, proto_ike2ip(this->protocol), this->reqid, .src = src,
inbound ? this->mark_in : this->mark_out, tfc, .dst = dst,
lifetime, enc_alg, encr, int_alg, integ, this->mode, .spi = spi,
this->ipcomp, cpi, this->config->get_replay_window(this->config), .proto = proto_ike2ip(this->protocol),
initiator, this->encap, esn, inbound, update, src_ts, dst_ts); .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); 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, 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)
{ {
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_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, status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy);
other_addr, my_addr, other_ts, my_ts, status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
POLICY_IN, type, my_sa,
this->mark_in, priority);
if (this->mode != MODE_TRANSPORT) if (this->mode != MODE_TRANSPORT)
{ {
status |= charon->kernel->add_policy(charon->kernel, in_id.dir = POLICY_FWD;
other_addr, my_addr, other_ts, my_ts, status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
POLICY_FWD, type, my_sa,
this->mark_in, priority);
} }
return status; 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, 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)
{ {
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, charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
my_addr, other_addr, my_ts, other_ts, POLICY_OUT, type, charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
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);
if (this->mode != MODE_TRANSPORT) if (this->mode != MODE_TRANSPORT)
{ {
charon->kernel->del_policy(charon->kernel, in_id.dir = POLICY_FWD;
other_addr, my_addr, other_ts, my_ts, POLICY_FWD, charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
type, my_sa, this->mark_in, priority);
} }
} }
@@ -994,11 +1085,22 @@ METHOD(child_sa_t, update, status_t,
/* update our (initiator) SA */ /* update our (initiator) SA */
if (this->my_spi) if (this->my_spi)
{ {
if (charon->kernel->update_sa(charon->kernel, kernel_ipsec_sa_id_t id = {
this->my_spi, proto_ike2ip(this->protocol), .src = this->other_addr,
this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0, .dst = this->my_addr,
this->other_addr, this->my_addr, other, me, .spi = this->my_spi,
this->encap, encap, this->mark_in) == NOT_SUPPORTED) .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); set_state(this, old);
return NOT_SUPPORTED; return NOT_SUPPORTED;
@@ -1008,11 +1110,22 @@ METHOD(child_sa_t, update, status_t,
/* update his (responder) SA */ /* update his (responder) SA */
if (this->other_spi) if (this->other_spi)
{ {
if (charon->kernel->update_sa(charon->kernel, kernel_ipsec_sa_id_t id = {
this->other_spi, proto_ike2ip(this->protocol), .src = this->my_addr,
this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0, .dst = this->other_addr,
this->my_addr, this->other_addr, me, other, .spi = this->other_spi,
this->encap, encap, this->mark_out) == NOT_SUPPORTED) .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); set_state(this, old);
return NOT_SUPPORTED; return NOT_SUPPORTED;
@@ -1137,17 +1250,31 @@ METHOD(child_sa_t, destroy, void,
/* delete SAs in the kernel, if they are set up */ /* delete SAs in the kernel, if they are set up */
if (this->my_spi) if (this->my_spi)
{ {
charon->kernel->del_sa(charon->kernel, kernel_ipsec_sa_id_t id = {
this->other_addr, this->my_addr, this->my_spi, .src = this->other_addr,
proto_ike2ip(this->protocol), this->my_cpi, .dst = this->my_addr,
this->mark_in); .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) if (this->other_spi)
{ {
charon->kernel->del_sa(charon->kernel, kernel_ipsec_sa_id_t id = {
this->my_addr, this->other_addr, this->other_spi, .src = this->my_addr,
proto_ike2ip(this->protocol), this->other_cpi, .dst = this->other_addr,
this->mark_out); .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) if (this->reqid_allocated)
+47 -35
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015 Tobias Brunner * Copyright (C) 2015-2016 Tobias Brunner
* Copyright (C) 2011 Andreas Steffen * Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil * HSR Hochschule fuer Technik Rapperswil
* *
@@ -110,25 +110,31 @@ static bool install_shunt_policy(child_cfg_t *child)
continue; continue;
} }
/* install out policy */ /* install out policy */
status |= charon->kernel->add_policy(charon->kernel, kernel_ipsec_policy_id_t id = {
host_any, host_any, .dir = POLICY_OUT,
my_ts, other_ts, POLICY_OUT, policy_type, .src_ts = my_ts,
&sa, child->get_mark(child, FALSE), .dst_ts = other_ts,
policy_prio); .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 */ /* install in policy */
status |= charon->kernel->add_policy(charon->kernel, id = (kernel_ipsec_policy_id_t){
host_any, host_any, .dir = POLICY_IN,
other_ts, my_ts, POLICY_IN, policy_type, .src_ts = other_ts,
&sa, child->get_mark(child, TRUE), .dst_ts = my_ts,
policy_prio); .mark = child->get_mark(child, TRUE),
};
status |= charon->kernel->add_policy(charon->kernel, &id, &policy);
/* install forward policy */ /* install forward policy */
status |= charon->kernel->add_policy(charon->kernel, id.dir = POLICY_FWD;
host_any, host_any, status |= charon->kernel->add_policy(charon->kernel, &id, &policy);
other_ts, my_ts, POLICY_FWD, policy_type,
&sa, child->get_mark(child, TRUE),
policy_prio);
} }
e_other_ts->destroy(e_other_ts); e_other_ts->destroy(e_other_ts);
} }
@@ -247,25 +253,31 @@ static void uninstall_shunt_policy(child_cfg_t *child)
continue; continue;
} }
/* uninstall out policy */ /* uninstall out policy */
status |= charon->kernel->del_policy(charon->kernel, kernel_ipsec_policy_id_t id = {
host_any, host_any, .dir = POLICY_OUT,
my_ts, other_ts, POLICY_OUT, policy_type, .src_ts = my_ts,
&sa, child->get_mark(child, FALSE), .dst_ts = other_ts,
policy_prio); .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 */ /* uninstall in policy */
status |= charon->kernel->del_policy(charon->kernel, id = (kernel_ipsec_policy_id_t){
host_any, host_any, .dir = POLICY_IN,
other_ts, my_ts, POLICY_IN, policy_type, .src_ts = other_ts,
&sa, child->get_mark(child, TRUE), .dst_ts = my_ts,
policy_prio); .mark = child->get_mark(child, TRUE),
};
status |= charon->kernel->del_policy(charon->kernel, &id, &policy);
/* uninstall forward policy */ /* uninstall forward policy */
status |= charon->kernel->del_policy(charon->kernel, id.dir = POLICY_FWD;
host_any, host_any, status |= charon->kernel->del_policy(charon->kernel, &id, &policy);
other_ts, my_ts, POLICY_FWD, policy_type,
&sa, child->get_mark(child, TRUE),
policy_prio);
} }
e_other_ts->destroy(e_other_ts); e_other_ts->destroy(e_other_ts);
} }