From bbd9df25a9410fcde8cb594e5c789cad5506d5ed Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 10 Jul 2013 11:08:01 +0200 Subject: kernel-pfkey: Remove latest IPsec SA mapping when deleting a policy If IPsec SAs are rekeyed due to an address change (e.g. because update_sa is not supported) the exact same policy with the same reqid will be installed, but with different addresses. After the rekeying the old SA and its policies are removed, using the first matching mapping breaks the mapping between the policies and the new SA (at least on FreeBSD, the Linux kernel might only use the reqid for this). Using the oldest matching SA is still an approximation but it solves the above issue. --- src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c') diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index dd9d354b1..86853e658 100644 --- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -2479,9 +2479,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t, struct sadb_msg *msg, *out; struct sadb_x_policy *pol; policy_entry_t *policy, *found = NULL; - policy_sa_t *mapping; + policy_sa_t *mapping, *to_remove = NULL; enumerator_t *enumerator; - bool is_installed = TRUE; + bool first = TRUE, is_installed = TRUE; u_int32_t priority; size_t len; @@ -2511,19 +2511,26 @@ METHOD(kernel_ipsec_t, del_policy, status_t, policy_entry_destroy(policy, this); policy = found; - /* remove mapping to SA by reqid and priority */ + /* remove mapping to SA by reqid and priority, if multiple match, which + * could happen when rekeying due to an address change, remove the oldest */ priority = get_priority(policy, prio); enumerator = policy->used_by->create_enumerator(policy->used_by); while (enumerator->enumerate(enumerator, (void**)&mapping)) { if (reqid == mapping->sa->cfg.reqid && priority == mapping->priority) { - policy->used_by->remove_at(policy->used_by, enumerator); + to_remove = mapping; + is_installed = first; + } + else if (priority < mapping->priority) + { break; } - is_installed = FALSE; + first = FALSE; } enumerator->destroy(enumerator); + policy->used_by->remove(policy->used_by, to_remove, NULL); + mapping = to_remove; if (policy->used_by->get_count(policy->used_by) > 0) { /* policy is used by more SAs, keep in kernel */ -- cgit v1.2.3