diff --git a/src/libcharon/kernel/kernel_interface.c b/src/libcharon/kernel/kernel_interface.c index ba5c03b9bf..b752ad7444 100644 --- a/src/libcharon/kernel/kernel_interface.c +++ b/src/libcharon/kernel/kernel_interface.c @@ -392,12 +392,19 @@ METHOD(kernel_interface_t, alloc_reqid, status_t, /* search by reqid if given */ entry = this->reqids->get(this->reqids, tmpl); } - if (entry && entry_equals_selectors(entry, tmpl)) + + /* if the IPsec stack supports sequence numbers for acquires, we can + * allocate a new reqid if narrowing occurred (otherwise, we get the same + * reqid back anyway). if not, we want to reuse the existing reqid of + * the trap polices and explicitly don't want to match the traffic + * selectors. another case where we want to reuse an existing reqid is + * when labels are used. because we currently only install policies once + * with the generic label, the reqid has to stay the same even if narrowing + * occurs. however, in either case we don't want to reuse the reqid if the + * additional selectors (e.g. marks) are different */ + if (entry && (label || !(get_features(this) & KERNEL_ACQUIRE_SEQ)) && + entry_equals_selectors(entry, tmpl)) { - /* we don't require a traffic selector match for existing reqids, - * as we want to reuse a reqid for trap-triggered policies that - * got narrowed during negotiation, but we don't want to reuse the - * reqid if the additional selectors (e.g. marks) are different */ reqid_entry_destroy(tmpl); } else diff --git a/src/libcharon/kernel/kernel_interface.h b/src/libcharon/kernel/kernel_interface.h index a70e7f8606..21cabe7f09 100644 --- a/src/libcharon/kernel/kernel_interface.h +++ b/src/libcharon/kernel/kernel_interface.h @@ -81,6 +81,8 @@ enum kernel_feature_t { KERNEL_POLICY_SPI = (1<<4), /** IPsec backend reports use time per SA via query_sa() */ KERNEL_SA_USE_TIME = (1<<5), + /** IPsec backend associates acquires and SAs with a sequence number */ + KERNEL_ACQUIRE_SEQ = (1<<6), }; /** diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 3c4f721cae..abb98a2f4e 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -2163,13 +2163,14 @@ child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config, if (!this->reqid) { /* reuse old reqid if we are rekeying an existing CHILD_SA and when - * initiating a trap policy. While the reqid cache would find the same - * reqid for our selectors, this does not work in a special case: If an - * SA is triggered by a trap policy, but the negotiated TS get - * narrowed, we still must reuse the same reqid to successfully - * replace the temporary SA on the kernel level. Rekeying such an SA - * requires an explicit reqid, as the cache currently knows the original - * selectors only for that reqid. */ + * initiating a trap policy. the reqid cache will generally find the + * same reqid for our selectors. but this does not work in a special + * case: if the IPsec stack does not use sequence numbers for acquires, + * an SA is triggered by a trap policy and the negotiated TS get + * narrowed, we still must reuse the same reqid to successfully replace + * the temporary SA on the kernel level. however, if sequence numbers + * are supported, the reqid will later get updated in case of narrowing + * when alloc_reqid() is called */ if (data->reqid && charon->kernel->ref_reqid(charon->kernel, data->reqid) == SUCCESS) {