]> git.ipfire.org Git - thirdparty/strongswan.git/blobdiff - src/libcharon/sa/ikev1/tasks/quick_mode.c
ike: Optionally allow private algorithms for IKE/CHILD_SAs
[thirdparty/strongswan.git] / src / libcharon / sa / ikev1 / tasks / quick_mode.c
index da41a3f8c95df6b74054e8a3bffca1d4550d60cb..f494e48c83ddb175b4e65141d4868abef1286285 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2012-2015 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2012-2019 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2011 Martin Willi
  * Copyright (C) 2011 revosec AG
@@ -146,24 +146,14 @@ struct private_quick_mode_t {
        uint32_t lifetime;
 
        /**
-        * Negotaited lifebytes of new SA
+        * Negotiated lifebytes of new SA
         */
        uint64_t lifebytes;
 
        /**
-        * Reqid to use, 0 for auto-allocate
+        * Data collected to create the CHILD_SA
         */
-       uint32_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;
+       child_sa_create_t child;
 
        /**
         * SPI of SA we rekey
@@ -185,11 +175,6 @@ struct private_quick_mode_t {
         */
        protocol_id_t proto;
 
-       /**
-        * Use UDP encapsulation
-        */
-       bool udp;
-
        /**
         * Message ID of handled quick mode exchange
         */
@@ -325,6 +310,17 @@ static bool install(private_quick_mode_t *this)
                return FALSE;
        }
 
+       if (this->initiator)
+       {
+               this->child_sa->set_policies(this->child_sa, tsi, tsr);
+       }
+       else
+       {
+               this->child_sa->set_policies(this->child_sa, tsr, tsi);
+       }
+       tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+       tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+
        if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh,
                                                this->spi_i, this->spi_r, this->nonce_i, this->nonce_r,
                                                &encr_i, &integ_i, &encr_r, &integ_r))
@@ -333,25 +329,21 @@ static bool install(private_quick_mode_t *this)
                {
                        status_i = this->child_sa->install(this->child_sa,
                                                                        encr_r, integ_r, this->spi_i, this->cpi_i,
-                                                                       this->initiator, TRUE, FALSE, tsi, tsr);
+                                                                       this->initiator, TRUE, FALSE);
                        status_o = this->child_sa->install(this->child_sa,
                                                                        encr_i, integ_i, this->spi_r, this->cpi_r,
-                                                                       this->initiator, FALSE, FALSE, tsi, tsr);
+                                                                       this->initiator, FALSE, FALSE);
                }
                else
                {
                        status_i = this->child_sa->install(this->child_sa,
                                                                        encr_i, integ_i, this->spi_r, this->cpi_r,
-                                                                       this->initiator, TRUE, FALSE, tsr, tsi);
+                                                                       this->initiator, TRUE, FALSE);
                        status_o = this->child_sa->install(this->child_sa,
                                                                        encr_r, integ_r, this->spi_i, this->cpi_i,
-                                                                       this->initiator, FALSE, FALSE, tsr, tsi);
+                                                                       this->initiator, FALSE, FALSE);
                }
        }
-       chunk_clear(&integ_i);
-       chunk_clear(&integ_r);
-       chunk_clear(&encr_i);
-       chunk_clear(&encr_r);
 
        if (status_i != SUCCESS || status_o != SUCCESS)
        {
@@ -359,34 +351,36 @@ static bool install(private_quick_mode_t *this)
                        (status_i != SUCCESS) ? "inbound " : "",
                        (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
                        (status_o != SUCCESS) ? "outbound " : "");
-               tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
-               tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
-               return FALSE;
-       }
-
-       if (this->initiator)
-       {
-               status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
+               status = FAILED;
        }
        else
        {
-               status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
+               status = this->child_sa->install_policies(this->child_sa);
+
+               if (status != SUCCESS)
+               {
+                       DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
+               }
+               else
+               {
+                       charon->bus->child_derived_keys(charon->bus, this->child_sa,
+                                                                                       this->initiator, encr_i, encr_r,
+                                                                                       integ_i, integ_r);
+               }
        }
-       tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
-       tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+       chunk_clear(&integ_i);
+       chunk_clear(&integ_r);
+       chunk_clear(&encr_i);
+       chunk_clear(&encr_r);
+
        if (status != SUCCESS)
        {
-               DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
                return FALSE;
        }
 
        charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
                                                        this->dh, this->nonce_i, this->nonce_r);
 
-       /* add to IKE_SA, and remove from task */
-       this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
-       this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
-
        my_ts = linked_list_create_from_enumerator(
                                this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
        other_ts = linked_list_create_from_enumerator(
@@ -402,6 +396,9 @@ static bool install(private_quick_mode_t *this)
        my_ts->destroy(my_ts);
        other_ts->destroy(other_ts);
 
+       this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
+       this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+
        if (this->rekey)
        {
                old = this->ike_sa->get_child_sa(this->ike_sa,
@@ -532,7 +529,7 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
 
        hosts = get_dynamic_hosts(this->ike_sa, local);
        list = this->config->get_traffic_selectors(this->config,
-                                                                                          local, supplied, hosts);
+                                                                                          local, supplied, hosts, TRUE);
        hosts->destroy(hosts);
        if (list->get_first(list, (void**)&ts) == SUCCESS)
        {
@@ -615,7 +612,7 @@ static bool get_ts(private_quick_mode_t *this, message_t *message)
                tsr = traffic_selector_create_from_subnet(hsr->clone(hsr),
                                        hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0, 65535);
        }
-       if (this->mode == MODE_TRANSPORT && this->udp &&
+       if (this->mode == MODE_TRANSPORT && this->child.encap &&
           (!tsi->is_host(tsi, hsi) || !tsr->is_host(tsr, hsr)))
        {       /* change TS in case of a NAT in transport mode */
                DBG2(DBG_IKE, "changing received traffic selectors %R=== %R due to NAT",
@@ -691,25 +688,30 @@ static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message)
 {
        identification_t *id;
        id_payload_t *nat_oa;
-       host_t *src, *dst;
+       host_t *init, *resp;
        payload_type_t nat_oa_payload_type;
 
-       src = message->get_source(message);
-       dst = message->get_destination(message);
-
-       src = this->initiator ? src : dst;
-       dst = this->initiator ? dst : src;
+       if (this->initiator)
+       {
+               init = message->get_source(message);
+               resp = message->get_destination(message);
+       }
+       else
+       {
+               init = message->get_destination(message);
+               resp = message->get_source(message);
+       }
 
        nat_oa_payload_type = get_nat_oa_payload_type(this->ike_sa);
 
        /* first NAT-OA is the initiator's address */
-       id = identification_create_from_sockaddr(src->get_sockaddr(src));
+       id = identification_create_from_sockaddr(init->get_sockaddr(init));
        nat_oa = id_payload_create_from_identification(nat_oa_payload_type, id);
        message->add_payload(message, (payload_t*)nat_oa);
        id->destroy(id);
 
        /* second NAT-OA is that of the responder */
-       id = identification_create_from_sockaddr(dst->get_sockaddr(dst));
+       id = identification_create_from_sockaddr(resp->get_sockaddr(resp));
        nat_oa = id_payload_create_from_identification(nat_oa_payload_type, id);
        message->add_payload(message, (payload_t*)nat_oa);
        id->destroy(id);
@@ -727,7 +729,7 @@ static void get_lifetimes(private_quick_mode_t *this)
        {
                this->lifetime = lft->time.life;
        }
-       else if (lft->bytes.life)
+       if (lft->bytes.life)
        {
                this->lifebytes = lft->bytes.life;
        }
@@ -742,8 +744,8 @@ static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload
        uint32_t lifetime;
        uint64_t lifebytes;
 
-       lifetime = sa_payload->get_lifetime(sa_payload);
-       lifebytes = sa_payload->get_lifebytes(sa_payload);
+       lifetime = sa_payload->get_lifetime(sa_payload, this->proposal);
+       lifebytes = sa_payload->get_lifebytes(sa_payload, this->proposal);
        if (this->lifetime != lifetime)
        {
                DBG1(DBG_IKE, "received %us lifetime, configured %us",
@@ -800,7 +802,7 @@ static linked_list_t *get_proposals(private_quick_mode_t *this,
                                proposal->destroy(proposal);
                                continue;
                        }
-                       proposal->strip_dh(proposal, group);
+                       proposal->promote_dh_group(proposal, group);
                }
                proposal->set_spi(proposal, this->spi_i);
        }
@@ -822,21 +824,25 @@ METHOD(task_t, build_i, status_t,
                        diffie_hellman_group_t group;
                        encap_t encap;
 
-                       this->udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
                        this->mode = this->config->get_mode(this->config);
+                       this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa,
+                                                                                                                          TRUE);
+                       this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa,
+                                                                                                                               FALSE);
+                       this->child.encap = this->ike_sa->has_condition(this->ike_sa,
+                                                                                                                       COND_NAT_ANY);
                        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->mark_in, this->mark_out);
+                                                                       this->config, &this->child);
 
-                       if (this->udp && this->mode == MODE_TRANSPORT)
+                       if (this->child.encap && this->mode == MODE_TRANSPORT)
                        {
                                /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
                                add_nat_oa_payloads(this, message);
                        }
 
-                       if (this->config->use_ipcomp(this->config))
+                       if (this->config->has_option(this->config, OPT_IPCOMP))
                        {
                                this->cpi_i = this->child_sa->alloc_cpi(this->child_sa);
                                if (!this->cpi_i)
@@ -846,7 +852,7 @@ METHOD(task_t, build_i, status_t,
                                }
                        }
 
-                       list = this->config->get_proposals(this->config, MODP_NONE);
+                       list = this->config->get_proposals(this->config, FALSE);
                        if (list->get_first(list, (void**)&proposal) == SUCCESS)
                        {
                                this->proto = proposal->get_protocol(proposal);
@@ -897,7 +903,7 @@ METHOD(task_t, build_i, status_t,
                        }
 
                        get_lifetimes(this);
-                       encap = get_encap(this->ike_sa, this->udp);
+                       encap = get_encap(this->ike_sa, this->child.encap);
                        sa_payload = sa_payload_create_from_proposals_v1(list,
                                                                this->lifetime, this->lifebytes, AUTH_NONE,
                                                                this->mode, encap, this->cpi_i);
@@ -988,17 +994,28 @@ static bool has_notify_errors(private_quick_mode_t *this, message_t *message)
 /**
  * Check if this is a rekey for an existing CHILD_SA, reuse reqid if so
  */
-static void check_for_rekeyed_child(private_quick_mode_t *this)
+static void check_for_rekeyed_child(private_quick_mode_t *this, bool responder)
 {
        enumerator_t *enumerator, *policies;
-       traffic_selector_t *local, *remote;
+       traffic_selector_t *local, *remote, *my_ts, *other_ts;
        child_sa_t *child_sa;
        proposal_t *proposal;
        char *name;
 
+       if (responder)
+       {
+               my_ts = this->tsr;
+               other_ts = this->tsi;
+       }
+       else
+       {
+               my_ts = this->tsi;
+               other_ts = this->tsr;
+       }
+
        name = this->config->get_name(this->config);
        enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
-       while (this->reqid == 0 && enumerator->enumerate(enumerator, &child_sa))
+       while (!this->child.reqid && enumerator->enumerate(enumerator, &child_sa))
        {
                if (streq(child_sa->get_name(child_sa), name))
                {
@@ -1009,16 +1026,20 @@ static void check_for_rekeyed_child(private_quick_mode_t *this)
                                case CHILD_REKEYING:
                                        policies = child_sa->create_policy_enumerator(child_sa);
                                        if (policies->enumerate(policies, &local, &remote) &&
-                                               local->equals(local, this->tsr) &&
-                                               remote->equals(remote, this->tsi) &&
+                                               local->equals(local, my_ts) &&
+                                               remote->equals(remote, other_ts) &&
                                                this->proposal->equals(this->proposal, proposal))
                                        {
-                                               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;
+                                               this->child.reqid = child_sa->get_reqid(child_sa);
+                                               this->child.mark_in = child_sa->get_mark(child_sa,
+                                                                                                                                TRUE).value;
+                                               this->child.mark_out = child_sa->get_mark(child_sa,
+                                                                                                                                 FALSE).value;
+                                               this->child.if_id_in = child_sa->get_if_id(child_sa,
+                                                                                                                                  TRUE);
+                                               this->child.if_id_out = child_sa->get_if_id(child_sa,
+                                                                                                                                       FALSE);
                                                child_sa->set_state(child_sa, CHILD_REKEYING);
                                                DBG1(DBG_IKE, "detected rekeying of CHILD_SA %s{%u}",
                                                         child_sa->get_name(child_sa),
@@ -1051,7 +1072,7 @@ METHOD(task_t, process_r, status_t,
                        linked_list_t *tsi, *tsr, *hostsi, *hostsr, *list = NULL;
                        peer_cfg_t *peer_cfg;
                        uint16_t group;
-                       bool private;
+                       proposal_selection_flag_t flags = 0;
 
                        sa_payload = (sa_payload_t*)message->get_payload(message,
                                                                                                        PLV1_SECURITY_ASSOCIATION);
@@ -1061,7 +1082,8 @@ METHOD(task_t, process_r, status_t,
                                return send_notify(this, INVALID_PAYLOAD_TYPE);
                        }
 
-                       this->mode = sa_payload->get_encap_mode(sa_payload, &this->udp);
+                       this->mode = sa_payload->get_encap_mode(sa_payload,
+                                                                                                       &this->child.encap);
 
                        if (!get_ts(this, message))
                        {
@@ -1082,16 +1104,19 @@ METHOD(task_t, process_r, status_t,
                                this->tsi = select_ts(this, FALSE, tsi);
                                this->tsr = select_ts(this, TRUE, tsr);
                        }
-                       tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
-                       tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
                        if (!this->config || !this->tsi || !this->tsr ||
                                this->mode != this->config->get_mode(this->config))
                        {
-                               DBG1(DBG_IKE, "no matching CHILD_SA config found");
+                               DBG1(DBG_IKE, "no matching CHILD_SA config found for "
+                                        "%#R === %#R", tsi, tsr);
+                               tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+                               tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
                                return send_notify(this, INVALID_ID_INFORMATION);
                        }
+                       tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+                       tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
 
-                       if (this->config->use_ipcomp(this->config))
+                       if (this->config->has_option(this->config, OPT_IPCOMP))
                        {
                                list = sa_payload->get_ipcomp_proposals(sa_payload,
                                                                                                                &this->cpi_i);
@@ -1107,10 +1132,19 @@ METHOD(task_t, process_r, status_t,
                                DESTROY_IF(list);
                                list = sa_payload->get_proposals(sa_payload);
                        }
-                       private = this->ike_sa->supports_extension(this->ike_sa,
-                                                                                                          EXT_STRONGSWAN);
-                       this->proposal = this->config->select_proposal(this->config,
-                                                                                                                  list, FALSE, private);
+                       if (!this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN)
+                               && !lib->settings->get_bool(lib->settings,
+                                                                       "%s.accept_private_algs", FALSE, lib->ns))
+                       {
+                               flags |= PROPOSAL_SKIP_PRIVATE;
+                       }
+                       if (!lib->settings->get_bool(lib->settings,
+                                                       "%s.prefer_configured_proposals", TRUE, lib->ns))
+                       {
+                               flags |= PROPOSAL_PREFER_SUPPLIED;
+                       }
+                       this->proposal = this->config->select_proposal(this->config, list,
+                                                                                                                  flags);
                        list->destroy_offset(list, offsetof(proposal_t, destroy));
 
                        get_lifetimes(this);
@@ -1146,13 +1180,15 @@ METHOD(task_t, process_r, status_t,
                                }
                        }
 
-                       check_for_rekeyed_child(this);
-
+                       check_for_rekeyed_child(this, TRUE);
+                       this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa,
+                                                                                                                          TRUE);
+                       this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa,
+                                                                                                                               FALSE);
                        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->mark_in, this->mark_out);
+                                                                       this->config, &this->child);
 
                        tsi = linked_list_create_with_items(this->tsi, NULL);
                        tsr = linked_list_create_with_items(this->tsr, NULL);
@@ -1189,6 +1225,21 @@ METHOD(task_t, process_r, status_t,
                                }
                                return SUCCESS;
                        }
+                       if (!this->rekey)
+                       {
+                               /* do another check in case SAs were created since we handled
+                                * the QM request, this is consistent with the rekey check
+                                * before installation on the initiator */
+                               check_for_rekeyed_child(this, TRUE);
+                               if (this->rekey)
+                               {
+                                       this->child_sa->destroy(this->child_sa);
+                                       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->child);
+                               }
+                       }
                        if (!install(this))
                        {
                                ike_sa_t *ike_sa = this->ike_sa;
@@ -1244,13 +1295,13 @@ METHOD(task_t, build_r, status_t,
                                }
                        }
 
-                       if (this->udp && this->mode == MODE_TRANSPORT)
+                       if (this->child.encap && this->mode == MODE_TRANSPORT)
                        {
                                /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
                                add_nat_oa_payloads(this, message);
                        }
 
-                       encap = get_encap(this->ike_sa, this->udp);
+                       encap = get_encap(this->ike_sa, this->child.encap);
                        sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
                                                                this->lifetime, this->lifebytes, AUTH_NONE,
                                                                this->mode, encap, this->cpi_r);
@@ -1296,7 +1347,7 @@ METHOD(task_t, process_i, status_t,
                {
                        sa_payload_t *sa_payload;
                        linked_list_t *list = NULL;
-                       bool private;
+                       proposal_selection_flag_t flags = 0;
 
                        sa_payload = (sa_payload_t*)message->get_payload(message,
                                                                                                        PLV1_SECURITY_ASSOCIATION);
@@ -1311,7 +1362,7 @@ METHOD(task_t, process_i, status_t,
                                                                                                                &this->cpi_r);
                                if (!list->get_count(list))
                                {
-                                       DBG1(DBG_IKE, "peer did not acccept our IPComp proposal, "
+                                       DBG1(DBG_IKE, "peer did not accept our IPComp proposal, "
                                                 "IPComp disabled");
                                        this->cpi_i = 0;
                                }
@@ -1321,10 +1372,14 @@ METHOD(task_t, process_i, status_t,
                                DESTROY_IF(list);
                                list = sa_payload->get_proposals(sa_payload);
                        }
-                       private = this->ike_sa->supports_extension(this->ike_sa,
-                                                                                                          EXT_STRONGSWAN);
-                       this->proposal = this->config->select_proposal(this->config,
-                                                                                                                  list, FALSE, private);
+                       if (!this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN)
+                               && !lib->settings->get_bool(lib->settings,
+                                                                       "%s.accept_private_algs", FALSE, lib->ns))
+                       {
+                               flags |= PROPOSAL_SKIP_PRIVATE;
+                       }
+                       this->proposal = this->config->select_proposal(this->config, list,
+                                                                                                                  flags);
                        list->destroy_offset(list, offsetof(proposal_t, destroy));
                        if (!this->proposal)
                        {
@@ -1347,6 +1402,7 @@ METHOD(task_t, process_i, status_t,
                        {
                                return send_notify(this, INVALID_PAYLOAD_TYPE);
                        }
+                       check_for_rekeyed_child(this, FALSE);
                        if (!install(this))
                        {
                                return send_notify(this, NO_PROPOSAL_CHOSEN);
@@ -1374,14 +1430,21 @@ METHOD(quick_mode_t, get_mid, uint32_t,
 METHOD(quick_mode_t, use_reqid, void,
        private_quick_mode_t *this, uint32_t reqid)
 {
-       this->reqid = reqid;
+       this->child.reqid = reqid;
 }
 
 METHOD(quick_mode_t, use_marks, void,
-       private_quick_mode_t *this, u_int in, u_int out)
+       private_quick_mode_t *this, uint32_t in, uint32_t out)
+{
+       this->child.mark_in = in;
+       this->child.mark_out = out;
+}
+
+METHOD(quick_mode_t, use_if_ids, void,
+       private_quick_mode_t *this, uint32_t in, uint32_t out)
 {
-       this->mark_in = in;
-       this->mark_out = out;
+       this->child.if_id_in = in;
+       this->child.if_id_out = out;
 }
 
 METHOD(quick_mode_t, rekey, void,
@@ -1412,8 +1475,7 @@ METHOD(task_t, migrate, void,
        this->dh = NULL;
        this->spi_i = 0;
        this->spi_r = 0;
-       this->mark_in = 0;
-       this->mark_out = 0;
+       this->child = (child_sa_create_t){};
 
        if (!this->initiator)
        {
@@ -1454,6 +1516,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
                        .get_mid = _get_mid,
                        .use_reqid = _use_reqid,
                        .use_marks = _use_marks,
+                       .use_if_ids = _use_if_ids,
                        .rekey = _rekey,
                },
                .ike_sa = ike_sa,