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 * active checklists (N) */
33 #define ME_INTERVAL 20 /* ms */
34 /* retransmission timeout is first ME_RTO_B * N for ME_BOOST retransmissions
35 * then gets reduced to ME_RTO * N. */
36 /* number of initial retransmissions sent in short interval */
38 /* retransmission timeout */
39 #define ME_RTO 100 /* ms */
40 /* max number of retransmissions */
41 #define ME_MAX_RETRANS 9
44 typedef struct private_connect_manager_t private_connect_manager_t
;
47 * Additional private members of connect_manager_t.
49 struct private_connect_manager_t
{
51 * Public interface of connect_manager_t.
53 connect_manager_t
public;
56 * Lock for exclusivly accessing the manager.
58 pthread_mutex_t mutex
;
61 * Hasher to generate signatures
66 * Linked list with initiated mediated connections
68 linked_list_t
*initiated
;
71 * Linked list with checklists (hash table with connect ID as key would be better).
73 linked_list_t
*checklists
;
76 typedef enum check_state_t check_state_t
;
86 typedef struct endpoint_pair_t endpoint_pair_t
;
89 * An entry in the check list.
91 struct endpoint_pair_t
{
101 /** remote endpoint */
107 /** number of retransmissions */
108 u_int32_t retransmitted
;
110 /** the generated packet */
115 * Destroys an endpoint pair
117 static void endpoint_pair_destroy(endpoint_pair_t
*this)
119 DESTROY_IF(this->local
);
120 DESTROY_IF(this->remote
);
121 DESTROY_IF(this->packet
);
126 * Creates a new entry for the list.
128 static endpoint_pair_t
*endpoint_pair_create(endpoint_notify_t
*initiator
,
129 endpoint_notify_t
*responder
, bool initiator_is_local
)
131 endpoint_pair_t
*this = malloc_thing(endpoint_pair_t
);
135 u_int32_t pi
= initiator
->get_priority(initiator
);
136 u_int32_t pr
= responder
->get_priority(responder
);
137 this->priority
= pow(2, 32) * min(pi
, pr
) + 2 * max(pi
, pr
) + (pi
> pr ?
1 : 0);
139 this->local
= initiator_is_local ? initiator
->get_base(initiator
) : responder
->get_base(responder
);
140 this->local
= this->local
->clone(this->local
);
141 this->remote
= initiator_is_local ? responder
->get_host(responder
) : initiator
->get_host(initiator
);
142 this->remote
= this->remote
->clone(this->remote
);
144 this->state
= CHECK_WAITING
;
145 this->retransmitted
= 0;
152 typedef struct check_list_t check_list_t
;
155 * An entry in the linked list.
157 struct check_list_t
{
160 /** initiator's id */
161 identification_t
*id
;
163 /** initiator's key */
166 /** initiator's endpoints */
167 linked_list_t
*endpoints
;
171 /** responder's id */
172 identification_t
*id
;
174 /** responder's key */
177 /** responder's endpoints */
178 linked_list_t
*endpoints
;
184 /** list of endpoint pairs */
185 linked_list_t
*pairs
;
187 /** pairs queued for triggered checks */
188 linked_list_t
*triggered
;
193 /** TRUE if this is the initiator */
199 * Destroys a checklist
201 static void check_list_destroy(check_list_t
*this)
203 DESTROY_IF(this->initiator
.id
);
204 DESTROY_IF(this->responder
.id
);
206 chunk_free(&this->connect_id
);
207 chunk_free(&this->initiator
.key
);
208 chunk_free(&this->responder
.key
);
210 DESTROY_OFFSET_IF(this->initiator
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
211 DESTROY_OFFSET_IF(this->responder
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
213 DESTROY_FUNCTION_IF(this->pairs
, (void*)endpoint_pair_destroy
);
214 /* this list contains some of the same elements as contained in this->pairs */
215 DESTROY_IF(this->triggered
);
221 * Creates a new checklist
223 static check_list_t
*check_list_create(identification_t
*initiator
, identification_t
*responder
,
224 chunk_t connect_id
, chunk_t initiator_key
, linked_list_t
*initiator_endpoints
,
227 check_list_t
*this = malloc_thing(check_list_t
);
229 this->connect_id
= chunk_clone(connect_id
);
231 this->initiator
.id
= initiator
->clone(initiator
);
232 this->initiator
.key
= chunk_clone(initiator_key
);
233 this->initiator
.endpoints
= initiator_endpoints
->clone_offset(initiator_endpoints
, offsetof(endpoint_notify_t
, clone
));
235 this->responder
.id
= responder
->clone(responder
);
236 this->responder
.key
= chunk_empty
;
237 this->responder
.endpoints
= NULL
;
239 this->pairs
= linked_list_create();
240 this->triggered
= linked_list_create();
241 this->state
= CHECK_NONE
;
242 this->is_initiator
= is_initiator
;
248 typedef struct waiting_sa_t waiting_sa_t
;
251 * For an initiator, the data stored about a waiting mediated sa
253 struct waiting_sa_t
{
255 ike_sa_id_t
*ike_sa_id
;
257 /** list of child_cfg_t */
258 linked_list_t
*childs
;
262 * Destroys a queued mediated sa
264 static void waiting_sa_destroy(waiting_sa_t
*this)
266 DESTROY_IF(this->ike_sa_id
);
267 this->childs
->destroy_offset(this->childs
, offsetof(child_cfg_t
, destroy
));
272 * Creates a new mediated sa object
274 static waiting_sa_t
*waiting_sa_create(ike_sa_id_t
*ike_sa_id
)
276 waiting_sa_t
*this = malloc_thing(waiting_sa_t
);
278 this->ike_sa_id
= ike_sa_id
->clone(ike_sa_id
);
279 this->childs
= linked_list_create();
284 typedef struct initiated_t initiated_t
;
287 * For an initiator, the data stored about initiated mediation connections
291 identification_t
*id
;
294 identification_t
*peer_id
;
296 /** list of mediated sas */
297 linked_list_t
*mediated
;
301 * Destroys a queued initiation
303 static void initiated_destroy(initiated_t
*this)
305 DESTROY_IF(this->id
);
306 DESTROY_IF(this->peer_id
);
307 this->mediated
->destroy_function(this->mediated
, (void*)waiting_sa_destroy
);
312 * Creates a queued initiation
314 static initiated_t
*initiated_create(identification_t
*id
, identification_t
*peer_id
)
316 initiated_t
*this = malloc_thing(initiated_t
);
318 this->id
= id
->clone(id
);
319 this->peer_id
= peer_id
->clone(peer_id
);
320 this->mediated
= linked_list_create();
326 typedef struct check_t check_t
;
329 * Data exchanged in a connectivity check
335 /** source of the connectivity check */
338 /** destination of the connectivity check */
345 endpoint_notify_t
*endpoint
;
347 /** raw endpoint payload (to verify the signature) */
348 chunk_t endpoint_raw
;
355 * Destroys a connectivity check
357 static void check_destroy(check_t
*this)
359 chunk_free(&this->connect_id
);
360 chunk_free(&this->endpoint_raw
);
361 chunk_free(&this->auth
);
362 DESTROY_IF(this->endpoint
);
367 * Creates a new connectivity check
369 static check_t
*check_create()
371 check_t
*this = malloc_thing(check_t
);
373 this->connect_id
= chunk_empty
;
374 this->auth
= chunk_empty
;
375 this->endpoint_raw
= chunk_empty
;
376 this->endpoint
= NULL
;
383 typedef struct sender_data_t sender_data_t
;
386 * Data required by the sender
388 struct sender_data_t
{
389 /** connect manager */
390 private_connect_manager_t
*connect_manager
;
397 * Destroys a sender data object
399 static void sender_data_destroy(sender_data_t
*this)
401 chunk_free(&this->connect_id
);
406 * Creates a new sender data object
408 static sender_data_t
*sender_data_create(private_connect_manager_t
*connect_manager
, chunk_t connect_id
)
410 sender_data_t
*this = malloc_thing(sender_data_t
);
411 this->connect_manager
= connect_manager
;
412 this->connect_id
= connect_id
;
416 typedef struct retransmit_data_t retransmit_data_t
;
419 * Data required by the retransmission job
421 struct retransmit_data_t
{
422 /** connect manager */
423 private_connect_manager_t
*connect_manager
;
428 /** message (pair) id */
433 * Destroys a retransmission data object
435 static void retransmit_data_destroy(retransmit_data_t
*this)
437 chunk_free(&this->connect_id
);
442 * Creates a new retransmission data object
444 static retransmit_data_t
*retransmit_data_create(private_connect_manager_t
*connect_manager
,
445 chunk_t connect_id
, u_int32_t mid
)
447 retransmit_data_t
*this = malloc_thing(retransmit_data_t
);
449 this->connect_manager
= connect_manager
;
450 this->connect_id
= connect_id
;
456 typedef struct initiate_data_t initiate_data_t
;
459 * Data required by the initiate mediated
461 struct initiate_data_t
{
463 check_list_t
*checklist
;
465 /** waiting mediated connections */
466 initiated_t
*initiated
;
470 * Destroys a initiate data object
472 static void initiate_data_destroy(initiate_data_t
*this)
474 check_list_destroy(this->checklist
);
475 initiated_destroy(this->initiated
);
480 * Creates a new initiate data object
482 static initiate_data_t
*initiate_data_create(check_list_t
*checklist
, initiated_t
*initiated
)
484 initiate_data_t
*this = malloc_thing(initiate_data_t
);
486 this->checklist
= checklist
;
487 this->initiated
= initiated
;
493 * Find an initiated connection by the peers' ids
495 static bool match_initiated_by_ids(initiated_t
*current
, identification_t
*id
,
496 identification_t
*peer_id
)
498 return id
->equals(id
, current
->id
) && peer_id
->equals(peer_id
, current
->peer_id
);
501 static status_t
get_initiated_by_ids(private_connect_manager_t
*this,
502 identification_t
*id
, identification_t
*peer_id
, initiated_t
**initiated
)
504 return this->initiated
->find_first(this->initiated
,
505 (linked_list_match_t
)match_initiated_by_ids
,
506 (void**)initiated
, id
, peer_id
);
510 * Removes data about initiated connections
512 static void remove_initiated(private_connect_manager_t
*this, initiated_t
*initiated
)
514 iterator_t
*iterator
;
515 initiated_t
*current
;
517 iterator
= this->initiated
->create_iterator(this->initiated
, TRUE
);
518 while (iterator
->iterate(iterator
, (void**)¤t
))
520 if (current
== initiated
)
522 iterator
->remove(iterator
);
526 iterator
->destroy(iterator
);
532 static bool match_waiting_sa(waiting_sa_t
*current
, ike_sa_id_t
*ike_sa_id
)
534 return ike_sa_id
->equals(ike_sa_id
, current
->ike_sa_id
);
537 static status_t
get_waiting_sa(initiated_t
*initiated
, ike_sa_id_t
*ike_sa_id
, waiting_sa_t
**waiting_sa
)
539 return initiated
->mediated
->find_first(initiated
->mediated
,
540 (linked_list_match_t
)match_waiting_sa
,
541 (void**)waiting_sa
, ike_sa_id
);
545 * Find the checklist with a specific connect ID
547 static bool match_checklist_by_id(check_list_t
*current
, chunk_t
*connect_id
)
549 return chunk_equals(*connect_id
, current
->connect_id
);
552 static status_t
get_checklist_by_id(private_connect_manager_t
*this,
553 chunk_t connect_id
, check_list_t
**check_list
)
555 return this->checklists
->find_first(this->checklists
,
556 (linked_list_match_t
)match_checklist_by_id
,
557 (void**)check_list
, &connect_id
);
561 * Removes a checklist
563 static void remove_checklist(private_connect_manager_t
*this, check_list_t
*checklist
)
565 iterator_t
*iterator
;
566 check_list_t
*current
;
568 iterator
= this->checklists
->create_iterator(this->checklists
, TRUE
);
569 while (iterator
->iterate(iterator
, (void**)¤t
))
571 if (current
== checklist
)
573 iterator
->remove(iterator
);
577 iterator
->destroy(iterator
);
581 * Checks if a list of endpoint_notify_t contains a certain host_t
583 static bool match_endpoint_by_host(endpoint_notify_t
*current
, host_t
*host
)
585 return host
->equals(host
, current
->get_host(current
));
588 static status_t
endpoints_contain(linked_list_t
*endpoints
, host_t
*host
, endpoint_notify_t
**endpoint
)
590 return endpoints
->find_first(endpoints
,
591 (linked_list_match_t
)match_endpoint_by_host
,
592 (void**)endpoint
, host
);
596 * Updates the state of the whole checklist
598 static void update_checklist_state(check_list_t
*checklist
)
600 iterator_t
*iterator
;
601 endpoint_pair_t
*current
;
602 bool in_progress
= FALSE
, succeeded
= FALSE
;
604 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
605 while (iterator
->iterate(iterator
, (void**)¤t
))
607 switch(current
->state
)
610 /* at least one is still waiting -> checklist remains
611 * in waiting state */
612 iterator
->destroy(iterator
);
614 case CHECK_IN_PROGRESS
:
617 case CHECK_SUCCEEDED
:
624 iterator
->destroy(iterator
);
628 checklist
->state
= CHECK_IN_PROGRESS
;
632 checklist
->state
= CHECK_SUCCEEDED
;
636 checklist
->state
= CHECK_FAILED
;
641 * Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
643 static void insert_pair_by_priority(linked_list_t
*pairs
, endpoint_pair_t
*pair
)
645 iterator_t
*iterator
;
646 endpoint_pair_t
*current
;
647 bool inserted
= FALSE
;
649 iterator
= pairs
->create_iterator(pairs
, TRUE
);
650 while (iterator
->iterate(iterator
, (void**)¤t
))
652 if (current
->priority
< pair
->priority
)
654 iterator
->insert_before(iterator
, pair
);
659 iterator
->destroy(iterator
);
663 pairs
->insert_last(pairs
, pair
);
668 * Searches a list of endpoint_pair_t for a pair with specific host_ts
670 static bool match_pair_by_hosts(endpoint_pair_t
*current
, host_t
*local
, host_t
*remote
)
672 return local
->equals(local
, current
->local
) && remote
->equals(remote
, current
->remote
);
675 static status_t
get_pair_by_hosts(linked_list_t
*pairs
, host_t
*local
, host_t
*remote
, endpoint_pair_t
**pair
)
677 return pairs
->find_first(pairs
,
678 (linked_list_match_t
)match_pair_by_hosts
,
679 (void**)pair
, local
, remote
);
682 static bool match_pair_by_id(endpoint_pair_t
*current
, u_int32_t
*id
)
684 return current
->id
== *id
;
688 * Searches for a pair with a specific id
690 static status_t
get_pair_by_id(check_list_t
*checklist
, u_int32_t id
, endpoint_pair_t
**pair
)
692 return checklist
->pairs
->find_first(checklist
->pairs
,
693 (linked_list_match_t
)match_pair_by_id
,
697 static bool match_succeeded_pair(endpoint_pair_t
*current
)
699 return current
->state
== CHECK_SUCCEEDED
;
703 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
705 static status_t
get_best_valid_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
707 return checklist
->pairs
->find_first(checklist
->pairs
,
708 (linked_list_match_t
)match_succeeded_pair
,
712 static bool match_waiting_pair(endpoint_pair_t
*current
)
714 return current
->state
== CHECK_WAITING
;
718 * Returns and *removes* the first triggered pair in state CHECK_WAITING.
720 static status_t
get_triggered_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
722 iterator_t
*iterator
;
723 endpoint_pair_t
*current
;
724 status_t status
= NOT_FOUND
;
726 iterator
= checklist
->triggered
->create_iterator(checklist
->triggered
, TRUE
);
727 while (iterator
->iterate(iterator
, (void**)¤t
))
729 iterator
->remove(iterator
);
731 if (current
->state
== CHECK_WAITING
)
741 iterator
->destroy(iterator
);
747 * Prunes identical pairs with lower priority from the list
748 * Note: this function also numbers the remaining pairs serially
750 static void prune_pairs(linked_list_t
*pairs
)
752 iterator_t
*iterator
, *search
;
753 endpoint_pair_t
*current
, *other
;
756 iterator
= pairs
->create_iterator(pairs
, TRUE
);
757 search
= pairs
->create_iterator(pairs
, TRUE
);
758 while (iterator
->iterate(iterator
, (void**)¤t
))
762 while (search
->iterate(search
, (void**)&other
))
764 if (current
== other
)
769 if (current
->local
->equals(current
->local
, other
->local
) &&
770 current
->remote
->equals(current
->remote
, other
->remote
))
772 /* since the list of pairs is sorted by priority in descending
773 * order, and we iterate the list from the beginning, we are
774 * sure that the priority of 'other' is lower than that of
775 * 'current', remove it */
776 DBG1(DBG_IKE
, "pruning endpoint pair %H - %H with priority %d",
777 other
->local
, other
->remote
, other
->priority
);
778 search
->remove(search
);
779 endpoint_pair_destroy(other
);
782 search
->reset(search
);
784 search
->destroy(search
);
785 iterator
->destroy(iterator
);
789 * Builds a list of endpoint pairs
791 static void build_pairs(check_list_t
*checklist
)
793 iterator_t
*iterator_i
, *iterator_r
;
794 endpoint_notify_t
*initiator
, *responder
;
796 iterator_i
= checklist
->initiator
.endpoints
->create_iterator(checklist
->initiator
.endpoints
, TRUE
);
797 while (iterator_i
->iterate(iterator_i
, (void**)&initiator
))
799 iterator_r
= checklist
->responder
.endpoints
->create_iterator(checklist
->responder
.endpoints
, TRUE
);
800 while (iterator_r
->iterate(iterator_r
, (void**)&responder
))
802 if (initiator
->get_family(initiator
) != responder
->get_family(responder
))
807 insert_pair_by_priority(checklist
->pairs
,
808 endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
));
810 iterator_r
->destroy(iterator_r
);
812 iterator_i
->destroy(iterator_i
);
814 prune_pairs(checklist
->pairs
);
818 * Processes the payloads of a connectivity check and returns the extracted data
820 static status_t
process_payloads(message_t
*message
, check_t
*check
)
822 iterator_t
*iterator
;
825 iterator
= message
->get_payload_iterator(message
);
826 while (iterator
->iterate(iterator
, (void**)&payload
))
828 if (payload
->get_type(payload
) != NOTIFY
)
830 DBG1(DBG_IKE
, "ignoring payload of type '%N' while processing "
831 "connectivity check", payload_type_names
, payload
->get_type(payload
));
835 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
837 switch (notify
->get_notify_type(notify
))
843 DBG1(DBG_IKE
, "connectivity check contains multiple ME_ENDPOINT notifies");
847 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
850 DBG1(DBG_IKE
, "received invalid ME_ENDPOINT notify");
853 check
->endpoint
= endpoint
;
854 check
->endpoint_raw
= chunk_clone(notify
->get_notification_data(notify
));
855 DBG2(DBG_IKE
, "received ME_ENDPOINT notify");
860 if (check
->connect_id
.ptr
)
862 DBG1(DBG_IKE
, "connectivity check contains multiple ME_CONNECTID notifies");
865 check
->connect_id
= chunk_clone(notify
->get_notification_data(notify
));
866 DBG2(DBG_IKE
, "received ME_CONNECTID %#B", &check
->connect_id
);
873 DBG1(DBG_IKE
, "connectivity check contains multiple ME_CONNECTAUTH notifies");
876 check
->auth
= chunk_clone(notify
->get_notification_data(notify
));
877 DBG2(DBG_IKE
, "received ME_CONNECTAUTH %#B", &check
->auth
);
884 iterator
->destroy(iterator
);
886 if (!check
->connect_id
.ptr
|| !check
->endpoint
|| !check
->auth
.ptr
)
888 DBG1(DBG_IKE
, "at least one payload was missing from the connectivity check");
896 * Builds the signature for a connectivity check
898 static chunk_t
build_signature(private_connect_manager_t
*this,
899 check_list_t
*checklist
, check_t
*check
, bool outbound
)
901 chunk_t mid_chunk
, key_chunk
, sig_chunk
;
904 mid_chunk
= chunk_from_thing(check
->mid
);
906 key_chunk
= (checklist
->is_initiator
&& outbound
) || (!checklist
->is_initiator
&& !outbound
)
907 ? checklist
->initiator
.key
: checklist
->responder
.key
;
909 /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */
910 sig_chunk
= chunk_cat("cccc", mid_chunk
, check
->connect_id
, check
->endpoint_raw
, key_chunk
);
911 this->hasher
->allocate_hash(this->hasher
, sig_chunk
, &sig_hash
);
912 DBG3(DBG_IKE
, "sig_chunk %B", &sig_chunk
);
913 DBG3(DBG_IKE
, "sig_hash %B", &sig_hash
);
915 chunk_free(&sig_chunk
);
919 static void queue_retransmission(private_connect_manager_t
*this, check_list_t
*checklist
, endpoint_pair_t
*pair
);
920 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
);
921 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
);
924 * This function is triggered for each sent check after a specific timeout
926 static job_requeue_t
retransmit(retransmit_data_t
*data
)
928 private_connect_manager_t
*this = data
->connect_manager
;
930 pthread_mutex_lock(&(this->mutex
));
932 check_list_t
*checklist
;
933 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
935 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't retransmit connectivity check",
937 pthread_mutex_unlock(&(this->mutex
));
938 return JOB_REQUEUE_NONE
;
941 endpoint_pair_t
*pair
;
942 if (get_pair_by_id(checklist
, data
->mid
, &pair
) != SUCCESS
)
944 DBG1(DBG_IKE
, "pair with id '%d' not found, can't retransmit connectivity check",
949 if (pair
->state
!= CHECK_IN_PROGRESS
)
951 DBG2(DBG_IKE
, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
952 data
->mid
, pair
->state
);
956 if (++pair
->retransmitted
>= ME_MAX_RETRANS
)
958 DBG2(DBG_IKE
, "pair with id '%d' failed after %d retransmissions",
959 data
->mid
, pair
->retransmitted
);
960 pair
->state
= CHECK_FAILED
;
964 charon
->sender
->send(charon
->sender
, pair
->packet
->clone(pair
->packet
));
966 queue_retransmission(this, checklist
, pair
);
969 update_checklist_state(checklist
);
971 switch(checklist
->state
)
973 case CHECK_SUCCEEDED
:
975 finish_checks(this, checklist
);
981 pthread_mutex_unlock(&(this->mutex
));
983 /* we reschedule it manually */
984 return JOB_REQUEUE_NONE
;
988 * Queues a retransmission job
990 static void queue_retransmission(private_connect_manager_t
*this, check_list_t
*checklist
, endpoint_pair_t
*pair
)
992 retransmit_data_t
*data
= retransmit_data_create(this, chunk_clone(checklist
->connect_id
), pair
->id
);
993 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)retransmit
, data
, (callback_job_cleanup_t
)retransmit_data_destroy
, NULL
);
997 checklist->pairs->invoke_function(checklist->pairs, (linked_list_invoke_t)count_waiting_pairs, &NW);
998 u_int32_t rto = max(ME_INTERVAL * N * (NW + 1), ME_RTO_MIN);
1000 u_int32_t N
= this->checklists
->get_count(this->checklists
);
1001 u_int32_t rto
= ME_INTERVAL
* N
;
1002 if (pair
->retransmitted
> ME_BOOST
)
1006 DBG2(DBG_IKE
, "retransmission of pair '%d' in %dms - %d active checklist(s)", pair
->id
, rto
, N
);
1007 charon
->scheduler
->schedule_job(charon
->scheduler
, (job_t
*)job
, rto
);
1013 static void send_check(private_connect_manager_t
*this, check_list_t
*checklist
,
1014 check_t
*check
, endpoint_pair_t
*pair
, bool request
)
1016 message_t
*message
= message_create();
1017 message
->set_message_id(message
, check
->mid
);
1018 message
->set_exchange_type(message
, INFORMATIONAL
);
1019 message
->set_request(message
, request
);
1020 message
->set_destination(message
, check
->dst
->clone(check
->dst
));
1021 message
->set_source(message
, check
->src
->clone(check
->src
));
1023 message
->set_ike_sa_id(message
, ike_sa_id_create(0, 0, request
));
1025 message
->add_notify(message
, FALSE
, ME_CONNECTID
, check
->connect_id
);
1026 DBG2(DBG_IKE
, "send ME_CONNECTID %#B", &check
->connect_id
);
1028 notify_payload_t
*endpoint
= check
->endpoint
->build_notify(check
->endpoint
);
1029 check
->endpoint_raw
= chunk_clone(endpoint
->get_notification_data(endpoint
));
1030 message
->add_payload(message
, (payload_t
*)endpoint
);
1031 DBG2(DBG_IKE
, "send ME_ENDPOINT notify");
1033 check
->auth
= build_signature(this, checklist
, check
, TRUE
);
1034 message
->add_notify(message
, FALSE
, ME_CONNECTAUTH
, check
->auth
);
1035 DBG2(DBG_IKE
, "send ME_CONNECTAUTH %#B", &check
->auth
);
1038 if (message
->generate(message
, NULL
, NULL
, &packet
) == SUCCESS
)
1040 charon
->sender
->send(charon
->sender
, packet
->clone(packet
));
1044 DESTROY_IF(pair
->packet
);
1045 pair
->packet
= packet
;
1046 queue_retransmission(this, checklist
, pair
);
1050 packet
->destroy(packet
);
1056 * Queues a triggered check
1058 static void queue_triggered_check(check_list_t
*checklist
, endpoint_pair_t
*pair
)
1060 pair
->state
= CHECK_WAITING
;
1061 checklist
->triggered
->insert_last(checklist
->triggered
, pair
);
1065 * This function is triggered for each checklist at a specific interval
1067 static job_requeue_t
sender(sender_data_t
*data
)
1069 private_connect_manager_t
*this = data
->connect_manager
;
1071 pthread_mutex_lock(&(this->mutex
));
1073 check_list_t
*checklist
;
1074 if (get_checklist_by_id(this, data
->connect_id
, &checklist
) != SUCCESS
)
1076 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't send connectivity check",
1078 pthread_mutex_unlock(&(this->mutex
));
1079 return JOB_REQUEUE_NONE
;
1082 endpoint_pair_t
*pair
;
1083 if (get_triggered_pair(checklist
, &pair
) != SUCCESS
)
1085 DBG1(DBG_IKE
, "no triggered check queued, sending an ordinary check");
1087 if (checklist
->pairs
->find_first(checklist
->pairs
,
1088 (linked_list_match_t
)match_waiting_pair
, (void**)&pair
) != SUCCESS
)
1090 pthread_mutex_unlock(&(this->mutex
));
1091 DBG1(DBG_IKE
, "no pairs in waiting state, aborting");
1092 return JOB_REQUEUE_NONE
;
1097 DBG1(DBG_IKE
, "triggered check found");
1100 check_t
*check
= check_create();
1101 check
->mid
= pair
->id
;
1102 check
->src
= pair
->local
->clone(pair
->local
);
1103 check
->dst
= pair
->remote
->clone(pair
->remote
);
1104 check
->connect_id
= chunk_clone(checklist
->connect_id
);
1105 check
->endpoint
= endpoint_notify_create();
1107 pair
->state
= CHECK_IN_PROGRESS
;
1109 send_check(this, checklist
, check
, pair
, TRUE
);
1111 check_destroy(check
);
1113 /* schedule this job again */
1114 u_int32_t N
= this->checklists
->get_count(this->checklists
);
1115 schedule_checks(this, checklist
, ME_INTERVAL
* N
);
1117 pthread_mutex_unlock(&(this->mutex
));
1119 /* we reschedule it manually */
1120 return JOB_REQUEUE_NONE
;
1124 * Schedules checks for a checklist (time in ms)
1126 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
)
1128 chunk_t connect_id
= chunk_clone(checklist
->connect_id
);
1129 sender_data_t
*data
= sender_data_create(this, connect_id
);
1130 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)sender
, data
, (callback_job_cleanup_t
)sender_data_destroy
, NULL
);
1131 charon
->scheduler
->schedule_job(charon
->scheduler
, job
, time
);
1135 * Initiates waiting mediated connections
1137 static job_requeue_t
initiate_mediated(initiate_data_t
*data
)
1139 check_list_t
*checklist
= data
->checklist
;
1140 initiated_t
*initiated
= data
->initiated
;
1142 endpoint_pair_t
*pair
;
1143 if (get_best_valid_pair(checklist
, &pair
) == SUCCESS
)
1145 waiting_sa_t
*waiting_sa
;
1146 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1147 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1149 ike_sa_t
*sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, waiting_sa
->ike_sa_id
);
1150 if (sa
->initiate_mediated(sa
, pair
->local
, pair
->remote
, waiting_sa
->childs
,
1151 checklist
->connect_id
) != SUCCESS
)
1153 SIG(IKE_UP_FAILED
, "establishing the mediated connection failed");
1154 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, sa
);
1156 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, sa
);
1158 iterator
->destroy(iterator
);
1162 /* this should (can?) not happen */
1165 return JOB_REQUEUE_NONE
;
1169 * Finishes checks for a checklist
1171 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
)
1173 if (checklist
->is_initiator
)
1175 initiated_t
*initiated
;
1176 if (get_initiated_by_ids(this, checklist
->initiator
.id
,
1177 checklist
->responder
.id
, &initiated
) == SUCCESS
)
1179 remove_checklist(this, checklist
);
1180 remove_initiated(this, initiated
);
1182 initiate_data_t
*data
= initiate_data_create(checklist
, initiated
);
1183 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiate_mediated
, data
, (callback_job_cleanup_t
)initiate_data_destroy
, NULL
);
1184 charon
->processor
->queue_job(charon
->processor
, job
);
1189 DBG1(DBG_IKE
, "there is no mediated connection waiting between '%D' "
1190 "and '%D'", checklist
->initiator
.id
, checklist
->responder
.id
);
1196 * Process the response to one of our requests
1198 static void process_response(private_connect_manager_t
*this, check_t
*check
,
1199 check_list_t
*checklist
)
1201 endpoint_pair_t
*pair
;
1202 if (get_pair_by_id(checklist
, check
->mid
, &pair
) == SUCCESS
)
1204 if (pair
->local
->equals(pair
->local
, check
->dst
) &&
1205 pair
->remote
->equals(pair
->remote
, check
->src
))
1207 DBG1(DBG_IKE
, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair
->id
,
1208 pair
->local
, pair
->remote
);
1209 pair
->state
= CHECK_SUCCEEDED
;
1212 linked_list_t
*local_endpoints
= checklist
->is_initiator ?
1213 checklist
->initiator
.endpoints
: checklist
->responder
.endpoints
;
1215 endpoint_notify_t
*local_endpoint
;
1216 if (endpoints_contain(local_endpoints
,
1217 check
->endpoint
->get_host(check
->endpoint
), &local_endpoint
) != SUCCESS
)
1219 local_endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1220 check
->endpoint
->get_host(check
->endpoint
), pair
->local
);
1221 local_endpoint
->set_priority(local_endpoint
, check
->endpoint
->get_priority(check
->endpoint
));
1222 local_endpoints
->insert_last(local_endpoints
, local_endpoint
);
1225 update_checklist_state(checklist
);
1227 switch(checklist
->state
)
1229 case CHECK_SUCCEEDED
:
1231 finish_checks(this, checklist
);
1239 DBG1(DBG_IKE
, "pair with id '%d' not found", check
->mid
);
1243 static void process_request(private_connect_manager_t
*this, check_t
*check
,
1244 check_list_t
*checklist
)
1246 linked_list_t
*remote_endpoints
= checklist
->is_initiator ?
1247 checklist
->responder
.endpoints
: checklist
->initiator
.endpoints
;
1249 endpoint_notify_t
*peer_reflexive
, *remote_endpoint
;
1250 peer_reflexive
= endpoint_notify_create_from_host(PEER_REFLEXIVE
, check
->src
, NULL
);
1251 peer_reflexive
->set_priority(peer_reflexive
, check
->endpoint
->get_priority(check
->endpoint
));
1253 if (endpoints_contain(remote_endpoints
, check
->src
, &remote_endpoint
) != SUCCESS
)
1255 remote_endpoint
= peer_reflexive
->clone(peer_reflexive
);
1256 remote_endpoints
->insert_last(remote_endpoints
, remote_endpoint
);
1259 endpoint_pair_t
*pair
;
1260 if (get_pair_by_hosts(checklist
->pairs
, check
->dst
, check
->src
, &pair
) == SUCCESS
)
1264 case CHECK_IN_PROGRESS
:
1265 /* prevent retransmissions */
1266 pair
->retransmitted
= ME_MAX_RETRANS
;
1267 /* FIXME: we should wait to the next rto to send the triggered check
1271 queue_triggered_check(checklist
, pair
);
1273 case CHECK_SUCCEEDED
:
1280 endpoint_notify_t
*local_endpoint
= endpoint_notify_create_from_host(HOST
, check
->dst
, NULL
);
1282 endpoint_notify_t
*initiator
= checklist
->is_initiator ? local_endpoint
: remote_endpoint
;
1283 endpoint_notify_t
*responder
= checklist
->is_initiator ? remote_endpoint
: local_endpoint
;
1285 pair
= endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
);
1286 pair
->id
= checklist
->pairs
->get_count(checklist
->pairs
) + 1;
1288 insert_pair_by_priority(checklist
->pairs
, pair
);
1290 queue_triggered_check(checklist
, pair
);
1292 local_endpoint
->destroy(local_endpoint
);
1296 check_t
*response
= check_create();
1298 response
->mid
= check
->mid
;
1299 response
->src
= check
->dst
->clone(check
->dst
);
1300 response
->dst
= check
->src
->clone(check
->src
);
1301 response
->connect_id
= chunk_clone(check
->connect_id
);
1302 response
->endpoint
= peer_reflexive
;
1304 send_check(this, checklist
, response
, pair
, FALSE
);
1306 check_destroy(response
);
1310 * Implementation of connect_manager_t.process_check.
1312 static void process_check(private_connect_manager_t
*this, message_t
*message
)
1314 if (message
->parse_body(message
, NULL
, NULL
) != SUCCESS
)
1316 DBG1(DBG_IKE
, "%N %s with message ID %d processing failed",
1317 exchange_type_names
, message
->get_exchange_type(message
),
1318 message
->get_request(message
) ?
"request" : "response",
1319 message
->get_message_id(message
));
1323 check_t
*check
= check_create();
1324 check
->mid
= message
->get_message_id(message
);
1325 check
->src
= message
->get_source(message
);
1326 check
->dst
= message
->get_destination(message
);
1328 if (process_payloads(message
, check
) != SUCCESS
)
1330 DBG1(DBG_IKE
, "invalid connectivity check %s received",
1331 message
->get_request(message
) ?
"request" : "response");
1332 check_destroy(check
);
1336 pthread_mutex_lock(&(this->mutex
));
1338 check_list_t
*checklist
;
1339 if (get_checklist_by_id(this, check
->connect_id
, &checklist
) != SUCCESS
)
1341 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1342 &check
->connect_id
);
1343 check_destroy(check
);
1344 pthread_mutex_unlock(&(this->mutex
));
1348 chunk_t sig
= build_signature(this, checklist
, check
, FALSE
);
1349 if (!chunk_equals(sig
, check
->auth
))
1351 DBG1(DBG_IKE
, "connectivity check verification failed");
1352 check_destroy(check
);
1354 pthread_mutex_unlock(&(this->mutex
));
1359 if (message
->get_request(message
))
1361 process_request(this, check
, checklist
);
1365 process_response(this, check
, checklist
);
1368 pthread_mutex_unlock(&(this->mutex
));
1370 check_destroy(check
);
1374 * Implementation of connect_manager_t.check_and_register.
1376 static bool check_and_register(private_connect_manager_t
*this,
1377 identification_t
*id
, identification_t
*peer_id
,
1378 ike_sa_id_t
*mediated_sa
, child_cfg_t
*child
)
1380 initiated_t
*initiated
;
1381 bool already_there
= TRUE
;
1383 pthread_mutex_lock(&(this->mutex
));
1385 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1387 DBG2(DBG_IKE
, "registered waiting mediated connection with '%D'", peer_id
);
1388 initiated
= initiated_create(id
, peer_id
);
1389 this->initiated
->insert_last(this->initiated
, initiated
);
1390 already_there
= FALSE
;
1393 waiting_sa_t
*waiting_sa
;
1394 if (get_waiting_sa(initiated
, mediated_sa
, &waiting_sa
) != SUCCESS
)
1396 waiting_sa
= waiting_sa_create(mediated_sa
);
1397 initiated
->mediated
->insert_last(initiated
->mediated
, waiting_sa
);
1400 child
->get_ref(child
);
1401 waiting_sa
->childs
->insert_last(waiting_sa
->childs
, child
);
1403 pthread_mutex_unlock(&(this->mutex
));
1405 return already_there
;
1409 * Implementation of connect_manager_t.check_and_initiate.
1411 static void check_and_initiate(private_connect_manager_t
*this, ike_sa_id_t
*mediation_sa
,
1412 identification_t
*id
, identification_t
*peer_id
)
1414 initiated_t
*initiated
;
1416 pthread_mutex_lock(&(this->mutex
));
1418 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1420 DBG2(DBG_IKE
, "no waiting mediated connections with '%D'", peer_id
);
1421 pthread_mutex_unlock(&(this->mutex
));
1425 waiting_sa_t
*waiting_sa
;
1426 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1427 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1429 job_t
*job
= (job_t
*)reinitiate_mediation_job_create(mediation_sa
,
1430 waiting_sa
->ike_sa_id
);
1431 charon
->processor
->queue_job(charon
->processor
, job
);
1434 pthread_mutex_unlock(&(this->mutex
));
1438 * Implementation of connect_manager_t.set_initiator_data.
1440 static status_t
set_initiator_data(private_connect_manager_t
*this,
1441 identification_t
*initiator
, identification_t
*responder
,
1442 chunk_t connect_id
, chunk_t key
, linked_list_t
*endpoints
, bool is_initiator
)
1444 check_list_t
*checklist
;
1446 pthread_mutex_lock(&(this->mutex
));
1448 if (get_checklist_by_id(this, connect_id
, NULL
) == SUCCESS
)
1450 DBG1(DBG_IKE
, "checklist with id '%B' already exists, aborting",
1452 pthread_mutex_unlock(&(this->mutex
));
1456 checklist
= check_list_create(initiator
, responder
, connect_id
, key
, endpoints
, is_initiator
);
1457 this->checklists
->insert_last(this->checklists
, checklist
);
1459 pthread_mutex_unlock(&(this->mutex
));
1465 * Implementation of connect_manager_t.set_responder_data.
1467 static status_t
set_responder_data(private_connect_manager_t
*this,
1468 chunk_t connect_id
, chunk_t key
, linked_list_t
*endpoints
)
1470 check_list_t
*checklist
;
1472 pthread_mutex_lock(&(this->mutex
));
1474 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1476 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1478 pthread_mutex_unlock(&(this->mutex
));
1482 checklist
->responder
.key
= chunk_clone(key
);
1483 checklist
->responder
.endpoints
= endpoints
->clone_offset(endpoints
, offsetof(endpoint_notify_t
, clone
));
1484 checklist
->state
= CHECK_WAITING
;
1486 build_pairs(checklist
);
1488 /* send the first check immediately */
1489 schedule_checks(this, checklist
, 0);
1491 pthread_mutex_unlock(&(this->mutex
));
1497 * Implementation of connect_manager_t.stop_checks.
1499 static status_t
stop_checks(private_connect_manager_t
*this, chunk_t connect_id
)
1501 check_list_t
*checklist
;
1503 pthread_mutex_lock(&(this->mutex
));
1505 if (get_checklist_by_id(this, connect_id
, &checklist
) != SUCCESS
)
1507 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1509 pthread_mutex_unlock(&(this->mutex
));
1513 DBG1(DBG_IKE
, "removing checklist with id '%B'", &connect_id
);
1515 remove_checklist(this, checklist
);
1516 check_list_destroy(checklist
);
1518 pthread_mutex_unlock(&(this->mutex
));
1524 * Implementation of connect_manager_t.destroy.
1526 static void destroy(private_connect_manager_t
*this)
1528 pthread_mutex_lock(&(this->mutex
));
1530 this->hasher
->destroy(this->hasher
);
1531 this->checklists
->destroy_function(this->checklists
, (void*)check_list_destroy
);
1532 this->initiated
->destroy_function(this->initiated
, (void*)initiated_destroy
);
1534 pthread_mutex_unlock(&(this->mutex
));
1535 pthread_mutex_destroy(&(this->mutex
));
1540 * Described in header.
1542 connect_manager_t
*connect_manager_create()
1544 private_connect_manager_t
*this = malloc_thing(private_connect_manager_t
);
1546 this->public.destroy
= (void(*)(connect_manager_t
*))destroy
;
1547 this->public.check_and_register
= (bool(*)(connect_manager_t
*,identification_t
*,identification_t
*,ike_sa_id_t
*,child_cfg_t
*))check_and_register
;
1548 this->public.check_and_initiate
= (void(*)(connect_manager_t
*,ike_sa_id_t
*,identification_t
*,identification_t
*))check_and_initiate
;
1549 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
;
1550 this->public.set_responder_data
= (status_t(*)(connect_manager_t
*,chunk_t
,chunk_t
,linked_list_t
*))set_responder_data
;
1551 this->public.process_check
= (void(*)(connect_manager_t
*,message_t
*))process_check
;
1552 this->public.stop_checks
= (status_t(*)(connect_manager_t
*,chunk_t
))stop_checks
;
1554 this->hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
1555 if (this->hasher
== NULL
)
1557 DBG1(DBG_IKE
, "unable to create connect manager, SHA1 not supported");
1562 this->checklists
= linked_list_create();
1563 this->initiated
= linked_list_create();
1565 pthread_mutex_init(&(this->mutex
), NULL
);
1567 return (connect_manager_t
*)this;