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
18 #include "connect_manager.h"
24 #include <utils/linked_list.h>
25 #include <crypto/hashers/hasher.h>
27 #include <processing/jobs/callback_job.h>
28 #include <processing/jobs/initiate_mediation_job.h>
29 #include <encoding/payloads/endpoint_notify.h>
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 */
38 /* base for retransmissions */
39 #define ME_RETRANS_BASE 1.8
40 /* max number of retransmissions */
41 #define ME_MAX_RETRANS 13
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 */
48 typedef struct private_connect_manager_t private_connect_manager_t
;
51 * Additional private members of connect_manager_t.
53 struct private_connect_manager_t
{
55 * Public interface of connect_manager_t.
57 connect_manager_t
public;
60 * Lock for exclusivly accessing the manager.
62 pthread_mutex_t mutex
;
65 * Hasher to generate signatures
70 * Linked list with initiated mediated connections
72 linked_list_t
*initiated
;
75 * Linked list with checklists (hash table with connect ID as key would be better).
77 linked_list_t
*checklists
;
80 typedef enum check_state_t check_state_t
;
90 typedef struct endpoint_pair_t endpoint_pair_t
;
93 * An entry in the check list.
95 struct endpoint_pair_t
{
102 /** local endpoint */
105 /** remote endpoint */
111 /** number of retransmissions */
112 u_int32_t retransmitted
;
114 /** the generated packet */
119 * Destroys an endpoint pair
121 static void endpoint_pair_destroy(endpoint_pair_t
*this)
123 DESTROY_IF(this->local
);
124 DESTROY_IF(this->remote
);
125 DESTROY_IF(this->packet
);
130 * Creates a new entry for the list.
132 static endpoint_pair_t
*endpoint_pair_create(endpoint_notify_t
*initiator
,
133 endpoint_notify_t
*responder
, bool initiator_is_local
)
135 endpoint_pair_t
*this = malloc_thing(endpoint_pair_t
);
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);
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
);
148 this->state
= CHECK_WAITING
;
149 this->retransmitted
= 0;
156 typedef struct check_list_t check_list_t
;
159 * An entry in the linked list.
161 struct check_list_t
{
164 /** initiator's id */
165 identification_t
*id
;
167 /** initiator's key */
170 /** initiator's endpoints */
171 linked_list_t
*endpoints
;
175 /** responder's id */
176 identification_t
*id
;
178 /** responder's key */
181 /** responder's endpoints */
182 linked_list_t
*endpoints
;
188 /** list of endpoint pairs */
189 linked_list_t
*pairs
;
191 /** pairs queued for triggered checks */
192 linked_list_t
*triggered
;
197 /** TRUE if this is the initiator */
200 /** TRUE if the initiator is finishing the checks */
203 /** the current sender job */
209 * Destroys a checklist
211 static void check_list_destroy(check_list_t
*this)
213 DESTROY_IF(this->initiator
.id
);
214 DESTROY_IF(this->responder
.id
);
216 chunk_free(&this->connect_id
);
217 chunk_free(&this->initiator
.key
);
218 chunk_free(&this->responder
.key
);
220 DESTROY_OFFSET_IF(this->initiator
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
221 DESTROY_OFFSET_IF(this->responder
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
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
);
231 * Creates a new checklist
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
,
237 check_list_t
*this = malloc_thing(check_list_t
);
239 this->connect_id
= chunk_clone(connect_id
);
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
));
245 this->responder
.id
= responder
->clone(responder
);
246 this->responder
.key
= chunk_empty
;
247 this->responder
.endpoints
= NULL
;
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
;
259 typedef struct waiting_sa_t waiting_sa_t
;
262 * For an initiator, the data stored about a waiting mediated sa
264 struct waiting_sa_t
{
266 ike_sa_id_t
*ike_sa_id
;
268 /** list of child_cfg_t */
269 linked_list_t
*childs
;
273 * Destroys a queued mediated sa
275 static void waiting_sa_destroy(waiting_sa_t
*this)
277 DESTROY_IF(this->ike_sa_id
);
278 this->childs
->destroy_offset(this->childs
, offsetof(child_cfg_t
, destroy
));
283 * Creates a new mediated sa object
285 static waiting_sa_t
*waiting_sa_create(ike_sa_id_t
*ike_sa_id
)
287 waiting_sa_t
*this = malloc_thing(waiting_sa_t
);
289 this->ike_sa_id
= ike_sa_id
->clone(ike_sa_id
);
290 this->childs
= linked_list_create();
295 typedef struct initiated_t initiated_t
;
298 * For an initiator, the data stored about initiated mediation connections
302 identification_t
*id
;
305 identification_t
*peer_id
;
307 /** list of mediated sas */
308 linked_list_t
*mediated
;
312 * Destroys a queued initiation
314 static void initiated_destroy(initiated_t
*this)
316 DESTROY_IF(this->id
);
317 DESTROY_IF(this->peer_id
);
318 this->mediated
->destroy_function(this->mediated
, (void*)waiting_sa_destroy
);
323 * Creates a queued initiation
325 static initiated_t
*initiated_create(identification_t
*id
, identification_t
*peer_id
)
327 initiated_t
*this = malloc_thing(initiated_t
);
329 this->id
= id
->clone(id
);
330 this->peer_id
= peer_id
->clone(peer_id
);
331 this->mediated
= linked_list_create();
337 typedef struct check_t check_t
;
340 * Data exchanged in a connectivity check
346 /** source of the connectivity check */
349 /** destination of the connectivity check */
356 endpoint_notify_t
*endpoint
;
358 /** raw endpoint payload (to verify the signature) */
359 chunk_t endpoint_raw
;
366 * Destroys a connectivity check
368 static void check_destroy(check_t
*this)
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
);
380 * Creates a new connectivity check
382 static check_t
*check_create()
384 check_t
*this = malloc_thing(check_t
);
386 this->connect_id
= chunk_empty
;
387 this->auth
= chunk_empty
;
388 this->endpoint_raw
= chunk_empty
;
391 this->endpoint
= NULL
;
398 typedef struct callback_data_t callback_data_t
;
401 * Data required by several callback jobs used in this file
403 struct callback_data_t
{
404 /** connect manager */
405 private_connect_manager_t
*connect_manager
;
410 /** message (pair) id */
415 * Destroys a callback data object
417 static void callback_data_destroy(callback_data_t
*this)
419 chunk_free(&this->connect_id
);
424 * Creates a new callback data object
426 static callback_data_t
*callback_data_create(private_connect_manager_t
*connect_manager
,
429 callback_data_t
*this = malloc_thing(callback_data_t
);
430 this->connect_manager
= connect_manager
;
431 this->connect_id
= chunk_clone(connect_id
);
437 * Creates a new retransmission data object
439 static callback_data_t
*retransmit_data_create(private_connect_manager_t
*connect_manager
,
440 chunk_t connect_id
, u_int32_t mid
)
442 callback_data_t
*this = callback_data_create(connect_manager
, connect_id
);
447 typedef struct initiate_data_t initiate_data_t
;
450 * Data required by the initiate mediated
452 struct initiate_data_t
{
454 check_list_t
*checklist
;
456 /** waiting mediated connections */
457 initiated_t
*initiated
;
461 * Destroys a initiate data object
463 static void initiate_data_destroy(initiate_data_t
*this)
465 check_list_destroy(this->checklist
);
466 initiated_destroy(this->initiated
);
471 * Creates a new initiate data object
473 static initiate_data_t
*initiate_data_create(check_list_t
*checklist
, initiated_t
*initiated
)
475 initiate_data_t
*this = malloc_thing(initiate_data_t
);
477 this->checklist
= checklist
;
478 this->initiated
= initiated
;
484 * Find an initiated connection by the peers' ids
486 static bool match_initiated_by_ids(initiated_t
*current
, identification_t
*id
,
487 identification_t
*peer_id
)
489 return id
->equals(id
, current
->id
) && peer_id
->equals(peer_id
, current
->peer_id
);
492 static status_t
get_initiated_by_ids(private_connect_manager_t
*this,
493 identification_t
*id
, identification_t
*peer_id
, initiated_t
**initiated
)
495 return this->initiated
->find_first(this->initiated
,
496 (linked_list_match_t
)match_initiated_by_ids
,
497 (void**)initiated
, id
, peer_id
);
501 * Removes data about initiated connections
503 static void remove_initiated(private_connect_manager_t
*this, initiated_t
*initiated
)
505 iterator_t
*iterator
;
506 initiated_t
*current
;
508 iterator
= this->initiated
->create_iterator(this->initiated
, TRUE
);
509 while (iterator
->iterate(iterator
, (void**)¤t
))
511 if (current
== initiated
)
513 iterator
->remove(iterator
);
517 iterator
->destroy(iterator
);
523 static bool match_waiting_sa(waiting_sa_t
*current
, ike_sa_id_t
*ike_sa_id
)
525 return ike_sa_id
->equals(ike_sa_id
, current
->ike_sa_id
);
528 static status_t
get_waiting_sa(initiated_t
*initiated
, ike_sa_id_t
*ike_sa_id
, waiting_sa_t
**waiting_sa
)
530 return initiated
->mediated
->find_first(initiated
->mediated
,
531 (linked_list_match_t
)match_waiting_sa
,
532 (void**)waiting_sa
, ike_sa_id
);
536 * Find the checklist with a specific connect ID
538 static bool match_checklist_by_id(check_list_t
*current
, chunk_t
*connect_id
)
540 return chunk_equals(*connect_id
, current
->connect_id
);
543 static status_t
get_checklist_by_id(private_connect_manager_t
*this,
544 chunk_t connect_id
, check_list_t
**check_list
)
546 return this->checklists
->find_first(this->checklists
,
547 (linked_list_match_t
)match_checklist_by_id
,
548 (void**)check_list
, &connect_id
);
552 * Removes a checklist
554 static void remove_checklist(private_connect_manager_t
*this, check_list_t
*checklist
)
556 iterator_t
*iterator
;
557 check_list_t
*current
;
559 iterator
= this->checklists
->create_iterator(this->checklists
, TRUE
);
560 while (iterator
->iterate(iterator
, (void**)¤t
))
562 if (current
== checklist
)
564 iterator
->remove(iterator
);
568 iterator
->destroy(iterator
);
572 * Checks if a list of endpoint_notify_t contains a certain host_t
574 static bool match_endpoint_by_host(endpoint_notify_t
*current
, host_t
*host
)
576 return host
->equals(host
, current
->get_host(current
));
579 static status_t
endpoints_contain(linked_list_t
*endpoints
, host_t
*host
, endpoint_notify_t
**endpoint
)
581 return endpoints
->find_first(endpoints
,
582 (linked_list_match_t
)match_endpoint_by_host
,
583 (void**)endpoint
, host
);
587 * Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
589 static void insert_pair_by_priority(linked_list_t
*pairs
, endpoint_pair_t
*pair
)
591 iterator_t
*iterator
;
592 endpoint_pair_t
*current
;
593 bool inserted
= FALSE
;
595 iterator
= pairs
->create_iterator(pairs
, TRUE
);
596 while (iterator
->iterate(iterator
, (void**)¤t
))
598 if (current
->priority
< pair
->priority
)
600 iterator
->insert_before(iterator
, pair
);
605 iterator
->destroy(iterator
);
609 pairs
->insert_last(pairs
, pair
);
614 * Searches a list of endpoint_pair_t for a pair with specific host_ts
616 static bool match_pair_by_hosts(endpoint_pair_t
*current
, host_t
*local
, host_t
*remote
)
618 return local
->equals(local
, current
->local
) && remote
->equals(remote
, current
->remote
);
621 static status_t
get_pair_by_hosts(linked_list_t
*pairs
, host_t
*local
, host_t
*remote
, endpoint_pair_t
**pair
)
623 return pairs
->find_first(pairs
,
624 (linked_list_match_t
)match_pair_by_hosts
,
625 (void**)pair
, local
, remote
);
628 static bool match_pair_by_id(endpoint_pair_t
*current
, u_int32_t
*id
)
630 return current
->id
== *id
;
634 * Searches for a pair with a specific id
636 static status_t
get_pair_by_id(check_list_t
*checklist
, u_int32_t id
, endpoint_pair_t
**pair
)
638 return checklist
->pairs
->find_first(checklist
->pairs
,
639 (linked_list_match_t
)match_pair_by_id
,
643 static bool match_succeeded_pair(endpoint_pair_t
*current
)
645 return current
->state
== CHECK_SUCCEEDED
;
649 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
651 static status_t
get_best_valid_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
653 return checklist
->pairs
->find_first(checklist
->pairs
,
654 (linked_list_match_t
)match_succeeded_pair
,
658 static bool match_waiting_pair(endpoint_pair_t
*current
)
660 return current
->state
== CHECK_WAITING
;
664 * Returns and *removes* the first triggered pair in state CHECK_WAITING.
666 static status_t
get_triggered_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
668 iterator_t
*iterator
;
669 endpoint_pair_t
*current
;
670 status_t status
= NOT_FOUND
;
672 iterator
= checklist
->triggered
->create_iterator(checklist
->triggered
, TRUE
);
673 while (iterator
->iterate(iterator
, (void**)¤t
))
675 iterator
->remove(iterator
);
677 if (current
->state
== CHECK_WAITING
)
687 iterator
->destroy(iterator
);
693 * Prunes identical pairs with lower priority from the list
694 * Note: this function also numbers the remaining pairs serially
696 static void prune_pairs(linked_list_t
*pairs
)
698 iterator_t
*iterator
, *search
;
699 endpoint_pair_t
*current
, *other
;
702 iterator
= pairs
->create_iterator(pairs
, TRUE
);
703 search
= pairs
->create_iterator(pairs
, TRUE
);
704 while (iterator
->iterate(iterator
, (void**)¤t
))
708 while (search
->iterate(search
, (void**)&other
))
710 if (current
== other
)
715 if (current
->local
->equals(current
->local
, other
->local
) &&
716 current
->remote
->equals(current
->remote
, other
->remote
))
718 /* since the list of pairs is sorted by priority in descending
719 * order, and we iterate the list from the beginning, we are
720 * sure that the priority of 'other' is lower than that of
721 * 'current', remove it */
722 DBG1(DBG_IKE
, "pruning endpoint pair %H - %H with priority %d",
723 other
->local
, other
->remote
, other
->priority
);
724 search
->remove(search
);
725 endpoint_pair_destroy(other
);
728 search
->reset(search
);
730 search
->destroy(search
);
731 iterator
->destroy(iterator
);
735 * Builds a list of endpoint pairs
737 static void build_pairs(check_list_t
*checklist
)
739 iterator_t
*iterator_i
, *iterator_r
;
740 endpoint_notify_t
*initiator
, *responder
;
742 iterator_i
= checklist
->initiator
.endpoints
->create_iterator(checklist
->initiator
.endpoints
, TRUE
);
743 while (iterator_i
->iterate(iterator_i
, (void**)&initiator
))
745 iterator_r
= checklist
->responder
.endpoints
->create_iterator(checklist
->responder
.endpoints
, TRUE
);
746 while (iterator_r
->iterate(iterator_r
, (void**)&responder
))
748 if (initiator
->get_family(initiator
) != responder
->get_family(responder
))
753 insert_pair_by_priority(checklist
->pairs
,
754 endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
));
756 iterator_r
->destroy(iterator_r
);
758 iterator_i
->destroy(iterator_i
);
760 prune_pairs(checklist
->pairs
);
764 * Processes the payloads of a connectivity check and returns the extracted data
766 static status_t
process_payloads(message_t
*message
, check_t
*check
)
768 iterator_t
*iterator
;
771 iterator
= message
->get_payload_iterator(message
);
772 while (iterator
->iterate(iterator
, (void**)&payload
))
774 if (payload
->get_type(payload
) != NOTIFY
)
776 DBG1(DBG_IKE
, "ignoring payload of type '%N' while processing "
777 "connectivity check", payload_type_names
, payload
->get_type(payload
));
781 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
783 switch (notify
->get_notify_type(notify
))
789 DBG1(DBG_IKE
, "connectivity check contains multiple ME_ENDPOINT notifies");
793 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
796 DBG1(DBG_IKE
, "received invalid ME_ENDPOINT notify");
799 check
->endpoint
= endpoint
;
800 check
->endpoint_raw
= chunk_clone(notify
->get_notification_data(notify
));
801 DBG2(DBG_IKE
, "received ME_ENDPOINT notify");
806 if (check
->connect_id
.ptr
)
808 DBG1(DBG_IKE
, "connectivity check contains multiple ME_CONNECTID notifies");
811 check
->connect_id
= chunk_clone(notify
->get_notification_data(notify
));
812 DBG2(DBG_IKE
, "received ME_CONNECTID %#B", &check
->connect_id
);
819 DBG1(DBG_IKE
, "connectivity check contains multiple ME_CONNECTAUTH notifies");
822 check
->auth
= chunk_clone(notify
->get_notification_data(notify
));
823 DBG2(DBG_IKE
, "received ME_CONNECTAUTH %#B", &check
->auth
);
830 iterator
->destroy(iterator
);
832 if (!check
->connect_id
.ptr
|| !check
->endpoint
|| !check
->auth
.ptr
)
834 DBG1(DBG_IKE
, "at least one payload was missing from the connectivity check");
842 * Builds the signature for a connectivity check
844 static chunk_t
build_signature(private_connect_manager_t
*this,
845 check_list_t
*checklist
, check_t
*check
, bool outbound
)
847 chunk_t mid_chunk
, key_chunk
, sig_chunk
;
850 mid_chunk
= chunk_from_thing(check
->mid
);
852 key_chunk
= (checklist
->is_initiator
&& outbound
) || (!checklist
->is_initiator
&& !outbound
)
853 ? checklist
->initiator
.key
: checklist
->responder
.key
;
855 /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */
856 sig_chunk
= chunk_cat("cccc", mid_chunk
, check
->connect_id
, check
->endpoint_raw
, key_chunk
);
857 this->hasher
->allocate_hash(this->hasher
, sig_chunk
, &sig_hash
);
858 DBG3(DBG_IKE
, "sig_chunk %#B", &sig_chunk
);
859 DBG3(DBG_IKE
, "sig_hash %#B", &sig_hash
);
861 chunk_free(&sig_chunk
);
865 static void queue_retransmission(private_connect_manager_t
*this, check_list_t
*checklist
, endpoint_pair_t
*pair
);
866 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
);
867 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
);
870 * After one of the initiator's pairs has succeeded we finish the checks without
871 * waiting for all the timeouts
873 static job_requeue_t
initiator_finish(callback_data_t
*data
)
875 private_connect_manager_t
*this = data
->connect_manager
;
877 pthread_mutex_lock(&(this->mutex
));
879 check_list_t
*checklist
;
880 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
882 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't finish connectivity checks",
884 pthread_mutex_unlock(&(this->mutex
));
885 return JOB_REQUEUE_NONE
;
888 finish_checks(this, checklist
);
890 pthread_mutex_unlock(&(this->mutex
));
892 return JOB_REQUEUE_NONE
;
896 * Updates the state of the whole checklist
898 static void update_checklist_state(private_connect_manager_t
*this, check_list_t
*checklist
)
900 iterator_t
*iterator
;
901 endpoint_pair_t
*current
;
902 bool in_progress
= FALSE
, succeeded
= FALSE
;
904 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
905 while (iterator
->iterate(iterator
, (void**)¤t
))
907 switch(current
->state
)
910 /* at least one is still waiting -> checklist remains
911 * in waiting state */
912 iterator
->destroy(iterator
);
914 case CHECK_IN_PROGRESS
:
917 case CHECK_SUCCEEDED
:
924 iterator
->destroy(iterator
);
926 if (checklist
->is_initiator
&& succeeded
&& !checklist
->is_finishing
)
928 /* instead of waiting until all checks have finished (i.e. all
929 * retransmissions have failed) the initiator finishes the checks
930 * right after the first check has succeeded. to allow a probably
931 * better pair to succeed, we still wait a certain time */
932 DBG2(DBG_IKE
, "fast finishing checks for checklist '%#B'", &checklist
->connect_id
);
934 callback_data_t
*data
= callback_data_create(this, checklist
->connect_id
);
935 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiator_finish
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
936 charon
->scheduler
->schedule_job(charon
->scheduler
, job
, ME_WAIT_TO_FINISH
);
937 checklist
->is_finishing
= TRUE
;
942 checklist
->state
= CHECK_IN_PROGRESS
;
946 checklist
->state
= CHECK_SUCCEEDED
;
950 checklist
->state
= CHECK_FAILED
;
955 * This function is triggered for each sent check after a specific timeout
957 static job_requeue_t
retransmit(callback_data_t
*data
)
959 private_connect_manager_t
*this = data
->connect_manager
;
961 pthread_mutex_lock(&(this->mutex
));
963 check_list_t
*checklist
;
964 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
966 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't retransmit connectivity check",
968 pthread_mutex_unlock(&(this->mutex
));
969 return JOB_REQUEUE_NONE
;
972 endpoint_pair_t
*pair
;
973 if (get_pair_by_id(checklist
, data
->mid
, &pair
) != SUCCESS
)
975 DBG1(DBG_IKE
, "pair with id '%d' not found, can't retransmit connectivity check",
980 if (pair
->state
!= CHECK_IN_PROGRESS
)
982 DBG2(DBG_IKE
, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
983 data
->mid
, pair
->state
);
987 if (++pair
->retransmitted
> ME_MAX_RETRANS
)
989 DBG2(DBG_IKE
, "pair with id '%d' failed after %d retransmissions",
990 data
->mid
, ME_MAX_RETRANS
);
991 pair
->state
= CHECK_FAILED
;
995 charon
->sender
->send(charon
->sender
, pair
->packet
->clone(pair
->packet
));
997 queue_retransmission(this, checklist
, pair
);
1000 update_checklist_state(this, checklist
);
1002 switch(checklist
->state
)
1004 case CHECK_SUCCEEDED
:
1006 finish_checks(this, checklist
);
1012 pthread_mutex_unlock(&(this->mutex
));
1014 /* we reschedule it manually */
1015 return JOB_REQUEUE_NONE
;
1019 * Queues a retransmission job
1021 static void queue_retransmission(private_connect_manager_t
*this, check_list_t
*checklist
, endpoint_pair_t
*pair
)
1023 callback_data_t
*data
= retransmit_data_create(this, checklist
->connect_id
, pair
->id
);
1024 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)retransmit
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
1026 u_int32_t retransmission
= pair
->retransmitted
+ 1;
1027 u_int32_t rto
= ME_INTERVAL
;
1028 if (retransmission
> ME_BOOST
)
1030 rto
= (u_int32_t
)(ME_INTERVAL
* pow(ME_RETRANS_BASE
, retransmission
- ME_BOOST
));
1032 DBG2(DBG_IKE
, "scheduling retransmission %d of pair '%d' in %dms", retransmission
, pair
->id
, rto
);
1034 charon
->scheduler
->schedule_job(charon
->scheduler
, (job_t
*)job
, rto
);
1040 static void send_check(private_connect_manager_t
*this, check_list_t
*checklist
,
1041 check_t
*check
, endpoint_pair_t
*pair
, bool request
)
1043 message_t
*message
= message_create();
1044 message
->set_message_id(message
, check
->mid
);
1045 message
->set_exchange_type(message
, INFORMATIONAL
);
1046 message
->set_request(message
, request
);
1047 message
->set_destination(message
, check
->dst
->clone(check
->dst
));
1048 message
->set_source(message
, check
->src
->clone(check
->src
));
1050 ike_sa_id_t
*ike_sa_id
= ike_sa_id_create(0, 0, request
);
1051 message
->set_ike_sa_id(message
, ike_sa_id
);
1052 ike_sa_id
->destroy(ike_sa_id
);
1054 message
->add_notify(message
, FALSE
, ME_CONNECTID
, check
->connect_id
);
1055 DBG2(DBG_IKE
, "send ME_CONNECTID %#B", &check
->connect_id
);
1057 notify_payload_t
*endpoint
= check
->endpoint
->build_notify(check
->endpoint
);
1058 check
->endpoint_raw
= chunk_clone(endpoint
->get_notification_data(endpoint
));
1059 message
->add_payload(message
, (payload_t
*)endpoint
);
1060 DBG2(DBG_IKE
, "send ME_ENDPOINT notify");
1062 check
->auth
= build_signature(this, checklist
, check
, TRUE
);
1063 message
->add_notify(message
, FALSE
, ME_CONNECTAUTH
, check
->auth
);
1064 DBG2(DBG_IKE
, "send ME_CONNECTAUTH %#B", &check
->auth
);
1067 if (message
->generate(message
, NULL
, NULL
, &packet
) == SUCCESS
)
1069 charon
->sender
->send(charon
->sender
, packet
->clone(packet
));
1073 DESTROY_IF(pair
->packet
);
1074 pair
->packet
= packet
;
1075 queue_retransmission(this, checklist
, pair
);
1079 packet
->destroy(packet
);
1082 message
->destroy(message
);
1086 * Queues a triggered check
1088 static void queue_triggered_check(private_connect_manager_t
*this,
1089 check_list_t
*checklist
, endpoint_pair_t
*pair
)
1091 pair
->state
= CHECK_WAITING
;
1092 checklist
->triggered
->insert_last(checklist
->triggered
, pair
);
1094 if (checklist
->sender
)
1096 /* if the sender is not running we restart it */
1097 schedule_checks(this, checklist
, ME_INTERVAL
);
1102 * This function is triggered for each checklist at a specific interval
1104 static job_requeue_t
sender(callback_data_t
*data
)
1106 private_connect_manager_t
*this = data
->connect_manager
;
1108 pthread_mutex_lock(&(this->mutex
));
1110 check_list_t
*checklist
;
1111 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
1113 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't send connectivity check",
1115 pthread_mutex_unlock(&(this->mutex
));
1116 return JOB_REQUEUE_NONE
;
1119 /* reset the sender */
1120 checklist
->sender
= NULL
;
1122 endpoint_pair_t
*pair
;
1123 if (get_triggered_pair(checklist
, &pair
) != SUCCESS
)
1125 DBG1(DBG_IKE
, "no triggered check queued, sending an ordinary check");
1127 if (checklist
->pairs
->find_first(checklist
->pairs
,
1128 (linked_list_match_t
)match_waiting_pair
, (void**)&pair
) != SUCCESS
)
1130 pthread_mutex_unlock(&(this->mutex
));
1131 DBG1(DBG_IKE
, "no pairs in waiting state, aborting");
1132 return JOB_REQUEUE_NONE
;
1137 DBG1(DBG_IKE
, "triggered check found");
1140 check_t
*check
= check_create();
1141 check
->mid
= pair
->id
;
1142 check
->src
= pair
->local
->clone(pair
->local
);
1143 check
->dst
= pair
->remote
->clone(pair
->remote
);
1144 check
->connect_id
= chunk_clone(checklist
->connect_id
);
1145 check
->endpoint
= endpoint_notify_create();
1147 pair
->state
= CHECK_IN_PROGRESS
;
1149 send_check(this, checklist
, check
, pair
, TRUE
);
1151 check_destroy(check
);
1153 /* schedule this job again */
1154 schedule_checks(this, checklist
, ME_INTERVAL
);
1156 pthread_mutex_unlock(&(this->mutex
));
1158 /* we reschedule it manually */
1159 return JOB_REQUEUE_NONE
;
1163 * Schedules checks for a checklist (time in ms)
1165 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
)
1167 callback_data_t
*data
= callback_data_create(this, checklist
->connect_id
);
1168 checklist
->sender
= (job_t
*)callback_job_create((callback_job_cb_t
)sender
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
1169 charon
->scheduler
->schedule_job(charon
->scheduler
, checklist
->sender
, time
);
1173 * Initiates waiting mediated connections
1175 static job_requeue_t
initiate_mediated(initiate_data_t
*data
)
1177 check_list_t
*checklist
= data
->checklist
;
1178 initiated_t
*initiated
= data
->initiated
;
1180 endpoint_pair_t
*pair
;
1181 if (get_best_valid_pair(checklist
, &pair
) == SUCCESS
)
1183 waiting_sa_t
*waiting_sa
;
1184 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1185 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1187 ike_sa_t
*sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, waiting_sa
->ike_sa_id
);
1188 if (sa
->initiate_mediated(sa
, pair
->local
, pair
->remote
, waiting_sa
->childs
,
1189 checklist
->connect_id
) != SUCCESS
)
1191 SIG(IKE_UP_FAILED
, "establishing the mediated connection failed");
1192 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, sa
);
1194 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, sa
);
1196 iterator
->destroy(iterator
);
1200 /* this should (can?) not happen */
1203 return JOB_REQUEUE_NONE
;
1207 * Finishes checks for a checklist
1209 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
)
1211 if (checklist
->is_initiator
)
1213 initiated_t
*initiated
;
1214 if (get_initiated_by_ids(this, checklist
->initiator
.id
,
1215 checklist
->responder
.id
, &initiated
) == SUCCESS
)
1217 remove_checklist(this, checklist
);
1218 remove_initiated(this, initiated
);
1220 initiate_data_t
*data
= initiate_data_create(checklist
, initiated
);
1221 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiate_mediated
, data
, (callback_job_cleanup_t
)initiate_data_destroy
, NULL
);
1222 charon
->processor
->queue_job(charon
->processor
, job
);
1227 DBG1(DBG_IKE
, "there is no mediated connection waiting between '%D' "
1228 "and '%D'", checklist
->initiator
.id
, checklist
->responder
.id
);
1234 * Process the response to one of our requests
1236 static void process_response(private_connect_manager_t
*this, check_t
*check
,
1237 check_list_t
*checklist
)
1239 endpoint_pair_t
*pair
;
1240 if (get_pair_by_id(checklist
, check
->mid
, &pair
) == SUCCESS
)
1242 if (pair
->local
->equals(pair
->local
, check
->dst
) &&
1243 pair
->remote
->equals(pair
->remote
, check
->src
))
1245 DBG1(DBG_IKE
, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair
->id
,
1246 pair
->local
, pair
->remote
);
1247 pair
->state
= CHECK_SUCCEEDED
;
1250 linked_list_t
*local_endpoints
= checklist
->is_initiator ?
1251 checklist
->initiator
.endpoints
: checklist
->responder
.endpoints
;
1253 endpoint_notify_t
*local_endpoint
;
1254 if (endpoints_contain(local_endpoints
,
1255 check
->endpoint
->get_host(check
->endpoint
), &local_endpoint
) != SUCCESS
)
1257 local_endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1258 check
->endpoint
->get_host(check
->endpoint
), pair
->local
);
1259 local_endpoint
->set_priority(local_endpoint
, check
->endpoint
->get_priority(check
->endpoint
));
1260 local_endpoints
->insert_last(local_endpoints
, local_endpoint
);
1263 update_checklist_state(this, checklist
);
1265 switch(checklist
->state
)
1267 case CHECK_SUCCEEDED
:
1269 finish_checks(this, checklist
);
1277 DBG1(DBG_IKE
, "pair with id '%d' not found", check
->mid
);
1281 static void process_request(private_connect_manager_t
*this, check_t
*check
,
1282 check_list_t
*checklist
)
1284 linked_list_t
*remote_endpoints
= checklist
->is_initiator ?
1285 checklist
->responder
.endpoints
: checklist
->initiator
.endpoints
;
1287 endpoint_notify_t
*peer_reflexive
, *remote_endpoint
;
1288 peer_reflexive
= endpoint_notify_create_from_host(PEER_REFLEXIVE
, check
->src
, NULL
);
1289 peer_reflexive
->set_priority(peer_reflexive
, check
->endpoint
->get_priority(check
->endpoint
));
1291 if (endpoints_contain(remote_endpoints
, check
->src
, &remote_endpoint
) != SUCCESS
)
1293 remote_endpoint
= peer_reflexive
->clone(peer_reflexive
);
1294 remote_endpoints
->insert_last(remote_endpoints
, remote_endpoint
);
1297 endpoint_pair_t
*pair
;
1298 if (get_pair_by_hosts(checklist
->pairs
, check
->dst
, check
->src
, &pair
) == SUCCESS
)
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 check
1309 queue_triggered_check(this, checklist
, pair
);
1311 case CHECK_SUCCEEDED
:
1318 endpoint_notify_t
*local_endpoint
= endpoint_notify_create_from_host(HOST
, check
->dst
, NULL
);
1320 endpoint_notify_t
*initiator
= checklist
->is_initiator ? local_endpoint
: remote_endpoint
;
1321 endpoint_notify_t
*responder
= checklist
->is_initiator ? remote_endpoint
: local_endpoint
;
1323 pair
= endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
);
1324 pair
->id
= checklist
->pairs
->get_count(checklist
->pairs
) + 1;
1326 insert_pair_by_priority(checklist
->pairs
, pair
);
1328 queue_triggered_check(this, checklist
, pair
);
1330 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
);
1348 * Implementation of connect_manager_t.process_check.
1350 static void process_check(private_connect_manager_t
*this, message_t
*message
)
1352 if (message
->parse_body(message
, NULL
, NULL
) != SUCCESS
)
1354 DBG1(DBG_IKE
, "%N %s with message ID %d processing failed",
1355 exchange_type_names
, message
->get_exchange_type(message
),
1356 message
->get_request(message
) ?
"request" : "response",
1357 message
->get_message_id(message
));
1361 check_t
*check
= check_create();
1362 check
->mid
= message
->get_message_id(message
);
1363 check
->src
= message
->get_source(message
);
1364 check
->src
= check
->src
->clone(check
->src
);
1365 check
->dst
= message
->get_destination(message
);
1366 check
->dst
= check
->dst
->clone(check
->dst
);
1368 if (process_payloads(message
, check
) != SUCCESS
)
1370 DBG1(DBG_IKE
, "invalid connectivity check %s received",
1371 message
->get_request(message
) ?
"request" : "response");
1372 check_destroy(check
);
1376 pthread_mutex_lock(&(this->mutex
));
1378 check_list_t
*checklist
;
1379 if (get_checklist_by_id(this, check
->connect_id
, &checklist
) != SUCCESS
)
1381 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1382 &check
->connect_id
);
1383 check_destroy(check
);
1384 pthread_mutex_unlock(&(this->mutex
));
1388 chunk_t sig
= build_signature(this, checklist
, check
, FALSE
);
1389 if (!chunk_equals(sig
, check
->auth
))
1391 DBG1(DBG_IKE
, "connectivity check verification failed");
1392 check_destroy(check
);
1394 pthread_mutex_unlock(&(this->mutex
));
1399 if (message
->get_request(message
))
1401 process_request(this, check
, checklist
);
1405 process_response(this, check
, checklist
);
1408 pthread_mutex_unlock(&(this->mutex
));
1410 check_destroy(check
);
1414 * Implementation of connect_manager_t.check_and_register.
1416 static bool check_and_register(private_connect_manager_t
*this,
1417 identification_t
*id
, identification_t
*peer_id
,
1418 ike_sa_id_t
*mediated_sa
, child_cfg_t
*child
)
1420 initiated_t
*initiated
;
1421 bool already_there
= TRUE
;
1423 pthread_mutex_lock(&(this->mutex
));
1425 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1427 DBG2(DBG_IKE
, "registered waiting mediated connection with '%D'", peer_id
);
1428 initiated
= initiated_create(id
, peer_id
);
1429 this->initiated
->insert_last(this->initiated
, initiated
);
1430 already_there
= FALSE
;
1433 waiting_sa_t
*waiting_sa
;
1434 if (get_waiting_sa(initiated
, mediated_sa
, &waiting_sa
) != SUCCESS
)
1436 waiting_sa
= waiting_sa_create(mediated_sa
);
1437 initiated
->mediated
->insert_last(initiated
->mediated
, waiting_sa
);
1440 child
->get_ref(child
);
1441 waiting_sa
->childs
->insert_last(waiting_sa
->childs
, child
);
1443 pthread_mutex_unlock(&(this->mutex
));
1445 return already_there
;
1449 * Implementation of connect_manager_t.check_and_initiate.
1451 static void check_and_initiate(private_connect_manager_t
*this, ike_sa_id_t
*mediation_sa
,
1452 identification_t
*id
, identification_t
*peer_id
)
1454 initiated_t
*initiated
;
1456 pthread_mutex_lock(&(this->mutex
));
1458 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1460 DBG2(DBG_IKE
, "no waiting mediated connections with '%D'", peer_id
);
1461 pthread_mutex_unlock(&(this->mutex
));
1465 waiting_sa_t
*waiting_sa
;
1466 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1467 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1469 job_t
*job
= (job_t
*)reinitiate_mediation_job_create(mediation_sa
,
1470 waiting_sa
->ike_sa_id
);
1471 charon
->processor
->queue_job(charon
->processor
, job
);
1473 iterator
->destroy(iterator
);
1475 pthread_mutex_unlock(&(this->mutex
));
1479 * Implementation of connect_manager_t.set_initiator_data.
1481 static status_t
set_initiator_data(private_connect_manager_t
*this,
1482 identification_t
*initiator
, identification_t
*responder
,
1483 chunk_t connect_id
, chunk_t key
, linked_list_t
*endpoints
, bool is_initiator
)
1485 check_list_t
*checklist
;
1487 pthread_mutex_lock(&(this->mutex
));
1489 if (get_checklist_by_id(this, connect_id
, NULL
) == SUCCESS
)
1491 DBG1(DBG_IKE
, "checklist with id '%#B' already exists, aborting",
1493 pthread_mutex_unlock(&(this->mutex
));
1497 checklist
= check_list_create(initiator
, responder
, connect_id
, key
, endpoints
, is_initiator
);
1498 this->checklists
->insert_last(this->checklists
, checklist
);
1500 pthread_mutex_unlock(&(this->mutex
));
1506 * Implementation of connect_manager_t.set_responder_data.
1508 static status_t
set_responder_data(private_connect_manager_t
*this,
1509 chunk_t connect_id
, chunk_t key
, linked_list_t
*endpoints
)
1511 check_list_t
*checklist
;
1513 pthread_mutex_lock(&(this->mutex
));
1515 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1517 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1519 pthread_mutex_unlock(&(this->mutex
));
1523 checklist
->responder
.key
= chunk_clone(key
);
1524 checklist
->responder
.endpoints
= endpoints
->clone_offset(endpoints
, offsetof(endpoint_notify_t
, clone
));
1525 checklist
->state
= CHECK_WAITING
;
1527 build_pairs(checklist
);
1529 /* send the first check immediately */
1530 schedule_checks(this, checklist
, 0);
1532 pthread_mutex_unlock(&(this->mutex
));
1538 * Implementation of connect_manager_t.stop_checks.
1540 static status_t
stop_checks(private_connect_manager_t
*this, chunk_t connect_id
)
1542 check_list_t
*checklist
;
1544 pthread_mutex_lock(&(this->mutex
));
1546 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1548 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1550 pthread_mutex_unlock(&(this->mutex
));
1554 DBG1(DBG_IKE
, "removing checklist with id '%#B'", &connect_id
);
1556 remove_checklist(this, checklist
);
1557 check_list_destroy(checklist
);
1559 pthread_mutex_unlock(&(this->mutex
));
1565 * Implementation of connect_manager_t.destroy.
1567 static void destroy(private_connect_manager_t
*this)
1569 pthread_mutex_lock(&(this->mutex
));
1571 this->hasher
->destroy(this->hasher
);
1572 this->checklists
->destroy_function(this->checklists
, (void*)check_list_destroy
);
1573 this->initiated
->destroy_function(this->initiated
, (void*)initiated_destroy
);
1575 pthread_mutex_unlock(&(this->mutex
));
1576 pthread_mutex_destroy(&(this->mutex
));
1581 * Described in header.
1583 connect_manager_t
*connect_manager_create()
1585 private_connect_manager_t
*this = malloc_thing(private_connect_manager_t
);
1587 this->public.destroy
= (void(*)(connect_manager_t
*))destroy
;
1588 this->public.check_and_register
= (bool(*)(connect_manager_t
*,identification_t
*,identification_t
*,ike_sa_id_t
*,child_cfg_t
*))check_and_register
;
1589 this->public.check_and_initiate
= (void(*)(connect_manager_t
*,ike_sa_id_t
*,identification_t
*,identification_t
*))check_and_initiate
;
1590 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
;
1591 this->public.set_responder_data
= (status_t(*)(connect_manager_t
*,chunk_t
,chunk_t
,linked_list_t
*))set_responder_data
;
1592 this->public.process_check
= (void(*)(connect_manager_t
*,message_t
*))process_check
;
1593 this->public.stop_checks
= (status_t(*)(connect_manager_t
*,chunk_t
))stop_checks
;
1595 this->hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
1596 if (this->hasher
== NULL
)
1598 DBG1(DBG_IKE
, "unable to create connect manager, SHA1 not supported");
1603 this->checklists
= linked_list_create();
1604 this->initiated
= linked_list_create();
1606 pthread_mutex_init(&(this->mutex
), NULL
);
1608 return (connect_manager_t
*)this;