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