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"
22 #include <threading/mutex.h>
23 #include <utils/linked_list.h>
24 #include <crypto/hashers/hasher.h>
26 #include <processing/jobs/callback_job.h>
27 #include <processing/jobs/initiate_mediation_job.h>
28 #include <encoding/payloads/endpoint_notify.h>
31 * the check interval is ME_INTERVAL */
32 #define ME_INTERVAL 25 /* ms */
33 /* retransmission timeout is first ME_INTERVAL for ME_BOOST retransmissions
34 * then gets reduced to ME_INTERVAL * ME_RETRANS_BASE ^ (sent retransmissions - ME_BOOST). */
35 /* number of initial retransmissions sent in short interval */
37 /* base for retransmissions */
38 #define ME_RETRANS_BASE 1.8
39 /* max number of retransmissions */
40 #define ME_MAX_RETRANS 13
42 /* time to wait before the initiator finishes the connectivity checks after
43 * the first check has succeeded */
44 #define ME_WAIT_TO_FINISH 1000 /* ms */
46 typedef struct private_connect_manager_t private_connect_manager_t
;
49 * Additional private members of connect_manager_t.
51 struct private_connect_manager_t
{
53 * Public interface of connect_manager_t.
55 connect_manager_t
public;
58 * Lock for exclusivly accessing the manager.
63 * Hasher to generate signatures
68 * Linked list with initiated mediated connections
70 linked_list_t
*initiated
;
73 * Linked list with checklists (hash table with connect ID as key would
76 linked_list_t
*checklists
;
79 typedef enum check_state_t check_state_t
;
89 typedef struct endpoint_pair_t endpoint_pair_t
;
92 * An entry in the check list.
94 struct endpoint_pair_t
{
101 /** local endpoint */
104 /** remote endpoint */
110 /** number of retransmissions */
111 u_int32_t retransmitted
;
113 /** the generated packet */
118 * Destroys an endpoint pair
120 static void endpoint_pair_destroy(endpoint_pair_t
*this)
122 DESTROY_IF(this->local
);
123 DESTROY_IF(this->remote
);
124 DESTROY_IF(this->packet
);
129 * Creates a new entry for the list.
131 static endpoint_pair_t
*endpoint_pair_create(endpoint_notify_t
*initiator
,
132 endpoint_notify_t
*responder
, bool initiator_is_local
)
134 endpoint_pair_t
*this = malloc_thing(endpoint_pair_t
);
138 u_int32_t pi
= initiator
->get_priority(initiator
);
139 u_int32_t pr
= responder
->get_priority(responder
);
140 this->priority
= pow(2, 32) * min(pi
, pr
) + 2 * max(pi
, pr
) + (pi
> pr ?
1 : 0);
142 this->local
= initiator_is_local ? initiator
->get_base(initiator
)
143 : responder
->get_base(responder
);
144 this->local
= this->local
->clone(this->local
);
145 this->remote
= initiator_is_local ? responder
->get_host(responder
)
146 : initiator
->get_host(initiator
);
147 this->remote
= this->remote
->clone(this->remote
);
149 this->state
= CHECK_WAITING
;
150 this->retransmitted
= 0;
157 typedef struct check_list_t check_list_t
;
160 * An entry in the linked list.
162 struct check_list_t
{
165 /** initiator's id */
166 identification_t
*id
;
168 /** initiator's key */
171 /** initiator's endpoints */
172 linked_list_t
*endpoints
;
176 /** responder's id */
177 identification_t
*id
;
179 /** responder's key */
182 /** responder's endpoints */
183 linked_list_t
*endpoints
;
189 /** list of endpoint pairs */
190 linked_list_t
*pairs
;
192 /** pairs queued for triggered checks */
193 linked_list_t
*triggered
;
198 /** TRUE if this is the initiator */
201 /** TRUE if the initiator is finishing the checks */
204 /** the current sender job */
210 * Destroys a checklist
212 static void check_list_destroy(check_list_t
*this)
214 DESTROY_IF(this->initiator
.id
);
215 DESTROY_IF(this->responder
.id
);
217 chunk_free(&this->connect_id
);
218 chunk_free(&this->initiator
.key
);
219 chunk_free(&this->responder
.key
);
221 DESTROY_OFFSET_IF(this->initiator
.endpoints
,
222 offsetof(endpoint_notify_t
, destroy
));
223 DESTROY_OFFSET_IF(this->responder
.endpoints
,
224 offsetof(endpoint_notify_t
, destroy
));
226 DESTROY_FUNCTION_IF(this->pairs
, (void*)endpoint_pair_destroy
);
227 /* this list contains some of the elements contained in this->pairs */
228 DESTROY_IF(this->triggered
);
234 * Creates a new checklist
236 static check_list_t
*check_list_create(identification_t
*initiator
,
237 identification_t
*responder
,
239 chunk_t initiator_key
,
240 linked_list_t
*initiator_endpoints
,
243 check_list_t
*this = malloc_thing(check_list_t
);
245 this->connect_id
= chunk_clone(connect_id
);
247 this->initiator
.id
= initiator
->clone(initiator
);
248 this->initiator
.key
= chunk_clone(initiator_key
);
249 this->initiator
.endpoints
= initiator_endpoints
->clone_offset(initiator_endpoints
, offsetof(endpoint_notify_t
, clone
));
251 this->responder
.id
= responder
->clone(responder
);
252 this->responder
.key
= chunk_empty
;
253 this->responder
.endpoints
= NULL
;
255 this->pairs
= linked_list_create();
256 this->triggered
= linked_list_create();
257 this->state
= CHECK_NONE
;
258 this->is_initiator
= is_initiator
;
259 this->is_finishing
= FALSE
;
264 typedef struct initiated_t initiated_t
;
267 * For an initiator, the data stored about initiated mediation connections
271 identification_t
*id
;
274 identification_t
*peer_id
;
276 /** list of mediated sas */
277 linked_list_t
*mediated
;
281 * Destroys a queued initiation
283 static void initiated_destroy(initiated_t
*this)
285 DESTROY_IF(this->id
);
286 DESTROY_IF(this->peer_id
);
287 this->mediated
->destroy_offset(this->mediated
,
288 offsetof(ike_sa_id_t
, destroy
));
293 * Creates a queued initiation
295 static initiated_t
*initiated_create(identification_t
*id
,
296 identification_t
*peer_id
)
298 initiated_t
*this = malloc_thing(initiated_t
);
300 this->id
= id
->clone(id
);
301 this->peer_id
= peer_id
->clone(peer_id
);
302 this->mediated
= linked_list_create();
308 typedef struct check_t check_t
;
311 * Data exchanged in a connectivity check
317 /** source of the connectivity check */
320 /** destination of the connectivity check */
327 endpoint_notify_t
*endpoint
;
329 /** raw endpoint payload (to verify the signature) */
330 chunk_t endpoint_raw
;
337 * Destroys a connectivity check
339 static void check_destroy(check_t
*this)
341 chunk_free(&this->connect_id
);
342 chunk_free(&this->endpoint_raw
);
343 chunk_free(&this->auth
);
344 DESTROY_IF(this->src
);
345 DESTROY_IF(this->dst
);
346 DESTROY_IF(this->endpoint
);
351 * Creates a new connectivity check
353 static check_t
*check_create()
355 check_t
*this = malloc_thing(check_t
);
357 this->connect_id
= chunk_empty
;
358 this->auth
= chunk_empty
;
359 this->endpoint_raw
= chunk_empty
;
362 this->endpoint
= NULL
;
369 typedef struct callback_data_t callback_data_t
;
372 * Data required by several callback jobs used in this file
374 struct callback_data_t
{
375 /** connect manager */
376 private_connect_manager_t
*connect_manager
;
381 /** message (pair) id */
386 * Destroys a callback data object
388 static void callback_data_destroy(callback_data_t
*this)
390 chunk_free(&this->connect_id
);
395 * Creates a new callback data object
397 static callback_data_t
*callback_data_create(private_connect_manager_t
*connect_manager
,
400 callback_data_t
*this = malloc_thing(callback_data_t
);
401 this->connect_manager
= connect_manager
;
402 this->connect_id
= chunk_clone(connect_id
);
408 * Creates a new retransmission data object
410 static callback_data_t
*retransmit_data_create(private_connect_manager_t
*connect_manager
,
411 chunk_t connect_id
, u_int32_t mid
)
413 callback_data_t
*this = callback_data_create(connect_manager
, connect_id
);
418 typedef struct initiate_data_t initiate_data_t
;
421 * Data required by the initiate mediated
423 struct initiate_data_t
{
425 check_list_t
*checklist
;
427 /** waiting mediated connections */
428 initiated_t
*initiated
;
432 * Destroys a initiate data object
434 static void initiate_data_destroy(initiate_data_t
*this)
436 check_list_destroy(this->checklist
);
437 initiated_destroy(this->initiated
);
442 * Creates a new initiate data object
444 static initiate_data_t
*initiate_data_create(check_list_t
*checklist
,
445 initiated_t
*initiated
)
447 initiate_data_t
*this = malloc_thing(initiate_data_t
);
449 this->checklist
= checklist
;
450 this->initiated
= initiated
;
456 * Find an initiated connection by the peers' ids
458 static bool match_initiated_by_ids(initiated_t
*current
, identification_t
*id
,
459 identification_t
*peer_id
)
461 return id
->equals(id
, current
->id
) && peer_id
->equals(peer_id
, current
->peer_id
);
464 static status_t
get_initiated_by_ids(private_connect_manager_t
*this,
465 identification_t
*id
,
466 identification_t
*peer_id
,
467 initiated_t
**initiated
)
469 return this->initiated
->find_first(this->initiated
,
470 (linked_list_match_t
)match_initiated_by_ids
,
471 (void**)initiated
, id
, peer_id
);
475 * Removes data about initiated connections
477 static void remove_initiated(private_connect_manager_t
*this,
478 initiated_t
*initiated
)
480 iterator_t
*iterator
;
481 initiated_t
*current
;
483 iterator
= this->initiated
->create_iterator(this->initiated
, TRUE
);
484 while (iterator
->iterate(iterator
, (void**)¤t
))
486 if (current
== initiated
)
488 iterator
->remove(iterator
);
492 iterator
->destroy(iterator
);
496 * Find the checklist with a specific connect ID
498 static bool match_checklist_by_id(check_list_t
*current
, chunk_t
*connect_id
)
500 return chunk_equals(*connect_id
, current
->connect_id
);
503 static status_t
get_checklist_by_id(private_connect_manager_t
*this,
505 check_list_t
**check_list
)
507 return this->checklists
->find_first(this->checklists
,
508 (linked_list_match_t
)match_checklist_by_id
,
509 (void**)check_list
, &connect_id
);
513 * Removes a checklist
515 static void remove_checklist(private_connect_manager_t
*this,
516 check_list_t
*checklist
)
518 iterator_t
*iterator
;
519 check_list_t
*current
;
521 iterator
= this->checklists
->create_iterator(this->checklists
, TRUE
);
522 while (iterator
->iterate(iterator
, (void**)¤t
))
524 if (current
== checklist
)
526 iterator
->remove(iterator
);
530 iterator
->destroy(iterator
);
534 * Checks if a list of endpoint_notify_t contains a certain host_t
536 static bool match_endpoint_by_host(endpoint_notify_t
*current
, host_t
*host
)
538 return host
->equals(host
, current
->get_host(current
));
541 static status_t
endpoints_contain(linked_list_t
*endpoints
, host_t
*host
,
542 endpoint_notify_t
**endpoint
)
544 return endpoints
->find_first(endpoints
,
545 (linked_list_match_t
)match_endpoint_by_host
,
546 (void**)endpoint
, host
);
550 * Inserts an endpoint pair into a list of pairs ordered by priority (high to low)
552 static void insert_pair_by_priority(linked_list_t
*pairs
, endpoint_pair_t
*pair
)
554 iterator_t
*iterator
;
555 endpoint_pair_t
*current
;
556 bool inserted
= FALSE
;
558 iterator
= pairs
->create_iterator(pairs
, TRUE
);
559 while (iterator
->iterate(iterator
, (void**)¤t
))
561 if (current
->priority
< pair
->priority
)
563 iterator
->insert_before(iterator
, pair
);
568 iterator
->destroy(iterator
);
572 pairs
->insert_last(pairs
, pair
);
577 * Searches a list of endpoint_pair_t for a pair with specific host_ts
579 static bool match_pair_by_hosts(endpoint_pair_t
*current
, host_t
*local
,
582 return local
->equals(local
, current
->local
) && remote
->equals(remote
, current
->remote
);
585 static status_t
get_pair_by_hosts(linked_list_t
*pairs
, host_t
*local
,
586 host_t
*remote
, endpoint_pair_t
**pair
)
588 return pairs
->find_first(pairs
, (linked_list_match_t
)match_pair_by_hosts
,
589 (void**)pair
, local
, remote
);
592 static bool match_pair_by_id(endpoint_pair_t
*current
, u_int32_t
*id
)
594 return current
->id
== *id
;
598 * Searches for a pair with a specific id
600 static status_t
get_pair_by_id(check_list_t
*checklist
, u_int32_t id
,
601 endpoint_pair_t
**pair
)
603 return checklist
->pairs
->find_first(checklist
->pairs
,
604 (linked_list_match_t
)match_pair_by_id
,
608 static bool match_succeeded_pair(endpoint_pair_t
*current
)
610 return current
->state
== CHECK_SUCCEEDED
;
614 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
616 static status_t
get_best_valid_pair(check_list_t
*checklist
,
617 endpoint_pair_t
**pair
)
619 return checklist
->pairs
->find_first(checklist
->pairs
,
620 (linked_list_match_t
)match_succeeded_pair
,
624 static bool match_waiting_pair(endpoint_pair_t
*current
)
626 return current
->state
== CHECK_WAITING
;
630 * Returns and *removes* the first triggered pair in state CHECK_WAITING.
632 static status_t
get_triggered_pair(check_list_t
*checklist
,
633 endpoint_pair_t
**pair
)
635 iterator_t
*iterator
;
636 endpoint_pair_t
*current
;
637 status_t status
= NOT_FOUND
;
639 iterator
= checklist
->triggered
->create_iterator(checklist
->triggered
, TRUE
);
640 while (iterator
->iterate(iterator
, (void**)¤t
))
642 iterator
->remove(iterator
);
644 if (current
->state
== CHECK_WAITING
)
654 iterator
->destroy(iterator
);
660 * Prints all the pairs on a checklist
662 static void print_checklist(check_list_t
*checklist
)
664 iterator_t
*iterator
;
665 endpoint_pair_t
*current
;
667 DBG1(DBG_IKE
, "pairs on checklist %#B:", &checklist
->connect_id
);
668 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
669 while (iterator
->iterate(iterator
, (void**)¤t
))
671 DBG1(DBG_IKE
, " * %#H - %#H (%d)", current
->local
, current
->remote
,
674 iterator
->destroy(iterator
);
678 * Prunes identical pairs with lower priority from the list
679 * Note: this function also numbers the remaining pairs serially
681 static void prune_pairs(linked_list_t
*pairs
)
683 iterator_t
*iterator
, *search
;
684 endpoint_pair_t
*current
, *other
;
687 iterator
= pairs
->create_iterator(pairs
, TRUE
);
688 search
= pairs
->create_iterator(pairs
, TRUE
);
689 while (iterator
->iterate(iterator
, (void**)¤t
))
693 while (search
->iterate(search
, (void**)&other
))
695 if (current
== other
)
700 if (current
->local
->equals(current
->local
, other
->local
) &&
701 current
->remote
->equals(current
->remote
, other
->remote
))
703 /* since the list of pairs is sorted by priority in descending
704 * order, and we iterate the list from the beginning, we are
705 * sure that the priority of 'other' is lower than that of
706 * 'current', remove it */
707 DBG1(DBG_IKE
, "pruning endpoint pair %#H - %#H with priority %d",
708 other
->local
, other
->remote
, other
->priority
);
709 search
->remove(search
);
710 endpoint_pair_destroy(other
);
713 search
->reset(search
);
715 search
->destroy(search
);
716 iterator
->destroy(iterator
);
720 * Builds a list of endpoint pairs
722 static void build_pairs(check_list_t
*checklist
)
724 /* FIXME: limit endpoints and pairs */
725 iterator_t
*iterator_i
, *iterator_r
;
726 endpoint_notify_t
*initiator
, *responder
;
728 iterator_i
= checklist
->initiator
.endpoints
->create_iterator(
729 checklist
->initiator
.endpoints
, TRUE
);
730 while (iterator_i
->iterate(iterator_i
, (void**)&initiator
))
732 iterator_r
= checklist
->responder
.endpoints
->create_iterator(
733 checklist
->responder
.endpoints
, TRUE
);
734 while (iterator_r
->iterate(iterator_r
, (void**)&responder
))
736 if (initiator
->get_family(initiator
) != responder
->get_family(responder
))
741 insert_pair_by_priority(checklist
->pairs
, endpoint_pair_create(
742 initiator
, responder
, checklist
->is_initiator
));
744 iterator_r
->destroy(iterator_r
);
746 iterator_i
->destroy(iterator_i
);
748 print_checklist(checklist
);
750 prune_pairs(checklist
->pairs
);
754 * Processes the payloads of a connectivity check and returns the extracted data
756 static status_t
process_payloads(message_t
*message
, check_t
*check
)
758 enumerator_t
*enumerator
;
761 enumerator
= message
->create_payload_enumerator(message
);
762 while (enumerator
->enumerate(enumerator
, &payload
))
764 if (payload
->get_type(payload
) != NOTIFY
)
766 DBG1(DBG_IKE
, "ignoring payload of type '%N' while processing "
767 "connectivity check", payload_type_names
,
768 payload
->get_type(payload
));
772 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
774 switch (notify
->get_notify_type(notify
))
780 DBG1(DBG_IKE
, "connectivity check contains multiple "
781 "ME_ENDPOINT notifies");
785 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
788 DBG1(DBG_IKE
, "received invalid ME_ENDPOINT notify");
791 check
->endpoint
= endpoint
;
792 check
->endpoint_raw
= chunk_clone(notify
->get_notification_data(notify
));
793 DBG2(DBG_IKE
, "received ME_ENDPOINT notify");
798 if (check
->connect_id
.ptr
)
800 DBG1(DBG_IKE
, "connectivity check contains multiple "
801 "ME_CONNECTID notifies");
804 check
->connect_id
= chunk_clone(notify
->get_notification_data(notify
));
805 DBG2(DBG_IKE
, "received ME_CONNECTID %#B", &check
->connect_id
);
812 DBG1(DBG_IKE
, "connectivity check contains multiple "
813 "ME_CONNECTAUTH notifies");
816 check
->auth
= chunk_clone(notify
->get_notification_data(notify
));
817 DBG2(DBG_IKE
, "received ME_CONNECTAUTH %#B", &check
->auth
);
824 enumerator
->destroy(enumerator
);
826 if (!check
->connect_id
.ptr
|| !check
->endpoint
|| !check
->auth
.ptr
)
828 DBG1(DBG_IKE
, "at least one required payload was missing from the "
829 "connectivity check");
837 * Builds the signature for a connectivity check
839 static chunk_t
build_signature(private_connect_manager_t
*this,
840 check_list_t
*checklist
, check_t
*check
, bool outbound
)
843 chunk_t mid_chunk
, key_chunk
, sig_chunk
;
846 mid
= htonl(check
->mid
);
847 mid_chunk
= chunk_from_thing(mid
);
849 key_chunk
= (checklist
->is_initiator
&& outbound
) || (!checklist
->is_initiator
&& !outbound
)
850 ? checklist
->initiator
.key
: checklist
->responder
.key
;
852 /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */
853 sig_chunk
= chunk_cat("cccc", mid_chunk
, check
->connect_id
,
854 check
->endpoint_raw
, key_chunk
);
855 this->hasher
->allocate_hash(this->hasher
, sig_chunk
, &sig_hash
);
856 DBG3(DBG_IKE
, "sig_chunk %#B", &sig_chunk
);
857 DBG3(DBG_IKE
, "sig_hash %#B", &sig_hash
);
859 chunk_free(&sig_chunk
);
863 static void queue_retransmission(private_connect_manager_t
*this, check_list_t
*checklist
, endpoint_pair_t
*pair
);
864 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
);
865 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
);
868 * After one of the initiator's pairs has succeeded we finish the checks without
869 * waiting for all the timeouts
871 static job_requeue_t
initiator_finish(callback_data_t
*data
)
873 private_connect_manager_t
*this = data
->connect_manager
;
875 this->mutex
->lock(this->mutex
);
877 check_list_t
*checklist
;
878 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
880 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't finish "
881 "connectivity checks", &data
->connect_id
);
882 this->mutex
->unlock(this->mutex
);
883 return JOB_REQUEUE_NONE
;
886 finish_checks(this, checklist
);
888 this->mutex
->unlock(this->mutex
);
890 return JOB_REQUEUE_NONE
;
894 * Updates the state of the whole checklist
896 static void update_checklist_state(private_connect_manager_t
*this,
897 check_list_t
*checklist
)
899 iterator_t
*iterator
;
900 endpoint_pair_t
*current
;
901 bool in_progress
= FALSE
, succeeded
= FALSE
;
903 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
904 while (iterator
->iterate(iterator
, (void**)¤t
))
906 switch(current
->state
)
909 /* at least one is still waiting -> checklist remains
910 * in waiting state */
911 iterator
->destroy(iterator
);
913 case CHECK_IN_PROGRESS
:
916 case CHECK_SUCCEEDED
:
923 iterator
->destroy(iterator
);
925 if (checklist
->is_initiator
&& succeeded
&& !checklist
->is_finishing
)
927 /* instead of waiting until all checks have finished (i.e. all
928 * retransmissions have failed) the initiator finishes the checks
929 * right after the first check has succeeded. to allow a probably
930 * better pair to succeed, we still wait a certain time */
931 DBG2(DBG_IKE
, "fast finishing checks for checklist '%#B'",
932 &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 hydra
->scheduler
->schedule_job_ms(hydra
->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 this->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 "
967 "connectivity check", &data
->connect_id
);
968 this->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 "
976 "connectivity check", data
->mid
);
980 if (pair
->state
!= CHECK_IN_PROGRESS
)
982 DBG2(DBG_IKE
, "pair with id '%d' is in wrong state [%d], don't "
983 "retransmit the connectivity check", 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 this->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",
1033 retransmission
, pair
->id
, rto
);
1035 hydra
->scheduler
->schedule_job_ms(hydra
->scheduler
, (job_t
*)job
, rto
);
1041 static void send_check(private_connect_manager_t
*this, check_list_t
*checklist
,
1042 check_t
*check
, endpoint_pair_t
*pair
, bool request
)
1044 message_t
*message
= message_create();
1045 message
->set_message_id(message
, check
->mid
);
1046 message
->set_exchange_type(message
, INFORMATIONAL
);
1047 message
->set_request(message
, request
);
1048 message
->set_destination(message
, check
->dst
->clone(check
->dst
));
1049 message
->set_source(message
, check
->src
->clone(check
->src
));
1051 ike_sa_id_t
*ike_sa_id
= ike_sa_id_create(0, 0, request
);
1052 message
->set_ike_sa_id(message
, ike_sa_id
);
1053 ike_sa_id
->destroy(ike_sa_id
);
1055 message
->add_notify(message
, FALSE
, ME_CONNECTID
, check
->connect_id
);
1056 DBG2(DBG_IKE
, "send ME_CONNECTID %#B", &check
->connect_id
);
1058 notify_payload_t
*endpoint
= check
->endpoint
->build_notify(check
->endpoint
);
1059 check
->endpoint_raw
= chunk_clone(endpoint
->get_notification_data(endpoint
));
1060 message
->add_payload(message
, (payload_t
*)endpoint
);
1061 DBG2(DBG_IKE
, "send ME_ENDPOINT notify");
1063 check
->auth
= build_signature(this, checklist
, check
, TRUE
);
1064 message
->add_notify(message
, FALSE
, ME_CONNECTAUTH
, check
->auth
);
1065 DBG2(DBG_IKE
, "send ME_CONNECTAUTH %#B", &check
->auth
);
1068 if (message
->generate(message
, NULL
, &packet
) == SUCCESS
)
1070 charon
->sender
->send(charon
->sender
, packet
->clone(packet
));
1074 DESTROY_IF(pair
->packet
);
1075 pair
->packet
= packet
;
1076 pair
->retransmitted
= 0;
1077 queue_retransmission(this, checklist
, pair
);
1081 packet
->destroy(packet
);
1084 message
->destroy(message
);
1088 * Queues a triggered check
1090 static void queue_triggered_check(private_connect_manager_t
*this,
1091 check_list_t
*checklist
, endpoint_pair_t
*pair
)
1093 DBG2(DBG_IKE
, "queueing triggered check for pair '%d'", pair
->id
);
1094 pair
->state
= CHECK_WAITING
;
1095 checklist
->triggered
->insert_last(checklist
->triggered
, pair
);
1097 if (!checklist
->sender
)
1099 /* if the sender is not running we restart it */
1100 schedule_checks(this, checklist
, ME_INTERVAL
);
1105 * This function is triggered for each checklist at a specific interval
1107 static job_requeue_t
sender(callback_data_t
*data
)
1109 private_connect_manager_t
*this = data
->connect_manager
;
1111 this->mutex
->lock(this->mutex
);
1113 check_list_t
*checklist
;
1114 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
1116 DBG1(DBG_IKE
, "checklist with id '%#B' not found, can't send "
1117 "connectivity check", &data
->connect_id
);
1118 this->mutex
->unlock(this->mutex
);
1119 return JOB_REQUEUE_NONE
;
1122 /* reset the sender */
1123 checklist
->sender
= NULL
;
1125 endpoint_pair_t
*pair
;
1126 if (get_triggered_pair(checklist
, &pair
) != SUCCESS
)
1128 DBG1(DBG_IKE
, "no triggered check queued, sending an ordinary check");
1130 if (checklist
->pairs
->find_first(checklist
->pairs
,
1131 (linked_list_match_t
)match_waiting_pair
,
1132 (void**)&pair
) != SUCCESS
)
1134 this->mutex
->unlock(this->mutex
);
1135 DBG1(DBG_IKE
, "no pairs in waiting state, aborting");
1136 return JOB_REQUEUE_NONE
;
1141 DBG1(DBG_IKE
, "triggered check found");
1144 check_t
*check
= check_create();
1145 check
->mid
= pair
->id
;
1146 check
->src
= pair
->local
->clone(pair
->local
);
1147 check
->dst
= pair
->remote
->clone(pair
->remote
);
1148 check
->connect_id
= chunk_clone(checklist
->connect_id
);
1149 check
->endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
, NULL
,
1152 pair
->state
= CHECK_IN_PROGRESS
;
1154 send_check(this, checklist
, check
, pair
, TRUE
);
1156 check_destroy(check
);
1158 /* schedule this job again */
1159 schedule_checks(this, checklist
, ME_INTERVAL
);
1161 this->mutex
->unlock(this->mutex
);
1163 /* we reschedule it manually */
1164 return JOB_REQUEUE_NONE
;
1168 * Schedules checks for a checklist (time in ms)
1170 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
)
1172 callback_data_t
*data
= callback_data_create(this, checklist
->connect_id
);
1173 checklist
->sender
= (job_t
*)callback_job_create((callback_job_cb_t
)sender
, data
, (callback_job_cleanup_t
)callback_data_destroy
, NULL
);
1174 hydra
->scheduler
->schedule_job_ms(hydra
->scheduler
, checklist
->sender
, time
);
1178 * Initiates waiting mediated connections
1180 static job_requeue_t
initiate_mediated(initiate_data_t
*data
)
1182 check_list_t
*checklist
= data
->checklist
;
1183 initiated_t
*initiated
= data
->initiated
;
1185 endpoint_pair_t
*pair
;
1186 if (get_best_valid_pair(checklist
, &pair
) == SUCCESS
)
1188 ike_sa_id_t
*waiting_sa
;
1189 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1190 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1192 ike_sa_t
*sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, waiting_sa
);
1193 if (sa
->initiate_mediated(sa
, pair
->local
, pair
->remote
, checklist
->connect_id
) != SUCCESS
)
1195 DBG1(DBG_IKE
, "establishing mediated connection failed");
1196 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, sa
);
1198 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, sa
);
1200 iterator
->destroy(iterator
);
1204 /* this should (can?) not happen */
1207 return JOB_REQUEUE_NONE
;
1211 * Finishes checks for a checklist
1213 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
)
1215 if (checklist
->is_initiator
)
1217 initiated_t
*initiated
;
1218 if (get_initiated_by_ids(this, checklist
->initiator
.id
,
1219 checklist
->responder
.id
, &initiated
) == SUCCESS
)
1221 remove_checklist(this, checklist
);
1222 remove_initiated(this, initiated
);
1224 initiate_data_t
*data
= initiate_data_create(checklist
, initiated
);
1225 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiate_mediated
, data
, (callback_job_cleanup_t
)initiate_data_destroy
, NULL
);
1226 hydra
->processor
->queue_job(hydra
->processor
, job
);
1231 DBG1(DBG_IKE
, "there is no mediated connection waiting between '%Y'"
1232 " and '%Y'", checklist
->initiator
.id
, checklist
->responder
.id
);
1238 * Process the response to one of our requests
1240 static void process_response(private_connect_manager_t
*this, check_t
*check
,
1241 check_list_t
*checklist
)
1243 endpoint_pair_t
*pair
;
1244 if (get_pair_by_id(checklist
, check
->mid
, &pair
) == SUCCESS
)
1246 if (pair
->local
->equals(pair
->local
, check
->dst
) &&
1247 pair
->remote
->equals(pair
->remote
, check
->src
))
1249 DBG1(DBG_IKE
, "endpoint pair '%d' is valid: '%#H' - '%#H'",
1250 pair
->id
, pair
->local
, pair
->remote
);
1251 pair
->state
= CHECK_SUCCEEDED
;
1254 linked_list_t
*local_endpoints
= checklist
->is_initiator ?
1255 checklist
->initiator
.endpoints
: checklist
->responder
.endpoints
;
1257 endpoint_notify_t
*local_endpoint
;
1258 if (endpoints_contain(local_endpoints
,
1259 check
->endpoint
->get_host(check
->endpoint
),
1260 &local_endpoint
) != SUCCESS
)
1262 local_endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1263 check
->endpoint
->get_host(check
->endpoint
), pair
->local
);
1264 local_endpoint
->set_priority(local_endpoint
,
1265 check
->endpoint
->get_priority(check
->endpoint
));
1266 local_endpoints
->insert_last(local_endpoints
, local_endpoint
);
1269 update_checklist_state(this, checklist
);
1271 switch(checklist
->state
)
1273 case CHECK_SUCCEEDED
:
1275 finish_checks(this, checklist
);
1283 DBG1(DBG_IKE
, "pair with id '%d' not found", check
->mid
);
1287 static void process_request(private_connect_manager_t
*this, check_t
*check
,
1288 check_list_t
*checklist
)
1290 linked_list_t
*remote_endpoints
= checklist
->is_initiator ?
1291 checklist
->responder
.endpoints
: checklist
->initiator
.endpoints
;
1293 endpoint_notify_t
*peer_reflexive
, *remote_endpoint
;
1294 peer_reflexive
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1296 peer_reflexive
->set_priority(peer_reflexive
,
1297 check
->endpoint
->get_priority(check
->endpoint
));
1299 if (endpoints_contain(remote_endpoints
, check
->src
, &remote_endpoint
) != SUCCESS
)
1301 remote_endpoint
= peer_reflexive
->clone(peer_reflexive
);
1302 remote_endpoints
->insert_last(remote_endpoints
, remote_endpoint
);
1305 endpoint_pair_t
*pair
;
1306 if (get_pair_by_hosts(checklist
->pairs
, check
->dst
, check
->src
,
1311 case CHECK_IN_PROGRESS
:
1312 /* prevent retransmissions */
1313 pair
->retransmitted
= ME_MAX_RETRANS
;
1314 /* FIXME: we should wait to the next rto to send the triggered
1319 queue_triggered_check(this, checklist
, pair
);
1321 case CHECK_SUCCEEDED
:
1328 endpoint_notify_t
*local_endpoint
= endpoint_notify_create_from_host(HOST
, check
->dst
, NULL
);
1330 endpoint_notify_t
*initiator
= checklist
->is_initiator ? local_endpoint
: remote_endpoint
;
1331 endpoint_notify_t
*responder
= checklist
->is_initiator ? remote_endpoint
: local_endpoint
;
1333 pair
= endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
);
1334 pair
->id
= checklist
->pairs
->get_count(checklist
->pairs
) + 1;
1336 insert_pair_by_priority(checklist
->pairs
, pair
);
1338 queue_triggered_check(this, checklist
, pair
);
1340 local_endpoint
->destroy(local_endpoint
);
1343 check_t
*response
= check_create();
1345 response
->mid
= check
->mid
;
1346 response
->src
= check
->dst
->clone(check
->dst
);
1347 response
->dst
= check
->src
->clone(check
->src
);
1348 response
->connect_id
= chunk_clone(check
->connect_id
);
1349 response
->endpoint
= peer_reflexive
;
1351 send_check(this, checklist
, response
, pair
, FALSE
);
1353 check_destroy(response
);
1357 * Implementation of connect_manager_t.process_check.
1359 static void process_check(private_connect_manager_t
*this, message_t
*message
)
1361 if (message
->parse_body(message
, NULL
) != SUCCESS
)
1363 DBG1(DBG_IKE
, "%N %s with message ID %d processing failed",
1364 exchange_type_names
, message
->get_exchange_type(message
),
1365 message
->get_request(message
) ?
"request" : "response",
1366 message
->get_message_id(message
));
1370 check_t
*check
= check_create();
1371 check
->mid
= message
->get_message_id(message
);
1372 check
->src
= message
->get_source(message
);
1373 check
->src
= check
->src
->clone(check
->src
);
1374 check
->dst
= message
->get_destination(message
);
1375 check
->dst
= check
->dst
->clone(check
->dst
);
1377 if (process_payloads(message
, check
) != SUCCESS
)
1379 DBG1(DBG_IKE
, "invalid connectivity check %s received",
1380 message
->get_request(message
) ?
"request" : "response");
1381 check_destroy(check
);
1385 this->mutex
->lock(this->mutex
);
1387 check_list_t
*checklist
;
1388 if (get_checklist_by_id(this, check
->connect_id
, &checklist
) != SUCCESS
)
1390 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1391 &check
->connect_id
);
1392 check_destroy(check
);
1393 this->mutex
->unlock(this->mutex
);
1397 chunk_t sig
= build_signature(this, checklist
, check
, FALSE
);
1398 if (!chunk_equals(sig
, check
->auth
))
1400 DBG1(DBG_IKE
, "connectivity check verification failed");
1401 check_destroy(check
);
1403 this->mutex
->unlock(this->mutex
);
1408 if (message
->get_request(message
))
1410 process_request(this, check
, checklist
);
1414 process_response(this, check
, checklist
);
1417 this->mutex
->unlock(this->mutex
);
1419 check_destroy(check
);
1423 * Implementation of connect_manager_t.check_and_register.
1425 static bool check_and_register(private_connect_manager_t
*this,
1426 identification_t
*id
, identification_t
*peer_id
,
1427 ike_sa_id_t
*mediated_sa
)
1429 initiated_t
*initiated
;
1430 bool already_there
= TRUE
;
1432 this->mutex
->lock(this->mutex
);
1434 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1436 DBG2(DBG_IKE
, "registered waiting mediated connection with '%Y'",
1438 initiated
= initiated_create(id
, peer_id
);
1439 this->initiated
->insert_last(this->initiated
, initiated
);
1440 already_there
= FALSE
;
1443 if (initiated
->mediated
->find_first(initiated
->mediated
,
1444 (linked_list_match_t
)mediated_sa
->equals
,
1445 NULL
, mediated_sa
) != SUCCESS
)
1447 initiated
->mediated
->insert_last(initiated
->mediated
,
1448 mediated_sa
->clone(mediated_sa
));
1451 this->mutex
->unlock(this->mutex
);
1453 return already_there
;
1457 * Implementation of connect_manager_t.check_and_initiate.
1459 static void check_and_initiate(private_connect_manager_t
*this,
1460 ike_sa_id_t
*mediation_sa
, identification_t
*id
,
1461 identification_t
*peer_id
)
1463 initiated_t
*initiated
;
1465 this->mutex
->lock(this->mutex
);
1467 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1469 DBG2(DBG_IKE
, "no waiting mediated connections with '%Y'", peer_id
);
1470 this->mutex
->unlock(this->mutex
);
1474 ike_sa_id_t
*waiting_sa
;
1475 iterator_t
*iterator
= initiated
->mediated
->create_iterator(
1476 initiated
->mediated
, TRUE
);
1477 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1479 job_t
*job
= (job_t
*)reinitiate_mediation_job_create(mediation_sa
,
1481 hydra
->processor
->queue_job(hydra
->processor
, job
);
1483 iterator
->destroy(iterator
);
1485 this->mutex
->unlock(this->mutex
);
1489 * Implementation of connect_manager_t.set_initiator_data.
1491 static status_t
set_initiator_data(private_connect_manager_t
*this,
1492 identification_t
*initiator
,
1493 identification_t
*responder
,
1494 chunk_t connect_id
, chunk_t key
,
1495 linked_list_t
*endpoints
, bool is_initiator
)
1497 check_list_t
*checklist
;
1499 this->mutex
->lock(this->mutex
);
1501 if (get_checklist_by_id(this, connect_id
, NULL
) == SUCCESS
)
1503 DBG1(DBG_IKE
, "checklist with id '%#B' already exists, aborting",
1505 this->mutex
->unlock(this->mutex
);
1509 checklist
= check_list_create(initiator
, responder
, connect_id
, key
,
1510 endpoints
, is_initiator
);
1511 this->checklists
->insert_last(this->checklists
, checklist
);
1513 this->mutex
->unlock(this->mutex
);
1519 * Implementation of connect_manager_t.set_responder_data.
1521 static status_t
set_responder_data(private_connect_manager_t
*this,
1522 chunk_t connect_id
, chunk_t key
,
1523 linked_list_t
*endpoints
)
1525 check_list_t
*checklist
;
1527 this->mutex
->lock(this->mutex
);
1529 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1531 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1533 this->mutex
->unlock(this->mutex
);
1537 checklist
->responder
.key
= chunk_clone(key
);
1538 checklist
->responder
.endpoints
= endpoints
->clone_offset(endpoints
,
1539 offsetof(endpoint_notify_t
, clone
));
1540 checklist
->state
= CHECK_WAITING
;
1542 build_pairs(checklist
);
1544 /* send the first check immediately */
1545 schedule_checks(this, checklist
, 0);
1547 this->mutex
->unlock(this->mutex
);
1553 * Implementation of connect_manager_t.stop_checks.
1555 static status_t
stop_checks(private_connect_manager_t
*this, chunk_t connect_id
)
1557 check_list_t
*checklist
;
1559 this->mutex
->lock(this->mutex
);
1561 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1563 DBG1(DBG_IKE
, "checklist with id '%#B' not found",
1565 this->mutex
->unlock(this->mutex
);
1569 DBG1(DBG_IKE
, "removing checklist with id '%#B'", &connect_id
);
1571 remove_checklist(this, checklist
);
1572 check_list_destroy(checklist
);
1574 this->mutex
->unlock(this->mutex
);
1580 * Implementation of connect_manager_t.destroy.
1582 static void destroy(private_connect_manager_t
*this)
1584 this->mutex
->lock(this->mutex
);
1586 this->hasher
->destroy(this->hasher
);
1587 this->checklists
->destroy_function(this->checklists
, (void*)check_list_destroy
);
1588 this->initiated
->destroy_function(this->initiated
, (void*)initiated_destroy
);
1590 this->mutex
->unlock(this->mutex
);
1591 this->mutex
->destroy(this->mutex
);
1596 * Described in header.
1598 connect_manager_t
*connect_manager_create()
1600 private_connect_manager_t
*this = malloc_thing(private_connect_manager_t
);
1602 this->public.destroy
= (void(*)(connect_manager_t
*))destroy
;
1603 this->public.check_and_register
= (bool(*)(connect_manager_t
*,identification_t
*,identification_t
*,ike_sa_id_t
*))check_and_register
;
1604 this->public.check_and_initiate
= (void(*)(connect_manager_t
*,ike_sa_id_t
*,identification_t
*,identification_t
*))check_and_initiate
;
1605 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
;
1606 this->public.set_responder_data
= (status_t(*)(connect_manager_t
*,chunk_t
,chunk_t
,linked_list_t
*))set_responder_data
;
1607 this->public.process_check
= (void(*)(connect_manager_t
*,message_t
*))process_check
;
1608 this->public.stop_checks
= (status_t(*)(connect_manager_t
*,chunk_t
))stop_checks
;
1610 this->hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
1611 if (this->hasher
== NULL
)
1613 DBG1(DBG_IKE
, "unable to create connect manager, SHA1 not supported");
1618 this->checklists
= linked_list_create();
1619 this->initiated
= linked_list_create();
1621 this->mutex
= mutex_create(MUTEX_TYPE_DEFAULT
);
1623 return (connect_manager_t
*)this;