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 = malloc_thing(endpoint_pair_t
);
137 u_int32_t pi
= initiator
->get_priority(initiator
);
138 u_int32_t pr
= responder
->get_priority(responder
);
139 this->priority
= pow(2, 32) * min(pi
, pr
) + 2 * max(pi
, pr
) + (pi
> pr ?
1 : 0);
141 this->local
= initiator_is_local ? initiator
->get_base(initiator
)
142 : responder
->get_base(responder
);
143 this->local
= this->local
->clone(this->local
);
144 this->remote
= initiator_is_local ? responder
->get_host(responder
)
145 : 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
,
221 offsetof(endpoint_notify_t
, destroy
));
222 DESTROY_OFFSET_IF(this->responder
.endpoints
,
223 offsetof(endpoint_notify_t
, destroy
));
225 DESTROY_FUNCTION_IF(this->pairs
, (void*)endpoint_pair_destroy
);
226 /* this list contains some of the elements contained in this->pairs */
227 DESTROY_IF(this->triggered
);
233 * Creates a new checklist
235 static check_list_t
*check_list_create(identification_t
*initiator
,
236 identification_t
*responder
,
238 chunk_t initiator_key
,
239 linked_list_t
*initiator_endpoints
,
242 check_list_t
*this = malloc_thing(check_list_t
);
244 this->connect_id
= chunk_clone(connect_id
);
246 this->initiator
.id
= initiator
->clone(initiator
);
247 this->initiator
.key
= chunk_clone(initiator_key
);
248 this->initiator
.endpoints
= initiator_endpoints
->clone_offset(initiator_endpoints
, offsetof(endpoint_notify_t
, clone
));
250 this->responder
.id
= responder
->clone(responder
);
251 this->responder
.key
= chunk_empty
;
252 this->responder
.endpoints
= NULL
;
254 this->pairs
= linked_list_create();
255 this->triggered
= linked_list_create();
256 this->state
= CHECK_NONE
;
257 this->is_initiator
= is_initiator
;
258 this->is_finishing
= FALSE
;
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
)
297 initiated_t
*this = malloc_thing(initiated_t
);
299 this->id
= id
->clone(id
);
300 this->peer_id
= peer_id
->clone(peer_id
);
301 this->mediated
= linked_list_create();
307 typedef struct check_t check_t
;
310 * Data exchanged in a connectivity check
316 /** source of the connectivity check */
319 /** destination of the connectivity check */
326 endpoint_notify_t
*endpoint
;
328 /** raw endpoint payload (to verify the signature) */
329 chunk_t endpoint_raw
;
336 * Destroys a connectivity check
338 static void check_destroy(check_t
*this)
340 chunk_free(&this->connect_id
);
341 chunk_free(&this->endpoint_raw
);
342 chunk_free(&this->auth
);
343 DESTROY_IF(this->src
);
344 DESTROY_IF(this->dst
);
345 DESTROY_IF(this->endpoint
);
350 * Creates a new connectivity check
352 static check_t
*check_create()
354 check_t
*this = malloc_thing(check_t
);
356 this->connect_id
= chunk_empty
;
357 this->auth
= chunk_empty
;
358 this->endpoint_raw
= chunk_empty
;
361 this->endpoint
= NULL
;
368 typedef struct callback_data_t callback_data_t
;
371 * Data required by several callback jobs used in this file
373 struct callback_data_t
{
374 /** connect manager */
375 private_connect_manager_t
*connect_manager
;
380 /** message (pair) id */
385 * Destroys a callback data object
387 static void callback_data_destroy(callback_data_t
*this)
389 chunk_free(&this->connect_id
);
394 * Creates a new callback data object
396 static callback_data_t
*callback_data_create(private_connect_manager_t
*connect_manager
,
399 callback_data_t
*this = malloc_thing(callback_data_t
);
400 this->connect_manager
= connect_manager
;
401 this->connect_id
= chunk_clone(connect_id
);
407 * Creates a new retransmission data object
409 static callback_data_t
*retransmit_data_create(private_connect_manager_t
*connect_manager
,
410 chunk_t connect_id
, u_int32_t mid
)
412 callback_data_t
*this = callback_data_create(connect_manager
, connect_id
);
417 typedef struct initiate_data_t initiate_data_t
;
420 * Data required by the initiate mediated
422 struct initiate_data_t
{
424 check_list_t
*checklist
;
426 /** waiting mediated connections */
427 initiated_t
*initiated
;
431 * Destroys a initiate data object
433 static void initiate_data_destroy(initiate_data_t
*this)
435 check_list_destroy(this->checklist
);
436 initiated_destroy(this->initiated
);
441 * Creates a new initiate data object
443 static initiate_data_t
*initiate_data_create(check_list_t
*checklist
,
444 initiated_t
*initiated
)
446 initiate_data_t
*this = malloc_thing(initiate_data_t
);
448 this->checklist
= checklist
;
449 this->initiated
= initiated
;
455 * Find an initiated connection by the peers' ids
457 static bool match_initiated_by_ids(initiated_t
*current
, identification_t
*id
,
458 identification_t
*peer_id
)
460 return id
->equals(id
, current
->id
) && peer_id
->equals(peer_id
, current
->peer_id
);
463 static status_t
get_initiated_by_ids(private_connect_manager_t
*this,
464 identification_t
*id
,
465 identification_t
*peer_id
,
466 initiated_t
**initiated
)
468 return this->initiated
->find_first(this->initiated
,
469 (linked_list_match_t
)match_initiated_by_ids
,
470 (void**)initiated
, id
, peer_id
);
474 * Removes data about initiated connections
476 static void remove_initiated(private_connect_manager_t
*this,
477 initiated_t
*initiated
)
479 enumerator_t
*enumerator
;
480 initiated_t
*current
;
482 enumerator
= this->initiated
->create_enumerator(this->initiated
);
483 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
485 if (current
== initiated
)
487 this->initiated
->remove_at(this->initiated
, enumerator
);
491 enumerator
->destroy(enumerator
);
495 * Find the checklist with a specific connect ID
497 static bool match_checklist_by_id(check_list_t
*current
, chunk_t
*connect_id
)
499 return chunk_equals(*connect_id
, current
->connect_id
);
502 static status_t
get_checklist_by_id(private_connect_manager_t
*this,
504 check_list_t
**check_list
)
506 return this->checklists
->find_first(this->checklists
,
507 (linked_list_match_t
)match_checklist_by_id
,
508 (void**)check_list
, &connect_id
);
512 * Removes a checklist
514 static void remove_checklist(private_connect_manager_t
*this,
515 check_list_t
*checklist
)
517 enumerator_t
*enumerator
;
518 check_list_t
*current
;
520 enumerator
= this->checklists
->create_enumerator(this->checklists
);
521 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
523 if (current
== checklist
)
525 this->checklists
->remove_at(this->checklists
, enumerator
);
529 enumerator
->destroy(enumerator
);
533 * Checks if a list of endpoint_notify_t contains a certain host_t
535 static bool match_endpoint_by_host(endpoint_notify_t
*current
, host_t
*host
)
537 return host
->equals(host
, current
->get_host(current
));
540 static status_t
endpoints_contain(linked_list_t
*endpoints
, host_t
*host
,
541 endpoint_notify_t
**endpoint
)
543 return endpoints
->find_first(endpoints
,
544 (linked_list_match_t
)match_endpoint_by_host
,
545 (void**)endpoint
, host
);
549 * Inserts an endpoint pair into a list of pairs ordered by priority (high to low)
551 static void insert_pair_by_priority(linked_list_t
*pairs
, endpoint_pair_t
*pair
)
553 enumerator_t
*enumerator
= pairs
->create_enumerator(pairs
);
554 endpoint_pair_t
*current
;
555 while (enumerator
->enumerate(enumerator
, (void**)¤t
) &&
556 current
->priority
>= pair
->priority
)
560 pairs
->insert_before(pairs
, enumerator
, pair
);
561 enumerator
->destroy(enumerator
);
565 * Searches a list of endpoint_pair_t for a pair with specific host_ts
567 static bool match_pair_by_hosts(endpoint_pair_t
*current
, host_t
*local
,
570 return local
->equals(local
, current
->local
) && remote
->equals(remote
, current
->remote
);
573 static status_t
get_pair_by_hosts(linked_list_t
*pairs
, host_t
*local
,
574 host_t
*remote
, endpoint_pair_t
**pair
)
576 return pairs
->find_first(pairs
, (linked_list_match_t
)match_pair_by_hosts
,
577 (void**)pair
, local
, remote
);
580 static bool match_pair_by_id(endpoint_pair_t
*current
, u_int32_t
*id
)
582 return current
->id
== *id
;
586 * Searches for a pair with a specific id
588 static status_t
get_pair_by_id(check_list_t
*checklist
, u_int32_t id
,
589 endpoint_pair_t
**pair
)
591 return checklist
->pairs
->find_first(checklist
->pairs
,
592 (linked_list_match_t
)match_pair_by_id
,
596 static bool match_succeeded_pair(endpoint_pair_t
*current
)
598 return current
->state
== CHECK_SUCCEEDED
;
602 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
604 static status_t
get_best_valid_pair(check_list_t
*checklist
,
605 endpoint_pair_t
**pair
)
607 return checklist
->pairs
->find_first(checklist
->pairs
,
608 (linked_list_match_t
)match_succeeded_pair
,
612 static bool match_waiting_pair(endpoint_pair_t
*current
)
614 return current
->state
== CHECK_WAITING
;
618 * Returns and *removes* the first triggered pair in state CHECK_WAITING.
620 static status_t
get_triggered_pair(check_list_t
*checklist
,
621 endpoint_pair_t
**pair
)
623 enumerator_t
*enumerator
;
624 endpoint_pair_t
*current
;
625 status_t status
= NOT_FOUND
;
627 enumerator
= checklist
->triggered
->create_enumerator(checklist
->triggered
);
628 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
630 checklist
->triggered
->remove_at(checklist
->triggered
, enumerator
);
632 if (current
->state
== CHECK_WAITING
)
642 enumerator
->destroy(enumerator
);
648 * Prints all the pairs on a checklist
650 static void print_checklist(check_list_t
*checklist
)
652 enumerator_t
*enumerator
;
653 endpoint_pair_t
*current
;
655 DBG1(DBG_IKE
, "pairs on checklist %#B:", &checklist
->connect_id
);
656 enumerator
= checklist
->pairs
->create_enumerator(checklist
->pairs
);
657 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
659 DBG1(DBG_IKE
, " * %#H - %#H (%d)", current
->local
, current
->remote
,
662 enumerator
->destroy(enumerator
);
666 * Prunes identical pairs with lower priority from the list
667 * Note: this function also numbers the remaining pairs serially
669 static void prune_pairs(linked_list_t
*pairs
)
671 enumerator_t
*enumerator
, *search
;
672 endpoint_pair_t
*current
, *other
;
675 enumerator
= pairs
->create_enumerator(pairs
);
676 search
= pairs
->create_enumerator(pairs
);
677 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
681 while (search
->enumerate(search
, (void**)&other
))
683 if (current
== other
)
688 if (current
->local
->equals(current
->local
, other
->local
) &&
689 current
->remote
->equals(current
->remote
, other
->remote
))
691 /* since the list of pairs is sorted by priority in descending
692 * order, and we iterate the list from the beginning, we are
693 * sure that the priority of 'other' is lower than that of
694 * 'current', remove it */
695 DBG1(DBG_IKE
, "pruning endpoint pair %#H - %#H with priority %d",
696 other
->local
, other
->remote
, other
->priority
);
697 pairs
->remove_at(pairs
, search
);
698 endpoint_pair_destroy(other
);
701 pairs
->reset_enumerator(pairs
, search
);
703 search
->destroy(search
);
704 enumerator
->destroy(enumerator
);
708 * Builds a list of endpoint pairs
710 static void build_pairs(check_list_t
*checklist
)
712 /* FIXME: limit endpoints and pairs */
713 enumerator_t
*enumerator_i
, *enumerator_r
;
714 endpoint_notify_t
*initiator
, *responder
;
716 enumerator_i
= checklist
->initiator
.endpoints
->create_enumerator(
717 checklist
->initiator
.endpoints
);
718 while (enumerator_i
->enumerate(enumerator_i
, (void**)&initiator
))
720 enumerator_r
= checklist
->responder
.endpoints
->create_enumerator(
721 checklist
->responder
.endpoints
);
722 while (enumerator_r
->enumerate(enumerator_r
, (void**)&responder
))
724 if (initiator
->get_family(initiator
) != responder
->get_family(responder
))
729 insert_pair_by_priority(checklist
->pairs
, endpoint_pair_create(
730 initiator
, responder
, checklist
->is_initiator
));
732 enumerator_r
->destroy(enumerator_r
);
734 enumerator_i
->destroy(enumerator_i
);
736 print_checklist(checklist
);
738 prune_pairs(checklist
->pairs
);
742 * Processes the payloads of a connectivity check and returns the extracted data
744 static status_t
process_payloads(message_t
*message
, check_t
*check
)
746 enumerator_t
*enumerator
;
749 enumerator
= message
->create_payload_enumerator(message
);
750 while (enumerator
->enumerate(enumerator
, &payload
))
752 if (payload
->get_type(payload
) != NOTIFY
)
754 DBG1(DBG_IKE
, "ignoring payload of type '%N' while processing "
755 "connectivity check", payload_type_names
,
756 payload
->get_type(payload
));
760 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
762 switch (notify
->get_notify_type(notify
))
768 DBG1(DBG_IKE
, "connectivity check contains multiple "
769 "ME_ENDPOINT notifies");
773 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
776 DBG1(DBG_IKE
, "received invalid ME_ENDPOINT notify");
779 check
->endpoint
= endpoint
;
780 check
->endpoint_raw
= chunk_clone(notify
->get_notification_data(notify
));
781 DBG2(DBG_IKE
, "received ME_ENDPOINT notify");
786 if (check
->connect_id
.ptr
)
788 DBG1(DBG_IKE
, "connectivity check contains multiple "
789 "ME_CONNECTID notifies");
792 check
->connect_id
= chunk_clone(notify
->get_notification_data(notify
));
793 DBG2(DBG_IKE
, "received ME_CONNECTID %#B", &check
->connect_id
);
800 DBG1(DBG_IKE
, "connectivity check contains multiple "
801 "ME_CONNECTAUTH notifies");
804 check
->auth
= chunk_clone(notify
->get_notification_data(notify
));
805 DBG2(DBG_IKE
, "received ME_CONNECTAUTH %#B", &check
->auth
);
812 enumerator
->destroy(enumerator
);
814 if (!check
->connect_id
.ptr
|| !check
->endpoint
|| !check
->auth
.ptr
)
816 DBG1(DBG_IKE
, "at least one required payload was missing from the "
817 "connectivity check");
825 * Builds the signature for a connectivity check
827 static chunk_t
build_signature(private_connect_manager_t
*this,
828 check_list_t
*checklist
, check_t
*check
, bool outbound
)
831 chunk_t mid_chunk
, key_chunk
, sig_chunk
;
834 mid
= htonl(check
->mid
);
835 mid_chunk
= chunk_from_thing(mid
);
837 key_chunk
= (checklist
->is_initiator
&& outbound
) || (!checklist
->is_initiator
&& !outbound
)
838 ? checklist
->initiator
.key
: checklist
->responder
.key
;
840 /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */
841 sig_chunk
= chunk_cat("cccc", mid_chunk
, check
->connect_id
,
842 check
->endpoint_raw
, key_chunk
);
843 this->hasher
->allocate_hash(this->hasher
, sig_chunk
, &sig_hash
);
844 DBG3(DBG_IKE
, "sig_chunk %#B", &sig_chunk
);
845 DBG3(DBG_IKE
, "sig_hash %#B", &sig_hash
);
847 chunk_free(&sig_chunk
);
851 static void queue_retransmission(private_connect_manager_t
*this, check_list_t
*checklist
, endpoint_pair_t
*pair
);
852 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
);
853 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
);
856 * After one of the initiator's pairs has succeeded we finish the checks without
857 * waiting for all the timeouts
859 static job_requeue_t
initiator_finish(callback_data_t
*data
)
861 private_connect_manager_t
*this = data
->connect_manager
;
863 this->mutex
->lock(this->mutex
);
865 check_list_t
*checklist
;
866 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
868 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't finish "
869 "connectivity checks", &data
->connect_id
);
870 this->mutex
->unlock(this->mutex
);
871 return JOB_REQUEUE_NONE
;
874 finish_checks(this, checklist
);
876 this->mutex
->unlock(this->mutex
);
878 return JOB_REQUEUE_NONE
;
882 * Updates the state of the whole checklist
884 static void update_checklist_state(private_connect_manager_t
*this,
885 check_list_t
*checklist
)
887 enumerator_t
*enumerator
;
888 endpoint_pair_t
*current
;
889 bool in_progress
= FALSE
, succeeded
= FALSE
;
891 enumerator
= checklist
->pairs
->create_enumerator(checklist
->pairs
);
892 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
894 switch(current
->state
)
897 /* at least one is still waiting -> checklist remains
898 * in waiting state */
899 enumerator
->destroy(enumerator
);
901 case CHECK_IN_PROGRESS
:
904 case CHECK_SUCCEEDED
:
911 enumerator
->destroy(enumerator
);
913 if (checklist
->is_initiator
&& succeeded
&& !checklist
->is_finishing
)
915 /* instead of waiting until all checks have finished (i.e. all
916 * retransmissions have failed) the initiator finishes the checks
917 * right after the first check has succeeded. to allow a probably
918 * better pair to succeed, we still wait a certain time */
919 DBG2(DBG_IKE
, "fast finishing checks for checklist '%#B'",
920 &checklist
->connect_id
);
922 callback_data_t
*data
= callback_data_create(this, checklist
->connect_id
);
923 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiator_finish
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
924 lib
->scheduler
->schedule_job_ms(lib
->scheduler
, job
, ME_WAIT_TO_FINISH
);
925 checklist
->is_finishing
= TRUE
;
930 checklist
->state
= CHECK_IN_PROGRESS
;
934 checklist
->state
= CHECK_SUCCEEDED
;
938 checklist
->state
= CHECK_FAILED
;
943 * This function is triggered for each sent check after a specific timeout
945 static job_requeue_t
retransmit(callback_data_t
*data
)
947 private_connect_manager_t
*this = data
->connect_manager
;
949 this->mutex
->lock(this->mutex
);
951 check_list_t
*checklist
;
952 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
954 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't retransmit "
955 "connectivity check", &data
->connect_id
);
956 this->mutex
->unlock(this->mutex
);
957 return JOB_REQUEUE_NONE
;
960 endpoint_pair_t
*pair
;
961 if (get_pair_by_id(checklist
, data
->mid
, &pair
) != SUCCESS
)
963 DBG1(DBG_IKE
, "pair with id '%d' not found, can't retransmit "
964 "connectivity check", data
->mid
);
968 if (pair
->state
!= CHECK_IN_PROGRESS
)
970 DBG2(DBG_IKE
, "pair with id '%d' is in wrong state [%d], don't "
971 "retransmit the connectivity check", data
->mid
, pair
->state
);
975 if (++pair
->retransmitted
> ME_MAX_RETRANS
)
977 DBG2(DBG_IKE
, "pair with id '%d' failed after %d retransmissions",
978 data
->mid
, ME_MAX_RETRANS
);
979 pair
->state
= CHECK_FAILED
;
983 charon
->sender
->send(charon
->sender
, pair
->packet
->clone(pair
->packet
));
985 queue_retransmission(this, checklist
, pair
);
988 update_checklist_state(this, checklist
);
990 switch(checklist
->state
)
992 case CHECK_SUCCEEDED
:
994 finish_checks(this, checklist
);
1000 this->mutex
->unlock(this->mutex
);
1002 /* we reschedule it manually */
1003 return JOB_REQUEUE_NONE
;
1007 * Queues a retransmission job
1009 static void queue_retransmission(private_connect_manager_t
*this, check_list_t
*checklist
, endpoint_pair_t
*pair
)
1011 callback_data_t
*data
= retransmit_data_create(this, checklist
->connect_id
, pair
->id
);
1012 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)retransmit
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
1014 u_int32_t retransmission
= pair
->retransmitted
+ 1;
1015 u_int32_t rto
= ME_INTERVAL
;
1016 if (retransmission
> ME_BOOST
)
1018 rto
= (u_int32_t
)(ME_INTERVAL
* pow(ME_RETRANS_BASE
, retransmission
- ME_BOOST
));
1020 DBG2(DBG_IKE
, "scheduling retransmission %d of pair '%d' in %dms",
1021 retransmission
, pair
->id
, rto
);
1023 lib
->scheduler
->schedule_job_ms(lib
->scheduler
, (job_t
*)job
, rto
);
1029 static void send_check(private_connect_manager_t
*this, check_list_t
*checklist
,
1030 check_t
*check
, endpoint_pair_t
*pair
, bool request
)
1032 message_t
*message
= message_create();
1033 message
->set_message_id(message
, check
->mid
);
1034 message
->set_exchange_type(message
, INFORMATIONAL
);
1035 message
->set_request(message
, request
);
1036 message
->set_destination(message
, check
->dst
->clone(check
->dst
));
1037 message
->set_source(message
, check
->src
->clone(check
->src
));
1039 ike_sa_id_t
*ike_sa_id
= ike_sa_id_create(0, 0, request
);
1040 message
->set_ike_sa_id(message
, ike_sa_id
);
1041 ike_sa_id
->destroy(ike_sa_id
);
1043 message
->add_notify(message
, FALSE
, ME_CONNECTID
, check
->connect_id
);
1044 DBG2(DBG_IKE
, "send ME_CONNECTID %#B", &check
->connect_id
);
1046 notify_payload_t
*endpoint
= check
->endpoint
->build_notify(check
->endpoint
);
1047 check
->endpoint_raw
= chunk_clone(endpoint
->get_notification_data(endpoint
));
1048 message
->add_payload(message
, (payload_t
*)endpoint
);
1049 DBG2(DBG_IKE
, "send ME_ENDPOINT notify");
1051 check
->auth
= build_signature(this, checklist
, check
, TRUE
);
1052 message
->add_notify(message
, FALSE
, ME_CONNECTAUTH
, check
->auth
);
1053 DBG2(DBG_IKE
, "send ME_CONNECTAUTH %#B", &check
->auth
);
1056 if (message
->generate(message
, NULL
, &packet
) == SUCCESS
)
1058 charon
->sender
->send(charon
->sender
, packet
->clone(packet
));
1062 DESTROY_IF(pair
->packet
);
1063 pair
->packet
= packet
;
1064 pair
->retransmitted
= 0;
1065 queue_retransmission(this, checklist
, pair
);
1069 packet
->destroy(packet
);
1072 message
->destroy(message
);
1076 * Queues a triggered check
1078 static void queue_triggered_check(private_connect_manager_t
*this,
1079 check_list_t
*checklist
, endpoint_pair_t
*pair
)
1081 DBG2(DBG_IKE
, "queueing triggered check for pair '%d'", pair
->id
);
1082 pair
->state
= CHECK_WAITING
;
1083 checklist
->triggered
->insert_last(checklist
->triggered
, pair
);
1085 if (!checklist
->sender
)
1087 /* if the sender is not running we restart it */
1088 schedule_checks(this, checklist
, ME_INTERVAL
);
1093 * This function is triggered for each checklist at a specific interval
1095 static job_requeue_t
sender(callback_data_t
*data
)
1097 private_connect_manager_t
*this = data
->connect_manager
;
1099 this->mutex
->lock(this->mutex
);
1101 check_list_t
*checklist
;
1102 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
1104 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't send "
1105 "connectivity check", &data
->connect_id
);
1106 this->mutex
->unlock(this->mutex
);
1107 return JOB_REQUEUE_NONE
;
1110 /* reset the sender */
1111 checklist
->sender
= NULL
;
1113 endpoint_pair_t
*pair
;
1114 if (get_triggered_pair(checklist
, &pair
) != SUCCESS
)
1116 DBG1(DBG_IKE
, "no triggered check queued, sending an ordinary check");
1118 if (checklist
->pairs
->find_first(checklist
->pairs
,
1119 (linked_list_match_t
)match_waiting_pair
,
1120 (void**)&pair
) != SUCCESS
)
1122 this->mutex
->unlock(this->mutex
);
1123 DBG1(DBG_IKE
, "no pairs in waiting state, aborting");
1124 return JOB_REQUEUE_NONE
;
1129 DBG1(DBG_IKE
, "triggered check found");
1132 check_t
*check
= check_create();
1133 check
->mid
= pair
->id
;
1134 check
->src
= pair
->local
->clone(pair
->local
);
1135 check
->dst
= pair
->remote
->clone(pair
->remote
);
1136 check
->connect_id
= chunk_clone(checklist
->connect_id
);
1137 check
->endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
, NULL
,
1140 pair
->state
= CHECK_IN_PROGRESS
;
1142 send_check(this, checklist
, check
, pair
, TRUE
);
1144 check_destroy(check
);
1146 /* schedule this job again */
1147 schedule_checks(this, checklist
, ME_INTERVAL
);
1149 this->mutex
->unlock(this->mutex
);
1151 /* we reschedule it manually */
1152 return JOB_REQUEUE_NONE
;
1156 * Schedules checks for a checklist (time in ms)
1158 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
)
1160 callback_data_t
*data
= callback_data_create(this, checklist
->connect_id
);
1161 checklist
->sender
= (job_t
*)callback_job_create((callback_job_cb_t
)sender
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
1162 lib
->scheduler
->schedule_job_ms(lib
->scheduler
, checklist
->sender
, time
);
1166 * Initiates waiting mediated connections
1168 static job_requeue_t
initiate_mediated(initiate_data_t
*data
)
1170 check_list_t
*checklist
= data
->checklist
;
1171 initiated_t
*initiated
= data
->initiated
;
1173 endpoint_pair_t
*pair
;
1174 if (get_best_valid_pair(checklist
, &pair
) == SUCCESS
)
1176 ike_sa_id_t
*waiting_sa
;
1177 enumerator_t
*enumerator
= initiated
->mediated
->create_enumerator(
1178 initiated
->mediated
);
1179 while (enumerator
->enumerate(enumerator
, (void**)&waiting_sa
))
1181 ike_sa_t
*sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, waiting_sa
);
1182 if (sa
->initiate_mediated(sa
, pair
->local
, pair
->remote
, checklist
->connect_id
) != SUCCESS
)
1184 DBG1(DBG_IKE
, "establishing mediated connection failed");
1185 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, sa
);
1189 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, sa
);
1192 enumerator
->destroy(enumerator
);
1196 /* this should (can?) not happen */
1199 return JOB_REQUEUE_NONE
;
1203 * Finishes checks for a checklist
1205 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
)
1207 if (checklist
->is_initiator
)
1209 initiated_t
*initiated
;
1210 if (get_initiated_by_ids(this, checklist
->initiator
.id
,
1211 checklist
->responder
.id
, &initiated
) == SUCCESS
)
1213 remove_checklist(this, checklist
);
1214 remove_initiated(this, initiated
);
1216 initiate_data_t
*data
= initiate_data_create(checklist
, initiated
);
1217 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiate_mediated
, data
, (callback_job_cleanup_t
)initiate_data_destroy
, NULL
);
1218 lib
->processor
->queue_job(lib
->processor
, job
);
1223 DBG1(DBG_IKE
, "there is no mediated connection waiting between '%Y'"
1224 " and '%Y'", checklist
->initiator
.id
, checklist
->responder
.id
);
1230 * Process the response to one of our requests
1232 static void process_response(private_connect_manager_t
*this, check_t
*check
,
1233 check_list_t
*checklist
)
1235 endpoint_pair_t
*pair
;
1236 if (get_pair_by_id(checklist
, check
->mid
, &pair
) == SUCCESS
)
1238 if (pair
->local
->equals(pair
->local
, check
->dst
) &&
1239 pair
->remote
->equals(pair
->remote
, check
->src
))
1241 DBG1(DBG_IKE
, "endpoint pair '%d' is valid: '%#H' - '%#H'",
1242 pair
->id
, pair
->local
, pair
->remote
);
1243 pair
->state
= CHECK_SUCCEEDED
;
1246 linked_list_t
*local_endpoints
= checklist
->is_initiator ?
1247 checklist
->initiator
.endpoints
: checklist
->responder
.endpoints
;
1249 endpoint_notify_t
*local_endpoint
;
1250 if (endpoints_contain(local_endpoints
,
1251 check
->endpoint
->get_host(check
->endpoint
),
1252 &local_endpoint
) != SUCCESS
)
1254 local_endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1255 check
->endpoint
->get_host(check
->endpoint
), pair
->local
);
1256 local_endpoint
->set_priority(local_endpoint
,
1257 check
->endpoint
->get_priority(check
->endpoint
));
1258 local_endpoints
->insert_last(local_endpoints
, local_endpoint
);
1261 update_checklist_state(this, checklist
);
1263 switch(checklist
->state
)
1265 case CHECK_SUCCEEDED
:
1267 finish_checks(this, checklist
);
1275 DBG1(DBG_IKE
, "pair with id '%d' not found", check
->mid
);
1279 static void process_request(private_connect_manager_t
*this, check_t
*check
,
1280 check_list_t
*checklist
)
1282 linked_list_t
*remote_endpoints
= checklist
->is_initiator ?
1283 checklist
->responder
.endpoints
: checklist
->initiator
.endpoints
;
1285 endpoint_notify_t
*peer_reflexive
, *remote_endpoint
;
1286 peer_reflexive
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1288 peer_reflexive
->set_priority(peer_reflexive
,
1289 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
,
1303 case CHECK_IN_PROGRESS
:
1304 /* prevent retransmissions */
1305 pair
->retransmitted
= ME_MAX_RETRANS
;
1306 /* FIXME: we should wait to the next rto to send the triggered
1311 queue_triggered_check(this, checklist
, pair
);
1313 case CHECK_SUCCEEDED
:
1320 endpoint_notify_t
*local_endpoint
= endpoint_notify_create_from_host(HOST
, check
->dst
, NULL
);
1322 endpoint_notify_t
*initiator
= checklist
->is_initiator ? local_endpoint
: remote_endpoint
;
1323 endpoint_notify_t
*responder
= checklist
->is_initiator ? remote_endpoint
: local_endpoint
;
1325 pair
= endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
);
1326 pair
->id
= checklist
->pairs
->get_count(checklist
->pairs
) + 1;
1328 insert_pair_by_priority(checklist
->pairs
, pair
);
1330 queue_triggered_check(this, checklist
, pair
);
1332 local_endpoint
->destroy(local_endpoint
);
1335 check_t
*response
= check_create();
1337 response
->mid
= check
->mid
;
1338 response
->src
= check
->dst
->clone(check
->dst
);
1339 response
->dst
= check
->src
->clone(check
->src
);
1340 response
->connect_id
= chunk_clone(check
->connect_id
);
1341 response
->endpoint
= peer_reflexive
;
1343 send_check(this, checklist
, response
, pair
, FALSE
);
1345 check_destroy(response
);
1349 * Implementation of connect_manager_t.process_check.
1351 static void process_check(private_connect_manager_t
*this, message_t
*message
)
1353 if (message
->parse_body(message
, NULL
) != SUCCESS
)
1355 DBG1(DBG_IKE
, "%N %s with message ID %d processing failed",
1356 exchange_type_names
, message
->get_exchange_type(message
),
1357 message
->get_request(message
) ?
"request" : "response",
1358 message
->get_message_id(message
));
1362 check_t
*check
= check_create();
1363 check
->mid
= message
->get_message_id(message
);
1364 check
->src
= message
->get_source(message
);
1365 check
->src
= check
->src
->clone(check
->src
);
1366 check
->dst
= message
->get_destination(message
);
1367 check
->dst
= check
->dst
->clone(check
->dst
);
1369 if (process_payloads(message
, check
) != SUCCESS
)
1371 DBG1(DBG_IKE
, "invalid connectivity check %s received",
1372 message
->get_request(message
) ?
"request" : "response");
1373 check_destroy(check
);
1377 this->mutex
->lock(this->mutex
);
1379 check_list_t
*checklist
;
1380 if (get_checklist_by_id(this, check
->connect_id
, &checklist
) != SUCCESS
)
1382 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1383 &check
->connect_id
);
1384 check_destroy(check
);
1385 this->mutex
->unlock(this->mutex
);
1389 chunk_t sig
= build_signature(this, checklist
, check
, FALSE
);
1390 if (!chunk_equals(sig
, check
->auth
))
1392 DBG1(DBG_IKE
, "connectivity check verification failed");
1393 check_destroy(check
);
1395 this->mutex
->unlock(this->mutex
);
1400 if (message
->get_request(message
))
1402 process_request(this, check
, checklist
);
1406 process_response(this, check
, checklist
);
1409 this->mutex
->unlock(this->mutex
);
1411 check_destroy(check
);
1415 * Implementation of connect_manager_t.check_and_register.
1417 static bool check_and_register(private_connect_manager_t
*this,
1418 identification_t
*id
, identification_t
*peer_id
,
1419 ike_sa_id_t
*mediated_sa
)
1421 initiated_t
*initiated
;
1422 bool already_there
= TRUE
;
1424 this->mutex
->lock(this->mutex
);
1426 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1428 DBG2(DBG_IKE
, "registered waiting mediated connection with '%Y'",
1430 initiated
= initiated_create(id
, peer_id
);
1431 this->initiated
->insert_last(this->initiated
, initiated
);
1432 already_there
= FALSE
;
1435 if (initiated
->mediated
->find_first(initiated
->mediated
,
1436 (linked_list_match_t
)mediated_sa
->equals
,
1437 NULL
, mediated_sa
) != SUCCESS
)
1439 initiated
->mediated
->insert_last(initiated
->mediated
,
1440 mediated_sa
->clone(mediated_sa
));
1443 this->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,
1452 ike_sa_id_t
*mediation_sa
, identification_t
*id
,
1453 identification_t
*peer_id
)
1455 initiated_t
*initiated
;
1457 this->mutex
->lock(this->mutex
);
1459 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1461 DBG2(DBG_IKE
, "no waiting mediated connections with '%Y'", peer_id
);
1462 this->mutex
->unlock(this->mutex
);
1466 ike_sa_id_t
*waiting_sa
;
1467 enumerator_t
*enumerator
= initiated
->mediated
->create_enumerator(
1468 initiated
->mediated
);
1469 while (enumerator
->enumerate(enumerator
, (void**)&waiting_sa
))
1471 job_t
*job
= (job_t
*)reinitiate_mediation_job_create(mediation_sa
,
1473 lib
->processor
->queue_job(lib
->processor
, job
);
1475 enumerator
->destroy(enumerator
);
1477 this->mutex
->unlock(this->mutex
);
1481 * Implementation of connect_manager_t.set_initiator_data.
1483 static status_t
set_initiator_data(private_connect_manager_t
*this,
1484 identification_t
*initiator
,
1485 identification_t
*responder
,
1486 chunk_t connect_id
, chunk_t key
,
1487 linked_list_t
*endpoints
, bool is_initiator
)
1489 check_list_t
*checklist
;
1491 this->mutex
->lock(this->mutex
);
1493 if (get_checklist_by_id(this, connect_id
, NULL
) == SUCCESS
)
1495 DBG1(DBG_IKE
, "checklist with id '%#B' already exists, aborting",
1497 this->mutex
->unlock(this->mutex
);
1501 checklist
= check_list_create(initiator
, responder
, connect_id
, key
,
1502 endpoints
, is_initiator
);
1503 this->checklists
->insert_last(this->checklists
, checklist
);
1505 this->mutex
->unlock(this->mutex
);
1511 * Implementation of connect_manager_t.set_responder_data.
1513 static status_t
set_responder_data(private_connect_manager_t
*this,
1514 chunk_t connect_id
, chunk_t key
,
1515 linked_list_t
*endpoints
)
1517 check_list_t
*checklist
;
1519 this->mutex
->lock(this->mutex
);
1521 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1523 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1525 this->mutex
->unlock(this->mutex
);
1529 checklist
->responder
.key
= chunk_clone(key
);
1530 checklist
->responder
.endpoints
= endpoints
->clone_offset(endpoints
,
1531 offsetof(endpoint_notify_t
, clone
));
1532 checklist
->state
= CHECK_WAITING
;
1534 build_pairs(checklist
);
1536 /* send the first check immediately */
1537 schedule_checks(this, checklist
, 0);
1539 this->mutex
->unlock(this->mutex
);
1545 * Implementation of connect_manager_t.stop_checks.
1547 static status_t
stop_checks(private_connect_manager_t
*this, chunk_t connect_id
)
1549 check_list_t
*checklist
;
1551 this->mutex
->lock(this->mutex
);
1553 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1555 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1557 this->mutex
->unlock(this->mutex
);
1561 DBG1(DBG_IKE
, "removing checklist with id '%#B'", &connect_id
);
1563 remove_checklist(this, checklist
);
1564 check_list_destroy(checklist
);
1566 this->mutex
->unlock(this->mutex
);
1572 * Implementation of connect_manager_t.destroy.
1574 static void destroy(private_connect_manager_t
*this)
1576 this->mutex
->lock(this->mutex
);
1578 this->hasher
->destroy(this->hasher
);
1579 this->checklists
->destroy_function(this->checklists
, (void*)check_list_destroy
);
1580 this->initiated
->destroy_function(this->initiated
, (void*)initiated_destroy
);
1582 this->mutex
->unlock(this->mutex
);
1583 this->mutex
->destroy(this->mutex
);
1588 * Described in header.
1590 connect_manager_t
*connect_manager_create()
1592 private_connect_manager_t
*this = malloc_thing(private_connect_manager_t
);
1594 this->public.destroy
= (void(*)(connect_manager_t
*))destroy
;
1595 this->public.check_and_register
= (bool(*)(connect_manager_t
*,identification_t
*,identification_t
*,ike_sa_id_t
*))check_and_register
;
1596 this->public.check_and_initiate
= (void(*)(connect_manager_t
*,ike_sa_id_t
*,identification_t
*,identification_t
*))check_and_initiate
;
1597 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
;
1598 this->public.set_responder_data
= (status_t(*)(connect_manager_t
*,chunk_t
,chunk_t
,linked_list_t
*))set_responder_data
;
1599 this->public.process_check
= (void(*)(connect_manager_t
*,message_t
*))process_check
;
1600 this->public.stop_checks
= (status_t(*)(connect_manager_t
*,chunk_t
))stop_checks
;
1602 this->hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
1603 if (this->hasher
== NULL
)
1605 DBG1(DBG_IKE
, "unable to create connect manager, SHA1 not supported");
1610 this->checklists
= linked_list_create();
1611 this->initiated
= linked_list_create();
1613 this->mutex
= mutex_create(MUTEX_TYPE_DEFAULT
);
1615 return (connect_manager_t
*)this;