]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/sa/task_manager_v1.c
Derive IKEv1 CHILD_SA keymat twice, once for each IPsec SA
[thirdparty/strongswan.git] / src / libcharon / sa / task_manager_v1.c
CommitLineData
4a09d9ee
MW
1/*
2 * Copyright (C) 2007 Tobias Brunner
3 * Copyright (C) 2007-2010 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17#include "task_manager_v1.h"
18
4a09d9ee 19#include <daemon.h>
c73c832c 20#include <sa/tasks/main_mode.h>
744c0801 21#include <sa/tasks/quick_mode.h>
4a09d9ee
MW
22
23typedef struct exchange_t exchange_t;
24
25/**
26 * An exchange in the air, used do detect and handle retransmission
27 */
28struct exchange_t {
29
30 /**
31 * Message ID used for this transaction
32 */
33 u_int32_t mid;
34
35 /**
36 * generated packet for retransmission
37 */
38 packet_t *packet;
39};
40
41typedef struct private_task_manager_t private_task_manager_t;
42
43/**
44 * private data of the task manager
45 */
46struct private_task_manager_t {
47
48 /**
49 * public functions
50 */
51 task_manager_v1_t public;
52
53 /**
54 * associated IKE_SA we are serving
55 */
56 ike_sa_t *ike_sa;
57
73aaf76b
MW
58 /**
59 * RNG to create message IDs
60 */
61 rng_t *rng;
62
4a09d9ee
MW
63 /**
64 * Exchange we are currently handling as responder
65 */
66 struct {
67 /**
68 * Message ID of the exchange
69 */
70 u_int32_t mid;
71
9cc8bd4f
MW
72 /**
73 * Hash of a previously received message
74 */
75 u_int32_t hash;
76
4a09d9ee
MW
77 /**
78 * packet for retransmission
79 */
80 packet_t *packet;
81
82 } responding;
83
84 /**
85 * Exchange we are currently handling as initiator
86 */
87 struct {
88 /**
89 * Message ID of the exchange
90 */
91 u_int32_t mid;
92
9cc8bd4f
MW
93 /**
94 * Hash of a previously received message
95 */
96 u_int32_t hash;
97
4a09d9ee
MW
98 /**
99 * how many times we have retransmitted so far
100 */
101 u_int retransmitted;
102
103 /**
104 * packet for retransmission
105 */
106 packet_t *packet;
107
108 /**
109 * type of the initated exchange
110 */
111 exchange_type_t type;
112
113 } initiating;
114
115 /**
116 * List of queued tasks not yet in action
117 */
118 linked_list_t *queued_tasks;
119
120 /**
121 * List of active tasks, initiated by ourselve
122 */
123 linked_list_t *active_tasks;
124
125 /**
126 * List of tasks initiated by peer
127 */
128 linked_list_t *passive_tasks;
129
4a09d9ee
MW
130 /**
131 * Number of times we retransmit messages before giving up
132 */
133 u_int retransmit_tries;
134
135 /**
136 * Retransmission timeout
137 */
138 double retransmit_timeout;
139
140 /**
141 * Base to calculate retransmission timeout
142 */
143 double retransmit_base;
144};
145
146/**
147 * flush all tasks in the task manager
148 */
149static void flush(private_task_manager_t *this)
150{
151 this->queued_tasks->destroy_offset(this->queued_tasks,
152 offsetof(task_t, destroy));
153 this->queued_tasks = linked_list_create();
154 this->passive_tasks->destroy_offset(this->passive_tasks,
155 offsetof(task_t, destroy));
156 this->passive_tasks = linked_list_create();
157 this->active_tasks->destroy_offset(this->active_tasks,
158 offsetof(task_t, destroy));
159 this->active_tasks = linked_list_create();
160}
161
26b55dc6
MW
162/**
163 * move a task of a specific type from the queue to the active list
164 */
165static bool activate_task(private_task_manager_t *this, task_type_t type)
166{
167 enumerator_t *enumerator;
168 task_t *task;
169 bool found = FALSE;
170
171 enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
172 while (enumerator->enumerate(enumerator, (void**)&task))
173 {
174 if (task->get_type(task) == type)
175 {
176 DBG2(DBG_IKE, " activating %N task", task_type_names, type);
177 this->queued_tasks->remove_at(this->queued_tasks, enumerator);
178 this->active_tasks->insert_last(this->active_tasks, task);
179 found = TRUE;
180 break;
181 }
182 }
183 enumerator->destroy(enumerator);
184 return found;
185}
186
23f4e4b4
CO
187METHOD(task_manager_t, retransmit, status_t,
188 private_task_manager_t *this, u_int32_t message_id)
189{
190 if (message_id == this->initiating.mid)
191 {
192 u_int32_t timeout;
193 job_t *job;
194 enumerator_t *enumerator;
195 packet_t *packet;
196 task_t *task;
197
198 if (this->initiating.retransmitted <= this->retransmit_tries)
199 {
200 timeout = (u_int32_t)(this->retransmit_timeout * 1000.0 *
201 pow(this->retransmit_base, this->initiating.retransmitted));
202 }
203 else
204 {
205 DBG1(DBG_IKE, "giving up after %d retransmits",
206 this->initiating.retransmitted - 1);
207 if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING)
208 {
209 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
210 }
211 return DESTROY_ME;
212 }
213
214 if (this->initiating.retransmitted)
215 {
216 DBG1(DBG_IKE, "retransmit %d of request with message ID %d",
217 this->initiating.retransmitted, message_id);
218 }
219 packet = this->initiating.packet->clone(this->initiating.packet);
220 charon->sender->send(charon->sender, packet);
221
222 this->initiating.retransmitted++;
223 job = (job_t*)retransmit_job_create(this->initiating.mid,
224 this->ike_sa->get_id(this->ike_sa));
225 lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout);
226 }
227 return SUCCESS;
228}
229
4a09d9ee
MW
230METHOD(task_manager_t, initiate, status_t,
231 private_task_manager_t *this)
232{
26b55dc6
MW
233 enumerator_t *enumerator;
234 task_t *task;
235 message_t *message;
236 host_t *me, *other;
237 status_t status;
73aaf76b
MW
238 exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED;
239
240 if (!this->rng)
241 {
242 DBG1(DBG_IKE, "no RNG supported");
243 return FAILED;
244 }
26b55dc6
MW
245
246 if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED)
247 {
248 DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress",
249 exchange_type_names, this->initiating.type);
250 /* do not initiate if we already have a message in the air */
251 return SUCCESS;
252 }
253
254 if (this->active_tasks->get_count(this->active_tasks) == 0)
255 {
256 DBG2(DBG_IKE, "activating new tasks");
257 switch (this->ike_sa->get_state(this->ike_sa))
258 {
259 case IKE_CREATED:
a09972df 260 if (activate_task(this, TASK_MAIN_MODE))
26b55dc6
MW
261 {
262 exchange = ID_PROT;
263 }
264 break;
744c0801
MW
265 case IKE_ESTABLISHED:
266 if (activate_task(this, TASK_QUICK_MODE))
267 {
268 exchange = QUICK_MODE;
269 }
23f4e4b4
CO
270
271 if (activate_task(this, TASK_XAUTH_REQUEST))
272 {
273 exchange = TRANSACTION;
274 }
744c0801 275 break;
26b55dc6
MW
276 default:
277 break;
278 }
279 }
280 else
281 {
282 DBG2(DBG_IKE, "reinitiating already active tasks");
283 enumerator = this->active_tasks->create_enumerator(this->active_tasks);
284 while (enumerator->enumerate(enumerator, (void**)&task))
285 {
286 DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task));
287 switch (task->get_type(task))
288 {
a09972df 289 case TASK_MAIN_MODE:
26b55dc6
MW
290 exchange = ID_PROT;
291 break;
744c0801
MW
292 case TASK_QUICK_MODE:
293 exchange = QUICK_MODE;
294 break;
26b55dc6
MW
295 default:
296 continue;
297 }
298 break;
299 }
300 enumerator->destroy(enumerator);
301 }
302
73aaf76b 303 if (exchange == EXCHANGE_TYPE_UNDEFINED)
26b55dc6
MW
304 {
305 DBG2(DBG_IKE, "nothing to initiate");
306 /* nothing to do yet... */
307 return SUCCESS;
308 }
309
310 me = this->ike_sa->get_my_host(this->ike_sa);
311 other = this->ike_sa->get_other_host(this->ike_sa);
312
313 message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION);
314 if (exchange != ID_PROT)
315 {
73aaf76b
MW
316 this->rng->get_bytes(this->rng, sizeof(this->initiating.mid),
317 (void*)&this->initiating.mid);
318 message->set_message_id(message, this->initiating.mid);
26b55dc6
MW
319 }
320 message->set_source(message, me->clone(me));
321 message->set_destination(message, other->clone(other));
322 message->set_exchange_type(message, exchange);
323 this->initiating.type = exchange;
324 this->initiating.retransmitted = 0;
325
326 enumerator = this->active_tasks->create_enumerator(this->active_tasks);
327 while (enumerator->enumerate(enumerator, (void*)&task))
328 {
329 switch (task->build(task, message))
330 {
331 case SUCCESS:
332 /* task completed, remove it */
333 this->active_tasks->remove_at(this->active_tasks, enumerator);
334 task->destroy(task);
335 break;
336 case NEED_MORE:
337 /* processed, but task needs another exchange */
338 break;
339 case FAILED:
340 default:
341 if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING)
342 {
343 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
344 }
345 /* FALL */
346 case DESTROY_ME:
347 /* critical failure, destroy IKE_SA */
348 enumerator->destroy(enumerator);
349 message->destroy(message);
350 flush(this);
351 return DESTROY_ME;
352 }
353 }
354 enumerator->destroy(enumerator);
355
356 /* update exchange type if a task changed it */
357 this->initiating.type = message->get_exchange_type(message);
358
359 status = this->ike_sa->generate_message(this->ike_sa, message,
360 &this->initiating.packet);
361 if (status != SUCCESS)
362 {
363 /* message generation failed. There is nothing more to do than to
364 * close the SA */
365 message->destroy(message);
366 flush(this);
367 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
368 return DESTROY_ME;
369 }
370 message->destroy(message);
371
372 charon->sender->send(charon->sender,
373 this->initiating.packet->clone(this->initiating.packet));
374
375 return SUCCESS;
4a09d9ee
MW
376}
377
378/**
379 * handle exchange collisions
380 */
381static bool handle_collisions(private_task_manager_t *this, task_t *task)
382{
383 return FALSE;
384}
385
386/**
387 * build a response depending on the "passive" task list
388 */
389static status_t build_response(private_task_manager_t *this, message_t *request)
390{
391 enumerator_t *enumerator;
392 task_t *task;
393 message_t *message;
394 host_t *me, *other;
395 bool delete = FALSE;
396 status_t status;
397
398 me = request->get_destination(request);
399 other = request->get_source(request);
400
401 message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION);
402 message->set_exchange_type(message, request->get_exchange_type(request));
403 /* send response along the path the request came in */
404 message->set_source(message, me->clone(me));
405 message->set_destination(message, other->clone(other));
73aaf76b 406 message->set_message_id(message, request->get_message_id(request));
4a09d9ee
MW
407 message->set_request(message, FALSE);
408
409 enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
410 while (enumerator->enumerate(enumerator, (void*)&task))
411 {
412 switch (task->build(task, message))
413 {
414 case SUCCESS:
415 /* task completed, remove it */
416 this->passive_tasks->remove_at(this->passive_tasks, enumerator);
417 if (!handle_collisions(this, task))
418 {
419 task->destroy(task);
420 }
421 break;
422 case NEED_MORE:
423 /* processed, but task needs another exchange */
424 if (handle_collisions(this, task))
425 {
426 this->passive_tasks->remove_at(this->passive_tasks,
427 enumerator);
428 }
429 break;
430 case FAILED:
431 default:
432 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
433 /* FALL */
434 case DESTROY_ME:
435 /* destroy IKE_SA, but SEND response first */
436 delete = TRUE;
437 break;
438 }
439 if (delete)
440 {
441 break;
442 }
443 }
444 enumerator->destroy(enumerator);
445
446 /* message complete, send it */
447 DESTROY_IF(this->responding.packet);
448 this->responding.packet = NULL;
449 status = this->ike_sa->generate_message(this->ike_sa, message,
450 &this->responding.packet);
451 message->destroy(message);
452 if (status != SUCCESS)
453 {
454 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
455 return DESTROY_ME;
456 }
457
458 charon->sender->send(charon->sender,
459 this->responding.packet->clone(this->responding.packet));
460 if (delete)
461 {
462 return DESTROY_ME;
463 }
464 return SUCCESS;
465}
466
467/**
468 * handle an incoming request message
469 */
470static status_t process_request(private_task_manager_t *this,
471 message_t *message)
472{
473 enumerator_t *enumerator;
474 task_t *task = NULL;
475
476 if (this->passive_tasks->get_count(this->passive_tasks) == 0)
477 { /* create tasks depending on request type, if not already some queued */
478 switch (message->get_exchange_type(message))
479 {
480 case ID_PROT:
c73c832c
MW
481 task = (task_t *)main_mode_create(this->ike_sa, FALSE);
482 this->passive_tasks->insert_last(this->passive_tasks, task);
4a09d9ee
MW
483 break;
484 case AGGRESSIVE:
485 /* TODO-IKEv1: agressive mode */
486 return FAILED;
487 case QUICK_MODE:
744c0801
MW
488 task = (task_t *)quick_mode_create(this->ike_sa, NULL,
489 NULL, NULL);
490 this->passive_tasks->insert_last(this->passive_tasks, task);
491 break;
4a09d9ee
MW
492 case INFORMATIONAL_V1:
493 /* TODO-IKEv1: informational */
494 return FAILED;
495 default:
496 return FAILED;
497 }
498 }
499 /* let the tasks process the message */
500 enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
501 while (enumerator->enumerate(enumerator, (void*)&task))
502 {
503 switch (task->process(task, message))
504 {
505 case SUCCESS:
506 /* task completed, remove it */
507 this->passive_tasks->remove_at(this->passive_tasks, enumerator);
508 task->destroy(task);
21b7db99
MW
509 enumerator->destroy(enumerator);
510 return SUCCESS;
4a09d9ee
MW
511 case NEED_MORE:
512 /* processed, but task needs at least another call to build() */
513 break;
514 case FAILED:
515 default:
516 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
517 /* FALL */
518 case DESTROY_ME:
519 /* critical failure, destroy IKE_SA */
520 this->passive_tasks->remove_at(this->passive_tasks, enumerator);
521 enumerator->destroy(enumerator);
522 task->destroy(task);
523 return DESTROY_ME;
524 }
525 }
526 enumerator->destroy(enumerator);
527
528 return build_response(this, message);
529}
530
26b55dc6
MW
531/**
532 * handle an incoming response message
533 */
534static status_t process_response(private_task_manager_t *this,
535 message_t *message)
536{
537 enumerator_t *enumerator;
538 task_t *task;
539
540 if (message->get_exchange_type(message) != this->initiating.type)
541 {
542 DBG1(DBG_IKE, "received %N response, but expected %N",
543 exchange_type_names, message->get_exchange_type(message),
544 exchange_type_names, this->initiating.type);
545 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
546 return DESTROY_ME;
547 }
548
549 enumerator = this->active_tasks->create_enumerator(this->active_tasks);
550 while (enumerator->enumerate(enumerator, (void*)&task))
551 {
552 switch (task->process(task, message))
553 {
554 case SUCCESS:
555 /* task completed, remove it */
556 this->active_tasks->remove_at(this->active_tasks, enumerator);
557 task->destroy(task);
558 break;
559 case NEED_MORE:
560 /* processed, but task needs another exchange */
561 break;
562 case FAILED:
563 default:
564 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
565 /* FALL */
566 case DESTROY_ME:
567 /* critical failure, destroy IKE_SA */
568 this->active_tasks->remove_at(this->active_tasks, enumerator);
569 enumerator->destroy(enumerator);
570 task->destroy(task);
571 return DESTROY_ME;
572 }
573 }
574 enumerator->destroy(enumerator);
575
576 this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
577 this->initiating.packet->destroy(this->initiating.packet);
578 this->initiating.packet = NULL;
579
580 return initiate(this);
581}
582
4a09d9ee
MW
583METHOD(task_manager_t, process_message, status_t,
584 private_task_manager_t *this, message_t *msg)
585{
73aaf76b 586 u_int32_t hash, mid;
3d59c5c3 587 host_t *me, *other;
73aaf76b
MW
588
589 mid = msg->get_message_id(msg);
73aaf76b 590
3d59c5c3
TB
591 /* TODO-IKEv1: update hosts more selectively */
592 me = msg->get_destination(msg);
593 other = msg->get_source(msg);
594
73aaf76b
MW
595 if ((mid && mid == this->initiating.mid) ||
596 (this->initiating.mid == 0 &&
597 this->active_tasks->get_count(this->active_tasks)))
4a09d9ee 598 {
3d59c5c3 599 this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE);
73aaf76b
MW
600 charon->bus->message(charon->bus, msg, FALSE);
601 if (process_response(this, msg) != SUCCESS)
4a09d9ee
MW
602 {
603 flush(this);
604 return DESTROY_ME;
605 }
606 }
607 else
608 {
9cc8bd4f
MW
609 hash = chunk_hash(msg->get_packet_data(msg));
610 if (hash == this->responding.hash)
73aaf76b
MW
611 {
612 DBG1(DBG_IKE, "received retransmit of request with ID %d, "
613 "retransmitting response", mid);
614 charon->sender->send(charon->sender,
615 this->responding.packet->clone(this->responding.packet));
616 return SUCCESS;
617 }
3d59c5c3 618 this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE);
73aaf76b
MW
619 charon->bus->message(charon->bus, msg, TRUE);
620 if (process_request(this, msg) != SUCCESS)
26b55dc6
MW
621 {
622 flush(this);
623 return DESTROY_ME;
624 }
73aaf76b 625
73aaf76b 626 this->responding.mid = mid;
9cc8bd4f 627 this->responding.hash = hash;
4a09d9ee
MW
628 }
629 return SUCCESS;
630}
631
632METHOD(task_manager_t, queue_task, void,
633 private_task_manager_t *this, task_t *task)
634{
635 DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task));
636 this->queued_tasks->insert_last(this->queued_tasks, task);
637}
638
639METHOD(task_manager_t, adopt_tasks, void,
640 private_task_manager_t *this, task_manager_t *other_public)
641{
642 private_task_manager_t *other = (private_task_manager_t*)other_public;
643 task_t *task;
644
645 /* move queued tasks from other to this */
646 while (other->queued_tasks->remove_last(other->queued_tasks,
647 (void**)&task) == SUCCESS)
648 {
649 DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task));
650 task->migrate(task, this->ike_sa);
651 this->queued_tasks->insert_first(this->queued_tasks, task);
652 }
653}
654
655METHOD(task_manager_t, busy, bool,
656 private_task_manager_t *this)
657{
658 return (this->active_tasks->get_count(this->active_tasks) > 0);
659}
660
661METHOD(task_manager_t, incr_mid, void,
662 private_task_manager_t *this, bool initiate)
663{
4a09d9ee
MW
664}
665
666METHOD(task_manager_t, reset, void,
667 private_task_manager_t *this, u_int32_t initiate, u_int32_t respond)
668{
4a09d9ee
MW
669}
670
671METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
672 private_task_manager_t *this, task_queue_t queue)
673{
674 switch (queue)
675 {
676 case TASK_QUEUE_ACTIVE:
677 return this->active_tasks->create_enumerator(this->active_tasks);
678 case TASK_QUEUE_PASSIVE:
679 return this->passive_tasks->create_enumerator(this->passive_tasks);
680 case TASK_QUEUE_QUEUED:
681 return this->queued_tasks->create_enumerator(this->queued_tasks);
682 default:
683 return enumerator_create_empty();
684 }
685}
686
687METHOD(task_manager_t, destroy, void,
688 private_task_manager_t *this)
689{
690 flush(this);
691
692 this->active_tasks->destroy(this->active_tasks);
693 this->queued_tasks->destroy(this->queued_tasks);
694 this->passive_tasks->destroy(this->passive_tasks);
695
696 DESTROY_IF(this->responding.packet);
697 DESTROY_IF(this->initiating.packet);
73aaf76b 698 DESTROY_IF(this->rng);
4a09d9ee
MW
699 free(this);
700}
701
702/*
703 * see header file
704 */
705task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
706{
707 private_task_manager_t *this;
708
709 INIT(this,
710 .public = {
711 .task_manager = {
712 .process_message = _process_message,
713 .queue_task = _queue_task,
714 .initiate = _initiate,
715 .retransmit = _retransmit,
716 .incr_mid = _incr_mid,
717 .reset = _reset,
718 .adopt_tasks = _adopt_tasks,
719 .busy = _busy,
720 .create_task_enumerator = _create_task_enumerator,
721 .destroy = _destroy,
722 },
723 },
724 .ike_sa = ike_sa,
725 .initiating.type = EXCHANGE_TYPE_UNDEFINED,
73aaf76b 726 .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
4a09d9ee
MW
727 .queued_tasks = linked_list_create(),
728 .active_tasks = linked_list_create(),
729 .passive_tasks = linked_list_create(),
730 .retransmit_tries = lib->settings->get_int(lib->settings,
731 "charon.retransmit_tries", RETRANSMIT_TRIES),
732 .retransmit_timeout = lib->settings->get_double(lib->settings,
733 "charon.retransmit_timeout", RETRANSMIT_TIMEOUT),
734 .retransmit_base = lib->settings->get_double(lib->settings,
735 "charon.retransmit_base", RETRANSMIT_BASE),
736 );
737
738 return &this->public;
739}