2 * Copyright (C) 2007-2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
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>.
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
16 #include "connect_manager.h"
21 #include <threading/mutex.h>
22 #include <utils/linked_list.h>
23 #include <crypto/hashers/hasher.h>
25 #include <processing/jobs/callback_job.h>
26 #include <processing/jobs/initiate_mediation_job.h>
27 #include <encoding/payloads/endpoint_notify.h>
30 * the check interval is ME_INTERVAL */
31 #define ME_INTERVAL 25 /* ms */
32 /* retransmission timeout is first ME_INTERVAL for ME_BOOST retransmissions
33 * then gets reduced to ME_INTERVAL * ME_RETRANS_BASE ^ (sent retransmissions - ME_BOOST). */
34 /* number of initial retransmissions sent in short interval */
36 /* base for retransmissions */
37 #define ME_RETRANS_BASE 1.8
38 /* max number of retransmissions */
39 #define ME_MAX_RETRANS 13
41 /* time to wait before the initiator finishes the connectivity checks after
42 * the first check has succeeded */
43 #define ME_WAIT_TO_FINISH 1000 /* ms */
45 typedef struct private_connect_manager_t private_connect_manager_t
;
48 * Additional private members of connect_manager_t.
50 struct private_connect_manager_t
{
52 * Public interface of connect_manager_t.
54 connect_manager_t
public;
57 * Lock for exclusivly accessing the manager.
62 * Hasher to generate signatures
67 * Linked list with initiated mediated connections
69 linked_list_t
*initiated
;
72 * Linked list with checklists (hash table with connect ID as key would
75 linked_list_t
*checklists
;
78 typedef enum check_state_t check_state_t
;
88 typedef struct endpoint_pair_t endpoint_pair_t
;
91 * An entry in the check list.
93 struct endpoint_pair_t
{
100 /** local endpoint */
103 /** remote endpoint */
109 /** number of retransmissions */
110 u_int32_t retransmitted
;
112 /** the generated packet */
117 * Destroys an endpoint pair
119 static void endpoint_pair_destroy(endpoint_pair_t
*this)
121 DESTROY_IF(this->local
);
122 DESTROY_IF(this->remote
);
123 DESTROY_IF(this->packet
);
128 * Creates a new entry for the list.
130 static endpoint_pair_t
*endpoint_pair_create(endpoint_notify_t
*initiator
,
131 endpoint_notify_t
*responder
, bool initiator_is_local
)
133 endpoint_pair_t
*this;
135 u_int32_t pi
= initiator
->get_priority(initiator
);
136 u_int32_t pr
= responder
->get_priority(responder
);
139 .priority
= pow(2, 32) * min(pi
, pr
) + 2 * max(pi
, pr
)
141 .local
= initiator_is_local ? initiator
->get_base(initiator
)
142 : responder
->get_base(responder
),
143 .remote
= initiator_is_local ? responder
->get_host(responder
)
144 : initiator
->get_host(initiator
),
145 .state
= CHECK_WAITING
,
148 this->local
= this->local
->clone(this->local
);
149 this->remote
= this->remote
->clone(this->remote
);
155 typedef struct check_list_t check_list_t
;
158 * An entry in the linked list.
160 struct check_list_t
{
163 /** initiator's id */
164 identification_t
*id
;
166 /** initiator's key */
169 /** initiator's endpoints */
170 linked_list_t
*endpoints
;
174 /** responder's id */
175 identification_t
*id
;
177 /** responder's key */
180 /** responder's endpoints */
181 linked_list_t
*endpoints
;
187 /** list of endpoint pairs */
188 linked_list_t
*pairs
;
190 /** pairs queued for triggered checks */
191 linked_list_t
*triggered
;
196 /** TRUE if this is the initiator */
199 /** TRUE if the initiator is finishing the checks */
202 /** the current sender job */
208 * Destroys a checklist
210 static void check_list_destroy(check_list_t
*this)
212 DESTROY_IF(this->initiator
.id
);
213 DESTROY_IF(this->responder
.id
);
215 chunk_free(&this->connect_id
);
216 chunk_free(&this->initiator
.key
);
217 chunk_free(&this->responder
.key
);
219 DESTROY_OFFSET_IF(this->initiator
.endpoints
,
220 offsetof(endpoint_notify_t
, destroy
));
221 DESTROY_OFFSET_IF(this->responder
.endpoints
,
222 offsetof(endpoint_notify_t
, destroy
));
224 DESTROY_FUNCTION_IF(this->pairs
, (void*)endpoint_pair_destroy
);
225 /* this list contains some of the elements contained in this->pairs */
226 DESTROY_IF(this->triggered
);
232 * Creates a new checklist
234 static check_list_t
*check_list_create(identification_t
*initiator
,
235 identification_t
*responder
,
237 chunk_t initiator_key
,
238 linked_list_t
*initiator_endpoints
,
244 .connect_id
= chunk_clone(connect_id
),
246 .id
= initiator
->clone(initiator
),
247 .key
= chunk_clone(initiator_key
),
248 .endpoints
= initiator_endpoints
->clone_offset(initiator_endpoints
,
249 offsetof(endpoint_notify_t
, clone
)),
252 .id
= responder
->clone(responder
),
254 .pairs
= linked_list_create(),
255 .triggered
= linked_list_create(),
257 .is_initiator
= is_initiator
,
263 typedef struct initiated_t initiated_t
;
266 * For an initiator, the data stored about initiated mediation connections
270 identification_t
*id
;
273 identification_t
*peer_id
;
275 /** list of mediated sas */
276 linked_list_t
*mediated
;
280 * Destroys a queued initiation
282 static void initiated_destroy(initiated_t
*this)
284 DESTROY_IF(this->id
);
285 DESTROY_IF(this->peer_id
);
286 this->mediated
->destroy_offset(this->mediated
,
287 offsetof(ike_sa_id_t
, destroy
));
292 * Creates a queued initiation
294 static initiated_t
*initiated_create(identification_t
*id
,
295 identification_t
*peer_id
)
301 .peer_id
= peer_id
->clone(peer_id
),
302 .mediated
= linked_list_create(),
309 typedef struct check_t check_t
;
312 * Data exchanged in a connectivity check
318 /** source of the connectivity check */
321 /** destination of the connectivity check */
328 endpoint_notify_t
*endpoint
;
330 /** raw endpoint payload (to verify the signature) */
331 chunk_t endpoint_raw
;
338 * Destroys a connectivity check
340 static void check_destroy(check_t
*this)
342 chunk_free(&this->connect_id
);
343 chunk_free(&this->endpoint_raw
);
344 chunk_free(&this->auth
);
345 DESTROY_IF(this->src
);
346 DESTROY_IF(this->dst
);
347 DESTROY_IF(this->endpoint
);
352 * Creates a new connectivity check
354 static check_t
*check_create()
365 typedef struct callback_data_t callback_data_t
;
368 * Data required by several callback jobs used in this file
370 struct callback_data_t
{
371 /** connect manager */
372 private_connect_manager_t
*connect_manager
;
377 /** message (pair) id */
382 * Destroys a callback data object
384 static void callback_data_destroy(callback_data_t
*this)
386 chunk_free(&this->connect_id
);
391 * Creates a new callback data object
393 static callback_data_t
*callback_data_create(private_connect_manager_t
*connect_manager
,
396 callback_data_t
*this;
398 .connect_manager
= connect_manager
,
399 .connect_id
= chunk_clone(connect_id
),
406 * Creates a new retransmission data object
408 static callback_data_t
*retransmit_data_create(private_connect_manager_t
*connect_manager
,
409 chunk_t connect_id
, u_int32_t mid
)
411 callback_data_t
*this = callback_data_create(connect_manager
, connect_id
);
416 typedef struct initiate_data_t initiate_data_t
;
419 * Data required by the initiate mediated
421 struct initiate_data_t
{
423 check_list_t
*checklist
;
425 /** waiting mediated connections */
426 initiated_t
*initiated
;
430 * Destroys a initiate data object
432 static void initiate_data_destroy(initiate_data_t
*this)
434 check_list_destroy(this->checklist
);
435 initiated_destroy(this->initiated
);
440 * Creates a new initiate data object
442 static initiate_data_t
*initiate_data_create(check_list_t
*checklist
,
443 initiated_t
*initiated
)
445 initiate_data_t
*this;
447 .checklist
= checklist
,
448 .initiated
= initiated
,
454 * Find an initiated connection by the peers' ids
456 static bool match_initiated_by_ids(initiated_t
*current
, identification_t
*id
,
457 identification_t
*peer_id
)
459 return id
->equals(id
, current
->id
) && peer_id
->equals(peer_id
, current
->peer_id
);
462 static status_t
get_initiated_by_ids(private_connect_manager_t
*this,
463 identification_t
*id
,
464 identification_t
*peer_id
,
465 initiated_t
**initiated
)
467 return this->initiated
->find_first(this->initiated
,
468 (linked_list_match_t
)match_initiated_by_ids
,
469 (void**)initiated
, id
, peer_id
);
473 * Removes data about initiated connections
475 static void remove_initiated(private_connect_manager_t
*this,
476 initiated_t
*initiated
)
478 enumerator_t
*enumerator
;
479 initiated_t
*current
;
481 enumerator
= this->initiated
->create_enumerator(this->initiated
);
482 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
484 if (current
== initiated
)
486 this->initiated
->remove_at(this->initiated
, enumerator
);
490 enumerator
->destroy(enumerator
);
494 * Find the checklist with a specific connect ID
496 static bool match_checklist_by_id(check_list_t
*current
, chunk_t
*connect_id
)
498 return chunk_equals(*connect_id
, current
->connect_id
);
501 static status_t
get_checklist_by_id(private_connect_manager_t
*this,
503 check_list_t
**check_list
)
505 return this->checklists
->find_first(this->checklists
,
506 (linked_list_match_t
)match_checklist_by_id
,
507 (void**)check_list
, &connect_id
);
511 * Removes a checklist
513 static void remove_checklist(private_connect_manager_t
*this,
514 check_list_t
*checklist
)
516 enumerator_t
*enumerator
;
517 check_list_t
*current
;
519 enumerator
= this->checklists
->create_enumerator(this->checklists
);
520 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
522 if (current
== checklist
)
524 this->checklists
->remove_at(this->checklists
, enumerator
);
528 enumerator
->destroy(enumerator
);
532 * Checks if a list of endpoint_notify_t contains a certain host_t
534 static bool match_endpoint_by_host(endpoint_notify_t
*current
, host_t
*host
)
536 return host
->equals(host
, current
->get_host(current
));
539 static status_t
endpoints_contain(linked_list_t
*endpoints
, host_t
*host
,
540 endpoint_notify_t
**endpoint
)
542 return endpoints
->find_first(endpoints
,
543 (linked_list_match_t
)match_endpoint_by_host
,
544 (void**)endpoint
, host
);
548 * Inserts an endpoint pair into a list of pairs ordered by priority (high to low)
550 static void insert_pair_by_priority(linked_list_t
*pairs
, endpoint_pair_t
*pair
)
552 enumerator_t
*enumerator
= pairs
->create_enumerator(pairs
);
553 endpoint_pair_t
*current
;
554 while (enumerator
->enumerate(enumerator
, (void**)¤t
) &&
555 current
->priority
>= pair
->priority
)
559 pairs
->insert_before(pairs
, enumerator
, pair
);
560 enumerator
->destroy(enumerator
);
564 * Searches a list of endpoint_pair_t for a pair with specific host_ts
566 static bool match_pair_by_hosts(endpoint_pair_t
*current
, host_t
*local
,
569 return local
->equals(local
, current
->local
) && remote
->equals(remote
, current
->remote
);
572 static status_t
get_pair_by_hosts(linked_list_t
*pairs
, host_t
*local
,
573 host_t
*remote
, endpoint_pair_t
**pair
)
575 return pairs
->find_first(pairs
, (linked_list_match_t
)match_pair_by_hosts
,
576 (void**)pair
, local
, remote
);
579 static bool match_pair_by_id(endpoint_pair_t
*current
, u_int32_t
*id
)
581 return current
->id
== *id
;
585 * Searches for a pair with a specific id
587 static status_t
get_pair_by_id(check_list_t
*checklist
, u_int32_t id
,
588 endpoint_pair_t
**pair
)
590 return checklist
->pairs
->find_first(checklist
->pairs
,
591 (linked_list_match_t
)match_pair_by_id
,
595 static bool match_succeeded_pair(endpoint_pair_t
*current
)
597 return current
->state
== CHECK_SUCCEEDED
;
601 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
603 static status_t
get_best_valid_pair(check_list_t
*checklist
,
604 endpoint_pair_t
**pair
)
606 return checklist
->pairs
->find_first(checklist
->pairs
,
607 (linked_list_match_t
)match_succeeded_pair
,
611 static bool match_waiting_pair(endpoint_pair_t
*current
)
613 return current
->state
== CHECK_WAITING
;
617 * Returns and *removes* the first triggered pair in state CHECK_WAITING.
619 static status_t
get_triggered_pair(check_list_t
*checklist
,
620 endpoint_pair_t
**pair
)
622 enumerator_t
*enumerator
;
623 endpoint_pair_t
*current
;
624 status_t status
= NOT_FOUND
;
626 enumerator
= checklist
->triggered
->create_enumerator(checklist
->triggered
);
627 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
629 checklist
->triggered
->remove_at(checklist
->triggered
, enumerator
);
631 if (current
->state
== CHECK_WAITING
)
641 enumerator
->destroy(enumerator
);
647 * Prints all the pairs on a checklist
649 static void print_checklist(check_list_t
*checklist
)
651 enumerator_t
*enumerator
;
652 endpoint_pair_t
*current
;
654 DBG1(DBG_IKE
, "pairs on checklist %#B:", &checklist
->connect_id
);
655 enumerator
= checklist
->pairs
->create_enumerator(checklist
->pairs
);
656 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
658 DBG1(DBG_IKE
, " * %#H - %#H (%d)", current
->local
, current
->remote
,
661 enumerator
->destroy(enumerator
);
665 * Prunes identical pairs with lower priority from the list
666 * Note: this function also numbers the remaining pairs serially
668 static void prune_pairs(linked_list_t
*pairs
)
670 enumerator_t
*enumerator
, *search
;
671 endpoint_pair_t
*current
, *other
;
674 enumerator
= pairs
->create_enumerator(pairs
);
675 search
= pairs
->create_enumerator(pairs
);
676 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
680 while (search
->enumerate(search
, (void**)&other
))
682 if (current
== other
)
687 if (current
->local
->equals(current
->local
, other
->local
) &&
688 current
->remote
->equals(current
->remote
, other
->remote
))
690 /* since the list of pairs is sorted by priority in descending
691 * order, and we iterate the list from the beginning, we are
692 * sure that the priority of 'other' is lower than that of
693 * 'current', remove it */
694 DBG1(DBG_IKE
, "pruning endpoint pair %#H - %#H with priority %d",
695 other
->local
, other
->remote
, other
->priority
);
696 pairs
->remove_at(pairs
, search
);
697 endpoint_pair_destroy(other
);
700 pairs
->reset_enumerator(pairs
, search
);
702 search
->destroy(search
);
703 enumerator
->destroy(enumerator
);
707 * Builds a list of endpoint pairs
709 static void build_pairs(check_list_t
*checklist
)
711 /* FIXME: limit endpoints and pairs */
712 enumerator_t
*enumerator_i
, *enumerator_r
;
713 endpoint_notify_t
*initiator
, *responder
;
715 enumerator_i
= checklist
->initiator
.endpoints
->create_enumerator(
716 checklist
->initiator
.endpoints
);
717 while (enumerator_i
->enumerate(enumerator_i
, (void**)&initiator
))
719 enumerator_r
= checklist
->responder
.endpoints
->create_enumerator(
720 checklist
->responder
.endpoints
);
721 while (enumerator_r
->enumerate(enumerator_r
, (void**)&responder
))
723 if (initiator
->get_family(initiator
) != responder
->get_family(responder
))
728 insert_pair_by_priority(checklist
->pairs
, endpoint_pair_create(
729 initiator
, responder
, checklist
->is_initiator
));
731 enumerator_r
->destroy(enumerator_r
);
733 enumerator_i
->destroy(enumerator_i
);
735 print_checklist(checklist
);
737 prune_pairs(checklist
->pairs
);
741 * Processes the payloads of a connectivity check and returns the extracted data
743 static status_t
process_payloads(message_t
*message
, check_t
*check
)
745 enumerator_t
*enumerator
;
748 enumerator
= message
->create_payload_enumerator(message
);
749 while (enumerator
->enumerate(enumerator
, &payload
))
751 if (payload
->get_type(payload
) != NOTIFY
)
753 DBG1(DBG_IKE
, "ignoring payload of type '%N' while processing "
754 "connectivity check", payload_type_names
,
755 payload
->get_type(payload
));
759 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
761 switch (notify
->get_notify_type(notify
))
767 DBG1(DBG_IKE
, "connectivity check contains multiple "
768 "ME_ENDPOINT notifies");
772 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
775 DBG1(DBG_IKE
, "received invalid ME_ENDPOINT notify");
778 check
->endpoint
= endpoint
;
779 check
->endpoint_raw
= chunk_clone(notify
->get_notification_data(notify
));
780 DBG2(DBG_IKE
, "received ME_ENDPOINT notify");
785 if (check
->connect_id
.ptr
)
787 DBG1(DBG_IKE
, "connectivity check contains multiple "
788 "ME_CONNECTID notifies");
791 check
->connect_id
= chunk_clone(notify
->get_notification_data(notify
));
792 DBG2(DBG_IKE
, "received ME_CONNECTID %#B", &check
->connect_id
);
799 DBG1(DBG_IKE
, "connectivity check contains multiple "
800 "ME_CONNECTAUTH notifies");
803 check
->auth
= chunk_clone(notify
->get_notification_data(notify
));
804 DBG2(DBG_IKE
, "received ME_CONNECTAUTH %#B", &check
->auth
);
811 enumerator
->destroy(enumerator
);
813 if (!check
->connect_id
.ptr
|| !check
->endpoint
|| !check
->auth
.ptr
)
815 DBG1(DBG_IKE
, "at least one required payload was missing from the "
816 "connectivity check");
824 * Builds the signature for a connectivity check
826 static chunk_t
build_signature(private_connect_manager_t
*this,
827 check_list_t
*checklist
, check_t
*check
, bool outbound
)
830 chunk_t mid_chunk
, key_chunk
, sig_chunk
;
833 mid
= htonl(check
->mid
);
834 mid_chunk
= chunk_from_thing(mid
);
836 key_chunk
= (checklist
->is_initiator
&& outbound
) || (!checklist
->is_initiator
&& !outbound
)
837 ? checklist
->initiator
.key
: checklist
->responder
.key
;
839 /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */
840 sig_chunk
= chunk_cat("cccc", mid_chunk
, check
->connect_id
,
841 check
->endpoint_raw
, key_chunk
);
842 this->hasher
->allocate_hash(this->hasher
, sig_chunk
, &sig_hash
);
843 DBG3(DBG_IKE
, "sig_chunk %#B", &sig_chunk
);
844 DBG3(DBG_IKE
, "sig_hash %#B", &sig_hash
);
846 chunk_free(&sig_chunk
);
850 static void queue_retransmission(private_connect_manager_t
*this, check_list_t
*checklist
, endpoint_pair_t
*pair
);
851 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
);
852 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
);
855 * After one of the initiator's pairs has succeeded we finish the checks without
856 * waiting for all the timeouts
858 static job_requeue_t
initiator_finish(callback_data_t
*data
)
860 private_connect_manager_t
*this = data
->connect_manager
;
862 this->mutex
->lock(this->mutex
);
864 check_list_t
*checklist
;
865 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
867 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't finish "
868 "connectivity checks", &data
->connect_id
);
869 this->mutex
->unlock(this->mutex
);
870 return JOB_REQUEUE_NONE
;
873 finish_checks(this, checklist
);
875 this->mutex
->unlock(this->mutex
);
877 return JOB_REQUEUE_NONE
;
881 * Updates the state of the whole checklist
883 static void update_checklist_state(private_connect_manager_t
*this,
884 check_list_t
*checklist
)
886 enumerator_t
*enumerator
;
887 endpoint_pair_t
*current
;
888 bool in_progress
= FALSE
, succeeded
= FALSE
;
890 enumerator
= checklist
->pairs
->create_enumerator(checklist
->pairs
);
891 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
893 switch(current
->state
)
896 /* at least one is still waiting -> checklist remains
897 * in waiting state */
898 enumerator
->destroy(enumerator
);
900 case CHECK_IN_PROGRESS
:
903 case CHECK_SUCCEEDED
:
910 enumerator
->destroy(enumerator
);
912 if (checklist
->is_initiator
&& succeeded
&& !checklist
->is_finishing
)
914 /* instead of waiting until all checks have finished (i.e. all
915 * retransmissions have failed) the initiator finishes the checks
916 * right after the first check has succeeded. to allow a probably
917 * better pair to succeed, we still wait a certain time */
918 DBG2(DBG_IKE
, "fast finishing checks for checklist '%#B'",
919 &checklist
->connect_id
);
921 callback_data_t
*data
= callback_data_create(this, checklist
->connect_id
);
922 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiator_finish
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
923 lib
->scheduler
->schedule_job_ms(lib
->scheduler
, job
, ME_WAIT_TO_FINISH
);
924 checklist
->is_finishing
= TRUE
;
929 checklist
->state
= CHECK_IN_PROGRESS
;
933 checklist
->state
= CHECK_SUCCEEDED
;
937 checklist
->state
= CHECK_FAILED
;
942 * This function is triggered for each sent check after a specific timeout
944 static job_requeue_t
retransmit(callback_data_t
*data
)
946 private_connect_manager_t
*this = data
->connect_manager
;
948 this->mutex
->lock(this->mutex
);
950 check_list_t
*checklist
;
951 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
953 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't retransmit "
954 "connectivity check", &data
->connect_id
);
955 this->mutex
->unlock(this->mutex
);
956 return JOB_REQUEUE_NONE
;
959 endpoint_pair_t
*pair
;
960 if (get_pair_by_id(checklist
, data
->mid
, &pair
) != SUCCESS
)
962 DBG1(DBG_IKE
, "pair with id '%d' not found, can't retransmit "
963 "connectivity check", data
->mid
);
967 if (pair
->state
!= CHECK_IN_PROGRESS
)
969 DBG2(DBG_IKE
, "pair with id '%d' is in wrong state [%d], don't "
970 "retransmit the connectivity check", data
->mid
, pair
->state
);
974 if (++pair
->retransmitted
> ME_MAX_RETRANS
)
976 DBG2(DBG_IKE
, "pair with id '%d' failed after %d retransmissions",
977 data
->mid
, ME_MAX_RETRANS
);
978 pair
->state
= CHECK_FAILED
;
982 charon
->sender
->send(charon
->sender
, pair
->packet
->clone(pair
->packet
));
984 queue_retransmission(this, checklist
, pair
);
987 update_checklist_state(this, checklist
);
989 switch(checklist
->state
)
991 case CHECK_SUCCEEDED
:
993 finish_checks(this, checklist
);
999 this->mutex
->unlock(this->mutex
);
1001 /* we reschedule it manually */
1002 return JOB_REQUEUE_NONE
;
1006 * Queues a retransmission job
1008 static void queue_retransmission(private_connect_manager_t
*this, check_list_t
*checklist
, endpoint_pair_t
*pair
)
1010 callback_data_t
*data
= retransmit_data_create(this, checklist
->connect_id
, pair
->id
);
1011 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)retransmit
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
1013 u_int32_t retransmission
= pair
->retransmitted
+ 1;
1014 u_int32_t rto
= ME_INTERVAL
;
1015 if (retransmission
> ME_BOOST
)
1017 rto
= (u_int32_t
)(ME_INTERVAL
* pow(ME_RETRANS_BASE
, retransmission
- ME_BOOST
));
1019 DBG2(DBG_IKE
, "scheduling retransmission %d of pair '%d' in %dms",
1020 retransmission
, pair
->id
, rto
);
1022 lib
->scheduler
->schedule_job_ms(lib
->scheduler
, (job_t
*)job
, rto
);
1028 static void send_check(private_connect_manager_t
*this, check_list_t
*checklist
,
1029 check_t
*check
, endpoint_pair_t
*pair
, bool request
)
1031 message_t
*message
= message_create();
1032 message
->set_message_id(message
, check
->mid
);
1033 message
->set_exchange_type(message
, INFORMATIONAL
);
1034 message
->set_request(message
, request
);
1035 message
->set_destination(message
, check
->dst
->clone(check
->dst
));
1036 message
->set_source(message
, check
->src
->clone(check
->src
));
1038 ike_sa_id_t
*ike_sa_id
= ike_sa_id_create(0, 0, request
);
1039 message
->set_ike_sa_id(message
, ike_sa_id
);
1040 ike_sa_id
->destroy(ike_sa_id
);
1042 message
->add_notify(message
, FALSE
, ME_CONNECTID
, check
->connect_id
);
1043 DBG2(DBG_IKE
, "send ME_CONNECTID %#B", &check
->connect_id
);
1045 notify_payload_t
*endpoint
= check
->endpoint
->build_notify(check
->endpoint
);
1046 check
->endpoint_raw
= chunk_clone(endpoint
->get_notification_data(endpoint
));
1047 message
->add_payload(message
, (payload_t
*)endpoint
);
1048 DBG2(DBG_IKE
, "send ME_ENDPOINT notify");
1050 check
->auth
= build_signature(this, checklist
, check
, TRUE
);
1051 message
->add_notify(message
, FALSE
, ME_CONNECTAUTH
, check
->auth
);
1052 DBG2(DBG_IKE
, "send ME_CONNECTAUTH %#B", &check
->auth
);
1055 if (message
->generate(message
, NULL
, &packet
) == SUCCESS
)
1057 charon
->sender
->send(charon
->sender
, packet
->clone(packet
));
1061 DESTROY_IF(pair
->packet
);
1062 pair
->packet
= packet
;
1063 pair
->retransmitted
= 0;
1064 queue_retransmission(this, checklist
, pair
);
1068 packet
->destroy(packet
);
1071 message
->destroy(message
);
1075 * Queues a triggered check
1077 static void queue_triggered_check(private_connect_manager_t
*this,
1078 check_list_t
*checklist
, endpoint_pair_t
*pair
)
1080 DBG2(DBG_IKE
, "queueing triggered check for pair '%d'", pair
->id
);
1081 pair
->state
= CHECK_WAITING
;
1082 checklist
->triggered
->insert_last(checklist
->triggered
, pair
);
1084 if (!checklist
->sender
)
1086 /* if the sender is not running we restart it */
1087 schedule_checks(this, checklist
, ME_INTERVAL
);
1092 * This function is triggered for each checklist at a specific interval
1094 static job_requeue_t
sender(callback_data_t
*data
)
1096 private_connect_manager_t
*this = data
->connect_manager
;
1098 this->mutex
->lock(this->mutex
);
1100 check_list_t
*checklist
;
1101 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
1103 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't send "
1104 "connectivity check", &data
->connect_id
);
1105 this->mutex
->unlock(this->mutex
);
1106 return JOB_REQUEUE_NONE
;
1109 /* reset the sender */
1110 checklist
->sender
= NULL
;
1112 endpoint_pair_t
*pair
;
1113 if (get_triggered_pair(checklist
, &pair
) != SUCCESS
)
1115 DBG1(DBG_IKE
, "no triggered check queued, sending an ordinary check");
1117 if (checklist
->pairs
->find_first(checklist
->pairs
,
1118 (linked_list_match_t
)match_waiting_pair
,
1119 (void**)&pair
) != SUCCESS
)
1121 this->mutex
->unlock(this->mutex
);
1122 DBG1(DBG_IKE
, "no pairs in waiting state, aborting");
1123 return JOB_REQUEUE_NONE
;
1128 DBG1(DBG_IKE
, "triggered check found");
1131 check_t
*check
= check_create();
1132 check
->mid
= pair
->id
;
1133 check
->src
= pair
->local
->clone(pair
->local
);
1134 check
->dst
= pair
->remote
->clone(pair
->remote
);
1135 check
->connect_id
= chunk_clone(checklist
->connect_id
);
1136 check
->endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
, NULL
,
1139 pair
->state
= CHECK_IN_PROGRESS
;
1141 send_check(this, checklist
, check
, pair
, TRUE
);
1143 check_destroy(check
);
1145 /* schedule this job again */
1146 schedule_checks(this, checklist
, ME_INTERVAL
);
1148 this->mutex
->unlock(this->mutex
);
1150 /* we reschedule it manually */
1151 return JOB_REQUEUE_NONE
;
1155 * Schedules checks for a checklist (time in ms)
1157 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
)
1159 callback_data_t
*data
= callback_data_create(this, checklist
->connect_id
);
1160 checklist
->sender
= (job_t
*)callback_job_create((callback_job_cb_t
)sender
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
1161 lib
->scheduler
->schedule_job_ms(lib
->scheduler
, checklist
->sender
, time
);
1165 * Initiates waiting mediated connections
1167 static job_requeue_t
initiate_mediated(initiate_data_t
*data
)
1169 check_list_t
*checklist
= data
->checklist
;
1170 initiated_t
*initiated
= data
->initiated
;
1172 endpoint_pair_t
*pair
;
1173 if (get_best_valid_pair(checklist
, &pair
) == SUCCESS
)
1175 ike_sa_id_t
*waiting_sa
;
1176 enumerator_t
*enumerator
= initiated
->mediated
->create_enumerator(
1177 initiated
->mediated
);
1178 while (enumerator
->enumerate(enumerator
, (void**)&waiting_sa
))
1180 ike_sa_t
*sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, waiting_sa
);
1181 if (sa
->initiate_mediated(sa
, pair
->local
, pair
->remote
, checklist
->connect_id
) != SUCCESS
)
1183 DBG1(DBG_IKE
, "establishing mediated connection failed");
1184 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, sa
);
1188 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, sa
);
1191 enumerator
->destroy(enumerator
);
1195 /* this should (can?) not happen */
1198 return JOB_REQUEUE_NONE
;
1202 * Finishes checks for a checklist
1204 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
)
1206 if (checklist
->is_initiator
)
1208 initiated_t
*initiated
;
1209 if (get_initiated_by_ids(this, checklist
->initiator
.id
,
1210 checklist
->responder
.id
, &initiated
) == SUCCESS
)
1212 remove_checklist(this, checklist
);
1213 remove_initiated(this, initiated
);
1215 initiate_data_t
*data
= initiate_data_create(checklist
, initiated
);
1216 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiate_mediated
, data
, (callback_job_cleanup_t
)initiate_data_destroy
, NULL
);
1217 lib
->processor
->queue_job(lib
->processor
, job
);
1222 DBG1(DBG_IKE
, "there is no mediated connection waiting between '%Y'"
1223 " and '%Y'", checklist
->initiator
.id
, checklist
->responder
.id
);
1229 * Process the response to one of our requests
1231 static void process_response(private_connect_manager_t
*this, check_t
*check
,
1232 check_list_t
*checklist
)
1234 endpoint_pair_t
*pair
;
1235 if (get_pair_by_id(checklist
, check
->mid
, &pair
) == SUCCESS
)
1237 if (pair
->local
->equals(pair
->local
, check
->dst
) &&
1238 pair
->remote
->equals(pair
->remote
, check
->src
))
1240 DBG1(DBG_IKE
, "endpoint pair '%d' is valid: '%#H' - '%#H'",
1241 pair
->id
, pair
->local
, pair
->remote
);
1242 pair
->state
= CHECK_SUCCEEDED
;
1245 linked_list_t
*local_endpoints
= checklist
->is_initiator ?
1246 checklist
->initiator
.endpoints
: checklist
->responder
.endpoints
;
1248 endpoint_notify_t
*local_endpoint
;
1249 if (endpoints_contain(local_endpoints
,
1250 check
->endpoint
->get_host(check
->endpoint
),
1251 &local_endpoint
) != SUCCESS
)
1253 local_endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1254 check
->endpoint
->get_host(check
->endpoint
), pair
->local
);
1255 local_endpoint
->set_priority(local_endpoint
,
1256 check
->endpoint
->get_priority(check
->endpoint
));
1257 local_endpoints
->insert_last(local_endpoints
, local_endpoint
);
1260 update_checklist_state(this, checklist
);
1262 switch(checklist
->state
)
1264 case CHECK_SUCCEEDED
:
1266 finish_checks(this, checklist
);
1274 DBG1(DBG_IKE
, "pair with id '%d' not found", check
->mid
);
1278 static void process_request(private_connect_manager_t
*this, check_t
*check
,
1279 check_list_t
*checklist
)
1281 linked_list_t
*remote_endpoints
= checklist
->is_initiator ?
1282 checklist
->responder
.endpoints
: checklist
->initiator
.endpoints
;
1284 endpoint_notify_t
*peer_reflexive
, *remote_endpoint
;
1285 peer_reflexive
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1287 peer_reflexive
->set_priority(peer_reflexive
,
1288 check
->endpoint
->get_priority(check
->endpoint
));
1290 if (endpoints_contain(remote_endpoints
, check
->src
, &remote_endpoint
) != SUCCESS
)
1292 remote_endpoint
= peer_reflexive
->clone(peer_reflexive
);
1293 remote_endpoints
->insert_last(remote_endpoints
, remote_endpoint
);
1296 endpoint_pair_t
*pair
;
1297 if (get_pair_by_hosts(checklist
->pairs
, check
->dst
, check
->src
,
1302 case CHECK_IN_PROGRESS
:
1303 /* prevent retransmissions */
1304 pair
->retransmitted
= ME_MAX_RETRANS
;
1305 /* FIXME: we should wait to the next rto to send the triggered
1310 queue_triggered_check(this, checklist
, pair
);
1312 case CHECK_SUCCEEDED
:
1319 endpoint_notify_t
*local_endpoint
= endpoint_notify_create_from_host(HOST
, check
->dst
, NULL
);
1321 endpoint_notify_t
*initiator
= checklist
->is_initiator ? local_endpoint
: remote_endpoint
;
1322 endpoint_notify_t
*responder
= checklist
->is_initiator ? remote_endpoint
: local_endpoint
;
1324 pair
= endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
);
1325 pair
->id
= checklist
->pairs
->get_count(checklist
->pairs
) + 1;
1327 insert_pair_by_priority(checklist
->pairs
, pair
);
1329 queue_triggered_check(this, checklist
, pair
);
1331 local_endpoint
->destroy(local_endpoint
);
1334 check_t
*response
= check_create();
1336 response
->mid
= check
->mid
;
1337 response
->src
= check
->dst
->clone(check
->dst
);
1338 response
->dst
= check
->src
->clone(check
->src
);
1339 response
->connect_id
= chunk_clone(check
->connect_id
);
1340 response
->endpoint
= peer_reflexive
;
1342 send_check(this, checklist
, response
, pair
, FALSE
);
1344 check_destroy(response
);
1347 METHOD(connect_manager_t
, process_check
, void,
1348 private_connect_manager_t
*this, message_t
*message
)
1350 if (message
->parse_body(message
, NULL
) != SUCCESS
)
1352 DBG1(DBG_IKE
, "%N %s with message ID %d processing failed",
1353 exchange_type_names
, message
->get_exchange_type(message
),
1354 message
->get_request(message
) ?
"request" : "response",
1355 message
->get_message_id(message
));
1359 check_t
*check
= check_create();
1360 check
->mid
= message
->get_message_id(message
);
1361 check
->src
= message
->get_source(message
);
1362 check
->src
= check
->src
->clone(check
->src
);
1363 check
->dst
= message
->get_destination(message
);
1364 check
->dst
= check
->dst
->clone(check
->dst
);
1366 if (process_payloads(message
, check
) != SUCCESS
)
1368 DBG1(DBG_IKE
, "invalid connectivity check %s received",
1369 message
->get_request(message
) ?
"request" : "response");
1370 check_destroy(check
);
1374 this->mutex
->lock(this->mutex
);
1376 check_list_t
*checklist
;
1377 if (get_checklist_by_id(this, check
->connect_id
, &checklist
) != SUCCESS
)
1379 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1380 &check
->connect_id
);
1381 check_destroy(check
);
1382 this->mutex
->unlock(this->mutex
);
1386 chunk_t sig
= build_signature(this, checklist
, check
, FALSE
);
1387 if (!chunk_equals(sig
, check
->auth
))
1389 DBG1(DBG_IKE
, "connectivity check verification failed");
1390 check_destroy(check
);
1392 this->mutex
->unlock(this->mutex
);
1397 if (message
->get_request(message
))
1399 process_request(this, check
, checklist
);
1403 process_response(this, check
, checklist
);
1406 this->mutex
->unlock(this->mutex
);
1408 check_destroy(check
);
1411 METHOD(connect_manager_t
, check_and_register
, bool,
1412 private_connect_manager_t
*this, identification_t
*id
,
1413 identification_t
*peer_id
, ike_sa_id_t
*mediated_sa
)
1415 initiated_t
*initiated
;
1416 bool already_there
= TRUE
;
1418 this->mutex
->lock(this->mutex
);
1420 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1422 DBG2(DBG_IKE
, "registered waiting mediated connection with '%Y'",
1424 initiated
= initiated_create(id
, peer_id
);
1425 this->initiated
->insert_last(this->initiated
, initiated
);
1426 already_there
= FALSE
;
1429 if (initiated
->mediated
->find_first(initiated
->mediated
,
1430 (linked_list_match_t
)mediated_sa
->equals
,
1431 NULL
, mediated_sa
) != SUCCESS
)
1433 initiated
->mediated
->insert_last(initiated
->mediated
,
1434 mediated_sa
->clone(mediated_sa
));
1437 this->mutex
->unlock(this->mutex
);
1439 return already_there
;
1442 METHOD(connect_manager_t
, check_and_initiate
, void,
1443 private_connect_manager_t
*this, ike_sa_id_t
*mediation_sa
,
1444 identification_t
*id
, identification_t
*peer_id
)
1446 initiated_t
*initiated
;
1448 this->mutex
->lock(this->mutex
);
1450 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1452 DBG2(DBG_IKE
, "no waiting mediated connections with '%Y'", peer_id
);
1453 this->mutex
->unlock(this->mutex
);
1457 ike_sa_id_t
*waiting_sa
;
1458 enumerator_t
*enumerator
= initiated
->mediated
->create_enumerator(
1459 initiated
->mediated
);
1460 while (enumerator
->enumerate(enumerator
, (void**)&waiting_sa
))
1462 job_t
*job
= (job_t
*)reinitiate_mediation_job_create(mediation_sa
,
1464 lib
->processor
->queue_job(lib
->processor
, job
);
1466 enumerator
->destroy(enumerator
);
1468 this->mutex
->unlock(this->mutex
);
1471 METHOD(connect_manager_t
, set_initiator_data
, status_t
,
1472 private_connect_manager_t
*this, identification_t
*initiator
,
1473 identification_t
*responder
, chunk_t connect_id
, chunk_t key
,
1474 linked_list_t
*endpoints
, bool is_initiator
)
1476 check_list_t
*checklist
;
1478 this->mutex
->lock(this->mutex
);
1480 if (get_checklist_by_id(this, connect_id
, NULL
) == SUCCESS
)
1482 DBG1(DBG_IKE
, "checklist with id '%#B' already exists, aborting",
1484 this->mutex
->unlock(this->mutex
);
1488 checklist
= check_list_create(initiator
, responder
, connect_id
, key
,
1489 endpoints
, is_initiator
);
1490 this->checklists
->insert_last(this->checklists
, checklist
);
1492 this->mutex
->unlock(this->mutex
);
1497 METHOD(connect_manager_t
, set_responder_data
, status_t
,
1498 private_connect_manager_t
*this, chunk_t connect_id
, chunk_t key
,
1499 linked_list_t
*endpoints
)
1501 check_list_t
*checklist
;
1503 this->mutex
->lock(this->mutex
);
1505 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1507 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1509 this->mutex
->unlock(this->mutex
);
1513 checklist
->responder
.key
= chunk_clone(key
);
1514 checklist
->responder
.endpoints
= endpoints
->clone_offset(endpoints
,
1515 offsetof(endpoint_notify_t
, clone
));
1516 checklist
->state
= CHECK_WAITING
;
1518 build_pairs(checklist
);
1520 /* send the first check immediately */
1521 schedule_checks(this, checklist
, 0);
1523 this->mutex
->unlock(this->mutex
);
1528 METHOD(connect_manager_t
, stop_checks
, status_t
,
1529 private_connect_manager_t
*this, chunk_t connect_id
)
1531 check_list_t
*checklist
;
1533 this->mutex
->lock(this->mutex
);
1535 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1537 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1539 this->mutex
->unlock(this->mutex
);
1543 DBG1(DBG_IKE
, "removing checklist with id '%#B'", &connect_id
);
1545 remove_checklist(this, checklist
);
1546 check_list_destroy(checklist
);
1548 this->mutex
->unlock(this->mutex
);
1553 METHOD(connect_manager_t
, destroy
, void,
1554 private_connect_manager_t
*this)
1556 this->mutex
->lock(this->mutex
);
1558 this->checklists
->destroy_function(this->checklists
,
1559 (void*)check_list_destroy
);
1560 this->initiated
->destroy_function(this->initiated
,
1561 (void*)initiated_destroy
);
1562 DESTROY_IF(this->hasher
);
1564 this->mutex
->unlock(this->mutex
);
1565 this->mutex
->destroy(this->mutex
);
1570 * Described in header.
1572 connect_manager_t
*connect_manager_create()
1574 private_connect_manager_t
*this;
1578 .destroy
= _destroy
,
1579 .check_and_register
= _check_and_register
,
1580 .check_and_initiate
= _check_and_initiate
,
1581 .set_initiator_data
= _set_initiator_data
,
1582 .set_responder_data
= _set_responder_data
,
1583 .process_check
= _process_check
,
1584 .stop_checks
= _stop_checks
,
1586 .hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
),
1587 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
1588 .checklists
= linked_list_create(),
1589 .initiated
= linked_list_create(),
1592 if (this->hasher
== NULL
)
1594 DBG1(DBG_IKE
, "unable to create connect manager, SHA1 not supported");
1599 return &this->public;