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