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 sending interval is P2P_INTERVAL * active checklists (N)
33 * retransmission timeout is P2P_INTERVAL * N * checks in waiting state (NW) */
34 #define P2P_INTERVAL 20 /* ms */
35 /* min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state) */
36 #define P2P_RTO_MIN 100 /* ms */
37 /* max number of retransmissions (+ the initial check) */
38 #define P2P_MAX_RETRANS 2
41 typedef struct private_connect_manager_t private_connect_manager_t
;
44 * Additional private members of connect_manager_t.
46 struct private_connect_manager_t
{
48 * Public interface of connect_manager_t.
50 connect_manager_t
public;
53 * Lock for exclusivly accessing the manager.
55 pthread_mutex_t mutex
;
58 * Hasher to generate signatures
63 * Linked list with initiated mediated connections
65 linked_list_t
*initiated
;
68 * Linked list with checklists (hash table with session ID as key would be better).
70 linked_list_t
*checklists
;
73 typedef enum check_state_t check_state_t
;
83 typedef struct endpoint_pair_t endpoint_pair_t
;
86 * An entry in the check list.
88 struct endpoint_pair_t
{
98 /** remote endpoint */
104 /** number of retransmissions */
105 u_int32_t retransmitted
;
107 /** the generated packet */
112 * Destroys an endpoint pair
114 static void endpoint_pair_destroy(endpoint_pair_t
*this)
116 DESTROY_IF(this->local
);
117 DESTROY_IF(this->remote
);
118 DESTROY_IF(this->packet
);
123 * Creates a new entry for the list.
125 static endpoint_pair_t
*endpoint_pair_create(endpoint_notify_t
*initiator
,
126 endpoint_notify_t
*responder
, bool initiator_is_local
)
128 endpoint_pair_t
*this = malloc_thing(endpoint_pair_t
);
132 u_int32_t pi
= initiator
->get_priority(initiator
);
133 u_int32_t pr
= responder
->get_priority(responder
);
134 this->priority
= pow(2, 32) * min(pi
, pr
) + 2 * max(pi
, pr
) + (pi
> pr ?
1 : 0);
136 this->local
= initiator_is_local ? initiator
->get_base(initiator
) : responder
->get_base(responder
);
137 this->local
= this->local
->clone(this->local
);
138 this->remote
= initiator_is_local ? responder
->get_host(responder
) : initiator
->get_host(initiator
);
139 this->remote
= this->remote
->clone(this->remote
);
141 this->state
= CHECK_WAITING
;
142 this->retransmitted
= 0;
149 typedef struct check_list_t check_list_t
;
152 * An entry in the linked list.
154 struct check_list_t
{
157 /** initiator's id */
158 identification_t
*id
;
160 /** initiator's key */
163 /** initiator's endpoints */
164 linked_list_t
*endpoints
;
168 /** responder's id */
169 identification_t
*id
;
171 /** responder's key */
174 /** responder's endpoints */
175 linked_list_t
*endpoints
;
181 /** list of endpoint pairs */
182 linked_list_t
*pairs
;
184 /** pairs queued for triggered checks */
185 linked_list_t
*triggered
;
190 /** TRUE if this is the initiator */
196 * Destroys a checklist
198 static void check_list_destroy(check_list_t
*this)
200 DESTROY_IF(this->initiator
.id
);
201 DESTROY_IF(this->responder
.id
);
203 chunk_free(&this->session_id
);
204 chunk_free(&this->initiator
.key
);
205 chunk_free(&this->responder
.key
);
207 DESTROY_OFFSET_IF(this->initiator
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
208 DESTROY_OFFSET_IF(this->responder
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
210 DESTROY_FUNCTION_IF(this->pairs
, (void*)endpoint_pair_destroy
);
211 /* this list contains some of the same elements as contained in this->pairs */
212 DESTROY_IF(this->triggered
);
218 * Creates a new checklist
220 static check_list_t
*check_list_create(identification_t
*initiator
, identification_t
*responder
,
221 chunk_t session_id
, chunk_t initiator_key
, linked_list_t
*initiator_endpoints
,
224 check_list_t
*this = malloc_thing(check_list_t
);
226 this->session_id
= chunk_clone(session_id
);
228 this->initiator
.id
= initiator
->clone(initiator
);
229 this->initiator
.key
= chunk_clone(initiator_key
);
230 this->initiator
.endpoints
= initiator_endpoints
->clone_offset(initiator_endpoints
, offsetof(endpoint_notify_t
, clone
));
232 this->responder
.id
= responder
->clone(responder
);
233 this->responder
.key
= chunk_empty
;
234 this->responder
.endpoints
= NULL
;
236 this->pairs
= linked_list_create();
237 this->triggered
= linked_list_create();
238 this->state
= CHECK_NONE
;
239 this->is_initiator
= is_initiator
;
245 typedef struct waiting_sa_t waiting_sa_t
;
248 * For an initiator, the data stored about a waiting mediated sa
250 struct waiting_sa_t
{
252 ike_sa_id_t
*ike_sa_id
;
254 /** list of child_cfg_t */
255 linked_list_t
*childs
;
259 * Destroys a queued mediated sa
261 static void waiting_sa_destroy(waiting_sa_t
*this)
263 DESTROY_IF(this->ike_sa_id
);
264 this->childs
->destroy_offset(this->childs
, offsetof(child_cfg_t
, destroy
));
269 * Creates a new mediated sa object
271 static waiting_sa_t
*waiting_sa_create(ike_sa_id_t
*ike_sa_id
)
273 waiting_sa_t
*this = malloc_thing(waiting_sa_t
);
275 this->ike_sa_id
= ike_sa_id
->clone(ike_sa_id
);
276 this->childs
= linked_list_create();
281 typedef struct initiated_t initiated_t
;
284 * For an initiator, the data stored about initiated mediation connections
288 identification_t
*id
;
291 identification_t
*peer_id
;
293 /** list of mediated sas */
294 linked_list_t
*mediated
;
298 * Destroys a queued initiation
300 static void initiated_destroy(initiated_t
*this)
302 DESTROY_IF(this->id
);
303 DESTROY_IF(this->peer_id
);
304 this->mediated
->destroy_function(this->mediated
, (void*)waiting_sa_destroy
);
309 * Creates a queued initiation
311 static initiated_t
*initiated_create(identification_t
*id
, identification_t
*peer_id
)
313 initiated_t
*this = malloc_thing(initiated_t
);
315 this->id
= id
->clone(id
);
316 this->peer_id
= peer_id
->clone(peer_id
);
317 this->mediated
= linked_list_create();
323 typedef struct check_t check_t
;
326 * Data exchanged in a connectivity check
332 /** source of the connectivity check */
335 /** destination of the connectivity check */
342 endpoint_notify_t
*endpoint
;
344 /** raw endpoint payload (to verify the signature) */
345 chunk_t endpoint_raw
;
352 * Destroys a connectivity check
354 static void check_destroy(check_t
*this)
356 chunk_free(&this->session_id
);
357 chunk_free(&this->endpoint_raw
);
358 chunk_free(&this->cookie
);
359 DESTROY_IF(this->endpoint
);
364 * Creates a new connectivity check
366 static check_t
*check_create()
368 check_t
*this = malloc_thing(check_t
);
370 this->session_id
= chunk_empty
;
371 this->cookie
= chunk_empty
;
372 this->endpoint_raw
= chunk_empty
;
373 this->endpoint
= NULL
;
380 typedef struct sender_data_t sender_data_t
;
383 * Data required by the sender
385 struct sender_data_t
{
386 /** connect manager */
387 private_connect_manager_t
*connect_manager
;
394 * Destroys a sender data object
396 static void sender_data_destroy(sender_data_t
*this)
398 chunk_free(&this->session_id
);
403 * Creates a new sender data object
405 static sender_data_t
*sender_data_create(private_connect_manager_t
*connect_manager
, chunk_t session_id
)
407 sender_data_t
*this = malloc_thing(sender_data_t
);
408 this->connect_manager
= connect_manager
;
409 this->session_id
= session_id
;
413 typedef struct retransmit_data_t retransmit_data_t
;
416 * Data required by the retransmission job
418 struct retransmit_data_t
{
419 /** connect manager */
420 private_connect_manager_t
*connect_manager
;
425 /** message (pair) id */
430 * Destroys a retransmission data object
432 static void retransmit_data_destroy(retransmit_data_t
*this)
434 chunk_free(&this->session_id
);
439 * Creates a new retransmission data object
441 static retransmit_data_t
*retransmit_data_create(private_connect_manager_t
*connect_manager
,
442 chunk_t session_id
, u_int32_t mid
)
444 retransmit_data_t
*this = malloc_thing(retransmit_data_t
);
446 this->connect_manager
= connect_manager
;
447 this->session_id
= session_id
;
453 typedef struct initiate_data_t initiate_data_t
;
456 * Data required by the initiate mediated
458 struct initiate_data_t
{
460 check_list_t
*checklist
;
462 /** waiting mediated connections */
463 initiated_t
*initiated
;
467 * Destroys a initiate data object
469 static void initiate_data_destroy(initiate_data_t
*this)
471 check_list_destroy(this->checklist
);
472 initiated_destroy(this->initiated
);
477 * Creates a new initiate data object
479 static initiate_data_t
*initiate_data_create(check_list_t
*checklist
, initiated_t
*initiated
)
481 initiate_data_t
*this = malloc_thing(initiate_data_t
);
483 this->checklist
= checklist
;
484 this->initiated
= initiated
;
490 * Find an initiated connection by the peers' ids
492 static bool match_initiated_by_ids(initiated_t
*current
, identification_t
*id
,
493 identification_t
*peer_id
)
495 return id
->equals(id
, current
->id
) && peer_id
->equals(peer_id
, current
->peer_id
);
498 static status_t
get_initiated_by_ids(private_connect_manager_t
*this,
499 identification_t
*id
, identification_t
*peer_id
, initiated_t
**initiated
)
501 return this->initiated
->find_first(this->initiated
,
502 (linked_list_match_t
)match_initiated_by_ids
,
503 (void**)initiated
, id
, peer_id
);
507 * Removes data about initiated connections
509 static void remove_initiated(private_connect_manager_t
*this, initiated_t
*initiated
)
511 iterator_t
*iterator
;
512 initiated_t
*current
;
514 iterator
= this->initiated
->create_iterator(this->initiated
, TRUE
);
515 while (iterator
->iterate(iterator
, (void**)¤t
))
517 if (current
== initiated
)
519 iterator
->remove(iterator
);
523 iterator
->destroy(iterator
);
529 static bool match_waiting_sa(waiting_sa_t
*current
, ike_sa_id_t
*ike_sa_id
)
531 return ike_sa_id
->equals(ike_sa_id
, current
->ike_sa_id
);
534 static status_t
get_waiting_sa(initiated_t
*initiated
, ike_sa_id_t
*ike_sa_id
, waiting_sa_t
**waiting_sa
)
536 return initiated
->mediated
->find_first(initiated
->mediated
,
537 (linked_list_match_t
)match_waiting_sa
,
538 (void**)waiting_sa
, ike_sa_id
);
542 * Find the checklist with a specific session ID
544 static bool match_checklist_by_id(check_list_t
*current
, chunk_t
*session_id
)
546 return chunk_equals(*session_id
, current
->session_id
);
549 static status_t
get_checklist_by_id(private_connect_manager_t
*this,
550 chunk_t session_id
, check_list_t
**check_list
)
552 return this->checklists
->find_first(this->checklists
,
553 (linked_list_match_t
)match_checklist_by_id
,
554 (void**)check_list
, &session_id
);
558 * Removes a checklist
560 static void remove_checklist(private_connect_manager_t
*this, check_list_t
*checklist
)
562 iterator_t
*iterator
;
563 check_list_t
*current
;
565 iterator
= this->checklists
->create_iterator(this->checklists
, TRUE
);
566 while (iterator
->iterate(iterator
, (void**)¤t
))
568 if (current
== checklist
)
570 iterator
->remove(iterator
);
574 iterator
->destroy(iterator
);
578 * Checks if a list of endpoint_notify_t contains a certain host_t
580 static bool match_endpoint_by_host(endpoint_notify_t
*current
, host_t
*host
)
582 return host
->equals(host
, current
->get_host(current
));
585 static status_t
endpoints_contain(linked_list_t
*endpoints
, host_t
*host
, endpoint_notify_t
**endpoint
)
587 return endpoints
->find_first(endpoints
,
588 (linked_list_match_t
)match_endpoint_by_host
,
589 (void**)endpoint
, host
);
593 * Updates the state of the whole checklist
595 static void update_checklist_state(check_list_t
*checklist
)
597 iterator_t
*iterator
;
598 endpoint_pair_t
*current
;
599 bool in_progress
= FALSE
, succeeded
= FALSE
;
601 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
602 while (iterator
->iterate(iterator
, (void**)¤t
))
604 switch(current
->state
)
607 /* at least one is still waiting -> checklist remains
608 * in waiting state */
609 iterator
->destroy(iterator
);
611 case CHECK_IN_PROGRESS
:
614 case CHECK_SUCCEEDED
:
621 iterator
->destroy(iterator
);
625 checklist
->state
= CHECK_IN_PROGRESS
;
629 checklist
->state
= CHECK_SUCCEEDED
;
633 checklist
->state
= CHECK_FAILED
;
638 * Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
640 static void insert_pair_by_priority(linked_list_t
*pairs
, endpoint_pair_t
*pair
)
642 iterator_t
*iterator
;
643 endpoint_pair_t
*current
;
644 bool inserted
= FALSE
;
646 iterator
= pairs
->create_iterator(pairs
, TRUE
);
647 while (iterator
->iterate(iterator
, (void**)¤t
))
649 if (current
->priority
< pair
->priority
)
651 iterator
->insert_before(iterator
, pair
);
656 iterator
->destroy(iterator
);
660 pairs
->insert_last(pairs
, pair
);
665 * Searches a list of endpoint_pair_t for a pair with specific host_ts
667 static bool match_pair_by_hosts(endpoint_pair_t
*current
, host_t
*local
, host_t
*remote
)
669 return local
->equals(local
, current
->local
) && remote
->equals(remote
, current
->remote
);
672 static status_t
get_pair_by_hosts(linked_list_t
*pairs
, host_t
*local
, host_t
*remote
, endpoint_pair_t
**pair
)
674 return pairs
->find_first(pairs
,
675 (linked_list_match_t
)match_pair_by_hosts
,
676 (void**)pair
, local
, remote
);
680 * Searches for a pair with a specific id
682 static bool match_pair_by_id(endpoint_pair_t
*current
, u_int32_t
*id
)
684 return current
->id
== *id
;
687 static status_t
get_pair_by_id(check_list_t
*checklist
, u_int32_t id
, endpoint_pair_t
**pair
)
689 return checklist
->pairs
->find_first(checklist
->pairs
,
690 (linked_list_match_t
)match_pair_by_id
,
695 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
697 static bool match_succeeded_pair(endpoint_pair_t
*current
)
699 return current
->state
== CHECK_SUCCEEDED
;
702 static status_t
get_best_valid_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
704 return checklist
->pairs
->find_first(checklist
->pairs
,
705 (linked_list_match_t
)match_succeeded_pair
,
710 * Returns and *removes* the first triggered pair in state CHECK_WAITING.
712 static bool match_waiting_pair(endpoint_pair_t
*current
)
714 return current
->state
== CHECK_WAITING
;
717 static status_t
get_triggered_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
719 iterator_t
*iterator
;
720 endpoint_pair_t
*current
;
721 status_t status
= NOT_FOUND
;
723 iterator
= checklist
->triggered
->create_iterator(checklist
->triggered
, TRUE
);
724 while (iterator
->iterate(iterator
, (void**)¤t
))
726 iterator
->remove(iterator
);
728 if (current
->state
== CHECK_WAITING
)
738 iterator
->destroy(iterator
);
744 * Prunes identical pairs with lower priority from the list
745 * Note: this function also numbers the remaining pairs serially
747 static void prune_pairs(linked_list_t
*pairs
)
749 iterator_t
*iterator
, *search
;
750 endpoint_pair_t
*current
, *other
;
753 iterator
= pairs
->create_iterator(pairs
, TRUE
);
754 search
= pairs
->create_iterator(pairs
, TRUE
);
755 while (iterator
->iterate(iterator
, (void**)¤t
))
759 while (search
->iterate(search
, (void**)&other
))
761 if (current
== other
)
766 if (current
->local
->equals(current
->local
, other
->local
) &&
767 current
->remote
->equals(current
->remote
, other
->remote
))
769 /* since the list of pairs is sorted by priority in descending
770 * order, and we iterate the list from the beginning, we are
771 * sure that the priority of 'other' is lower than that of
772 * 'current', remove it */
773 DBG1(DBG_IKE
, "pruning endpoint pair %H - %H with priority %d",
774 other
->local
, other
->remote
, other
->priority
);
775 search
->remove(search
);
776 endpoint_pair_destroy(other
);
779 search
->reset(search
);
781 search
->destroy(search
);
782 iterator
->destroy(iterator
);
786 * Builds a list of endpoint pairs
788 static void build_pairs(check_list_t
*checklist
)
790 iterator_t
*iterator_i
, *iterator_r
;
791 endpoint_notify_t
*initiator
, *responder
;
793 iterator_i
= checklist
->initiator
.endpoints
->create_iterator(checklist
->initiator
.endpoints
, TRUE
);
794 while (iterator_i
->iterate(iterator_i
, (void**)&initiator
))
796 iterator_r
= checklist
->responder
.endpoints
->create_iterator(checklist
->responder
.endpoints
, TRUE
);
797 while (iterator_r
->iterate(iterator_r
, (void**)&responder
))
799 if (initiator
->get_family(initiator
) != responder
->get_family(responder
))
804 insert_pair_by_priority(checklist
->pairs
,
805 endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
));
807 iterator_r
->destroy(iterator_r
);
809 iterator_i
->destroy(iterator_i
);
811 prune_pairs(checklist
->pairs
);
815 * Processes the payloads of a connectivity check and returns the extracted data
817 static status_t
process_payloads(message_t
*message
, check_t
*check
)
819 iterator_t
*iterator
;
822 iterator
= message
->get_payload_iterator(message
);
823 while (iterator
->iterate(iterator
, (void**)&payload
))
825 if (payload
->get_type(payload
) != NOTIFY
)
827 DBG1(DBG_IKE
, "ignoring payload of type '%N' while processing "
828 "connectivity check", payload_type_names
, payload
->get_type(payload
));
832 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
834 switch (notify
->get_notify_type(notify
))
840 DBG1(DBG_IKE
, "connectivity check contains multiple P2P_ENDPOINT notifies");
844 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
847 DBG1(DBG_IKE
, "received invalid P2P_ENDPOINT notify");
850 check
->endpoint
= endpoint
;
851 check
->endpoint_raw
= chunk_clone(notify
->get_notification_data(notify
));
852 DBG2(DBG_IKE
, "received P2P_ENDPOINT notify");
857 if (check
->session_id
.ptr
)
859 DBG1(DBG_IKE
, "connectivity check contains multiple P2P_SESSIONID notifies");
862 check
->session_id
= chunk_clone(notify
->get_notification_data(notify
));
863 DBG2(DBG_IKE
, "received P2P_SESSIONID %#B", &check
->session_id
);
868 if (check
->cookie
.ptr
)
870 DBG1(DBG_IKE
, "connectivity check contains multiple COOKIE notifies");
873 check
->cookie
= chunk_clone(notify
->get_notification_data(notify
));
874 DBG2(DBG_IKE
, "received COOKIE %#B", &check
->cookie
);
881 iterator
->destroy(iterator
);
883 if (!check
->session_id
.ptr
|| !check
->endpoint
|| !check
->cookie
.ptr
)
885 DBG1(DBG_IKE
, "at least one payload was missing from the connectivity check");
893 * Builds the signature for a connectivity check
895 static chunk_t
build_signature(private_connect_manager_t
*this,
896 check_list_t
*checklist
, check_t
*check
, bool outbound
)
898 chunk_t mid_chunk
, key_chunk
, sig_chunk
;
901 mid_chunk
= chunk_from_thing(check
->mid
);
903 key_chunk
= (checklist
->is_initiator
&& outbound
) || (!checklist
->is_initiator
&& !outbound
)
904 ? checklist
->initiator
.key
: checklist
->responder
.key
;
906 /* signature = SHA1( MID | P2P_SESSIONID | P2P_ENDPOINT | P2P_SESSIONKEY ) */
907 sig_chunk
= chunk_cat("cccc", mid_chunk
, check
->session_id
, check
->endpoint_raw
, key_chunk
);
908 this->hasher
->allocate_hash(this->hasher
, sig_chunk
, &sig_hash
);
909 DBG3(DBG_IKE
, "sig_chunk %B", &sig_chunk
);
910 DBG3(DBG_IKE
, "sig_hash %B", &sig_hash
);
912 chunk_free(&sig_chunk
);
916 static void queue_retransmission(private_connect_manager_t
*this, chunk_t session_id
, u_int32_t mid
);
917 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
);
918 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
);
921 * This function is triggered for each sent check after a specific timeout
923 static job_requeue_t
retransmit(retransmit_data_t
*data
)
925 private_connect_manager_t
*this = data
->connect_manager
;
927 pthread_mutex_lock(&(this->mutex
));
929 check_list_t
*checklist
;
930 if (get_checklist_by_id(this, data
->session_id
, &checklist
) != SUCCESS
)
932 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't retransmit connectivity check",
934 pthread_mutex_unlock(&(this->mutex
));
935 return JOB_REQUEUE_NONE
;
938 endpoint_pair_t
*pair
;
939 if (get_pair_by_id(checklist
, data
->mid
, &pair
) != SUCCESS
)
941 DBG1(DBG_IKE
, "pair with id '%d' not found, can't retransmit connectivity check",
946 if (pair
->state
!= CHECK_IN_PROGRESS
)
948 DBG2(DBG_IKE
, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
949 data
->mid
, pair
->state
);
953 if (++pair
->retransmitted
>= P2P_MAX_RETRANS
)
955 DBG2(DBG_IKE
, "pair with id '%d' failed after %d tries",
956 data
->mid
, pair
->retransmitted
);
957 pair
->state
= CHECK_FAILED
;
961 charon
->sender
->send(charon
->sender
, pair
->packet
->clone(pair
->packet
));
963 queue_retransmission(this, checklist
->session_id
, pair
->id
);
966 update_checklist_state(checklist
);
968 switch(checklist
->state
)
970 case CHECK_SUCCEEDED
:
972 finish_checks(this, checklist
);
978 pthread_mutex_unlock(&(this->mutex
));
980 /* we reschedule it manually */
981 return JOB_REQUEUE_NONE
;
985 * Queues a retransmission job
987 static void queue_retransmission(private_connect_manager_t
*this, chunk_t session_id
, u_int32_t mid
)
989 retransmit_data_t
*data
= retransmit_data_create(this, chunk_clone(session_id
), mid
);
990 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)retransmit
, data
, (callback_job_cleanup_t
)retransmit_data_destroy
, NULL
);
991 charon
->scheduler
->schedule_job(charon
->scheduler
, (job_t
*)job
, P2P_RTO_MIN
);
997 static void send_check(private_connect_manager_t
*this, check_list_t
*checklist
,
998 check_t
*check
, endpoint_pair_t
*pair
, bool request
)
1000 message_t
*message
= message_create();
1001 message
->set_message_id(message
, check
->mid
);
1002 message
->set_exchange_type(message
, INFORMATIONAL
);
1003 message
->set_request(message
, request
);
1004 message
->set_destination(message
, check
->dst
->clone(check
->dst
));
1005 message
->set_source(message
, check
->src
->clone(check
->src
));
1007 message
->set_ike_sa_id(message
, ike_sa_id_create(0, 0, request
));
1009 message
->add_notify(message
, FALSE
, P2P_SESSIONID
, check
->session_id
);
1010 DBG2(DBG_IKE
, "send P2P_SESSIONID %#B", &check
->session_id
);
1012 notify_payload_t
*endpoint
= check
->endpoint
->build_notify(check
->endpoint
);
1013 check
->endpoint_raw
= chunk_clone(endpoint
->get_notification_data(endpoint
));
1014 message
->add_payload(message
, (payload_t
*)endpoint
);
1015 DBG2(DBG_IKE
, "send P2P_ENDPOINT notify");
1017 check
->cookie
= build_signature(this, checklist
, check
, TRUE
);
1018 message
->add_notify(message
, FALSE
, COOKIE
, check
->cookie
);
1019 DBG2(DBG_IKE
, "send COOKIE %#B", &check
->cookie
);
1022 if (message
->generate(message
, NULL
, NULL
, &packet
) == SUCCESS
)
1024 charon
->sender
->send(charon
->sender
, packet
->clone(packet
));
1028 DESTROY_IF(pair
->packet
);
1029 pair
->packet
= packet
;
1030 queue_retransmission(this, checklist
->session_id
, pair
->id
);
1034 packet
->destroy(packet
);
1040 * Queues a triggered check
1042 static void queue_triggered_check(check_list_t
*checklist
, endpoint_pair_t
*pair
)
1044 pair
->state
= CHECK_WAITING
;
1045 checklist
->triggered
->insert_last(checklist
->triggered
, pair
);
1049 * This function is triggered for each checklist at a specific interval
1051 static job_requeue_t
sender(sender_data_t
*data
)
1053 private_connect_manager_t
*this = data
->connect_manager
;
1055 pthread_mutex_lock(&(this->mutex
));
1057 check_list_t
*checklist
;
1058 if (get_checklist_by_id(this, data
->session_id
, &checklist
) != SUCCESS
)
1060 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't send connectivity check",
1062 pthread_mutex_unlock(&(this->mutex
));
1063 return JOB_REQUEUE_NONE
;
1066 endpoint_pair_t
*pair
;
1067 if (get_triggered_pair(checklist
, &pair
) != SUCCESS
)
1069 DBG1(DBG_IKE
, "no triggered check queued, sending an ordinary check");
1071 if (checklist
->pairs
->find_first(checklist
->pairs
,
1072 (linked_list_match_t
)match_waiting_pair
, (void**)&pair
) != SUCCESS
)
1074 pthread_mutex_unlock(&(this->mutex
));
1075 DBG1(DBG_IKE
, "no pairs in waiting state, aborting");
1076 return JOB_REQUEUE_NONE
;
1081 DBG1(DBG_IKE
, "triggered check found");
1084 check_t
*check
= check_create();
1085 check
->mid
= pair
->id
;
1086 check
->src
= pair
->local
->clone(pair
->local
);
1087 check
->dst
= pair
->remote
->clone(pair
->remote
);
1088 check
->session_id
= chunk_clone(checklist
->session_id
);
1089 check
->endpoint
= endpoint_notify_create();
1091 pair
->state
= CHECK_IN_PROGRESS
;
1093 send_check(this, checklist
, check
, pair
, TRUE
);
1095 check_destroy(check
);
1097 /* schedule this job again */
1098 u_int32_t N
= this->checklists
->get_count(this->checklists
);
1099 schedule_checks(this, checklist
, P2P_INTERVAL
* N
);
1101 pthread_mutex_unlock(&(this->mutex
));
1103 /* we reschedule it manually */
1104 return JOB_REQUEUE_NONE
;
1108 * Schedules checks for a checklist (time in ms)
1110 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
)
1112 chunk_t session_id
= chunk_clone(checklist
->session_id
);
1113 sender_data_t
*data
= sender_data_create(this, session_id
);
1114 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)sender
, data
, (callback_job_cleanup_t
)sender_data_destroy
, NULL
);
1115 charon
->scheduler
->schedule_job(charon
->scheduler
, job
, time
);
1119 * Initiates waiting mediated connections
1121 static job_requeue_t
initiate_mediated(initiate_data_t
*data
)
1123 check_list_t
*checklist
= data
->checklist
;
1124 initiated_t
*initiated
= data
->initiated
;
1126 endpoint_pair_t
*pair
;
1127 if (get_best_valid_pair(checklist
, &pair
) == SUCCESS
)
1129 waiting_sa_t
*waiting_sa
;
1130 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1131 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1133 ike_sa_t
*sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, waiting_sa
->ike_sa_id
);
1134 if (sa
->initiate_mediated(sa
, pair
->local
, pair
->remote
, waiting_sa
->childs
) != SUCCESS
)
1136 SIG(IKE_UP_FAILED
, "establishing the mediated connection failed");
1137 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, sa
);
1139 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, sa
);
1141 iterator
->destroy(iterator
);
1145 /* this should (can?) not happen */
1148 return JOB_REQUEUE_NONE
;
1152 * Finishes checks for a checklist
1154 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
)
1156 if (checklist
->is_initiator
)
1158 initiated_t
*initiated
;
1159 if (get_initiated_by_ids(this, checklist
->initiator
.id
,
1160 checklist
->responder
.id
, &initiated
) == SUCCESS
)
1162 remove_checklist(this, checklist
);
1163 remove_initiated(this, initiated
);
1165 initiate_data_t
*data
= initiate_data_create(checklist
, initiated
);
1166 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiate_mediated
, data
, (callback_job_cleanup_t
)initiate_data_destroy
, NULL
);
1167 charon
->processor
->queue_job(charon
->processor
, job
);
1172 DBG1(DBG_IKE
, "there is no mediated connection waiting between '%D' "
1173 "and '%D'", checklist
->initiator
.id
, checklist
->responder
.id
);
1177 /* remove_checklist(this, checklist);
1178 * check_list_destroy(checklist);
1179 * FIXME: we should do this ^^^ after a specific timeout on the
1184 * Process the response to one of our requests
1186 static void process_response(private_connect_manager_t
*this, check_t
*check
,
1187 check_list_t
*checklist
)
1189 endpoint_pair_t
*pair
;
1190 if (get_pair_by_id(checklist
, check
->mid
, &pair
) == SUCCESS
)
1192 if (pair
->local
->equals(pair
->local
, check
->dst
) &&
1193 pair
->remote
->equals(pair
->remote
, check
->src
))
1195 DBG1(DBG_IKE
, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair
->id
,
1196 pair
->local
, pair
->remote
);
1197 pair
->state
= CHECK_SUCCEEDED
;
1200 linked_list_t
*local_endpoints
= checklist
->is_initiator ?
1201 checklist
->initiator
.endpoints
: checklist
->responder
.endpoints
;
1203 endpoint_notify_t
*local_endpoint
;
1204 if (endpoints_contain(local_endpoints
,
1205 check
->endpoint
->get_host(check
->endpoint
), &local_endpoint
) != SUCCESS
)
1207 local_endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1208 check
->endpoint
->get_host(check
->endpoint
), pair
->local
);
1209 local_endpoint
->set_priority(local_endpoint
, check
->endpoint
->get_priority(check
->endpoint
));
1210 local_endpoints
->insert_last(local_endpoints
, local_endpoint
);
1213 update_checklist_state(checklist
);
1215 switch(checklist
->state
)
1217 case CHECK_SUCCEEDED
:
1219 finish_checks(this, checklist
);
1227 DBG1(DBG_IKE
, "pair with id '%d' not found", check
->mid
);
1231 static void process_request(private_connect_manager_t
*this, check_t
*check
,
1232 check_list_t
*checklist
)
1234 linked_list_t
*remote_endpoints
= checklist
->is_initiator ?
1235 checklist
->responder
.endpoints
: checklist
->initiator
.endpoints
;
1237 endpoint_notify_t
*peer_reflexive
, *remote_endpoint
;
1238 peer_reflexive
= endpoint_notify_create_from_host(PEER_REFLEXIVE
, check
->src
, NULL
);
1239 peer_reflexive
->set_priority(peer_reflexive
, check
->endpoint
->get_priority(check
->endpoint
));
1241 if (endpoints_contain(remote_endpoints
, check
->src
, &remote_endpoint
) != SUCCESS
)
1243 remote_endpoint
= peer_reflexive
->clone(peer_reflexive
);
1244 remote_endpoints
->insert_last(remote_endpoints
, remote_endpoint
);
1247 endpoint_pair_t
*pair
;
1248 if (get_pair_by_hosts(checklist
->pairs
, check
->dst
, check
->src
, &pair
) == SUCCESS
)
1252 case CHECK_IN_PROGRESS
:
1253 /* prevent retransmissions */
1254 pair
->retransmitted
= P2P_MAX_RETRANS
;
1255 /* FIXME: we should wait to the next rto to send the triggered check
1259 queue_triggered_check(checklist
, pair
);
1261 case CHECK_SUCCEEDED
:
1268 endpoint_notify_t
*local_endpoint
= endpoint_notify_create_from_host(HOST
, check
->dst
, NULL
);
1270 endpoint_notify_t
*initiator
= checklist
->is_initiator ? local_endpoint
: remote_endpoint
;
1271 endpoint_notify_t
*responder
= checklist
->is_initiator ? remote_endpoint
: local_endpoint
;
1273 pair
= endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
);
1274 pair
->id
= checklist
->pairs
->get_count(checklist
->pairs
) + 1;
1276 insert_pair_by_priority(checklist
->pairs
, pair
);
1278 queue_triggered_check(checklist
, pair
);
1280 local_endpoint
->destroy(local_endpoint
);
1284 check_t
*response
= check_create();
1286 response
->mid
= check
->mid
;
1287 response
->src
= check
->dst
->clone(check
->dst
);
1288 response
->dst
= check
->src
->clone(check
->src
);
1289 response
->session_id
= chunk_clone(check
->session_id
);
1290 response
->endpoint
= peer_reflexive
;
1292 send_check(this, checklist
, response
, pair
, FALSE
);
1294 check_destroy(response
);
1298 * Implementation of connect_manager_t.process_check.
1300 static void process_check(private_connect_manager_t
*this, message_t
*message
)
1302 if (message
->parse_body(message
, NULL
, NULL
) != SUCCESS
)
1304 DBG1(DBG_IKE
, "%N %s with message ID %d processing failed",
1305 exchange_type_names
, message
->get_exchange_type(message
),
1306 message
->get_request(message
) ?
"request" : "response",
1307 message
->get_message_id(message
));
1311 check_t
*check
= check_create();
1312 check
->mid
= message
->get_message_id(message
);
1313 check
->src
= message
->get_source(message
);
1314 check
->dst
= message
->get_destination(message
);
1316 if (process_payloads(message
, check
) != SUCCESS
)
1318 DBG1(DBG_IKE
, "invalid connectivity check %s received",
1319 message
->get_request(message
) ?
"request" : "response");
1320 check_destroy(check
);
1324 pthread_mutex_lock(&(this->mutex
));
1326 check_list_t
*checklist
;
1327 if (get_checklist_by_id(this, check
->session_id
, &checklist
) != SUCCESS
)
1329 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1330 &check
->session_id
);
1331 check_destroy(check
);
1332 pthread_mutex_unlock(&(this->mutex
));
1336 chunk_t sig
= build_signature(this, checklist
, check
, FALSE
);
1337 if (!chunk_equals(sig
, check
->cookie
))
1339 DBG1(DBG_IKE
, "connectivity check verification failed");
1340 check_destroy(check
);
1342 pthread_mutex_unlock(&(this->mutex
));
1347 if (message
->get_request(message
))
1349 process_request(this, check
, checklist
);
1353 process_response(this, check
, checklist
);
1356 pthread_mutex_unlock(&(this->mutex
));
1358 check_destroy(check
);
1362 * Implementation of connect_manager_t.check_and_register.
1364 static bool check_and_register(private_connect_manager_t
*this,
1365 identification_t
*id
, identification_t
*peer_id
,
1366 ike_sa_id_t
*mediated_sa
, child_cfg_t
*child
)
1368 initiated_t
*initiated
;
1369 bool already_there
= TRUE
;
1371 pthread_mutex_lock(&(this->mutex
));
1373 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1375 DBG2(DBG_IKE
, "registered waiting mediated connection with '%D'", peer_id
);
1376 initiated
= initiated_create(id
, peer_id
);
1377 this->initiated
->insert_last(this->initiated
, initiated
);
1378 already_there
= FALSE
;
1381 waiting_sa_t
*waiting_sa
;
1382 if (get_waiting_sa(initiated
, mediated_sa
, &waiting_sa
) != SUCCESS
)
1384 waiting_sa
= waiting_sa_create(mediated_sa
);
1385 initiated
->mediated
->insert_last(initiated
->mediated
, waiting_sa
);
1388 child
->get_ref(child
);
1389 waiting_sa
->childs
->insert_last(waiting_sa
->childs
, child
);
1391 pthread_mutex_unlock(&(this->mutex
));
1393 return already_there
;
1397 * Implementation of connect_manager_t.check_and_initiate.
1399 static void check_and_initiate(private_connect_manager_t
*this, ike_sa_id_t
*mediation_sa
,
1400 identification_t
*id
, identification_t
*peer_id
)
1402 initiated_t
*initiated
;
1404 pthread_mutex_lock(&(this->mutex
));
1406 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1408 DBG2(DBG_IKE
, "no waiting mediated connections with '%D'", peer_id
);
1409 pthread_mutex_unlock(&(this->mutex
));
1413 waiting_sa_t
*waiting_sa
;
1414 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1415 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1417 job_t
*job
= (job_t
*)reinitiate_mediation_job_create(mediation_sa
,
1418 waiting_sa
->ike_sa_id
);
1419 charon
->processor
->queue_job(charon
->processor
, job
);
1422 pthread_mutex_unlock(&(this->mutex
));
1426 * Implementation of connect_manager_t.set_initiator_data.
1428 static status_t
set_initiator_data(private_connect_manager_t
*this,
1429 identification_t
*initiator
, identification_t
*responder
,
1430 chunk_t session_id
, chunk_t key
, linked_list_t
*endpoints
, bool is_initiator
)
1432 check_list_t
*checklist
;
1434 pthread_mutex_lock(&(this->mutex
));
1436 if (get_checklist_by_id(this, session_id
, NULL
) == SUCCESS
)
1438 DBG1(DBG_IKE
, "checklist with id '%B' already exists, aborting",
1440 pthread_mutex_unlock(&(this->mutex
));
1444 checklist
= check_list_create(initiator
, responder
, session_id
, key
, endpoints
, is_initiator
);
1445 this->checklists
->insert_last(this->checklists
, checklist
);
1447 pthread_mutex_unlock(&(this->mutex
));
1453 * Implementation of connect_manager_t.set_responder_data.
1455 static status_t
set_responder_data(private_connect_manager_t
*this,
1456 chunk_t session_id
, chunk_t key
, linked_list_t
*endpoints
)
1458 check_list_t
*checklist
;
1460 pthread_mutex_lock(&(this->mutex
));
1462 if (get_checklist_by_id(this, session_id
, &checklist
) != SUCCESS
)
1464 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1466 pthread_mutex_unlock(&(this->mutex
));
1470 checklist
->responder
.key
= chunk_clone(key
);
1471 checklist
->responder
.endpoints
= endpoints
->clone_offset(endpoints
, offsetof(endpoint_notify_t
, clone
));
1472 checklist
->state
= CHECK_WAITING
;
1474 build_pairs(checklist
);
1476 /* send the first check immediately */
1477 schedule_checks(this, checklist
, 0);
1479 pthread_mutex_unlock(&(this->mutex
));
1485 * Implementation of connect_manager_t.destroy.
1487 static void destroy(private_connect_manager_t
*this)
1489 pthread_mutex_lock(&(this->mutex
));
1491 this->hasher
->destroy(this->hasher
);
1492 this->checklists
->destroy_function(this->checklists
, (void*)check_list_destroy
);
1493 this->initiated
->destroy_function(this->initiated
, (void*)initiated_destroy
);
1495 pthread_mutex_unlock(&(this->mutex
));
1496 pthread_mutex_destroy(&(this->mutex
));
1501 * Described in header.
1503 connect_manager_t
*connect_manager_create()
1505 private_connect_manager_t
*this = malloc_thing(private_connect_manager_t
);
1507 this->public.destroy
= (void(*)(connect_manager_t
*))destroy
;
1508 this->public.check_and_register
= (bool(*)(connect_manager_t
*,identification_t
*,identification_t
*,ike_sa_id_t
*,child_cfg_t
*))check_and_register
;
1509 this->public.check_and_initiate
= (void(*)(connect_manager_t
*,ike_sa_id_t
*,identification_t
*,identification_t
*))check_and_initiate
;
1510 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
;
1511 this->public.set_responder_data
= (status_t(*)(connect_manager_t
*,chunk_t
,chunk_t
,linked_list_t
*))set_responder_data
;
1512 this->public.process_check
= (void(*)(connect_manager_t
*,message_t
*))process_check
;
1514 this->hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
1515 if (this->hasher
== NULL
)
1517 DBG1(DBG_IKE
, "unable to create connect manager, SHA1 not supported");
1522 this->checklists
= linked_list_create();
1523 this->initiated
= linked_list_create();
1525 pthread_mutex_init(&(this->mutex
), NULL
);
1527 return (connect_manager_t
*)this;