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