summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/ikev1/tasks
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2015-04-11 22:03:59 +0200
committerYves-Alexis Perez <corsac@debian.org>2015-04-11 22:03:59 +0200
commit83b8aebb19fe6e49e13a05d4e8f5ab9a06177642 (patch)
tree51255545ba43b84aa5d673bd0eb557cbd0155c9e /src/libcharon/sa/ikev1/tasks
parent2b8de74ff4c334c25e89988c4a401b24b5bcf03d (diff)
downloadvyos-strongswan-83b8aebb19fe6e49e13a05d4e8f5ab9a06177642.tar.gz
vyos-strongswan-83b8aebb19fe6e49e13a05d4e8f5ab9a06177642.zip
Imported Upstream version 5.3.0
Diffstat (limited to 'src/libcharon/sa/ikev1/tasks')
-rw-r--r--src/libcharon/sa/ikev1/tasks/isakmp_delete.c39
-rw-r--r--src/libcharon/sa/ikev1/tasks/main_mode.c39
-rw-r--r--src/libcharon/sa/ikev1/tasks/mode_config.c137
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_delete.c6
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c76
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.h8
6 files changed, 243 insertions, 62 deletions
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_delete.c b/src/libcharon/sa/ikev1/tasks/isakmp_delete.c
index bea0428c4..a56805afb 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_delete.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_delete.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2011 Martin Willi
* Copyright (C) 2011 revosec AG
*
@@ -74,6 +77,42 @@ METHOD(task_t, process_i, status_t,
METHOD(task_t, process_r, status_t,
private_isakmp_delete_t *this, message_t *message)
{
+ enumerator_t *payloads;
+ payload_t *payload;
+ delete_payload_t *delete_payload;
+ ike_sa_id_t *id;
+ u_int64_t spi_i, spi_r;
+ bool found = FALSE;
+
+ /* some peers send DELETE payloads for other IKE_SAs, e.g. those for expired
+ * ones after a rekeyeing, make sure the SPIs match */
+ id = this->ike_sa->get_id(this->ike_sa);
+ payloads = message->create_payload_enumerator(message);
+ while (payloads->enumerate(payloads, &payload))
+ {
+ if (payload->get_type(payload) == PLV1_DELETE)
+ {
+ delete_payload = (delete_payload_t*)payload;
+ if (!delete_payload->get_ike_spi(delete_payload, &spi_i, &spi_r))
+ {
+ continue;
+ }
+ if (id->get_initiator_spi(id) == spi_i &&
+ id->get_responder_spi(id) == spi_r)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ payloads->destroy(payloads);
+
+ if (!found)
+ {
+ DBG1(DBG_IKE, "received DELETE for different IKE_SA, ignored");
+ return SUCCESS;
+ }
+
DBG1(DBG_IKE, "received DELETE for IKE_SA %s[%d]",
this->ike_sa->get_name(this->ike_sa),
this->ike_sa->get_unique_id(this->ike_sa));
diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c
index 2fb4c6935..3ea4a2a85 100644
--- a/src/libcharon/sa/ikev1/tasks/main_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/main_mode.c
@@ -205,6 +205,43 @@ static status_t send_delete(private_main_mode_t *this)
return ALREADY_DONE;
}
+/**
+ * Add an INITIAL_CONTACT notify if first contact with peer
+ */
+static void add_initial_contact(private_main_mode_t *this, message_t *message,
+ identification_t *idi)
+{
+ identification_t *idr;
+ host_t *host;
+ notify_payload_t *notify;
+ ike_sa_id_t *ike_sa_id;
+ u_int64_t spi_i, spi_r;
+ chunk_t spi;
+
+ idr = this->ph1->get_id(this->ph1, this->peer_cfg, FALSE);
+ if (idr && !idr->contains_wildcards(idr))
+ {
+ if (this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NO &&
+ this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NEVER)
+ {
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ if (!charon->ike_sa_manager->has_contact(charon->ike_sa_manager,
+ idi, idr, host->get_family(host)))
+ {
+ notify = notify_payload_create_from_protocol_and_type(
+ PLV1_NOTIFY, PROTO_IKE, INITIAL_CONTACT_IKEV1);
+ ike_sa_id = this->ike_sa->get_id(this->ike_sa);
+ spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
+ spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
+ spi = chunk_cata("cc", chunk_from_thing(spi_i),
+ chunk_from_thing(spi_r));
+ notify->set_spi_data(notify, spi);
+ message->add_payload(message, (payload_t*)notify);
+ }
+ }
+ }
+}
+
METHOD(task_t, build_i, status_t,
private_main_mode_t *this, message_t *message)
{
@@ -311,6 +348,8 @@ METHOD(task_t, build_i, status_t,
return send_notify(this, AUTHENTICATION_FAILED);
}
+ add_initial_contact(this, message, id);
+
this->state = MM_AUTH;
return NEED_MORE;
}
diff --git a/src/libcharon/sa/ikev1/tasks/mode_config.c b/src/libcharon/sa/ikev1/tasks/mode_config.c
index 94026b9af..d0994a961 100644
--- a/src/libcharon/sa/ikev1/tasks/mode_config.c
+++ b/src/libcharon/sa/ikev1/tasks/mode_config.c
@@ -16,7 +16,6 @@
#include "mode_config.h"
#include <daemon.h>
-#include <hydra.h>
#include <encoding/payloads/cp_payload.h>
typedef struct private_mode_config_t private_mode_config_t;
@@ -136,9 +135,8 @@ static void handle_attribute(private_mode_config_t *this,
enumerator->destroy(enumerator);
/* and pass it to the handle function */
- handler = hydra->attributes->handle(hydra->attributes,
- this->ike_sa->get_other_id(this->ike_sa), handler,
- ca->get_type(ca), ca->get_chunk(ca));
+ handler = charon->attributes->handle(charon->attributes,
+ this->ike_sa, handler, ca->get_type(ca), ca->get_chunk(ca));
this->ike_sa->add_configuration_attribute(this->ike_sa,
handler, ca->get_type(ca), ca->get_chunk(ca));
}
@@ -326,9 +324,8 @@ static status_t build_request(private_mode_config_t *this, message_t *message)
enumerator->destroy(enumerator);
}
- enumerator = hydra->attributes->create_initiator_enumerator(
- hydra->attributes,
- this->ike_sa->get_other_id(this->ike_sa), vips);
+ enumerator = charon->attributes->create_initiator_enumerator(
+ charon->attributes, this->ike_sa, vips);
while (enumerator->enumerate(enumerator, &handler, &type, &data))
{
add_attribute(this, cp, type, data, handler);
@@ -353,7 +350,7 @@ static status_t build_set(private_mode_config_t *this, message_t *message)
cp_payload_t *cp;
peer_cfg_t *config;
identification_t *id;
- linked_list_t *pools;
+ linked_list_t *pools, *migrated, *vips;
host_t *any4, *any6, *found;
char *name;
@@ -361,45 +358,62 @@ static status_t build_set(private_mode_config_t *this, message_t *message)
id = this->ike_sa->get_other_eap_id(this->ike_sa);
config = this->ike_sa->get_peer_cfg(this->ike_sa);
- any4 = host_create_any(AF_INET);
- any6 = host_create_any(AF_INET6);
+ /* if we migrated virtual IPs during reauthentication, reassign them */
+ migrated = linked_list_create_from_enumerator(
+ this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
+ FALSE));
+ vips = migrated->clone_offset(migrated, offsetof(host_t, clone));
+ migrated->destroy(migrated);
this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
/* in push mode, we ask each configured pool for an address */
- enumerator = config->create_pool_enumerator(config);
- while (enumerator->enumerate(enumerator, &name))
+ if (!vips->get_count(vips))
{
- pools = linked_list_create_with_items(name, NULL);
- /* try IPv4, then IPv6 */
- found = hydra->attributes->acquire_address(hydra->attributes,
- pools, id, any4);
- if (!found)
- {
- found = hydra->attributes->acquire_address(hydra->attributes,
- pools, id, any6);
- }
- pools->destroy(pools);
- if (found)
+ any4 = host_create_any(AF_INET);
+ any6 = host_create_any(AF_INET6);
+ enumerator = config->create_pool_enumerator(config);
+ while (enumerator->enumerate(enumerator, &name))
{
- DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
- this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
- cp->add_attribute(cp, build_vip(found));
- this->vips->insert_last(this->vips, found);
+ pools = linked_list_create_with_items(name, NULL);
+ /* try IPv4, then IPv6 */
+ found = charon->attributes->acquire_address(charon->attributes,
+ pools, this->ike_sa, any4);
+ if (!found)
+ {
+ found = charon->attributes->acquire_address(charon->attributes,
+ pools, this->ike_sa, any6);
+ }
+ pools->destroy(pools);
+ if (found)
+ {
+ vips->insert_last(vips, found);
+ }
}
+ enumerator->destroy(enumerator);
+ any4->destroy(any4);
+ any6->destroy(any6);
}
- enumerator->destroy(enumerator);
- any4->destroy(any4);
- any6->destroy(any6);
+ enumerator = vips->create_enumerator(vips);
+ while (enumerator->enumerate(enumerator, &found))
+ {
+ DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
+ this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
+ cp->add_attribute(cp, build_vip(found));
+ this->vips->insert_last(this->vips, found);
+ vips->remove_at(vips, enumerator);
+ }
+ enumerator->destroy(enumerator);
+ vips->destroy(vips);
charon->bus->assign_vips(charon->bus, this->ike_sa, TRUE);
/* query registered providers for additional attributes to include */
pools = linked_list_create_from_enumerator(
config->create_pool_enumerator(config));
- enumerator = hydra->attributes->create_responder_enumerator(
- hydra->attributes, pools, id, this->vips);
+ enumerator = charon->attributes->create_responder_enumerator(
+ charon->attributes, pools, this->ike_sa, this->vips);
while (enumerator->enumerate(enumerator, &type, &value))
{
add_attribute(this, cp, type, value, NULL);
@@ -458,6 +472,28 @@ METHOD(task_t, process_r, status_t,
}
/**
+ * Assign a migrated virtual IP
+ */
+static host_t *assign_migrated_vip(linked_list_t *migrated, host_t *requested)
+{
+ enumerator_t *enumerator;
+ host_t *found = NULL, *vip;
+
+ enumerator = migrated->create_enumerator(migrated);
+ while (enumerator->enumerate(enumerator, &vip))
+ {
+ if (vip->ip_equals(vip, requested))
+ {
+ migrated->remove_at(migrated, enumerator);
+ found = vip;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+/**
* Build CFG_REPLY message after receiving CFG_REQUEST
*/
static status_t build_reply(private_mode_config_t *this, message_t *message)
@@ -468,29 +504,35 @@ static status_t build_reply(private_mode_config_t *this, message_t *message)
cp_payload_t *cp;
peer_cfg_t *config;
identification_t *id;
- linked_list_t *vips, *pools;
- host_t *requested;
+ linked_list_t *vips, *pools, *migrated;
+ host_t *requested, *found;
cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY);
id = this->ike_sa->get_other_eap_id(this->ike_sa);
config = this->ike_sa->get_peer_cfg(this->ike_sa);
- vips = linked_list_create();
pools = linked_list_create_from_enumerator(
config->create_pool_enumerator(config));
-
+ /* if we migrated virtual IPs during reauthentication, reassign them */
+ vips = linked_list_create_from_enumerator(
+ this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
+ FALSE));
+ migrated = vips->clone_offset(vips, offsetof(host_t, clone));
+ vips->destroy(vips);
this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
+ vips = linked_list_create();
enumerator = this->vips->create_enumerator(this->vips);
while (enumerator->enumerate(enumerator, &requested))
{
- host_t *found = NULL;
-
- /* query all pools until we get an address */
DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
- found = hydra->attributes->acquire_address(hydra->attributes,
- pools, id, requested);
+ found = assign_migrated_vip(migrated, requested);
+ if (!found)
+ {
+ found = charon->attributes->acquire_address(charon->attributes,
+ pools, this->ike_sa, requested);
+ }
if (found)
{
DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
@@ -509,8 +551,8 @@ static status_t build_reply(private_mode_config_t *this, message_t *message)
charon->bus->assign_vips(charon->bus, this->ike_sa, TRUE);
/* query registered providers for additional attributes to include */
- enumerator = hydra->attributes->create_responder_enumerator(
- hydra->attributes, pools, id, vips);
+ enumerator = charon->attributes->create_responder_enumerator(
+ charon->attributes, pools, this->ike_sa, vips);
while (enumerator->enumerate(enumerator, &type, &value))
{
cp->add_attribute(cp,
@@ -518,6 +560,15 @@ static status_t build_reply(private_mode_config_t *this, message_t *message)
type, value));
}
enumerator->destroy(enumerator);
+ /* if a client did not re-request all adresses, release them */
+ enumerator = migrated->create_enumerator(migrated);
+ while (enumerator->enumerate(enumerator, &found))
+ {
+ charon->attributes->release_address(charon->attributes,
+ pools, found, this->ike_sa);
+ }
+ enumerator->destroy(enumerator);
+ migrated->destroy_offset(migrated, offsetof(host_t, destroy));
vips->destroy_offset(vips, offsetof(host_t, destroy));
pools->destroy(pools);
diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c
index 499081caa..1b95a8b11 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_delete.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c
@@ -105,7 +105,7 @@ static bool delete_child(private_quick_delete_t *this, protocol_id_t protocol,
this->spi = spi = child_sa->get_spi(child_sa, TRUE);
}
- rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYING;
+ rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYED;
child_sa->set_state(child_sa, CHILD_DELETING);
my_ts = linked_list_create_from_enumerator(
@@ -116,7 +116,7 @@ static bool delete_child(private_quick_delete_t *this, protocol_id_t protocol,
{
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
- child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+ child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)),
ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
}
@@ -127,7 +127,7 @@ static bool delete_child(private_quick_delete_t *this, protocol_id_t protocol,
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs "
"%.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
- child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+ child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
my_ts, other_ts);
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 1133aab65..96edfd8d8 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -156,6 +156,16 @@ struct private_quick_mode_t {
u_int32_t reqid;
/**
+ * Explicit inbound mark value to use, if any
+ */
+ u_int mark_in;
+
+ /**
+ * Explicit inbound mark value to use, if any
+ */
+ u_int mark_out;
+
+ /**
* SPI of SA we rekey
*/
u_int32_t rekey;
@@ -196,8 +206,8 @@ static void schedule_inactivity_timeout(private_quick_mode_t *this)
close_ike = lib->settings->get_bool(lib->settings,
"%s.inactivity_close_ike", FALSE, lib->ns);
lib->scheduler->schedule_job(lib->scheduler, (job_t*)
- inactivity_job_create(this->child_sa->get_reqid(this->child_sa),
- timeout, close_ike), timeout);
+ inactivity_job_create(this->child_sa->get_unique_id(this->child_sa),
+ timeout, close_ike), timeout);
}
}
@@ -375,7 +385,7 @@ static bool install(private_quick_mode_t *this)
DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
this->child_sa->get_name(this->child_sa),
- this->child_sa->get_reqid(this->child_sa),
+ this->child_sa->get_unique_id(this->child_sa),
ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
@@ -391,15 +401,14 @@ static bool install(private_quick_mode_t *this)
if (old)
{
charon->bus->child_rekey(charon->bus, old, this->child_sa);
+ /* rekeyed CHILD_SAs stay installed until they expire */
+ old->set_state(old, CHILD_REKEYED);
}
else
{
charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
}
- if (!this->rekey)
- {
- schedule_inactivity_timeout(this);
- }
+ schedule_inactivity_timeout(this);
this->child_sa = NULL;
return TRUE;
}
@@ -456,12 +465,19 @@ static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce,
/**
* Add KE payload to message
*/
-static void add_ke(private_quick_mode_t *this, message_t *message)
+static bool add_ke(private_quick_mode_t *this, message_t *message)
{
ke_payload_t *ke_payload;
- ke_payload = ke_payload_create_from_diffie_hellman(PLV1_KEY_EXCHANGE, this->dh);
+ ke_payload = ke_payload_create_from_diffie_hellman(PLV1_KEY_EXCHANGE,
+ this->dh);
+ if (!ke_payload)
+ {
+ DBG1(DBG_IKE, "creating KE payload failed");
+ return FALSE;
+ }
message->add_payload(message, &ke_payload->payload_interface);
+ return TRUE;
}
/**
@@ -477,8 +493,12 @@ static bool get_ke(private_quick_mode_t *this, message_t *message)
DBG1(DBG_IKE, "KE payload missing");
return FALSE;
}
- this->dh->set_other_public_value(this->dh,
- ke_payload->get_key_exchange_data(ke_payload));
+ if (!this->dh->set_other_public_value(this->dh,
+ ke_payload->get_key_exchange_data(ke_payload)))
+ {
+ DBG1(DBG_IKE, "unable to apply received KE value");
+ return FALSE;
+ }
return TRUE;
}
@@ -788,7 +808,8 @@ METHOD(task_t, build_i, status_t,
this->child_sa = child_sa_create(
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
- this->config, this->reqid, this->udp);
+ this->config, this->reqid, this->udp,
+ this->mark_in, this->mark_out);
if (this->udp && this->mode == MODE_TRANSPORT)
{
@@ -870,7 +891,10 @@ METHOD(task_t, build_i, status_t,
}
if (group != MODP_NONE)
{
- add_ke(this, message);
+ if (!add_ke(this, message))
+ {
+ return FAILED;
+ }
}
if (!this->tsi)
{
@@ -964,6 +988,7 @@ static void check_for_rekeyed_child(private_quick_mode_t *this)
{
case CHILD_INSTALLED:
case CHILD_REKEYING:
+ case CHILD_REKEYED:
policies = child_sa->create_policy_enumerator(child_sa);
if (policies->enumerate(policies, &local, &remote) &&
local->equals(local, this->tsr) &&
@@ -972,9 +997,14 @@ static void check_for_rekeyed_child(private_quick_mode_t *this)
{
this->reqid = child_sa->get_reqid(child_sa);
this->rekey = child_sa->get_spi(child_sa, TRUE);
+ this->mark_in = child_sa->get_mark(child_sa,
+ TRUE).value;
+ this->mark_out = child_sa->get_mark(child_sa,
+ FALSE).value;
child_sa->set_state(child_sa, CHILD_REKEYING);
DBG1(DBG_IKE, "detected rekeying of CHILD_SA %s{%u}",
- child_sa->get_name(child_sa), this->reqid);
+ child_sa->get_name(child_sa),
+ child_sa->get_unique_id(child_sa));
}
policies->destroy(policies);
break;
@@ -1097,7 +1127,8 @@ METHOD(task_t, process_r, status_t,
this->child_sa = child_sa_create(
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
- this->config, this->reqid, this->udp);
+ this->config, this->reqid, this->udp,
+ this->mark_in, this->mark_out);
tsi = linked_list_create_with_items(this->tsi, NULL);
tsr = linked_list_create_with_items(this->tsr, NULL);
@@ -1202,7 +1233,10 @@ METHOD(task_t, build_r, status_t,
}
if (this->dh)
{
- add_ke(this, message);
+ if (!add_ke(this, message))
+ {
+ return FAILED;
+ }
}
add_ts(this, message);
@@ -1307,6 +1341,13 @@ METHOD(quick_mode_t, use_reqid, void,
this->reqid = reqid;
}
+METHOD(quick_mode_t, use_marks, void,
+ private_quick_mode_t *this, u_int in, u_int out)
+{
+ this->mark_in = in;
+ this->mark_out = out;
+}
+
METHOD(quick_mode_t, rekey, void,
private_quick_mode_t *this, u_int32_t spi)
{
@@ -1334,6 +1375,8 @@ METHOD(task_t, migrate, void,
this->dh = NULL;
this->spi_i = 0;
this->spi_r = 0;
+ this->mark_in = 0;
+ this->mark_out = 0;
if (!this->initiator)
{
@@ -1372,6 +1415,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
.destroy = _destroy,
},
.use_reqid = _use_reqid,
+ .use_marks = _use_marks,
.rekey = _rekey,
},
.ike_sa = ike_sa,
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.h b/src/libcharon/sa/ikev1/tasks/quick_mode.h
index 0b80cb836..ee9b64d13 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.h
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.h
@@ -45,6 +45,14 @@ struct quick_mode_t {
void (*use_reqid)(quick_mode_t *this, u_int32_t reqid);
/**
+ * Use specific mark values, overriding configuration.
+ *
+ * @param in inbound mark value
+ * @param out outbound mark value
+ */
+ void (*use_marks)(quick_mode_t *this, u_int in, u_int out);
+
+ /**
* Set the SPI of the old SA, if rekeying.
*
* @param spi spi of SA to rekey