mediation connections should now properly rekey
[strongswan.git] / src / charon / sa / connect_manager.c
1 /*
2 * Copyright (C) 2007-2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "connect_manager.h"
19
20 #include <pthread.h>
21 #include <math.h>
22
23 #include <daemon.h>
24 #include <utils/linked_list.h>
25 #include <crypto/hashers/hasher.h>
26
27 #include <processing/jobs/callback_job.h>
28 #include <processing/jobs/initiate_mediation_job.h>
29 #include <encoding/payloads/endpoint_notify.h>
30
31 /* base timeout
32 * the check interval is ME_INTERVAL */
33 #define ME_INTERVAL 25 /* ms */
34 /* retransmission timeout is first ME_INTERVAL for ME_BOOST retransmissions
35 * then gets reduced to ME_INTERVAL * ME_RETRANS_BASE ^ (sent retransmissions - ME_BOOST). */
36 /* number of initial retransmissions sent in short interval */
37 #define ME_BOOST 2
38 /* base for retransmissions */
39 #define ME_RETRANS_BASE 1.8
40 /* max number of retransmissions */
41 #define ME_MAX_RETRANS 13
42
43 /* time to wait before the initiator finishes the connectivity checks after
44 * the first check has succeeded */
45 #define ME_WAIT_TO_FINISH 1000 /* ms */
46
47
48 typedef struct private_connect_manager_t private_connect_manager_t;
49
50 /**
51 * Additional private members of connect_manager_t.
52 */
53 struct private_connect_manager_t {
54 /**
55 * Public interface of connect_manager_t.
56 */
57 connect_manager_t public;
58
59 /**
60 * Lock for exclusivly accessing the manager.
61 */
62 pthread_mutex_t mutex;
63
64 /**
65 * Hasher to generate signatures
66 */
67 hasher_t *hasher;
68
69 /**
70 * Linked list with initiated mediated connections
71 */
72 linked_list_t *initiated;
73
74 /**
75 * Linked list with checklists (hash table with connect ID as key would be better).
76 */
77 linked_list_t *checklists;
78 };
79
80 typedef enum check_state_t check_state_t;
81
82 enum check_state_t {
83 CHECK_NONE,
84 CHECK_WAITING,
85 CHECK_IN_PROGRESS,
86 CHECK_SUCCEEDED,
87 CHECK_FAILED
88 };
89
90 typedef struct endpoint_pair_t endpoint_pair_t;
91
92 /**
93 * An entry in the check list.
94 */
95 struct endpoint_pair_t {
96 /** pair id */
97 u_int32_t id;
98
99 /** priority */
100 u_int64_t priority;
101
102 /** local endpoint */
103 host_t *local;
104
105 /** remote endpoint */
106 host_t *remote;
107
108 /** state */
109 check_state_t state;
110
111 /** number of retransmissions */
112 u_int32_t retransmitted;
113
114 /** the generated packet */
115 packet_t *packet;
116 };
117
118 /**
119 * Destroys an endpoint pair
120 */
121 static void endpoint_pair_destroy(endpoint_pair_t *this)
122 {
123 DESTROY_IF(this->local);
124 DESTROY_IF(this->remote);
125 DESTROY_IF(this->packet);
126 free(this);
127 }
128
129 /**
130 * Creates a new entry for the list.
131 */
132 static endpoint_pair_t *endpoint_pair_create(endpoint_notify_t *initiator,
133 endpoint_notify_t *responder, bool initiator_is_local)
134 {
135 endpoint_pair_t *this = malloc_thing(endpoint_pair_t);
136
137 this->id = 0;
138
139 u_int32_t pi = initiator->get_priority(initiator);
140 u_int32_t pr = responder->get_priority(responder);
141 this->priority = pow(2, 32) * min(pi, pr) + 2 * max(pi, pr) + (pi > pr ? 1 : 0);
142
143 this->local = initiator_is_local ? initiator->get_base(initiator) : responder->get_base(responder);
144 this->local = this->local->clone(this->local);
145 this->remote = initiator_is_local ? responder->get_host(responder) : initiator->get_host(initiator);
146 this->remote = this->remote->clone(this->remote);
147
148 this->state = CHECK_WAITING;
149 this->retransmitted = 0;
150 this->packet = NULL;
151
152 return this;
153 }
154
155
156 typedef struct check_list_t check_list_t;
157
158 /**
159 * An entry in the linked list.
160 */
161 struct check_list_t {
162
163 struct {
164 /** initiator's id */
165 identification_t *id;
166
167 /** initiator's key */
168 chunk_t key;
169
170 /** initiator's endpoints */
171 linked_list_t *endpoints;
172 } initiator;
173
174 struct {
175 /** responder's id */
176 identification_t *id;
177
178 /** responder's key */
179 chunk_t key;
180
181 /** responder's endpoints */
182 linked_list_t *endpoints;
183 } responder;
184
185 /** connect id */
186 chunk_t connect_id;
187
188 /** list of endpoint pairs */
189 linked_list_t *pairs;
190
191 /** pairs queued for triggered checks */
192 linked_list_t *triggered;
193
194 /** state */
195 check_state_t state;
196
197 /** TRUE if this is the initiator */
198 bool is_initiator;
199
200 /** TRUE if the initiator is finishing the checks */
201 bool is_finishing;
202
203 /** the current sender job */
204 job_t *sender;
205
206 };
207
208 /**
209 * Destroys a checklist
210 */
211 static void check_list_destroy(check_list_t *this)
212 {
213 DESTROY_IF(this->initiator.id);
214 DESTROY_IF(this->responder.id);
215
216 chunk_free(&this->connect_id);
217 chunk_free(&this->initiator.key);
218 chunk_free(&this->responder.key);
219
220 DESTROY_OFFSET_IF(this->initiator.endpoints, offsetof(endpoint_notify_t, destroy));
221 DESTROY_OFFSET_IF(this->responder.endpoints, offsetof(endpoint_notify_t, destroy));
222
223 DESTROY_FUNCTION_IF(this->pairs, (void*)endpoint_pair_destroy);
224 /* this list contains some of the same elements as contained in this->pairs */
225 DESTROY_IF(this->triggered);
226
227 free(this);
228 }
229
230 /**
231 * Creates a new checklist
232 */
233 static check_list_t *check_list_create(identification_t *initiator, identification_t *responder,
234 chunk_t connect_id, chunk_t initiator_key, linked_list_t *initiator_endpoints,
235 bool is_initiator)
236 {
237 check_list_t *this = malloc_thing(check_list_t);
238
239 this->connect_id = chunk_clone(connect_id);
240
241 this->initiator.id = initiator->clone(initiator);
242 this->initiator.key = chunk_clone(initiator_key);
243 this->initiator.endpoints = initiator_endpoints->clone_offset(initiator_endpoints, offsetof(endpoint_notify_t, clone));
244
245 this->responder.id = responder->clone(responder);
246 this->responder.key = chunk_empty;
247 this->responder.endpoints = NULL;
248
249 this->pairs = linked_list_create();
250 this->triggered = linked_list_create();
251 this->state = CHECK_NONE;
252 this->is_initiator = is_initiator;
253 this->is_finishing = FALSE;
254
255 return this;
256 }
257
258
259 typedef struct waiting_sa_t waiting_sa_t;
260
261 /**
262 * For an initiator, the data stored about a waiting mediated sa
263 */
264 struct waiting_sa_t {
265 /** ike sa id */
266 ike_sa_id_t *ike_sa_id;
267
268 /** list of child_cfg_t */
269 linked_list_t *childs;
270 };
271
272 /**
273 * Destroys a queued mediated sa
274 */
275 static void waiting_sa_destroy(waiting_sa_t *this)
276 {
277 DESTROY_IF(this->ike_sa_id);
278 this->childs->destroy_offset(this->childs, offsetof(child_cfg_t, destroy));
279 free(this);
280 }
281
282 /**
283 * Creates a new mediated sa object
284 */
285 static waiting_sa_t *waiting_sa_create(ike_sa_id_t *ike_sa_id)
286 {
287 waiting_sa_t *this = malloc_thing(waiting_sa_t);
288
289 this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
290 this->childs = linked_list_create();
291
292 return this;
293 }
294
295 typedef struct initiated_t initiated_t;
296
297 /**
298 * For an initiator, the data stored about initiated mediation connections
299 */
300 struct initiated_t {
301 /** my id */
302 identification_t *id;
303
304 /** peer id */
305 identification_t *peer_id;
306
307 /** list of mediated sas */
308 linked_list_t *mediated;
309 };
310
311 /**
312 * Destroys a queued initiation
313 */
314 static void initiated_destroy(initiated_t *this)
315 {
316 DESTROY_IF(this->id);
317 DESTROY_IF(this->peer_id);
318 this->mediated->destroy_function(this->mediated, (void*)waiting_sa_destroy);
319 free(this);
320 }
321
322 /**
323 * Creates a queued initiation
324 */
325 static initiated_t *initiated_create(identification_t *id, identification_t *peer_id)
326 {
327 initiated_t *this = malloc_thing(initiated_t);
328
329 this->id = id->clone(id);
330 this->peer_id = peer_id->clone(peer_id);
331 this->mediated = linked_list_create();
332
333 return this;
334 }
335
336
337 typedef struct check_t check_t;
338
339 /**
340 * Data exchanged in a connectivity check
341 */
342 struct check_t {
343 /** message id */
344 u_int32_t mid;
345
346 /** source of the connectivity check */
347 host_t *src;
348
349 /** destination of the connectivity check */
350 host_t *dst;
351
352 /** connect id */
353 chunk_t connect_id;
354
355 /** endpoint */
356 endpoint_notify_t *endpoint;
357
358 /** raw endpoint payload (to verify the signature) */
359 chunk_t endpoint_raw;
360
361 /** connect auth */
362 chunk_t auth;
363 };
364
365 /**
366 * Destroys a connectivity check
367 */
368 static void check_destroy(check_t *this)
369 {
370 chunk_free(&this->connect_id);
371 chunk_free(&this->endpoint_raw);
372 chunk_free(&this->auth);
373 DESTROY_IF(this->src);
374 DESTROY_IF(this->dst);
375 DESTROY_IF(this->endpoint);
376 free(this);
377 }
378
379 /**
380 * Creates a new connectivity check
381 */
382 static check_t *check_create()
383 {
384 check_t *this = malloc_thing(check_t);
385
386 this->connect_id = chunk_empty;
387 this->auth = chunk_empty;
388 this->endpoint_raw = chunk_empty;
389 this->src = NULL;
390 this->dst = NULL;
391 this->endpoint = NULL;
392
393 this->mid = 0;
394
395 return this;
396 }
397
398 typedef struct callback_data_t callback_data_t;
399
400 /**
401 * Data required by several callback jobs used in this file
402 */
403 struct callback_data_t {
404 /** connect manager */
405 private_connect_manager_t *connect_manager;
406
407 /** connect id */
408 chunk_t connect_id;
409
410 /** message (pair) id */
411 u_int32_t mid;
412 };
413
414 /**
415 * Destroys a callback data object
416 */
417 static void callback_data_destroy(callback_data_t *this)
418 {
419 chunk_free(&this->connect_id);
420 free(this);
421 }
422
423 /**
424 * Creates a new callback data object
425 */
426 static callback_data_t *callback_data_create(private_connect_manager_t *connect_manager,
427 chunk_t connect_id)
428 {
429 callback_data_t *this = malloc_thing(callback_data_t);
430 this->connect_manager = connect_manager;
431 this->connect_id = chunk_clone(connect_id);
432 this->mid = 0;
433 return this;
434 }
435
436 /**
437 * Creates a new retransmission data object
438 */
439 static callback_data_t *retransmit_data_create(private_connect_manager_t *connect_manager,
440 chunk_t connect_id, u_int32_t mid)
441 {
442 callback_data_t *this = callback_data_create(connect_manager, connect_id);
443 this->mid = mid;
444 return this;
445 }
446
447 typedef struct initiate_data_t initiate_data_t;
448
449 /**
450 * Data required by the initiate mediated
451 */
452 struct initiate_data_t {
453 /** checklist */
454 check_list_t *checklist;
455
456 /** waiting mediated connections */
457 initiated_t *initiated;
458 };
459
460 /**
461 * Destroys a initiate data object
462 */
463 static void initiate_data_destroy(initiate_data_t *this)
464 {
465 check_list_destroy(this->checklist);
466 initiated_destroy(this->initiated);
467 free(this);
468 }
469
470 /**
471 * Creates a new initiate data object
472 */
473 static initiate_data_t *initiate_data_create(check_list_t *checklist, initiated_t *initiated)
474 {
475 initiate_data_t *this = malloc_thing(initiate_data_t);
476
477 this->checklist = checklist;
478 this->initiated = initiated;
479
480 return this;
481 }
482
483 /**
484 * Find an initiated connection by the peers' ids
485 */
486 static bool match_initiated_by_ids(initiated_t *current, identification_t *id,
487 identification_t *peer_id)
488 {
489 return id->equals(id, current->id) && peer_id->equals(peer_id, current->peer_id);
490 }
491
492 static status_t get_initiated_by_ids(private_connect_manager_t *this,
493 identification_t *id, identification_t *peer_id, initiated_t **initiated)
494 {
495 return this->initiated->find_first(this->initiated,
496 (linked_list_match_t)match_initiated_by_ids,
497 (void**)initiated, id, peer_id);
498 }
499
500 /**
501 * Removes data about initiated connections
502 */
503 static void remove_initiated(private_connect_manager_t *this, initiated_t *initiated)
504 {
505 iterator_t *iterator;
506 initiated_t *current;
507
508 iterator = this->initiated->create_iterator(this->initiated, TRUE);
509 while (iterator->iterate(iterator, (void**)&current))
510 {
511 if (current == initiated)
512 {
513 iterator->remove(iterator);
514 break;
515 }
516 }
517 iterator->destroy(iterator);
518 }
519
520 /**
521 * Finds a waiting sa
522 */
523 static bool match_waiting_sa(waiting_sa_t *current, ike_sa_id_t *ike_sa_id)
524 {
525 return ike_sa_id->equals(ike_sa_id, current->ike_sa_id);
526 }
527
528 static status_t get_waiting_sa(initiated_t *initiated, ike_sa_id_t *ike_sa_id, waiting_sa_t **waiting_sa)
529 {
530 return initiated->mediated->find_first(initiated->mediated,
531 (linked_list_match_t)match_waiting_sa,
532 (void**)waiting_sa, ike_sa_id);
533 }
534
535 /**
536 * Find the checklist with a specific connect ID
537 */
538 static bool match_checklist_by_id(check_list_t *current, chunk_t *connect_id)
539 {
540 return chunk_equals(*connect_id, current->connect_id);
541 }
542
543 static status_t get_checklist_by_id(private_connect_manager_t *this,
544 chunk_t connect_id, check_list_t **check_list)
545 {
546 return this->checklists->find_first(this->checklists,
547 (linked_list_match_t)match_checklist_by_id,
548 (void**)check_list, &connect_id);
549 }
550
551 /**
552 * Removes a checklist
553 */
554 static void remove_checklist(private_connect_manager_t *this, check_list_t *checklist)
555 {
556 iterator_t *iterator;
557 check_list_t *current;
558
559 iterator = this->checklists->create_iterator(this->checklists, TRUE);
560 while (iterator->iterate(iterator, (void**)&current))
561 {
562 if (current == checklist)
563 {
564 iterator->remove(iterator);
565 break;
566 }
567 }
568 iterator->destroy(iterator);
569 }
570
571 /**
572 * Checks if a list of endpoint_notify_t contains a certain host_t
573 */
574 static bool match_endpoint_by_host(endpoint_notify_t *current, host_t *host)
575 {
576 return host->equals(host, current->get_host(current));
577 }
578
579 static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, endpoint_notify_t **endpoint)
580 {
581 return endpoints->find_first(endpoints,
582 (linked_list_match_t)match_endpoint_by_host,
583 (void**)endpoint, host);
584 }
585
586 /**
587 * Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
588 */
589 static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair)
590 {
591 iterator_t *iterator;
592 endpoint_pair_t *current;
593 bool inserted = FALSE;
594
595 iterator = pairs->create_iterator(pairs, TRUE);
596 while (iterator->iterate(iterator, (void**)&current))
597 {
598 if (current->priority < pair->priority)
599 {
600 iterator->insert_before(iterator, pair);
601 inserted = TRUE;
602 break;
603 }
604 }
605 iterator->destroy(iterator);
606
607 if (!inserted)
608 {
609 pairs->insert_last(pairs, pair);
610 }
611 }
612
613 /**
614 * Searches a list of endpoint_pair_t for a pair with specific host_ts
615 */
616 static bool match_pair_by_hosts(endpoint_pair_t *current, host_t *local, host_t *remote)
617 {
618 return local->equals(local, current->local) && remote->equals(remote, current->remote);
619 }
620
621 static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local, host_t *remote, endpoint_pair_t **pair)
622 {
623 return pairs->find_first(pairs,
624 (linked_list_match_t)match_pair_by_hosts,
625 (void**)pair, local, remote);
626 }
627
628 static bool match_pair_by_id(endpoint_pair_t *current, u_int32_t *id)
629 {
630 return current->id == *id;
631 }
632
633 /**
634 * Searches for a pair with a specific id
635 */
636 static status_t get_pair_by_id(check_list_t *checklist, u_int32_t id, endpoint_pair_t **pair)
637 {
638 return checklist->pairs->find_first(checklist->pairs,
639 (linked_list_match_t)match_pair_by_id,
640 (void**)pair, &id);
641 }
642
643 static bool match_succeeded_pair(endpoint_pair_t *current)
644 {
645 return current->state == CHECK_SUCCEEDED;
646 }
647
648 /**
649 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
650 */
651 static status_t get_best_valid_pair(check_list_t *checklist, endpoint_pair_t **pair)
652 {
653 return checklist->pairs->find_first(checklist->pairs,
654 (linked_list_match_t)match_succeeded_pair,
655 (void**)pair);
656 }
657
658 static bool match_waiting_pair(endpoint_pair_t *current)
659 {
660 return current->state == CHECK_WAITING;
661 }
662
663 /**
664 * Returns and *removes* the first triggered pair in state CHECK_WAITING.
665 */
666 static status_t get_triggered_pair(check_list_t *checklist, endpoint_pair_t **pair)
667 {
668 iterator_t *iterator;
669 endpoint_pair_t *current;
670 status_t status = NOT_FOUND;
671
672 iterator = checklist->triggered->create_iterator(checklist->triggered, TRUE);
673 while (iterator->iterate(iterator, (void**)&current))
674 {
675 iterator->remove(iterator);
676
677 if (current->state == CHECK_WAITING)
678 {
679 if (pair)
680 {
681 *pair = current;
682 }
683 status = SUCCESS;
684 break;
685 }
686 }
687 iterator->destroy(iterator);
688
689 return status;
690 }
691
692 /**
693 * Prints all the pairs on a checklist
694 */
695 static void print_checklist(check_list_t *checklist)
696 {
697 iterator_t *iterator;
698 endpoint_pair_t *current;
699
700 DBG1(DBG_IKE, "pairs on checklist %#B:", &checklist->connect_id);
701 iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
702 while (iterator->iterate(iterator, (void**)&current))
703 {
704 DBG1(DBG_IKE, " * %#H - %#H (%d)", current->local, current->remote,
705 current->priority);
706 }
707 iterator->destroy(iterator);
708 }
709
710 /**
711 * Prunes identical pairs with lower priority from the list
712 * Note: this function also numbers the remaining pairs serially
713 */
714 static void prune_pairs(linked_list_t *pairs)
715 {
716 iterator_t *iterator, *search;
717 endpoint_pair_t *current, *other;
718 u_int32_t id = 0;
719
720 iterator = pairs->create_iterator(pairs, TRUE);
721 search = pairs->create_iterator(pairs, TRUE);
722 while (iterator->iterate(iterator, (void**)&current))
723 {
724 current->id = ++id;
725
726 while (search->iterate(search, (void**)&other))
727 {
728 if (current == other)
729 {
730 continue;
731 }
732
733 if (current->local->equals(current->local, other->local) &&
734 current->remote->equals(current->remote, other->remote))
735 {
736 /* since the list of pairs is sorted by priority in descending
737 * order, and we iterate the list from the beginning, we are
738 * sure that the priority of 'other' is lower than that of
739 * 'current', remove it */
740 DBG1(DBG_IKE, "pruning endpoint pair %#H - %#H with priority %d",
741 other->local, other->remote, other->priority);
742 search->remove(search);
743 endpoint_pair_destroy(other);
744 }
745 }
746 search->reset(search);
747 }
748 search->destroy(search);
749 iterator->destroy(iterator);
750 }
751
752 /**
753 * Builds a list of endpoint pairs
754 */
755 static void build_pairs(check_list_t *checklist)
756 {
757 /* FIXME: limit endpoints and pairs */
758 iterator_t *iterator_i, *iterator_r;
759 endpoint_notify_t *initiator, *responder;
760
761 iterator_i = checklist->initiator.endpoints->create_iterator(checklist->initiator.endpoints, TRUE);
762 while (iterator_i->iterate(iterator_i, (void**)&initiator))
763 {
764 iterator_r = checklist->responder.endpoints->create_iterator(checklist->responder.endpoints, TRUE);
765 while (iterator_r->iterate(iterator_r, (void**)&responder))
766 {
767 if (initiator->get_family(initiator) != responder->get_family(responder))
768 {
769 continue;
770 }
771
772 insert_pair_by_priority(checklist->pairs,
773 endpoint_pair_create(initiator, responder, checklist->is_initiator));
774 }
775 iterator_r->destroy(iterator_r);
776 }
777 iterator_i->destroy(iterator_i);
778
779 print_checklist(checklist);
780
781 prune_pairs(checklist->pairs);
782 }
783
784 /**
785 * Processes the payloads of a connectivity check and returns the extracted data
786 */
787 static status_t process_payloads(message_t *message, check_t *check)
788 {
789 iterator_t *iterator;
790 payload_t *payload;
791
792 iterator = message->get_payload_iterator(message);
793 while (iterator->iterate(iterator, (void**)&payload))
794 {
795 if (payload->get_type(payload) != NOTIFY)
796 {
797 DBG1(DBG_IKE, "ignoring payload of type '%N' while processing "
798 "connectivity check", payload_type_names, payload->get_type(payload));
799 continue;
800 }
801
802 notify_payload_t *notify = (notify_payload_t*)payload;
803
804 switch (notify->get_notify_type(notify))
805 {
806 case ME_ENDPOINT:
807 {
808 if (check->endpoint)
809 {
810 DBG1(DBG_IKE, "connectivity check contains multiple ME_ENDPOINT notifies");
811 break;
812 }
813
814 endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify);
815 if (!endpoint)
816 {
817 DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify");
818 break;
819 }
820 check->endpoint = endpoint;
821 check->endpoint_raw = chunk_clone(notify->get_notification_data(notify));
822 DBG2(DBG_IKE, "received ME_ENDPOINT notify");
823 break;
824 }
825 case ME_CONNECTID:
826 {
827 if (check->connect_id.ptr)
828 {
829 DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTID notifies");
830 break;
831 }
832 check->connect_id = chunk_clone(notify->get_notification_data(notify));
833 DBG2(DBG_IKE, "received ME_CONNECTID %#B", &check->connect_id);
834 break;
835 }
836 case ME_CONNECTAUTH:
837 {
838 if (check->auth.ptr)
839 {
840 DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTAUTH notifies");
841 break;
842 }
843 check->auth = chunk_clone(notify->get_notification_data(notify));
844 DBG2(DBG_IKE, "received ME_CONNECTAUTH %#B", &check->auth);
845 break;
846 }
847 default:
848 break;
849 }
850 }
851 iterator->destroy(iterator);
852
853 if (!check->connect_id.ptr || !check->endpoint || !check->auth.ptr)
854 {
855 DBG1(DBG_IKE, "at least one payload was missing from the connectivity check");
856 return FAILED;
857 }
858
859 return SUCCESS;
860 }
861
862 /**
863 * Builds the signature for a connectivity check
864 */
865 static chunk_t build_signature(private_connect_manager_t *this,
866 check_list_t *checklist, check_t *check, bool outbound)
867 {
868 u_int32_t mid;
869 chunk_t mid_chunk, key_chunk, sig_chunk;
870 chunk_t sig_hash;
871
872 mid = htonl(check->mid);
873 mid_chunk = chunk_from_thing(mid);
874
875 key_chunk = (checklist->is_initiator && outbound) || (!checklist->is_initiator && !outbound)
876 ? checklist->initiator.key : checklist->responder.key;
877
878 /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */
879 sig_chunk = chunk_cat("cccc", mid_chunk, check->connect_id, check->endpoint_raw, key_chunk);
880 this->hasher->allocate_hash(this->hasher, sig_chunk, &sig_hash);
881 DBG3(DBG_IKE, "sig_chunk %#B", &sig_chunk);
882 DBG3(DBG_IKE, "sig_hash %#B", &sig_hash);
883
884 chunk_free(&sig_chunk);
885 return sig_hash;
886 }
887
888 static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair);
889 static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time);
890 static void finish_checks(private_connect_manager_t *this, check_list_t *checklist);
891
892 /**
893 * After one of the initiator's pairs has succeeded we finish the checks without
894 * waiting for all the timeouts
895 */
896 static job_requeue_t initiator_finish(callback_data_t *data)
897 {
898 private_connect_manager_t *this = data->connect_manager;
899
900 pthread_mutex_lock(&(this->mutex));
901
902 check_list_t *checklist;
903 if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
904 {
905 DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish connectivity checks",
906 &data->connect_id);
907 pthread_mutex_unlock(&(this->mutex));
908 return JOB_REQUEUE_NONE;
909 }
910
911 finish_checks(this, checklist);
912
913 pthread_mutex_unlock(&(this->mutex));
914
915 return JOB_REQUEUE_NONE;
916 }
917
918 /**
919 * Updates the state of the whole checklist
920 */
921 static void update_checklist_state(private_connect_manager_t *this, check_list_t *checklist)
922 {
923 iterator_t *iterator;
924 endpoint_pair_t *current;
925 bool in_progress = FALSE, succeeded = FALSE;
926
927 iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
928 while (iterator->iterate(iterator, (void**)&current))
929 {
930 switch(current->state)
931 {
932 case CHECK_WAITING:
933 /* at least one is still waiting -> checklist remains
934 * in waiting state */
935 iterator->destroy(iterator);
936 return;
937 case CHECK_IN_PROGRESS:
938 in_progress = TRUE;
939 break;
940 case CHECK_SUCCEEDED:
941 succeeded = TRUE;
942 break;
943 default:
944 break;
945 }
946 }
947 iterator->destroy(iterator);
948
949 if (checklist->is_initiator && succeeded && !checklist->is_finishing)
950 {
951 /* instead of waiting until all checks have finished (i.e. all
952 * retransmissions have failed) the initiator finishes the checks
953 * right after the first check has succeeded. to allow a probably
954 * better pair to succeed, we still wait a certain time */
955 DBG2(DBG_IKE, "fast finishing checks for checklist '%#B'", &checklist->connect_id);
956
957 callback_data_t *data = callback_data_create(this, checklist->connect_id);
958 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, data, (callback_job_cleanup_t)callback_data_destroy, NULL);
959 charon->scheduler->schedule_job(charon->scheduler, job, ME_WAIT_TO_FINISH);
960 checklist->is_finishing = TRUE;
961 }
962
963 if (in_progress)
964 {
965 checklist->state = CHECK_IN_PROGRESS;
966 }
967 else if (succeeded)
968 {
969 checklist->state = CHECK_SUCCEEDED;
970 }
971 else
972 {
973 checklist->state = CHECK_FAILED;
974 }
975 }
976
977 /**
978 * This function is triggered for each sent check after a specific timeout
979 */
980 static job_requeue_t retransmit(callback_data_t *data)
981 {
982 private_connect_manager_t *this = data->connect_manager;
983
984 pthread_mutex_lock(&(this->mutex));
985
986 check_list_t *checklist;
987 if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
988 {
989 DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit connectivity check",
990 &data->connect_id);
991 pthread_mutex_unlock(&(this->mutex));
992 return JOB_REQUEUE_NONE;
993 }
994
995 endpoint_pair_t *pair;
996 if (get_pair_by_id(checklist, data->mid, &pair) != SUCCESS)
997 {
998 DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit connectivity check",
999 data->mid);
1000 goto retransmit_end;
1001 }
1002
1003 if (pair->state != CHECK_IN_PROGRESS)
1004 {
1005 DBG2(DBG_IKE, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
1006 data->mid, pair->state);
1007 goto retransmit_end;
1008 }
1009
1010 if (++pair->retransmitted > ME_MAX_RETRANS)
1011 {
1012 DBG2(DBG_IKE, "pair with id '%d' failed after %d retransmissions",
1013 data->mid, ME_MAX_RETRANS);
1014 pair->state = CHECK_FAILED;
1015 goto retransmit_end;
1016 }
1017
1018 charon->sender->send(charon->sender, pair->packet->clone(pair->packet));
1019
1020 queue_retransmission(this, checklist, pair);
1021
1022 retransmit_end:
1023 update_checklist_state(this, checklist);
1024
1025 switch(checklist->state)
1026 {
1027 case CHECK_SUCCEEDED:
1028 case CHECK_FAILED:
1029 finish_checks(this, checklist);
1030 break;
1031 default:
1032 break;
1033 }
1034
1035 pthread_mutex_unlock(&(this->mutex));
1036
1037 /* we reschedule it manually */
1038 return JOB_REQUEUE_NONE;
1039 }
1040
1041 /**
1042 * Queues a retransmission job
1043 */
1044 static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair)
1045 {
1046 callback_data_t *data = retransmit_data_create(this, checklist->connect_id, pair->id);
1047 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, (callback_job_cleanup_t)callback_data_destroy, NULL);
1048
1049 u_int32_t retransmission = pair->retransmitted + 1;
1050 u_int32_t rto = ME_INTERVAL;
1051 if (retransmission > ME_BOOST)
1052 {
1053 rto = (u_int32_t)(ME_INTERVAL * pow(ME_RETRANS_BASE, retransmission - ME_BOOST));
1054 }
1055 DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", retransmission, pair->id, rto);
1056
1057 charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, rto);
1058 }
1059
1060 /**
1061 * Sends a check
1062 */
1063 static void send_check(private_connect_manager_t *this, check_list_t *checklist,
1064 check_t *check, endpoint_pair_t *pair, bool request)
1065 {
1066 message_t *message = message_create();
1067 message->set_message_id(message, check->mid);
1068 message->set_exchange_type(message, INFORMATIONAL);
1069 message->set_request(message, request);
1070 message->set_destination(message, check->dst->clone(check->dst));
1071 message->set_source(message, check->src->clone(check->src));
1072
1073 ike_sa_id_t *ike_sa_id = ike_sa_id_create(0, 0, request);
1074 message->set_ike_sa_id(message, ike_sa_id);
1075 ike_sa_id->destroy(ike_sa_id);
1076
1077 message->add_notify(message, FALSE, ME_CONNECTID, check->connect_id);
1078 DBG2(DBG_IKE, "send ME_CONNECTID %#B", &check->connect_id);
1079
1080 notify_payload_t *endpoint = check->endpoint->build_notify(check->endpoint);
1081 check->endpoint_raw = chunk_clone(endpoint->get_notification_data(endpoint));
1082 message->add_payload(message, (payload_t*)endpoint);
1083 DBG2(DBG_IKE, "send ME_ENDPOINT notify");
1084
1085 check->auth = build_signature(this, checklist, check, TRUE);
1086 message->add_notify(message, FALSE, ME_CONNECTAUTH, check->auth);
1087 DBG2(DBG_IKE, "send ME_CONNECTAUTH %#B", &check->auth);
1088
1089 packet_t *packet;
1090 if (message->generate(message, NULL, NULL, &packet) == SUCCESS)
1091 {
1092 charon->sender->send(charon->sender, packet->clone(packet));
1093
1094 if (request)
1095 {
1096 DESTROY_IF(pair->packet);
1097 pair->packet = packet;
1098 pair->retransmitted = 0;
1099 queue_retransmission(this, checklist, pair);
1100 }
1101 else
1102 {
1103 packet->destroy(packet);
1104 }
1105 }
1106 message->destroy(message);
1107 }
1108
1109 /**
1110 * Queues a triggered check
1111 */
1112 static void queue_triggered_check(private_connect_manager_t *this,
1113 check_list_t *checklist, endpoint_pair_t *pair)
1114 {
1115 DBG2(DBG_IKE, "queueing triggered check for pair '%d'", pair->id);
1116 pair->state = CHECK_WAITING;
1117 checklist->triggered->insert_last(checklist->triggered, pair);
1118
1119 if (!checklist->sender)
1120 {
1121 /* if the sender is not running we restart it */
1122 schedule_checks(this, checklist, ME_INTERVAL);
1123 }
1124 }
1125
1126 /**
1127 * This function is triggered for each checklist at a specific interval
1128 */
1129 static job_requeue_t sender(callback_data_t *data)
1130 {
1131 private_connect_manager_t *this = data->connect_manager;
1132
1133 pthread_mutex_lock(&(this->mutex));
1134
1135 check_list_t *checklist;
1136 if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
1137 {
1138 DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send connectivity check",
1139 &data->connect_id);
1140 pthread_mutex_unlock(&(this->mutex));
1141 return JOB_REQUEUE_NONE;
1142 }
1143
1144 /* reset the sender */
1145 checklist->sender = NULL;
1146
1147 endpoint_pair_t *pair;
1148 if (get_triggered_pair(checklist, &pair) != SUCCESS)
1149 {
1150 DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check");
1151
1152 if (checklist->pairs->find_first(checklist->pairs,
1153 (linked_list_match_t)match_waiting_pair, (void**)&pair) != SUCCESS)
1154 {
1155 pthread_mutex_unlock(&(this->mutex));
1156 DBG1(DBG_IKE, "no pairs in waiting state, aborting");
1157 return JOB_REQUEUE_NONE;
1158 }
1159 }
1160 else
1161 {
1162 DBG1(DBG_IKE, "triggered check found");
1163 }
1164
1165 check_t *check = check_create();
1166 check->mid = pair->id;
1167 check->src = pair->local->clone(pair->local);
1168 check->dst = pair->remote->clone(pair->remote);
1169 check->connect_id = chunk_clone(checklist->connect_id);
1170 check->endpoint = endpoint_notify_create();
1171
1172 pair->state = CHECK_IN_PROGRESS;
1173
1174 send_check(this, checklist, check, pair, TRUE);
1175
1176 check_destroy(check);
1177
1178 /* schedule this job again */
1179 schedule_checks(this, checklist, ME_INTERVAL);
1180
1181 pthread_mutex_unlock(&(this->mutex));
1182
1183 /* we reschedule it manually */
1184 return JOB_REQUEUE_NONE;
1185 }
1186
1187 /**
1188 * Schedules checks for a checklist (time in ms)
1189 */
1190 static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time)
1191 {
1192 callback_data_t *data = callback_data_create(this, checklist->connect_id);
1193 checklist->sender = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)callback_data_destroy, NULL);
1194 charon->scheduler->schedule_job(charon->scheduler, checklist->sender, time);
1195 }
1196
1197 /**
1198 * Initiates waiting mediated connections
1199 */
1200 static job_requeue_t initiate_mediated(initiate_data_t *data)
1201 {
1202 check_list_t *checklist = data->checklist;
1203 initiated_t *initiated = data->initiated;
1204
1205 endpoint_pair_t *pair;
1206 if (get_best_valid_pair(checklist, &pair) == SUCCESS)
1207 {
1208 waiting_sa_t *waiting_sa;
1209 iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
1210 while (iterator->iterate(iterator, (void**)&waiting_sa))
1211 {
1212 ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa->ike_sa_id);
1213 if (sa->initiate_mediated(sa, pair->local, pair->remote, waiting_sa->childs,
1214 checklist->connect_id) != SUCCESS)
1215 {
1216 SIG(IKE_UP_FAILED, "establishing the mediated connection failed");
1217 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa);
1218 }
1219 charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa);
1220 }
1221 iterator->destroy(iterator);
1222 }
1223 else
1224 {
1225 /* this should (can?) not happen */
1226 }
1227
1228 return JOB_REQUEUE_NONE;
1229 }
1230
1231 /**
1232 * Finishes checks for a checklist
1233 */
1234 static void finish_checks(private_connect_manager_t *this, check_list_t *checklist)
1235 {
1236 if (checklist->is_initiator)
1237 {
1238 initiated_t *initiated;
1239 if (get_initiated_by_ids(this, checklist->initiator.id,
1240 checklist->responder.id, &initiated) == SUCCESS)
1241 {
1242 remove_checklist(this, checklist);
1243 remove_initiated(this, initiated);
1244
1245 initiate_data_t *data = initiate_data_create(checklist, initiated);
1246 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiate_mediated, data, (callback_job_cleanup_t)initiate_data_destroy, NULL);
1247 charon->processor->queue_job(charon->processor, job);
1248 return;
1249 }
1250 else
1251 {
1252 DBG1(DBG_IKE, "there is no mediated connection waiting between '%D' "
1253 "and '%D'", checklist->initiator.id, checklist->responder.id);
1254 }
1255 }
1256 }
1257
1258 /**
1259 * Process the response to one of our requests
1260 */
1261 static void process_response(private_connect_manager_t *this, check_t *check,
1262 check_list_t *checklist)
1263 {
1264 endpoint_pair_t *pair;
1265 if (get_pair_by_id(checklist, check->mid, &pair) == SUCCESS)
1266 {
1267 if (pair->local->equals(pair->local, check->dst) &&
1268 pair->remote->equals(pair->remote, check->src))
1269 {
1270 DBG1(DBG_IKE, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair->id,
1271 pair->local, pair->remote);
1272 pair->state = CHECK_SUCCEEDED;
1273 }
1274
1275 linked_list_t *local_endpoints = checklist->is_initiator ?
1276 checklist->initiator.endpoints : checklist->responder.endpoints;
1277
1278 endpoint_notify_t *local_endpoint;
1279 if (endpoints_contain(local_endpoints,
1280 check->endpoint->get_host(check->endpoint), &local_endpoint) != SUCCESS)
1281 {
1282 local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE,
1283 check->endpoint->get_host(check->endpoint), pair->local);
1284 local_endpoint->set_priority(local_endpoint, check->endpoint->get_priority(check->endpoint));
1285 local_endpoints->insert_last(local_endpoints, local_endpoint);
1286 }
1287
1288 update_checklist_state(this, checklist);
1289
1290 switch(checklist->state)
1291 {
1292 case CHECK_SUCCEEDED:
1293 case CHECK_FAILED:
1294 finish_checks(this, checklist);
1295 break;
1296 default:
1297 break;
1298 }
1299 }
1300 else
1301 {
1302 DBG1(DBG_IKE, "pair with id '%d' not found", check->mid);
1303 }
1304 }
1305
1306 static void process_request(private_connect_manager_t *this, check_t *check,
1307 check_list_t *checklist)
1308 {
1309 linked_list_t *remote_endpoints = checklist->is_initiator ?
1310 checklist->responder.endpoints : checklist->initiator.endpoints;
1311
1312 endpoint_notify_t *peer_reflexive, *remote_endpoint;
1313 peer_reflexive = endpoint_notify_create_from_host(PEER_REFLEXIVE, check->src, NULL);
1314 peer_reflexive->set_priority(peer_reflexive, check->endpoint->get_priority(check->endpoint));
1315
1316 if (endpoints_contain(remote_endpoints, check->src, &remote_endpoint) != SUCCESS)
1317 {
1318 remote_endpoint = peer_reflexive->clone(peer_reflexive);
1319 remote_endpoints->insert_last(remote_endpoints, remote_endpoint);
1320 }
1321
1322 endpoint_pair_t *pair;
1323 if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, &pair) == SUCCESS)
1324 {
1325 switch(pair->state)
1326 {
1327 case CHECK_IN_PROGRESS:
1328 /* prevent retransmissions */
1329 pair->retransmitted = ME_MAX_RETRANS;
1330 /* FIXME: we should wait to the next rto to send the triggered check
1331 * fall-through */
1332 case CHECK_WAITING:
1333 case CHECK_FAILED:
1334 queue_triggered_check(this, checklist, pair);
1335 break;
1336 case CHECK_SUCCEEDED:
1337 default:
1338 break;
1339 }
1340 }
1341 else
1342 {
1343 endpoint_notify_t *local_endpoint = endpoint_notify_create_from_host(HOST, check->dst, NULL);
1344
1345 endpoint_notify_t *initiator = checklist->is_initiator ? local_endpoint : remote_endpoint;
1346 endpoint_notify_t *responder = checklist->is_initiator ? remote_endpoint : local_endpoint;
1347
1348 pair = endpoint_pair_create(initiator, responder, checklist->is_initiator);
1349 pair->id = checklist->pairs->get_count(checklist->pairs) + 1;
1350
1351 insert_pair_by_priority(checklist->pairs, pair);
1352
1353 queue_triggered_check(this, checklist, pair);
1354
1355 local_endpoint->destroy(local_endpoint);
1356 }
1357
1358
1359 check_t *response = check_create();
1360
1361 response->mid = check->mid;
1362 response->src = check->dst->clone(check->dst);
1363 response->dst = check->src->clone(check->src);
1364 response->connect_id = chunk_clone(check->connect_id);
1365 response->endpoint = peer_reflexive;
1366
1367 send_check(this, checklist, response, pair, FALSE);
1368
1369 check_destroy(response);
1370 }
1371
1372 /**
1373 * Implementation of connect_manager_t.process_check.
1374 */
1375 static void process_check(private_connect_manager_t *this, message_t *message)
1376 {
1377 if (message->parse_body(message, NULL, NULL) != SUCCESS)
1378 {
1379 DBG1(DBG_IKE, "%N %s with message ID %d processing failed",
1380 exchange_type_names, message->get_exchange_type(message),
1381 message->get_request(message) ? "request" : "response",
1382 message->get_message_id(message));
1383 return;
1384 }
1385
1386 check_t *check = check_create();
1387 check->mid = message->get_message_id(message);
1388 check->src = message->get_source(message);
1389 check->src = check->src->clone(check->src);
1390 check->dst = message->get_destination(message);
1391 check->dst = check->dst->clone(check->dst);
1392
1393 if (process_payloads(message, check) != SUCCESS)
1394 {
1395 DBG1(DBG_IKE, "invalid connectivity check %s received",
1396 message->get_request(message) ? "request" : "response");
1397 check_destroy(check);
1398 return;
1399 }
1400
1401 pthread_mutex_lock(&(this->mutex));
1402
1403 check_list_t *checklist;
1404 if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS)
1405 {
1406 DBG1(DBG_IKE, "checklist with id '%#B' not found",
1407 &check->connect_id);
1408 check_destroy(check);
1409 pthread_mutex_unlock(&(this->mutex));
1410 return;
1411 }
1412
1413 chunk_t sig = build_signature(this, checklist, check, FALSE);
1414 if (!chunk_equals(sig, check->auth))
1415 {
1416 DBG1(DBG_IKE, "connectivity check verification failed");
1417 check_destroy(check);
1418 chunk_free(&sig);
1419 pthread_mutex_unlock(&(this->mutex));
1420 return;
1421 }
1422 chunk_free(&sig);
1423
1424 if (message->get_request(message))
1425 {
1426 process_request(this, check, checklist);
1427 }
1428 else
1429 {
1430 process_response(this, check, checklist);
1431 }
1432
1433 pthread_mutex_unlock(&(this->mutex));
1434
1435 check_destroy(check);
1436 }
1437
1438 /**
1439 * Implementation of connect_manager_t.check_and_register.
1440 */
1441 static bool check_and_register(private_connect_manager_t *this,
1442 identification_t *id, identification_t *peer_id,
1443 ike_sa_id_t *mediated_sa, child_cfg_t *child)
1444 {
1445 initiated_t *initiated;
1446 bool already_there = TRUE;
1447
1448 pthread_mutex_lock(&(this->mutex));
1449
1450 if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
1451 {
1452 DBG2(DBG_IKE, "registered waiting mediated connection with '%D'", peer_id);
1453 initiated = initiated_create(id, peer_id);
1454 this->initiated->insert_last(this->initiated, initiated);
1455 already_there = FALSE;
1456 }
1457
1458 waiting_sa_t *waiting_sa;
1459 if (get_waiting_sa(initiated, mediated_sa, &waiting_sa) != SUCCESS)
1460 {
1461 waiting_sa = waiting_sa_create(mediated_sa);
1462 initiated->mediated->insert_last(initiated->mediated, waiting_sa);
1463 }
1464
1465 child->get_ref(child);
1466 waiting_sa->childs->insert_last(waiting_sa->childs, child);
1467
1468 pthread_mutex_unlock(&(this->mutex));
1469
1470 return already_there;
1471 }
1472
1473 /**
1474 * Implementation of connect_manager_t.check_and_initiate.
1475 */
1476 static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *mediation_sa,
1477 identification_t *id, identification_t *peer_id)
1478 {
1479 initiated_t *initiated;
1480
1481 pthread_mutex_lock(&(this->mutex));
1482
1483 if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
1484 {
1485 DBG2(DBG_IKE, "no waiting mediated connections with '%D'", peer_id);
1486 pthread_mutex_unlock(&(this->mutex));
1487 return;
1488 }
1489
1490 waiting_sa_t *waiting_sa;
1491 iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
1492 while (iterator->iterate(iterator, (void**)&waiting_sa))
1493 {
1494 job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa,
1495 waiting_sa->ike_sa_id);
1496 charon->processor->queue_job(charon->processor, job);
1497 }
1498 iterator->destroy(iterator);
1499
1500 pthread_mutex_unlock(&(this->mutex));
1501 }
1502
1503 /**
1504 * Implementation of connect_manager_t.set_initiator_data.
1505 */
1506 static status_t set_initiator_data(private_connect_manager_t *this,
1507 identification_t *initiator, identification_t *responder,
1508 chunk_t connect_id, chunk_t key, linked_list_t *endpoints, bool is_initiator)
1509 {
1510 check_list_t *checklist;
1511
1512 pthread_mutex_lock(&(this->mutex));
1513
1514 if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS)
1515 {
1516 DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting",
1517 &connect_id);
1518 pthread_mutex_unlock(&(this->mutex));
1519 return FAILED;
1520 }
1521
1522 checklist = check_list_create(initiator, responder, connect_id, key, endpoints, is_initiator);
1523 this->checklists->insert_last(this->checklists, checklist);
1524
1525 pthread_mutex_unlock(&(this->mutex));
1526
1527 return SUCCESS;
1528 }
1529
1530 /**
1531 * Implementation of connect_manager_t.set_responder_data.
1532 */
1533 static status_t set_responder_data(private_connect_manager_t *this,
1534 chunk_t connect_id, chunk_t key, linked_list_t *endpoints)
1535 {
1536 check_list_t *checklist;
1537
1538 pthread_mutex_lock(&(this->mutex));
1539
1540 if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
1541 {
1542 DBG1(DBG_IKE, "checklist with id '%#B' not found",
1543 &connect_id);
1544 pthread_mutex_unlock(&(this->mutex));
1545 return NOT_FOUND;
1546 }
1547
1548 checklist->responder.key = chunk_clone(key);
1549 checklist->responder.endpoints = endpoints->clone_offset(endpoints, offsetof(endpoint_notify_t, clone));
1550 checklist->state = CHECK_WAITING;
1551
1552 build_pairs(checklist);
1553
1554 /* send the first check immediately */
1555 schedule_checks(this, checklist, 0);
1556
1557 pthread_mutex_unlock(&(this->mutex));
1558
1559 return SUCCESS;
1560 }
1561
1562 /**
1563 * Implementation of connect_manager_t.stop_checks.
1564 */
1565 static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id)
1566 {
1567 check_list_t *checklist;
1568
1569 pthread_mutex_lock(&(this->mutex));
1570
1571 if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
1572 {
1573 DBG1(DBG_IKE, "checklist with id '%#B' not found",
1574 &connect_id);
1575 pthread_mutex_unlock(&(this->mutex));
1576 return NOT_FOUND;
1577 }
1578
1579 DBG1(DBG_IKE, "removing checklist with id '%#B'", &connect_id);
1580
1581 remove_checklist(this, checklist);
1582 check_list_destroy(checklist);
1583
1584 pthread_mutex_unlock(&(this->mutex));
1585
1586 return SUCCESS;
1587 }
1588
1589 /**
1590 * Implementation of connect_manager_t.destroy.
1591 */
1592 static void destroy(private_connect_manager_t *this)
1593 {
1594 pthread_mutex_lock(&(this->mutex));
1595
1596 this->hasher->destroy(this->hasher);
1597 this->checklists->destroy_function(this->checklists, (void*)check_list_destroy);
1598 this->initiated->destroy_function(this->initiated, (void*)initiated_destroy);
1599
1600 pthread_mutex_unlock(&(this->mutex));
1601 pthread_mutex_destroy(&(this->mutex));
1602 free(this);
1603 }
1604
1605 /*
1606 * Described in header.
1607 */
1608 connect_manager_t *connect_manager_create()
1609 {
1610 private_connect_manager_t *this = malloc_thing(private_connect_manager_t);
1611
1612 this->public.destroy = (void(*)(connect_manager_t*))destroy;
1613 this->public.check_and_register = (bool(*)(connect_manager_t*,identification_t*,identification_t*,ike_sa_id_t*,child_cfg_t*))check_and_register;
1614 this->public.check_and_initiate = (void(*)(connect_manager_t*,ike_sa_id_t*,identification_t*,identification_t*))check_and_initiate;
1615 this->public.set_initiator_data = (status_t(*)(connect_manager_t*,identification_t*,identification_t*,chunk_t,chunk_t,linked_list_t*,bool))set_initiator_data;
1616 this->public.set_responder_data = (status_t(*)(connect_manager_t*,chunk_t,chunk_t,linked_list_t*))set_responder_data;
1617 this->public.process_check = (void(*)(connect_manager_t*,message_t*))process_check;
1618 this->public.stop_checks = (status_t(*)(connect_manager_t*,chunk_t))stop_checks;
1619
1620 this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
1621 if (this->hasher == NULL)
1622 {
1623 DBG1(DBG_IKE, "unable to create connect manager, SHA1 not supported");
1624 free(this);
1625 return NULL;
1626 }
1627
1628 this->checklists = linked_list_create();
1629 this->initiated = linked_list_create();
1630
1631 pthread_mutex_init(&(this->mutex), NULL);
1632
1633 return (connect_manager_t*)this;
1634 }