updated API doc for socket.h
[strongswan.git] / src / charon / sa / ike_sa_manager.c
1 /*
2 * Copyright (C) 2005-2006 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
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 * $Id$
17 */
18
19 #include <string.h>
20
21 #include "ike_sa_manager.h"
22
23 #include <daemon.h>
24 #include <sa/ike_sa_id.h>
25 #include <bus/bus.h>
26 #include <utils/mutex.h>
27 #include <utils/linked_list.h>
28 #include <crypto/hashers/hasher.h>
29
30 typedef struct entry_t entry_t;
31
32 /**
33 * An entry in the linked list, contains IKE_SA, locking and lookup data.
34 */
35 struct entry_t {
36
37 /**
38 * Number of threads waiting for this ike_sa_t object.
39 */
40 int waiting_threads;
41
42 /**
43 * Condvar where threads can wait until ike_sa_t object is free for use again.
44 */
45 condvar_t *condvar;
46
47 /**
48 * Is this ike_sa currently checked out?
49 */
50 bool checked_out;
51
52 /**
53 * Does this SA drives out new threads?
54 */
55 bool driveout_new_threads;
56
57 /**
58 * Does this SA drives out waiting threads?
59 */
60 bool driveout_waiting_threads;
61
62 /**
63 * Identifiaction of an IKE_SA (SPIs).
64 */
65 ike_sa_id_t *ike_sa_id;
66
67 /**
68 * The contained ike_sa_t object.
69 */
70 ike_sa_t *ike_sa;
71
72 /**
73 * hash of the IKE_SA_INIT message, used to detect retransmissions
74 */
75 chunk_t init_hash;
76
77 /**
78 * remote host address, required for DoS detection
79 */
80 host_t *other;
81
82 /**
83 * own identity, required for duplicate checking
84 */
85 identification_t *my_id;
86
87 /**
88 * remote identity, required for duplicate checking
89 */
90 identification_t *other_id;
91
92 /**
93 * message ID currently processing, if any
94 */
95 u_int32_t message_id;
96 };
97
98 /**
99 * Implementation of entry_t.destroy.
100 */
101 static status_t entry_destroy(entry_t *this)
102 {
103 /* also destroy IKE SA */
104 this->ike_sa->destroy(this->ike_sa);
105 this->ike_sa_id->destroy(this->ike_sa_id);
106 chunk_free(&this->init_hash);
107 DESTROY_IF(this->other);
108 DESTROY_IF(this->my_id);
109 DESTROY_IF(this->other_id);
110 this->condvar->destroy(this->condvar);
111 free(this);
112 return SUCCESS;
113 }
114
115 /**
116 * Creates a new entry for the ike_sa_t list.
117 */
118 static entry_t *entry_create(ike_sa_id_t *ike_sa_id)
119 {
120 entry_t *this = malloc_thing(entry_t);
121
122 this->waiting_threads = 0;
123 this->condvar = condvar_create(CONDVAR_DEFAULT);
124
125 /* we set checkout flag when we really give it out */
126 this->checked_out = FALSE;
127 this->driveout_new_threads = FALSE;
128 this->driveout_waiting_threads = FALSE;
129 this->message_id = -1;
130 this->init_hash = chunk_empty;
131 this->other = NULL;
132 this->my_id = NULL;
133 this->other_id = NULL;
134
135 /* ike_sa_id is always cloned */
136 this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
137
138 /* create new ike_sa */
139 this->ike_sa = ike_sa_create(ike_sa_id);
140
141 return this;
142 }
143
144
145 typedef struct private_ike_sa_manager_t private_ike_sa_manager_t;
146
147 /**
148 * Additional private members of ike_sa_manager_t.
149 */
150 struct private_ike_sa_manager_t {
151 /**
152 * Public interface of ike_sa_manager_t.
153 */
154 ike_sa_manager_t public;
155
156 /**
157 * Lock for exclusivly accessing the manager.
158 */
159 mutex_t *mutex;
160
161 /**
162 * Linked list with entries for the ike_sa_t objects.
163 */
164 linked_list_t *ike_sa_list;
165
166 /**
167 * RNG to get random SPIs for our side
168 */
169 rng_t *rng;
170
171 /**
172 * SHA1 hasher for IKE_SA_INIT retransmit detection
173 */
174 hasher_t *hasher;
175
176 /**
177 * reuse existing IKE_SAs in checkout_by_config
178 */
179 bool reuse_ikesa;
180 };
181
182 /**
183 * Implementation of private_ike_sa_manager_t.get_entry_by_id.
184 */
185 static status_t get_entry_by_id(private_ike_sa_manager_t *this,
186 ike_sa_id_t *ike_sa_id, entry_t **entry)
187 {
188 enumerator_t *enumerator;
189 entry_t *current;
190 status_t status;
191
192 /* create enumerator over list of ike_sa's */
193 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
194
195 /* default status */
196 status = NOT_FOUND;
197
198 while (enumerator->enumerate(enumerator, &current))
199 {
200 if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id))
201 {
202 DBG2(DBG_MGR, "found entry by both SPIs");
203 *entry = current;
204 status = SUCCESS;
205 break;
206 }
207 if (ike_sa_id->get_responder_spi(ike_sa_id) == 0 ||
208 current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0)
209 {
210 /* seems to be a half ready ike_sa */
211 if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
212 ike_sa_id->get_initiator_spi(ike_sa_id)) &&
213 (current->ike_sa_id->is_initiator(ike_sa_id) ==
214 ike_sa_id->is_initiator(current->ike_sa_id)))
215 {
216 DBG2(DBG_MGR, "found entry by initiator SPI");
217 *entry = current;
218 status = SUCCESS;
219 break;
220 }
221 }
222 }
223
224 enumerator->destroy(enumerator);
225 return status;
226 }
227
228 /**
229 * Implementation of private_ike_sa_manager_t.get_entry_by_sa.
230 */
231 static status_t get_entry_by_sa(private_ike_sa_manager_t *this,
232 ike_sa_t *ike_sa, entry_t **entry)
233 {
234 enumerator_t *enumerator;
235 entry_t *current;
236 status_t status;
237
238 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
239
240 /* default status */
241 status = NOT_FOUND;
242
243 while (enumerator->enumerate(enumerator, &current))
244 {
245 /* only pointers are compared */
246 if (current->ike_sa == ike_sa)
247 {
248 DBG2(DBG_MGR, "found entry by pointer");
249 *entry = current;
250 status = SUCCESS;
251 break;
252 }
253 }
254 enumerator->destroy(enumerator);
255
256 return status;
257 }
258
259 /**
260 * Implementation of private_ike_sa_manager_s.delete_entry.
261 */
262 static status_t delete_entry(private_ike_sa_manager_t *this, entry_t *entry)
263 {
264 enumerator_t *enumerator;
265 entry_t *current;
266 status_t status;
267
268 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
269
270 status = NOT_FOUND;
271
272 while (enumerator->enumerate(enumerator, &current))
273 {
274 if (current == entry)
275 {
276 /* mark it, so now new threads can get this entry */
277 entry->driveout_new_threads = TRUE;
278 /* wait until all workers have done their work */
279 while (entry->waiting_threads)
280 {
281 /* wake up all */
282 entry->condvar->broadcast(entry->condvar);
283 /* they will wake us again when their work is done */
284 entry->condvar->wait(entry->condvar, this->mutex);
285 }
286
287 DBG2(DBG_MGR, "found entry by pointer, deleting it");
288 this->ike_sa_list->remove_at(this->ike_sa_list, enumerator);
289 entry_destroy(entry);
290 status = SUCCESS;
291 break;
292 }
293 }
294 enumerator->destroy(enumerator);
295 return status;
296 }
297
298 /**
299 * Wait until no other thread is using an IKE_SA, return FALSE if entry not
300 * acquireable
301 */
302 static bool wait_for_entry(private_ike_sa_manager_t *this, entry_t *entry)
303 {
304 if (entry->driveout_new_threads)
305 {
306 /* we are not allowed to get this */
307 return FALSE;
308 }
309 while (entry->checked_out && !entry->driveout_waiting_threads)
310 {
311 /* so wait until we can get it for us.
312 * we register us as waiting. */
313 entry->waiting_threads++;
314 entry->condvar->wait(entry->condvar, this->mutex);
315 entry->waiting_threads--;
316 }
317 /* hm, a deletion request forbids us to get this SA, get next one */
318 if (entry->driveout_waiting_threads)
319 {
320 /* we must signal here, others may be waiting on it, too */
321 entry->condvar->signal(entry->condvar);
322 return FALSE;
323 }
324 return TRUE;
325 }
326
327 /**
328 * Implementation of private_ike_sa_manager_t.get_next_spi.
329 */
330 static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
331 {
332 u_int64_t spi;
333
334 this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi);
335 return spi;
336 }
337
338 /**
339 * Implementation of of ike_sa_manager.checkout.
340 */
341 static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
342 {
343 ike_sa_t *ike_sa = NULL;
344 entry_t *entry;
345
346 DBG2(DBG_MGR, "checkout IKE_SA, %d IKE_SAs in manager",
347 this->ike_sa_list->get_count(this->ike_sa_list));
348
349 this->mutex->lock(this->mutex);
350 if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
351 {
352 if (wait_for_entry(this, entry))
353 {
354 DBG2(DBG_MGR, "IKE_SA successfully checked out");
355 entry->checked_out = TRUE;
356 ike_sa = entry->ike_sa;
357 }
358 }
359 this->mutex->unlock(this->mutex);
360 charon->bus->set_sa(charon->bus, ike_sa);
361 return ike_sa;
362 }
363
364 /**
365 * Implementation of of ike_sa_manager.checkout_new.
366 */
367 static ike_sa_t *checkout_new(private_ike_sa_manager_t* this, bool initiator)
368 {
369 entry_t *entry;
370 ike_sa_id_t *id;
371
372 if (initiator)
373 {
374 id = ike_sa_id_create(get_next_spi(this), 0, TRUE);
375 }
376 else
377 {
378 id = ike_sa_id_create(0, get_next_spi(this), FALSE);
379 }
380 entry = entry_create(id);
381 id->destroy(id);
382 this->mutex->lock(this->mutex);
383 this->ike_sa_list->insert_last(this->ike_sa_list, entry);
384 entry->checked_out = TRUE;
385 this->mutex->unlock(this->mutex);
386 DBG2(DBG_MGR, "created IKE_SA, %d IKE_SAs in manager",
387 this->ike_sa_list->get_count(this->ike_sa_list));
388 return entry->ike_sa;
389 }
390
391 /**
392 * Implementation of of ike_sa_manager.checkout_by_message.
393 */
394 static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
395 message_t *message)
396 {
397 entry_t *entry;
398 ike_sa_t *ike_sa = NULL;
399 ike_sa_id_t *id = message->get_ike_sa_id(message);
400 id = id->clone(id);
401 id->switch_initiator(id);
402
403 DBG2(DBG_MGR, "checkout IKE_SA by message, %d IKE_SAs in manager",
404 this->ike_sa_list->get_count(this->ike_sa_list));
405
406 if (message->get_request(message) &&
407 message->get_exchange_type(message) == IKE_SA_INIT)
408 {
409 /* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */
410 enumerator_t *enumerator;
411 chunk_t data, hash;
412
413 data = message->get_packet_data(message);
414 this->hasher->allocate_hash(this->hasher, data, &hash);
415 chunk_free(&data);
416
417 this->mutex->lock(this->mutex);
418 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
419 while (enumerator->enumerate(enumerator, &entry))
420 {
421 if (chunk_equals(hash, entry->init_hash))
422 {
423 if (entry->message_id == 0)
424 {
425 enumerator->destroy(enumerator);
426 this->mutex->unlock(this->mutex);
427 chunk_free(&hash);
428 id->destroy(id);
429 DBG1(DBG_MGR, "ignoring IKE_SA_INIT, already processing");
430 return NULL;
431 }
432 else if (wait_for_entry(this, entry))
433 {
434 DBG2(DBG_MGR, "IKE_SA checked out by hash");
435 entry->checked_out = TRUE;
436 entry->message_id = message->get_message_id(message);
437 ike_sa = entry->ike_sa;
438 }
439 break;
440 }
441 }
442 enumerator->destroy(enumerator);
443 this->mutex->unlock(this->mutex);
444
445 if (ike_sa == NULL)
446 {
447 if (id->get_responder_spi(id) == 0 &&
448 message->get_exchange_type(message) == IKE_SA_INIT)
449 {
450 /* no IKE_SA found, create a new one */
451 id->set_responder_spi(id, get_next_spi(this));
452 entry = entry_create(id);
453
454 this->mutex->lock(this->mutex);
455 this->ike_sa_list->insert_last(this->ike_sa_list, entry);
456 entry->checked_out = TRUE;
457 entry->message_id = message->get_message_id(message);
458 this->mutex->unlock(this->mutex);
459 entry->init_hash = hash;
460 ike_sa = entry->ike_sa;
461 }
462 else
463 {
464 chunk_free(&hash);
465 DBG1(DBG_MGR, "ignoring message, no such IKE_SA");
466 }
467 }
468 else
469 {
470 chunk_free(&hash);
471 }
472 id->destroy(id);
473 charon->bus->set_sa(charon->bus, ike_sa);
474 return ike_sa;
475 }
476
477 this->mutex->lock(this->mutex);
478 if (get_entry_by_id(this, id, &entry) == SUCCESS)
479 {
480 /* only check out if we are not processing this request */
481 if (message->get_request(message) &&
482 message->get_message_id(message) == entry->message_id)
483 {
484 DBG1(DBG_MGR, "ignoring request with ID %d, already processing",
485 entry->message_id);
486 }
487 else if (wait_for_entry(this, entry))
488 {
489 ike_sa_id_t *ike_id = entry->ike_sa->get_id(entry->ike_sa);
490 DBG2(DBG_MGR, "IKE_SA successfully checked out");
491 entry->checked_out = TRUE;
492 entry->message_id = message->get_message_id(message);
493 if (ike_id->get_responder_spi(ike_id) == 0)
494 {
495 ike_id->set_responder_spi(ike_id, id->get_responder_spi(id));
496 }
497 ike_sa = entry->ike_sa;
498 }
499 }
500 this->mutex->unlock(this->mutex);
501 id->destroy(id);
502 charon->bus->set_sa(charon->bus, ike_sa);
503 return ike_sa;
504 }
505
506 /**
507 * Implementation of of ike_sa_manager.checkout_by_config.
508 */
509 static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this,
510 peer_cfg_t *peer_cfg)
511 {
512 enumerator_t *enumerator;
513 entry_t *entry;
514 ike_sa_t *ike_sa = NULL;
515 identification_t *my_id, *other_id;
516 host_t *my_host, *other_host;
517 ike_cfg_t *ike_cfg;
518
519 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
520 my_id = peer_cfg->get_my_id(peer_cfg);
521 other_id = peer_cfg->get_other_id(peer_cfg);
522 my_host = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg), 0, 0);
523 other_host = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg), 0, 0);
524
525 this->mutex->lock(this->mutex);
526
527 if (my_host && other_host && this->reuse_ikesa)
528 {
529 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
530 while (enumerator->enumerate(enumerator, &entry))
531 {
532 identification_t *found_my_id, *found_other_id;
533 host_t *found_my_host, *found_other_host;
534
535 if (!wait_for_entry(this, entry))
536 {
537 continue;
538 }
539
540 if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING)
541 {
542 /* skip IKE_SA which are not useable */
543 continue;
544 }
545
546 found_my_id = entry->ike_sa->get_my_id(entry->ike_sa);
547 found_other_id = entry->ike_sa->get_other_id(entry->ike_sa);
548 found_my_host = entry->ike_sa->get_my_host(entry->ike_sa);
549 found_other_host = entry->ike_sa->get_other_host(entry->ike_sa);
550
551 if (found_my_id->get_type(found_my_id) == ID_ANY &&
552 found_other_id->get_type(found_other_id) == ID_ANY)
553 {
554 /* IKE_SA has no IDs yet, so we can't use it */
555 continue;
556 }
557 DBG2(DBG_MGR, "candidate IKE_SA for \n"
558 " %H[%D]...%H[%D]\n"
559 " %H[%D]...%H[%D]",
560 my_host, my_id, other_host, other_id,
561 found_my_host, found_my_id, found_other_host, found_other_id);
562 /* compare ID and hosts. Supplied ID may contain wildcards, and IP
563 * may be %any. */
564 if ((my_host->is_anyaddr(my_host) ||
565 my_host->ip_equals(my_host, found_my_host)) &&
566 (other_host->is_anyaddr(other_host) ||
567 other_host->ip_equals(other_host, found_other_host)) &&
568 found_my_id->matches(found_my_id, my_id) &&
569 found_other_id->matches(found_other_id, other_id) &&
570 streq(peer_cfg->get_name(peer_cfg),
571 entry->ike_sa->get_name(entry->ike_sa)))
572 {
573 /* looks good, we take this one */
574 DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]",
575 my_host, my_id, other_host, other_id);
576 entry->checked_out = TRUE;
577 ike_sa = entry->ike_sa;
578 break;
579 }
580 }
581 enumerator->destroy(enumerator);
582 }
583 DESTROY_IF(my_host);
584 DESTROY_IF(other_host);
585
586 if (!ike_sa)
587 {
588 u_int64_t initiator_spi;
589 entry_t *new_entry;
590 ike_sa_id_t *new_ike_sa_id;
591
592 initiator_spi = get_next_spi(this);
593 new_ike_sa_id = ike_sa_id_create(0, 0, TRUE);
594 new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi);
595
596 /* create entry */
597 new_entry = entry_create(new_ike_sa_id);
598 DBG2(DBG_MGR, "created IKE_SA");
599 new_ike_sa_id->destroy(new_ike_sa_id);
600
601 this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
602
603 /* check ike_sa out */
604 DBG2(DBG_MGR, "new IKE_SA created for IDs [%D]...[%D]", my_id, other_id);
605 new_entry->checked_out = TRUE;
606 ike_sa = new_entry->ike_sa;
607 }
608 this->mutex->unlock(this->mutex);
609 charon->bus->set_sa(charon->bus, ike_sa);
610 return ike_sa;
611 }
612
613 /**
614 * Implementation of of ike_sa_manager.checkout_by_id.
615 */
616 static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
617 bool child)
618 {
619 enumerator_t *enumerator;
620 iterator_t *children;
621 entry_t *entry;
622 ike_sa_t *ike_sa = NULL;
623 child_sa_t *child_sa;
624
625 this->mutex->lock(this->mutex);
626
627 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
628 while (enumerator->enumerate(enumerator, &entry))
629 {
630 if (wait_for_entry(this, entry))
631 {
632 /* look for a child with such a reqid ... */
633 if (child)
634 {
635 children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
636 while (children->iterate(children, (void**)&child_sa))
637 {
638 if (child_sa->get_reqid(child_sa) == id)
639 {
640 ike_sa = entry->ike_sa;
641 break;
642 }
643 }
644 children->destroy(children);
645 }
646 else /* ... or for a IKE_SA with such a unique id */
647 {
648 if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
649 {
650 ike_sa = entry->ike_sa;
651 }
652 }
653 /* got one, return */
654 if (ike_sa)
655 {
656 entry->checked_out = TRUE;
657 break;
658 }
659 }
660 }
661 enumerator->destroy(enumerator);
662 this->mutex->unlock(this->mutex);
663
664 charon->bus->set_sa(charon->bus, ike_sa);
665 return ike_sa;
666 }
667
668 /**
669 * Implementation of of ike_sa_manager.checkout_by_name.
670 */
671 static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
672 bool child)
673 {
674 enumerator_t *enumerator;
675 iterator_t *children;
676 entry_t *entry;
677 ike_sa_t *ike_sa = NULL;
678 child_sa_t *child_sa;
679
680 this->mutex->lock(this->mutex);
681
682 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
683 while (enumerator->enumerate(enumerator, &entry))
684 {
685 if (wait_for_entry(this, entry))
686 {
687 /* look for a child with such a policy name ... */
688 if (child)
689 {
690 children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
691 while (children->iterate(children, (void**)&child_sa))
692 {
693 if (streq(child_sa->get_name(child_sa), name))
694 {
695 ike_sa = entry->ike_sa;
696 break;
697 }
698 }
699 children->destroy(children);
700 }
701 else /* ... or for a IKE_SA with such a connection name */
702 {
703 if (streq(entry->ike_sa->get_name(entry->ike_sa), name))
704 {
705 ike_sa = entry->ike_sa;
706 }
707 }
708 /* got one, return */
709 if (ike_sa)
710 {
711 entry->checked_out = TRUE;
712 break;
713 }
714 }
715 }
716 enumerator->destroy(enumerator);
717 this->mutex->unlock(this->mutex);
718
719 charon->bus->set_sa(charon->bus, ike_sa);
720 return ike_sa;
721 }
722
723 /**
724 * Implementation of ike_sa_manager_t.checkout_duplicate.
725 */
726 static ike_sa_t* checkout_duplicate(private_ike_sa_manager_t *this,
727 ike_sa_t *ike_sa)
728 {
729 enumerator_t *enumerator;
730 entry_t *entry;
731 ike_sa_t *duplicate = NULL;
732 identification_t *me, *other;
733
734 me = ike_sa->get_my_id(ike_sa);
735 other = ike_sa->get_other_id(ike_sa);
736
737 this->mutex->lock(this->mutex);
738 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
739 while (enumerator->enumerate(enumerator, &entry))
740 {
741 if (entry->ike_sa == ike_sa)
742 { /* self is not a duplicate */
743 continue;
744 }
745 if (entry->my_id && me->equals(me, entry->my_id) &&
746 entry->other_id && other->equals(other, entry->other_id))
747 {
748 /* we are sure that the other entry is not calling
749 * checkout_duplicate here, as the identities in entry would not
750 * have been set yet. Otherwise we would risk a deadlock. */
751 if (wait_for_entry(this, entry))
752 {
753 duplicate = entry->ike_sa;
754 entry->checked_out = TRUE;
755 break;
756 }
757 }
758 }
759 enumerator->destroy(enumerator);
760 this->mutex->unlock(this->mutex);
761 return duplicate;
762 }
763
764 /**
765 * enumerator cleanup function
766 */
767 static void enumerator_unlock(private_ike_sa_manager_t *this)
768 {
769 this->mutex->unlock(this->mutex);
770 }
771
772 /**
773 * enumerator filter function
774 */
775 static bool enumerator_filter(private_ike_sa_manager_t *this,
776 entry_t **in, ike_sa_t **out)
777 {
778 if (wait_for_entry(this, *in))
779 {
780 *out = (*in)->ike_sa;
781 return TRUE;
782 }
783 return FALSE;
784 }
785
786 /**
787 * Implementation of ike_sa_manager_t.create_iterator.
788 */
789 static enumerator_t *create_enumerator(private_ike_sa_manager_t* this)
790 {
791 this->mutex->lock(this->mutex);
792 return enumerator_create_filter(
793 this->ike_sa_list->create_enumerator(this->ike_sa_list),
794 (void*)enumerator_filter, this, (void*)enumerator_unlock);
795 }
796
797 /**
798 * Implementation of ike_sa_manager_t.checkin.
799 */
800 static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
801 {
802 /* to check the SA back in, we look for the pointer of the ike_sa
803 * in all entries.
804 * We can't search by SPI's since the MAY have changed (e.g. on reception
805 * of a IKE_SA_INIT response). Updating of the SPI MAY be necessary...
806 */
807 status_t retval;
808 entry_t *entry;
809 ike_sa_id_t *ike_sa_id;
810 host_t *other;
811 identification_t *my_id, *other_id;
812
813 ike_sa_id = ike_sa->get_id(ike_sa);
814
815 DBG2(DBG_MGR, "checkin IKE_SA");
816
817 this->mutex->lock(this->mutex);
818
819 /* look for the entry */
820 if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
821 {
822 /* ike_sa_id must be updated */
823 entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
824 /* signal waiting threads */
825 entry->checked_out = FALSE;
826 entry->message_id = -1;
827 /* apply remote address for DoS detection */
828 other = ike_sa->get_other_host(ike_sa);
829 if (!entry->other || !other->equals(other, entry->other))
830 {
831 DESTROY_IF(entry->other);
832 entry->other = other->clone(other);
833 }
834 /* apply identities for diplicate test */
835 my_id = ike_sa->get_my_id(ike_sa);
836 other_id = ike_sa->get_other_id(ike_sa);
837 if (!entry->my_id ||
838 entry->my_id->get_type(entry->my_id) == ID_ANY)
839 {
840 DESTROY_IF(entry->my_id);
841 entry->my_id = my_id->clone(my_id);
842 }
843 if (!entry->other_id ||
844 entry->other_id->get_type(entry->other_id) == ID_ANY)
845 {
846 DESTROY_IF(entry->other_id);
847 entry->other_id = other_id->clone(other_id);
848 }
849 DBG2(DBG_MGR, "check-in of IKE_SA successful.");
850 entry->condvar->signal(entry->condvar);
851 retval = SUCCESS;
852 }
853 else
854 {
855 DBG2(DBG_MGR, "tried to check in nonexisting IKE_SA");
856 /* this SA is no more, this REALLY should not happen */
857 retval = NOT_FOUND;
858 }
859
860 DBG2(DBG_MGR, "%d IKE_SAs in manager now",
861 this->ike_sa_list->get_count(this->ike_sa_list));
862 this->mutex->unlock(this->mutex);
863
864 charon->bus->set_sa(charon->bus, NULL);
865 return retval;
866 }
867
868
869 /**
870 * Implementation of ike_sa_manager_t.checkin_and_destroy.
871 */
872 static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
873 {
874 /* deletion is a bit complex, we must garant that no thread is waiting for
875 * this SA.
876 * We take this SA from the list, and start signaling while threads
877 * are in the condvar.
878 */
879 entry_t *entry;
880 status_t retval;
881 ike_sa_id_t *ike_sa_id;
882
883 ike_sa_id = ike_sa->get_id(ike_sa);
884 DBG2(DBG_MGR, "checkin and destroy IKE_SA");
885
886 this->mutex->lock(this->mutex);
887
888 if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
889 {
890 /* drive out waiting threads, as we are in hurry */
891 entry->driveout_waiting_threads = TRUE;
892
893 delete_entry(this, entry);
894
895 DBG2(DBG_MGR, "check-in and destroy of IKE_SA successful");
896 retval = SUCCESS;
897 }
898 else
899 {
900 DBG2(DBG_MGR, "tried to check-in and delete nonexisting IKE_SA");
901 retval = NOT_FOUND;
902 }
903 charon->bus->set_sa(charon->bus, NULL);
904
905 this->mutex->unlock(this->mutex);
906 return retval;
907 }
908
909 /**
910 * Implementation of ike_sa_manager_t.get_half_open_count.
911 */
912 static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip)
913 {
914 enumerator_t *enumerator;
915 entry_t *entry;
916 int count = 0;
917
918 this->mutex->lock(this->mutex);
919 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
920 while (enumerator->enumerate(enumerator, &entry))
921 {
922 /* we check if we have a responder CONNECTING IKE_SA without checkout */
923 if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) &&
924 entry->ike_sa->get_state(entry->ike_sa) == IKE_CONNECTING)
925 {
926 /* if we have a host, count only matching IKE_SAs */
927 if (ip)
928 {
929 if (entry->other && ip->ip_equals(ip, entry->other))
930 {
931 count++;
932 }
933 }
934 else
935 {
936 count++;
937 }
938 }
939 }
940 enumerator->destroy(enumerator);
941
942 this->mutex->unlock(this->mutex);
943 return count;
944 }
945
946 /**
947 * Implementation of ike_sa_manager_t.flush.
948 */
949 static void flush(private_ike_sa_manager_t *this)
950 {
951 /* destroy all list entries */
952 enumerator_t *enumerator;
953 entry_t *entry;
954
955 this->mutex->lock(this->mutex);
956 DBG2(DBG_MGR, "going to destroy IKE_SA manager and all managed IKE_SA's");
957 /* Step 1: drive out all waiting threads */
958 DBG2(DBG_MGR, "set driveout flags for all stored IKE_SA's");
959 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
960 while (enumerator->enumerate(enumerator, &entry))
961 {
962 /* do not accept new threads, drive out waiting threads */
963 entry->driveout_new_threads = TRUE;
964 entry->driveout_waiting_threads = TRUE;
965 }
966 enumerator->destroy(enumerator);
967 DBG2(DBG_MGR, "wait for all threads to leave IKE_SA's");
968 /* Step 2: wait until all are gone */
969 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
970 while (enumerator->enumerate(enumerator, &entry))
971 {
972 while (entry->waiting_threads)
973 {
974 /* wake up all */
975 entry->condvar->broadcast(entry->condvar);
976 /* go sleeping until they are gone */
977 entry->condvar->wait(entry->condvar, this->mutex);
978 }
979 }
980 enumerator->destroy(enumerator);
981 DBG2(DBG_MGR, "delete all IKE_SA's");
982 /* Step 3: initiate deletion of all IKE_SAs */
983 enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
984 while (enumerator->enumerate(enumerator, &entry))
985 {
986 charon->bus->set_sa(charon->bus, entry->ike_sa);
987 entry->ike_sa->delete(entry->ike_sa);
988 }
989 enumerator->destroy(enumerator);
990
991 DBG2(DBG_MGR, "destroy all entries");
992 /* Step 4: destroy all entries */
993 while (this->ike_sa_list->remove_last(this->ike_sa_list,
994 (void**)&entry) == SUCCESS)
995 {
996 charon->bus->set_sa(charon->bus, entry->ike_sa);
997 entry_destroy(entry);
998 }
999 charon->bus->set_sa(charon->bus, NULL);
1000 this->mutex->unlock(this->mutex);
1001 }
1002
1003 /**
1004 * Implementation of ike_sa_manager_t.destroy.
1005 */
1006 static void destroy(private_ike_sa_manager_t *this)
1007 {
1008 this->ike_sa_list->destroy(this->ike_sa_list);
1009 this->rng->destroy(this->rng);
1010 this->hasher->destroy(this->hasher);
1011 this->mutex->destroy(this->mutex);
1012 free(this);
1013 }
1014
1015 /*
1016 * Described in header.
1017 */
1018 ike_sa_manager_t *ike_sa_manager_create()
1019 {
1020 private_ike_sa_manager_t *this = malloc_thing(private_ike_sa_manager_t);
1021
1022 /* assign public functions */
1023 this->public.flush = (void(*)(ike_sa_manager_t*))flush;
1024 this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
1025 this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
1026 this->public.checkout_new = (ike_sa_t*(*)(ike_sa_manager_t*,bool))checkout_new;
1027 this->public.checkout_by_message = (ike_sa_t*(*)(ike_sa_manager_t*,message_t*))checkout_by_message;
1028 this->public.checkout_by_config = (ike_sa_t*(*)(ike_sa_manager_t*,peer_cfg_t*))checkout_by_config;
1029 this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
1030 this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
1031 this->public.checkout_duplicate = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_t *ike_sa))checkout_duplicate;
1032 this->public.create_enumerator = (enumerator_t*(*)(ike_sa_manager_t*))create_enumerator;
1033 this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
1034 this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
1035 this->public.get_half_open_count = (int(*)(ike_sa_manager_t*,host_t*))get_half_open_count;
1036
1037 /* initialize private variables */
1038 this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED);
1039 if (this->hasher == NULL)
1040 {
1041 DBG1(DBG_MGR, "manager initialization failed, no hasher supported");
1042 free(this);
1043 return NULL;
1044 }
1045 this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
1046 if (this->rng == NULL)
1047 {
1048 DBG1(DBG_MGR, "manager initialization failed, no RNG supported");
1049 this->hasher->destroy(this->hasher);
1050 free(this);
1051 return NULL;
1052 }
1053 this->ike_sa_list = linked_list_create();
1054 this->mutex = mutex_create(MUTEX_DEFAULT);
1055 this->reuse_ikesa = lib->settings->get_bool(lib->settings,
1056 "charon.reuse_ikesa", TRUE);
1057 return &this->public;
1058 }
1059