diff options
author | Tobias Brunner <tobias@strongswan.org> | 2013-07-10 11:08:01 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2013-07-17 17:45:17 +0200 |
commit | bbd9df25a9410fcde8cb594e5c789cad5506d5ed (patch) | |
tree | a2a715f22022775dba69684d3a98425f8e76f941 /src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | |
parent | a9f14ada34554bc42b819f8196899a002bade27b (diff) | |
download | strongswan-bbd9df25a9410fcde8cb594e5c789cad5506d5ed.tar.bz2 strongswan-bbd9df25a9410fcde8cb594e5c789cad5506d5ed.tar.xz |
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.
Diffstat (limited to 'src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c')
-rw-r--r-- | src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 17 |
1 files changed, 12 insertions, 5 deletions
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 */ |