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