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