ikev1: Allow immediate deletion of rekeyed CHILD_SAs
[strongswan.git] / src / libcharon / sa / ikev1 / tasks / quick_mode.c
1 /*
2 * Copyright (C) 2012-2015 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2011 Martin Willi
6 * Copyright (C) 2011 revosec AG
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 /*
20 * Copyright (C) 2012 Volker RĂ¼melin
21 *
22 * Permission is hereby granted, free of charge, to any person obtaining a copy
23 * of this software and associated documentation files (the "Software"), to deal
24 * in the Software without restriction, including without limitation the rights
25 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26 * copies of the Software, and to permit persons to whom the Software is
27 * furnished to do so, subject to the following conditions:
28 *
29 * The above copyright notice and this permission notice shall be included in
30 * all copies or substantial portions of the Software.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38 * THE SOFTWARE.
39 */
40
41 #include "quick_mode.h"
42
43 #include <string.h>
44
45 #include <daemon.h>
46 #include <sa/ikev1/keymat_v1.h>
47 #include <encoding/payloads/sa_payload.h>
48 #include <encoding/payloads/nonce_payload.h>
49 #include <encoding/payloads/ke_payload.h>
50 #include <encoding/payloads/id_payload.h>
51 #include <encoding/payloads/payload.h>
52 #include <sa/ikev1/tasks/informational.h>
53 #include <sa/ikev1/tasks/quick_delete.h>
54 #include <processing/jobs/inactivity_job.h>
55
56 typedef struct private_quick_mode_t private_quick_mode_t;
57
58 /**
59 * Private members of a quick_mode_t task.
60 */
61 struct private_quick_mode_t {
62
63 /**
64 * Public methods and task_t interface.
65 */
66 quick_mode_t public;
67
68 /**
69 * Assigned IKE_SA.
70 */
71 ike_sa_t *ike_sa;
72
73 /**
74 * TRUE if we are initiating quick mode
75 */
76 bool initiator;
77
78 /**
79 * Traffic selector of initiator
80 */
81 traffic_selector_t *tsi;
82
83 /**
84 * Traffic selector of responder
85 */
86 traffic_selector_t *tsr;
87
88 /**
89 * Initiators nonce
90 */
91 chunk_t nonce_i;
92
93 /**
94 * Responder nonce
95 */
96 chunk_t nonce_r;
97
98 /**
99 * Initiators ESP SPI
100 */
101 u_int32_t spi_i;
102
103 /**
104 * Responder ESP SPI
105 */
106 u_int32_t spi_r;
107
108 /**
109 * Initiators IPComp CPI
110 */
111 u_int16_t cpi_i;
112
113 /**
114 * Responders IPComp CPI
115 */
116 u_int16_t cpi_r;
117
118 /**
119 * selected CHILD_SA proposal
120 */
121 proposal_t *proposal;
122
123 /**
124 * Config of CHILD_SA to establish
125 */
126 child_cfg_t *config;
127
128 /**
129 * CHILD_SA we are about to establish
130 */
131 child_sa_t *child_sa;
132
133 /**
134 * IKEv1 keymat
135 */
136 keymat_v1_t *keymat;
137
138 /**
139 * DH exchange, when PFS is in use
140 */
141 diffie_hellman_t *dh;
142
143 /**
144 * Negotiated lifetime of new SA
145 */
146 u_int32_t lifetime;
147
148 /**
149 * Negotaited lifebytes of new SA
150 */
151 u_int64_t lifebytes;
152
153 /**
154 * Reqid to use, 0 for auto-allocate
155 */
156 u_int32_t reqid;
157
158 /**
159 * Explicit inbound mark value to use, if any
160 */
161 u_int mark_in;
162
163 /**
164 * Explicit inbound mark value to use, if any
165 */
166 u_int mark_out;
167
168 /**
169 * SPI of SA we rekey
170 */
171 u_int32_t rekey;
172
173 /**
174 * Delete old child after successful rekey
175 */
176 bool delete;
177
178 /**
179 * Negotiated mode, tunnel or transport
180 */
181 ipsec_mode_t mode;
182
183 /*
184 * SA protocol (ESP|AH) negotiated
185 */
186 protocol_id_t proto;
187
188 /**
189 * Use UDP encapsulation
190 */
191 bool udp;
192
193 /**
194 * Message ID of handled quick mode exchange
195 */
196 u_int32_t mid;
197
198 /** states of quick mode */
199 enum {
200 QM_INIT,
201 QM_NEGOTIATED,
202 } state;
203 };
204
205 /**
206 * Schedule inactivity timeout for CHILD_SA with reqid, if enabled
207 */
208 static void schedule_inactivity_timeout(private_quick_mode_t *this)
209 {
210 u_int32_t timeout;
211 bool close_ike;
212
213 timeout = this->config->get_inactivity(this->config);
214 if (timeout)
215 {
216 close_ike = lib->settings->get_bool(lib->settings,
217 "%s.inactivity_close_ike", FALSE, lib->ns);
218 lib->scheduler->schedule_job(lib->scheduler, (job_t*)
219 inactivity_job_create(this->child_sa->get_unique_id(this->child_sa),
220 timeout, close_ike), timeout);
221 }
222 }
223
224 /**
225 * Check if we have a an address pool configured
226 */
227 static bool have_pool(ike_sa_t *ike_sa)
228 {
229 enumerator_t *enumerator;
230 peer_cfg_t *peer_cfg;
231 char *pool;
232 bool found = FALSE;
233
234 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
235 if (peer_cfg)
236 {
237 enumerator = peer_cfg->create_pool_enumerator(peer_cfg);
238 if (enumerator->enumerate(enumerator, &pool))
239 {
240 found = TRUE;
241 }
242 enumerator->destroy(enumerator);
243 }
244 return found;
245 }
246
247 /**
248 * Get hosts to use for dynamic traffic selectors
249 */
250 static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool local)
251 {
252 enumerator_t *enumerator;
253 linked_list_t *list;
254 host_t *host;
255
256 list = linked_list_create();
257 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
258 while (enumerator->enumerate(enumerator, &host))
259 {
260 list->insert_last(list, host);
261 }
262 enumerator->destroy(enumerator);
263
264 if (list->get_count(list) == 0)
265 { /* no virtual IPs assigned */
266 if (local)
267 {
268 host = ike_sa->get_my_host(ike_sa);
269 list->insert_last(list, host);
270 }
271 else if (!have_pool(ike_sa))
272 { /* use host only if we don't have a pool configured */
273 host = ike_sa->get_other_host(ike_sa);
274 list->insert_last(list, host);
275 }
276 }
277 return list;
278 }
279
280 /**
281 * Install negotiated CHILD_SA
282 */
283 static bool install(private_quick_mode_t *this)
284 {
285 status_t status, status_i, status_o;
286 chunk_t encr_i, encr_r, integ_i, integ_r;
287 linked_list_t *tsi, *tsr, *my_ts, *other_ts;
288 child_sa_t *old = NULL;
289
290 this->child_sa->set_proposal(this->child_sa, this->proposal);
291 this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
292 this->child_sa->set_mode(this->child_sa, this->mode);
293
294 if (this->cpi_i && this->cpi_r)
295 { /* DEFLATE is the only transform we currently support */
296 this->child_sa->set_ipcomp(this->child_sa, IPCOMP_DEFLATE);
297 }
298 else
299 {
300 this->cpi_i = this->cpi_r = 0;
301 }
302
303 this->child_sa->set_protocol(this->child_sa,
304 this->proposal->get_protocol(this->proposal));
305
306 status_i = status_o = FAILED;
307 encr_i = encr_r = integ_i = integ_r = chunk_empty;
308 tsi = linked_list_create_with_items(this->tsi->clone(this->tsi), NULL);
309 tsr = linked_list_create_with_items(this->tsr->clone(this->tsr), NULL);
310 if (this->initiator)
311 {
312 charon->bus->narrow(charon->bus, this->child_sa,
313 NARROW_INITIATOR_POST_AUTH, tsi, tsr);
314 }
315 else
316 {
317 charon->bus->narrow(charon->bus, this->child_sa,
318 NARROW_RESPONDER_POST, tsr, tsi);
319 }
320 if (tsi->get_count(tsi) == 0 || tsr->get_count(tsr) == 0)
321 {
322 tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
323 tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
324 DBG1(DBG_IKE, "no acceptable traffic selectors found");
325 return FALSE;
326 }
327
328 if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh,
329 this->spi_i, this->spi_r, this->nonce_i, this->nonce_r,
330 &encr_i, &integ_i, &encr_r, &integ_r))
331 {
332 if (this->initiator)
333 {
334 status_i = this->child_sa->install(this->child_sa,
335 encr_r, integ_r, this->spi_i, this->cpi_i,
336 this->initiator, TRUE, FALSE, tsi, tsr);
337 status_o = this->child_sa->install(this->child_sa,
338 encr_i, integ_i, this->spi_r, this->cpi_r,
339 this->initiator, FALSE, FALSE, tsi, tsr);
340 }
341 else
342 {
343 status_i = this->child_sa->install(this->child_sa,
344 encr_i, integ_i, this->spi_r, this->cpi_r,
345 this->initiator, TRUE, FALSE, tsr, tsi);
346 status_o = this->child_sa->install(this->child_sa,
347 encr_r, integ_r, this->spi_i, this->cpi_i,
348 this->initiator, FALSE, FALSE, tsr, tsi);
349 }
350 }
351 chunk_clear(&integ_i);
352 chunk_clear(&integ_r);
353 chunk_clear(&encr_i);
354 chunk_clear(&encr_r);
355
356 if (status_i != SUCCESS || status_o != SUCCESS)
357 {
358 DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
359 (status_i != SUCCESS) ? "inbound " : "",
360 (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
361 (status_o != SUCCESS) ? "outbound " : "");
362 tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
363 tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
364 return FALSE;
365 }
366
367 if (this->initiator)
368 {
369 status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
370 }
371 else
372 {
373 status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
374 }
375 tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
376 tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
377 if (status != SUCCESS)
378 {
379 DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
380 return FALSE;
381 }
382
383 charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
384 this->dh, this->nonce_i, this->nonce_r);
385
386 /* add to IKE_SA, and remove from task */
387 this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
388 this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
389
390 my_ts = linked_list_create_from_enumerator(
391 this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
392 other_ts = linked_list_create_from_enumerator(
393 this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
394
395 DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
396 "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
397 this->child_sa->get_name(this->child_sa),
398 this->child_sa->get_unique_id(this->child_sa),
399 ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
400 ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
401
402 my_ts->destroy(my_ts);
403 other_ts->destroy(other_ts);
404
405 if (this->rekey)
406 {
407 old = this->ike_sa->get_child_sa(this->ike_sa,
408 this->proposal->get_protocol(this->proposal),
409 this->rekey, TRUE);
410 }
411 if (old)
412 {
413 charon->bus->child_rekey(charon->bus, old, this->child_sa);
414 /* rekeyed CHILD_SAs stay installed until they expire or are deleted
415 * by the other peer */
416 old->set_state(old, CHILD_REKEYED);
417 /* as initiator we delete the CHILD_SA if configured to do so */
418 if (this->initiator && this->delete)
419 {
420 this->ike_sa->queue_task(this->ike_sa,
421 (task_t*)quick_delete_create(this->ike_sa,
422 this->proposal->get_protocol(this->proposal),
423 this->rekey, TRUE, FALSE));
424 }
425 }
426 else
427 {
428 charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
429 }
430 schedule_inactivity_timeout(this);
431 this->child_sa = NULL;
432 return TRUE;
433 }
434
435 /**
436 * Generate and add NONCE
437 */
438 static bool add_nonce(private_quick_mode_t *this, chunk_t *nonce,
439 message_t *message)
440 {
441 nonce_payload_t *nonce_payload;
442 nonce_gen_t *nonceg;
443
444 nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
445 if (!nonceg)
446 {
447 DBG1(DBG_IKE, "no nonce generator found to create nonce");
448 return FALSE;
449 }
450 if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, nonce))
451 {
452 DBG1(DBG_IKE, "nonce allocation failed");
453 nonceg->destroy(nonceg);
454 return FALSE;
455 }
456 nonceg->destroy(nonceg);
457
458 nonce_payload = nonce_payload_create(PLV1_NONCE);
459 nonce_payload->set_nonce(nonce_payload, *nonce);
460 message->add_payload(message, &nonce_payload->payload_interface);
461
462 return TRUE;
463 }
464
465 /**
466 * Extract nonce from NONCE payload
467 */
468 static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce,
469 message_t *message)
470 {
471 nonce_payload_t *nonce_payload;
472
473 nonce_payload = (nonce_payload_t*)message->get_payload(message, PLV1_NONCE);
474 if (!nonce_payload)
475 {
476 DBG1(DBG_IKE, "NONCE payload missing in message");
477 return FALSE;
478 }
479 *nonce = nonce_payload->get_nonce(nonce_payload);
480
481 return TRUE;
482 }
483
484 /**
485 * Add KE payload to message
486 */
487 static bool add_ke(private_quick_mode_t *this, message_t *message)
488 {
489 ke_payload_t *ke_payload;
490
491 ke_payload = ke_payload_create_from_diffie_hellman(PLV1_KEY_EXCHANGE,
492 this->dh);
493 if (!ke_payload)
494 {
495 DBG1(DBG_IKE, "creating KE payload failed");
496 return FALSE;
497 }
498 message->add_payload(message, &ke_payload->payload_interface);
499 return TRUE;
500 }
501
502 /**
503 * Get DH value from a KE payload
504 */
505 static bool get_ke(private_quick_mode_t *this, message_t *message)
506 {
507 ke_payload_t *ke_payload;
508
509 ke_payload = (ke_payload_t*)message->get_payload(message, PLV1_KEY_EXCHANGE);
510 if (!ke_payload)
511 {
512 DBG1(DBG_IKE, "KE payload missing");
513 return FALSE;
514 }
515 if (!this->dh->set_other_public_value(this->dh,
516 ke_payload->get_key_exchange_data(ke_payload)))
517 {
518 DBG1(DBG_IKE, "unable to apply received KE value");
519 return FALSE;
520 }
521 return TRUE;
522 }
523
524 /**
525 * Select a traffic selector from configuration
526 */
527 static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
528 linked_list_t *supplied)
529 {
530 traffic_selector_t *ts;
531 linked_list_t *list, *hosts;
532
533 hosts = get_dynamic_hosts(this->ike_sa, local);
534 list = this->config->get_traffic_selectors(this->config,
535 local, supplied, hosts);
536 hosts->destroy(hosts);
537 if (list->get_first(list, (void**)&ts) == SUCCESS)
538 {
539 ts = ts->clone(ts);
540 }
541 else
542 {
543 DBG1(DBG_IKE, "%s traffic selector missing in configuration",
544 local ? "local" : "remote");
545 ts = NULL;
546 }
547 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
548 return ts;
549 }
550
551 /**
552 * Add selected traffic selectors to message
553 */
554 static void add_ts(private_quick_mode_t *this, message_t *message)
555 {
556 id_payload_t *id_payload;
557
558 id_payload = id_payload_create_from_ts(this->tsi);
559 message->add_payload(message, &id_payload->payload_interface);
560 id_payload = id_payload_create_from_ts(this->tsr);
561 message->add_payload(message, &id_payload->payload_interface);
562 }
563
564 /**
565 * Get traffic selectors from received message
566 */
567 static bool get_ts(private_quick_mode_t *this, message_t *message)
568 {
569 traffic_selector_t *tsi = NULL, *tsr = NULL;
570 enumerator_t *enumerator;
571 id_payload_t *id_payload;
572 payload_t *payload;
573 host_t *hsi, *hsr;
574 bool first = TRUE;
575
576 enumerator = message->create_payload_enumerator(message);
577 while (enumerator->enumerate(enumerator, &payload))
578 {
579 if (payload->get_type(payload) == PLV1_ID)
580 {
581 id_payload = (id_payload_t*)payload;
582
583 if (first)
584 {
585 tsi = id_payload->get_ts(id_payload);
586 first = FALSE;
587 }
588 else
589 {
590 tsr = id_payload->get_ts(id_payload);
591 break;
592 }
593 }
594 }
595 enumerator->destroy(enumerator);
596
597 /* create host2host selectors if ID payloads missing */
598 if (this->initiator)
599 {
600 hsi = this->ike_sa->get_my_host(this->ike_sa);
601 hsr = this->ike_sa->get_other_host(this->ike_sa);
602 }
603 else
604 {
605 hsr = this->ike_sa->get_my_host(this->ike_sa);
606 hsi = this->ike_sa->get_other_host(this->ike_sa);
607 }
608 if (!tsi)
609 {
610 tsi = traffic_selector_create_from_subnet(hsi->clone(hsi),
611 hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0, 65535);
612 }
613 if (!tsr)
614 {
615 tsr = traffic_selector_create_from_subnet(hsr->clone(hsr),
616 hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0, 65535);
617 }
618 if (this->mode == MODE_TRANSPORT && this->udp &&
619 (!tsi->is_host(tsi, hsi) || !tsr->is_host(tsr, hsr)))
620 { /* change TS in case of a NAT in transport mode */
621 DBG2(DBG_IKE, "changing received traffic selectors %R=== %R due to NAT",
622 tsi, tsr);
623 tsi->set_address(tsi, hsi);
624 tsr->set_address(tsr, hsr);
625 }
626
627 if (this->initiator)
628 {
629 traffic_selector_t *tsisub, *tsrsub;
630
631 /* check if peer selection is valid */
632 tsisub = this->tsi->get_subset(this->tsi, tsi);
633 tsrsub = this->tsr->get_subset(this->tsr, tsr);
634 if (!tsisub || !tsrsub)
635 {
636 DBG1(DBG_IKE, "peer selected invalid traffic selectors: "
637 "%R for %R, %R for %R", tsi, this->tsi, tsr, this->tsr);
638 DESTROY_IF(tsisub);
639 DESTROY_IF(tsrsub);
640 tsi->destroy(tsi);
641 tsr->destroy(tsr);
642 return FALSE;
643 }
644 tsi->destroy(tsi);
645 tsr->destroy(tsr);
646 this->tsi->destroy(this->tsi);
647 this->tsr->destroy(this->tsr);
648 this->tsi = tsisub;
649 this->tsr = tsrsub;
650 }
651 else
652 {
653 this->tsi = tsi;
654 this->tsr = tsr;
655 }
656 return TRUE;
657 }
658
659 /**
660 * Get encap
661 */
662 static encap_t get_encap(ike_sa_t* ike_sa, bool udp)
663 {
664 if (!udp)
665 {
666 return ENCAP_NONE;
667 }
668 if (ike_sa->supports_extension(ike_sa, EXT_NATT_DRAFT_02_03))
669 {
670 return ENCAP_UDP_DRAFT_00_03;
671 }
672 return ENCAP_UDP;
673 }
674
675 /**
676 * Get NAT-OA payload type (RFC 3947 or RFC 3947 drafts).
677 */
678 static payload_type_t get_nat_oa_payload_type(ike_sa_t *ike_sa)
679 {
680 if (ike_sa->supports_extension(ike_sa, EXT_NATT_DRAFT_02_03))
681 {
682 return PLV1_NAT_OA_DRAFT_00_03;
683 }
684 return PLV1_NAT_OA;
685 }
686
687 /**
688 * Add NAT-OA payloads
689 */
690 static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message)
691 {
692 identification_t *id;
693 id_payload_t *nat_oa;
694 host_t *src, *dst;
695 payload_type_t nat_oa_payload_type;
696
697 src = message->get_source(message);
698 dst = message->get_destination(message);
699
700 src = this->initiator ? src : dst;
701 dst = this->initiator ? dst : src;
702
703 nat_oa_payload_type = get_nat_oa_payload_type(this->ike_sa);
704
705 /* first NAT-OA is the initiator's address */
706 id = identification_create_from_sockaddr(src->get_sockaddr(src));
707 nat_oa = id_payload_create_from_identification(nat_oa_payload_type, id);
708 message->add_payload(message, (payload_t*)nat_oa);
709 id->destroy(id);
710
711 /* second NAT-OA is that of the responder */
712 id = identification_create_from_sockaddr(dst->get_sockaddr(dst));
713 nat_oa = id_payload_create_from_identification(nat_oa_payload_type, id);
714 message->add_payload(message, (payload_t*)nat_oa);
715 id->destroy(id);
716 }
717
718 /**
719 * Look up lifetimes
720 */
721 static void get_lifetimes(private_quick_mode_t *this)
722 {
723 lifetime_cfg_t *lft;
724
725 lft = this->config->get_lifetime(this->config);
726 if (lft->time.life)
727 {
728 this->lifetime = lft->time.life;
729 }
730 else if (lft->bytes.life)
731 {
732 this->lifebytes = lft->bytes.life;
733 }
734 free(lft);
735 }
736
737 /**
738 * Check and apply lifetimes
739 */
740 static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload)
741 {
742 u_int32_t lifetime;
743 u_int64_t lifebytes;
744
745 lifetime = sa_payload->get_lifetime(sa_payload);
746 lifebytes = sa_payload->get_lifebytes(sa_payload);
747 if (this->lifetime != lifetime)
748 {
749 DBG1(DBG_IKE, "received %us lifetime, configured %us",
750 lifetime, this->lifetime);
751 this->lifetime = lifetime;
752 }
753 if (this->lifebytes != lifebytes)
754 {
755 DBG1(DBG_IKE, "received %llu lifebytes, configured %llu",
756 lifebytes, this->lifebytes);
757 this->lifebytes = lifebytes;
758 }
759 }
760
761 /**
762 * Set the task ready to build notify error message
763 */
764 static status_t send_notify(private_quick_mode_t *this, notify_type_t type)
765 {
766 notify_payload_t *notify;
767
768 notify = notify_payload_create_from_protocol_and_type(PLV1_NOTIFY,
769 this->proto, type);
770 notify->set_spi(notify, this->spi_i);
771
772 this->ike_sa->queue_task(this->ike_sa,
773 (task_t*)informational_create(this->ike_sa, notify));
774 /* cancel all active/passive tasks in favour of informational */
775 this->ike_sa->flush_queue(this->ike_sa,
776 this->initiator ? TASK_QUEUE_ACTIVE : TASK_QUEUE_PASSIVE);
777 return ALREADY_DONE;
778 }
779
780 /**
781 * Prepare a list of proposals from child_config containing only the specified
782 * DH group, unless it is set to MODP_NONE.
783 */
784 static linked_list_t *get_proposals(private_quick_mode_t *this,
785 diffie_hellman_group_t group)
786 {
787 linked_list_t *list;
788 proposal_t *proposal;
789 enumerator_t *enumerator;
790
791 list = this->config->get_proposals(this->config, FALSE);
792 enumerator = list->create_enumerator(list);
793 while (enumerator->enumerate(enumerator, &proposal))
794 {
795 if (group != MODP_NONE)
796 {
797 if (!proposal->has_dh_group(proposal, group))
798 {
799 list->remove_at(list, enumerator);
800 proposal->destroy(proposal);
801 continue;
802 }
803 proposal->strip_dh(proposal, group);
804 }
805 proposal->set_spi(proposal, this->spi_i);
806 }
807 enumerator->destroy(enumerator);
808
809 return list;
810 }
811
812 METHOD(task_t, build_i, status_t,
813 private_quick_mode_t *this, message_t *message)
814 {
815 switch (this->state)
816 {
817 case QM_INIT:
818 {
819 sa_payload_t *sa_payload;
820 linked_list_t *list, *tsi, *tsr;
821 proposal_t *proposal;
822 diffie_hellman_group_t group;
823 encap_t encap;
824
825 this->udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
826 this->mode = this->config->get_mode(this->config);
827 this->child_sa = child_sa_create(
828 this->ike_sa->get_my_host(this->ike_sa),
829 this->ike_sa->get_other_host(this->ike_sa),
830 this->config, this->reqid, this->udp,
831 this->mark_in, this->mark_out);
832
833 if (this->udp && this->mode == MODE_TRANSPORT)
834 {
835 /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
836 add_nat_oa_payloads(this, message);
837 }
838
839 if (this->config->use_ipcomp(this->config))
840 {
841 this->cpi_i = this->child_sa->alloc_cpi(this->child_sa);
842 if (!this->cpi_i)
843 {
844 DBG1(DBG_IKE, "unable to allocate a CPI from kernel, "
845 "IPComp disabled");
846 }
847 }
848
849 list = this->config->get_proposals(this->config, MODP_NONE);
850 if (list->get_first(list, (void**)&proposal) == SUCCESS)
851 {
852 this->proto = proposal->get_protocol(proposal);
853 }
854 list->destroy_offset(list, offsetof(proposal_t, destroy));
855 this->spi_i = this->child_sa->alloc_spi(this->child_sa, this->proto);
856 if (!this->spi_i)
857 {
858 DBG1(DBG_IKE, "allocating SPI from kernel failed");
859 return FAILED;
860 }
861
862 group = this->config->get_dh_group(this->config);
863 if (group != MODP_NONE)
864 {
865 proposal_t *proposal;
866 u_int16_t preferred_group;
867
868 proposal = this->ike_sa->get_proposal(this->ike_sa);
869 proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP,
870 &preferred_group, NULL);
871 /* try the negotiated DH group from IKE_SA */
872 list = get_proposals(this, preferred_group);
873 if (list->get_count(list))
874 {
875 group = preferred_group;
876 }
877 else
878 {
879 /* fall back to the first configured DH group */
880 list->destroy(list);
881 list = get_proposals(this, group);
882 }
883
884 this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
885 group);
886 if (!this->dh)
887 {
888 DBG1(DBG_IKE, "configured DH group %N not supported",
889 diffie_hellman_group_names, group);
890 list->destroy_offset(list, offsetof(proposal_t, destroy));
891 return FAILED;
892 }
893 }
894 else
895 {
896 list = get_proposals(this, MODP_NONE);
897 }
898
899 get_lifetimes(this);
900 encap = get_encap(this->ike_sa, this->udp);
901 sa_payload = sa_payload_create_from_proposals_v1(list,
902 this->lifetime, this->lifebytes, AUTH_NONE,
903 this->mode, encap, this->cpi_i);
904 list->destroy_offset(list, offsetof(proposal_t, destroy));
905 message->add_payload(message, &sa_payload->payload_interface);
906
907 if (!add_nonce(this, &this->nonce_i, message))
908 {
909 return FAILED;
910 }
911 if (group != MODP_NONE)
912 {
913 if (!add_ke(this, message))
914 {
915 return FAILED;
916 }
917 }
918 if (!this->tsi)
919 {
920 this->tsi = select_ts(this, TRUE, NULL);
921 }
922 if (!this->tsr)
923 {
924 this->tsr = select_ts(this, FALSE, NULL);
925 }
926 tsi = linked_list_create_with_items(this->tsi, NULL);
927 tsr = linked_list_create_with_items(this->tsr, NULL);
928 this->tsi = this->tsr = NULL;
929 charon->bus->narrow(charon->bus, this->child_sa,
930 NARROW_INITIATOR_PRE_AUTH, tsi, tsr);
931 tsi->remove_first(tsi, (void**)&this->tsi);
932 tsr->remove_first(tsr, (void**)&this->tsr);
933 tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
934 tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
935 if (!this->tsi || !this->tsr)
936 {
937 return FAILED;
938 }
939 add_ts(this, message);
940 return NEED_MORE;
941 }
942 case QM_NEGOTIATED:
943 {
944 return SUCCESS;
945 }
946 default:
947 return FAILED;
948 }
949 }
950
951 /**
952 * Check for notify errors, return TRUE if error found
953 */
954 static bool has_notify_errors(private_quick_mode_t *this, message_t *message)
955 {
956 enumerator_t *enumerator;
957 payload_t *payload;
958 bool err = FALSE;
959
960 enumerator = message->create_payload_enumerator(message);
961 while (enumerator->enumerate(enumerator, &payload))
962 {
963 if (payload->get_type(payload) == PLV1_NOTIFY)
964 {
965 notify_payload_t *notify;
966 notify_type_t type;
967
968 notify = (notify_payload_t*)payload;
969 type = notify->get_notify_type(notify);
970 if (type < 16384)
971 {
972
973 DBG1(DBG_IKE, "received %N error notify",
974 notify_type_names, type);
975 err = TRUE;
976 }
977 else
978 {
979 DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
980 }
981 }
982 }
983 enumerator->destroy(enumerator);
984
985 return err;
986 }
987
988 /**
989 * Check if this is a rekey for an existing CHILD_SA, reuse reqid if so
990 */
991 static void check_for_rekeyed_child(private_quick_mode_t *this)
992 {
993 enumerator_t *enumerator, *policies;
994 traffic_selector_t *local, *remote;
995 child_sa_t *child_sa;
996 proposal_t *proposal;
997 char *name;
998
999 name = this->config->get_name(this->config);
1000 enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
1001 while (this->reqid == 0 && enumerator->enumerate(enumerator, &child_sa))
1002 {
1003 if (streq(child_sa->get_name(child_sa), name))
1004 {
1005 proposal = child_sa->get_proposal(child_sa);
1006 switch (child_sa->get_state(child_sa))
1007 {
1008 case CHILD_INSTALLED:
1009 case CHILD_REKEYING:
1010 case CHILD_REKEYED:
1011 policies = child_sa->create_policy_enumerator(child_sa);
1012 if (policies->enumerate(policies, &local, &remote) &&
1013 local->equals(local, this->tsr) &&
1014 remote->equals(remote, this->tsi) &&
1015 this->proposal->equals(this->proposal, proposal))
1016 {
1017 this->reqid = child_sa->get_reqid(child_sa);
1018 this->rekey = child_sa->get_spi(child_sa, TRUE);
1019 this->mark_in = child_sa->get_mark(child_sa,
1020 TRUE).value;
1021 this->mark_out = child_sa->get_mark(child_sa,
1022 FALSE).value;
1023 child_sa->set_state(child_sa, CHILD_REKEYING);
1024 DBG1(DBG_IKE, "detected rekeying of CHILD_SA %s{%u}",
1025 child_sa->get_name(child_sa),
1026 child_sa->get_unique_id(child_sa));
1027 }
1028 policies->destroy(policies);
1029 break;
1030 default:
1031 break;
1032 }
1033 }
1034 }
1035 enumerator->destroy(enumerator);
1036 }
1037
1038 METHOD(task_t, process_r, status_t,
1039 private_quick_mode_t *this, message_t *message)
1040 {
1041 if (this->mid && this->mid != message->get_message_id(message))
1042 { /* not responsible for this quick mode exchange */
1043 return INVALID_ARG;
1044 }
1045
1046 switch (this->state)
1047 {
1048 case QM_INIT:
1049 {
1050 sa_payload_t *sa_payload;
1051 linked_list_t *tsi, *tsr, *hostsi, *hostsr, *list = NULL;
1052 peer_cfg_t *peer_cfg;
1053 u_int16_t group;
1054 bool private;
1055
1056 sa_payload = (sa_payload_t*)message->get_payload(message,
1057 PLV1_SECURITY_ASSOCIATION);
1058 if (!sa_payload)
1059 {
1060 DBG1(DBG_IKE, "sa payload missing");
1061 return send_notify(this, INVALID_PAYLOAD_TYPE);
1062 }
1063
1064 this->mode = sa_payload->get_encap_mode(sa_payload, &this->udp);
1065
1066 if (!get_ts(this, message))
1067 {
1068 return FAILED;
1069 }
1070 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
1071 tsi = linked_list_create_with_items(this->tsi, NULL);
1072 tsr = linked_list_create_with_items(this->tsr, NULL);
1073 this->tsi = this->tsr = NULL;
1074 hostsi = get_dynamic_hosts(this->ike_sa, FALSE);
1075 hostsr = get_dynamic_hosts(this->ike_sa, TRUE);
1076 this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
1077 hostsr, hostsi);
1078 hostsi->destroy(hostsi);
1079 hostsr->destroy(hostsr);
1080 if (this->config)
1081 {
1082 this->tsi = select_ts(this, FALSE, tsi);
1083 this->tsr = select_ts(this, TRUE, tsr);
1084 }
1085 tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
1086 tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
1087 if (!this->config || !this->tsi || !this->tsr ||
1088 this->mode != this->config->get_mode(this->config))
1089 {
1090 DBG1(DBG_IKE, "no matching CHILD_SA config found");
1091 return send_notify(this, INVALID_ID_INFORMATION);
1092 }
1093
1094 if (this->config->use_ipcomp(this->config))
1095 {
1096 list = sa_payload->get_ipcomp_proposals(sa_payload,
1097 &this->cpi_i);
1098 if (!list->get_count(list))
1099 {
1100 DBG1(DBG_IKE, "expected IPComp proposal but peer did "
1101 "not send one, IPComp disabled");
1102 this->cpi_i = 0;
1103 }
1104 }
1105 if (!list || !list->get_count(list))
1106 {
1107 DESTROY_IF(list);
1108 list = sa_payload->get_proposals(sa_payload);
1109 }
1110 private = this->ike_sa->supports_extension(this->ike_sa,
1111 EXT_STRONGSWAN);
1112 this->proposal = this->config->select_proposal(this->config,
1113 list, FALSE, private);
1114 list->destroy_offset(list, offsetof(proposal_t, destroy));
1115
1116 get_lifetimes(this);
1117 apply_lifetimes(this, sa_payload);
1118
1119 if (!this->proposal)
1120 {
1121 DBG1(DBG_IKE, "no matching proposal found, sending %N",
1122 notify_type_names, NO_PROPOSAL_CHOSEN);
1123 return send_notify(this, NO_PROPOSAL_CHOSEN);
1124 }
1125 this->spi_i = this->proposal->get_spi(this->proposal);
1126
1127 if (!get_nonce(this, &this->nonce_i, message))
1128 {
1129 return send_notify(this, INVALID_PAYLOAD_TYPE);
1130 }
1131
1132 if (this->proposal->get_algorithm(this->proposal,
1133 DIFFIE_HELLMAN_GROUP, &group, NULL))
1134 {
1135 this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
1136 group);
1137 if (!this->dh)
1138 {
1139 DBG1(DBG_IKE, "negotiated DH group %N not supported",
1140 diffie_hellman_group_names, group);
1141 return send_notify(this, INVALID_KEY_INFORMATION);
1142 }
1143 if (!get_ke(this, message))
1144 {
1145 return send_notify(this, INVALID_PAYLOAD_TYPE);
1146 }
1147 }
1148
1149 check_for_rekeyed_child(this);
1150
1151 this->child_sa = child_sa_create(
1152 this->ike_sa->get_my_host(this->ike_sa),
1153 this->ike_sa->get_other_host(this->ike_sa),
1154 this->config, this->reqid, this->udp,
1155 this->mark_in, this->mark_out);
1156
1157 tsi = linked_list_create_with_items(this->tsi, NULL);
1158 tsr = linked_list_create_with_items(this->tsr, NULL);
1159 this->tsi = this->tsr = NULL;
1160 charon->bus->narrow(charon->bus, this->child_sa,
1161 NARROW_RESPONDER, tsr, tsi);
1162 if (tsi->remove_first(tsi, (void**)&this->tsi) != SUCCESS ||
1163 tsr->remove_first(tsr, (void**)&this->tsr) != SUCCESS)
1164 {
1165 tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
1166 tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
1167 return send_notify(this, INVALID_ID_INFORMATION);
1168 }
1169 tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
1170 tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
1171
1172 return NEED_MORE;
1173 }
1174 case QM_NEGOTIATED:
1175 {
1176 if (has_notify_errors(this, message))
1177 {
1178 return SUCCESS;
1179 }
1180 if (message->get_exchange_type(message) == INFORMATIONAL_V1)
1181 {
1182 if (message->get_payload(message, PLV1_DELETE))
1183 {
1184 /* If the DELETE for a Quick Mode follows immediately
1185 * after rekeying, we might receive it before the
1186 * third completing Quick Mode message. Ignore it, as
1187 * it gets handled by a separately queued delete task. */
1188 return NEED_MORE;
1189 }
1190 return SUCCESS;
1191 }
1192 if (!install(this))
1193 {
1194 ike_sa_t *ike_sa = this->ike_sa;
1195 task_t *task;
1196
1197 task = (task_t*)quick_delete_create(this->ike_sa,
1198 this->proposal->get_protocol(this->proposal),
1199 this->spi_i, TRUE, TRUE);
1200 /* flush_queue() destroys the current task */
1201 ike_sa->flush_queue(ike_sa, TASK_QUEUE_PASSIVE);
1202 ike_sa->queue_task(ike_sa, task);
1203 return ALREADY_DONE;
1204 }
1205 return SUCCESS;
1206 }
1207 default:
1208 return FAILED;
1209 }
1210 }
1211
1212 METHOD(task_t, build_r, status_t,
1213 private_quick_mode_t *this, message_t *message)
1214 {
1215 if (this->mid && this->mid != message->get_message_id(message))
1216 { /* not responsible for this quick mode exchange */
1217 return INVALID_ARG;
1218 }
1219
1220 switch (this->state)
1221 {
1222 case QM_INIT:
1223 {
1224 sa_payload_t *sa_payload;
1225 encap_t encap;
1226
1227 this->proto = this->proposal->get_protocol(this->proposal);
1228 this->spi_r = this->child_sa->alloc_spi(this->child_sa, this->proto);
1229 if (!this->spi_r)
1230 {
1231 DBG1(DBG_IKE, "allocating SPI from kernel failed");
1232 return send_notify(this, NO_PROPOSAL_CHOSEN);
1233 }
1234 this->proposal->set_spi(this->proposal, this->spi_r);
1235
1236 if (this->cpi_i)
1237 {
1238 this->cpi_r = this->child_sa->alloc_cpi(this->child_sa);
1239 if (!this->cpi_r)
1240 {
1241 DBG1(DBG_IKE, "unable to allocate a CPI from "
1242 "kernel, IPComp disabled");
1243 return send_notify(this, NO_PROPOSAL_CHOSEN);
1244 }
1245 }
1246
1247 if (this->udp && this->mode == MODE_TRANSPORT)
1248 {
1249 /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
1250 add_nat_oa_payloads(this, message);
1251 }
1252
1253 encap = get_encap(this->ike_sa, this->udp);
1254 sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
1255 this->lifetime, this->lifebytes, AUTH_NONE,
1256 this->mode, encap, this->cpi_r);
1257 message->add_payload(message, &sa_payload->payload_interface);
1258
1259 if (!add_nonce(this, &this->nonce_r, message))
1260 {
1261 return FAILED;
1262 }
1263 if (this->dh)
1264 {
1265 if (!add_ke(this, message))
1266 {
1267 return FAILED;
1268 }
1269 }
1270
1271 add_ts(this, message);
1272
1273 this->state = QM_NEGOTIATED;
1274 this->mid = message->get_message_id(message);
1275 return NEED_MORE;
1276 }
1277 case QM_NEGOTIATED:
1278 if (message->get_exchange_type(message) == INFORMATIONAL_V1)
1279 {
1280 /* skip INFORMATIONAL response if we received a INFORMATIONAL
1281 * delete, see process_r() */
1282 return ALREADY_DONE;
1283 }
1284 /* fall */
1285 default:
1286 return FAILED;
1287 }
1288 }
1289
1290 METHOD(task_t, process_i, status_t,
1291 private_quick_mode_t *this, message_t *message)
1292 {
1293 switch (this->state)
1294 {
1295 case QM_INIT:
1296 {
1297 sa_payload_t *sa_payload;
1298 linked_list_t *list = NULL;
1299 bool private;
1300
1301 sa_payload = (sa_payload_t*)message->get_payload(message,
1302 PLV1_SECURITY_ASSOCIATION);
1303 if (!sa_payload)
1304 {
1305 DBG1(DBG_IKE, "sa payload missing");
1306 return send_notify(this, NO_PROPOSAL_CHOSEN);
1307 }
1308 if (this->cpi_i)
1309 {
1310 list = sa_payload->get_ipcomp_proposals(sa_payload,
1311 &this->cpi_r);
1312 if (!list->get_count(list))
1313 {
1314 DBG1(DBG_IKE, "peer did not acccept our IPComp proposal, "
1315 "IPComp disabled");
1316 this->cpi_i = 0;
1317 }
1318 }
1319 if (!list || !list->get_count(list))
1320 {
1321 DESTROY_IF(list);
1322 list = sa_payload->get_proposals(sa_payload);
1323 }
1324 private = this->ike_sa->supports_extension(this->ike_sa,
1325 EXT_STRONGSWAN);
1326 this->proposal = this->config->select_proposal(this->config,
1327 list, FALSE, private);
1328 list->destroy_offset(list, offsetof(proposal_t, destroy));
1329 if (!this->proposal)
1330 {
1331 DBG1(DBG_IKE, "no matching proposal found");
1332 return send_notify(this, NO_PROPOSAL_CHOSEN);
1333 }
1334 this->spi_r = this->proposal->get_spi(this->proposal);
1335
1336 apply_lifetimes(this, sa_payload);
1337
1338 if (!get_nonce(this, &this->nonce_r, message))
1339 {
1340 return send_notify(this, INVALID_PAYLOAD_TYPE);
1341 }
1342 if (this->dh && !get_ke(this, message))
1343 {
1344 return send_notify(this, INVALID_KEY_INFORMATION);
1345 }
1346 if (!get_ts(this, message))
1347 {
1348 return send_notify(this, INVALID_PAYLOAD_TYPE);
1349 }
1350 if (!install(this))
1351 {
1352 return send_notify(this, NO_PROPOSAL_CHOSEN);
1353 }
1354 this->state = QM_NEGOTIATED;
1355 return NEED_MORE;
1356 }
1357 default:
1358 return FAILED;
1359 }
1360 }
1361
1362 METHOD(task_t, get_type, task_type_t,
1363 private_quick_mode_t *this)
1364 {
1365 return TASK_QUICK_MODE;
1366 }
1367
1368 METHOD(quick_mode_t, get_mid, u_int32_t,
1369 private_quick_mode_t *this)
1370 {
1371 return this->mid;
1372 }
1373
1374 METHOD(quick_mode_t, use_reqid, void,
1375 private_quick_mode_t *this, u_int32_t reqid)
1376 {
1377 this->reqid = reqid;
1378 }
1379
1380 METHOD(quick_mode_t, use_marks, void,
1381 private_quick_mode_t *this, u_int in, u_int out)
1382 {
1383 this->mark_in = in;
1384 this->mark_out = out;
1385 }
1386
1387 METHOD(quick_mode_t, rekey, void,
1388 private_quick_mode_t *this, u_int32_t spi)
1389 {
1390 this->rekey = spi;
1391 }
1392
1393 METHOD(task_t, migrate, void,
1394 private_quick_mode_t *this, ike_sa_t *ike_sa)
1395 {
1396 chunk_free(&this->nonce_i);
1397 chunk_free(&this->nonce_r);
1398 DESTROY_IF(this->tsi);
1399 DESTROY_IF(this->tsr);
1400 DESTROY_IF(this->proposal);
1401 DESTROY_IF(this->child_sa);
1402 DESTROY_IF(this->dh);
1403
1404 this->ike_sa = ike_sa;
1405 this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
1406 this->state = QM_INIT;
1407 this->mid = 0;
1408 this->tsi = NULL;
1409 this->tsr = NULL;
1410 this->proposal = NULL;
1411 this->child_sa = NULL;
1412 this->dh = NULL;
1413 this->spi_i = 0;
1414 this->spi_r = 0;
1415 this->mark_in = 0;
1416 this->mark_out = 0;
1417
1418 if (!this->initiator)
1419 {
1420 DESTROY_IF(this->config);
1421 this->config = NULL;
1422 }
1423 }
1424
1425 METHOD(task_t, destroy, void,
1426 private_quick_mode_t *this)
1427 {
1428 chunk_free(&this->nonce_i);
1429 chunk_free(&this->nonce_r);
1430 DESTROY_IF(this->tsi);
1431 DESTROY_IF(this->tsr);
1432 DESTROY_IF(this->proposal);
1433 DESTROY_IF(this->child_sa);
1434 DESTROY_IF(this->config);
1435 DESTROY_IF(this->dh);
1436 free(this);
1437 }
1438
1439 /*
1440 * Described in header.
1441 */
1442 quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
1443 traffic_selector_t *tsi, traffic_selector_t *tsr)
1444 {
1445 private_quick_mode_t *this;
1446
1447 INIT(this,
1448 .public = {
1449 .task = {
1450 .get_type = _get_type,
1451 .migrate = _migrate,
1452 .destroy = _destroy,
1453 },
1454 .get_mid = _get_mid,
1455 .use_reqid = _use_reqid,
1456 .use_marks = _use_marks,
1457 .rekey = _rekey,
1458 },
1459 .ike_sa = ike_sa,
1460 .initiator = config != NULL,
1461 .config = config,
1462 .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
1463 .state = QM_INIT,
1464 .tsi = tsi ? tsi->clone(tsi) : NULL,
1465 .tsr = tsr ? tsr->clone(tsr) : NULL,
1466 .proto = PROTO_ESP,
1467 .delete = lib->settings->get_bool(lib->settings,
1468 "%s.delete_rekeyed", FALSE, lib->ns),
1469 );
1470
1471 if (config)
1472 {
1473 this->public.task.build = _build_i;
1474 this->public.task.process = _process_i;
1475 }
1476 else
1477 {
1478 this->public.task.build = _build_r;
1479 this->public.task.process = _process_r;
1480 }
1481
1482 return &this->public;
1483 }