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