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
23 #include <config/peer_cfg.h>
24 #include <encoding/payloads/id_payload.h>
25 #include <encoding/payloads/notify_payload.h>
26 #include <encoding/payloads/endpoint_notify.h>
27 #include <processing/jobs/mediation_job.h>
29 #define ME_CONNECTID_LEN 4
30 #define ME_CONNECTKEY_LEN 16
32 typedef struct private_ike_me_t private_ike_me_t
;
35 * Private members of a ike_me_t task.
37 struct private_ike_me_t
{
40 * Public methods and task_t interface.
50 * Are we the initiator?
55 * Is this a mediation connection?
60 * Is this the response from another peer?
67 linked_list_t
*local_endpoints
;
72 linked_list_t
*remote_endpoints
;
75 * Did the peer request a callback?
80 * Did the connect fail?
85 * Was there anything wrong with the payloads?
92 identification_t
*peer_id
;
94 * Received ID used for connectivity checks
99 * Received key used for connectivity checks
104 * Peer config of the mediated connection
106 peer_cfg_t
*mediated_cfg
;
111 * Adds a list of endpoints as notifies to a given message
113 static void add_endpoints_to_message(message_t
*message
, linked_list_t
*endpoints
)
115 iterator_t
*iterator
;
116 endpoint_notify_t
*endpoint
;
118 iterator
= endpoints
->create_iterator(endpoints
, TRUE
);
119 while (iterator
->iterate(iterator
, (void**)&endpoint
))
121 message
->add_payload(message
, (payload_t
*)endpoint
->build_notify(endpoint
));
123 iterator
->destroy(iterator
);
127 * Gathers endpoints and adds them to the current message
129 static void gather_and_add_endpoints(private_ike_me_t
*this, message_t
*message
)
131 iterator_t
*iterator
;
135 /* get the port that is used to communicate with the ms */
136 host
= this->ike_sa
->get_my_host(this->ike_sa
);
137 port
= host
->get_port(host
);
139 iterator
= charon
->kernel_interface
->create_address_iterator(
140 charon
->kernel_interface
);
141 while (iterator
->iterate(iterator
, (void**)&addr
))
143 host
= addr
->clone(addr
);
144 host
->set_port(host
, port
);
146 this->local_endpoints
->insert_last(this->local_endpoints
,
147 endpoint_notify_create_from_host(HOST
, host
, NULL
));
151 iterator
->destroy(iterator
);
153 host
= this->ike_sa
->get_server_reflexive_host(this->ike_sa
);
156 this->local_endpoints
->insert_last(this->local_endpoints
,
157 endpoint_notify_create_from_host(SERVER_REFLEXIVE
, host
,
158 this->ike_sa
->get_my_host(this->ike_sa
)));
161 add_endpoints_to_message(message
, this->local_endpoints
);
165 * read notifys from message and evaluate them
167 static void process_payloads(private_ike_me_t
*this, message_t
*message
)
169 iterator_t
*iterator
;
172 iterator
= message
->get_payload_iterator(message
);
173 while (iterator
->iterate(iterator
, (void**)&payload
))
175 if (payload
->get_type(payload
) != NOTIFY
)
180 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
182 switch (notify
->get_notify_type(notify
))
184 case ME_CONNECT_FAILED
:
186 DBG2(DBG_IKE
, "received ME_CONNECT_FAILED notify");
192 DBG2(DBG_IKE
, "received ME_MEDIATION notify");
193 this->mediation
= TRUE
;
198 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
201 DBG1(DBG_IKE
, "received invalid ME_ENDPOINT notify");
204 DBG1(DBG_IKE
, "received %N ME_ENDPOINT %#H", me_endpoint_type_names
,
205 endpoint
->get_type(endpoint
), endpoint
->get_host(endpoint
));
207 this->remote_endpoints
->insert_last(this->remote_endpoints
, endpoint
);
212 DBG2(DBG_IKE
, "received ME_CALLBACK notify");
213 this->callback
= TRUE
;
218 chunk_free(&this->connect_id
);
219 this->connect_id
= chunk_clone(notify
->get_notification_data(notify
));
220 DBG2(DBG_IKE
, "received ME_CONNECTID %#B", &this->connect_id
);
225 chunk_free(&this->connect_key
);
226 this->connect_key
= chunk_clone(notify
->get_notification_data(notify
));
227 DBG4(DBG_IKE
, "received ME_CONNECTKEY %#B", &this->connect_key
);
232 DBG2(DBG_IKE
, "received ME_RESPONSE notify");
233 this->response
= TRUE
;
240 iterator
->destroy(iterator
);
244 * Implementation of task_t.build for initiator
246 static status_t
build_i(private_ike_me_t
*this, message_t
*message
)
248 switch(message
->get_exchange_type(message
))
252 peer_cfg_t
*peer_cfg
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
253 if (peer_cfg
->is_mediation(peer_cfg
))
255 DBG2(DBG_IKE
, "adding ME_MEDIATION");
256 message
->add_notify(message
, FALSE
, ME_MEDIATION
, chunk_empty
);
266 if (this->ike_sa
->has_condition(this->ike_sa
, COND_NAT_HERE
))
268 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_host(SERVER_REFLEXIVE
, NULL
, NULL
);
269 message
->add_payload(message
, (payload_t
*)endpoint
->build_notify(endpoint
));
270 endpoint
->destroy(endpoint
);
276 id_payload_t
*id_payload
;
277 randomizer_t
*rand
= randomizer_create();
279 id_payload
= id_payload_create_from_identification(ID_PEER
, this->peer_id
);
280 message
->add_payload(message
, (payload_t
*)id_payload
);
284 /* only the initiator creates a connect ID. the responder returns
285 * the connect ID that it received from the initiator */
286 if (rand
->allocate_pseudo_random_bytes(rand
,
287 ME_CONNECTID_LEN
, &this->connect_id
) != SUCCESS
)
289 DBG1(DBG_IKE
, "unable to generate connect ID for ME_CONNECT");
295 if (rand
->allocate_pseudo_random_bytes(rand
,
296 ME_CONNECTKEY_LEN
, &this->connect_key
) != SUCCESS
)
298 DBG1(DBG_IKE
, "unable to generate connect key for ME_CONNECT");
305 message
->add_notify(message
, FALSE
, ME_CONNECTID
, this->connect_id
);
306 message
->add_notify(message
, FALSE
, ME_CONNECTKEY
, this->connect_key
);
310 message
->add_notify(message
, FALSE
, ME_RESPONSE
, chunk_empty
);
314 /* FIXME: should we make that configurable? */
315 message
->add_notify(message
, FALSE
, ME_CALLBACK
, chunk_empty
);
318 gather_and_add_endpoints(this, message
);
329 * Implementation of task_t.process for responder
331 static status_t
process_r(private_ike_me_t
*this, message_t
*message
)
333 switch(message
->get_exchange_type(message
))
337 id_payload_t
*id_payload
;
338 id_payload
= (id_payload_t
*)message
->get_payload(message
, ID_PEER
);
341 DBG1(DBG_IKE
, "received ME_CONNECT without ID_PEER payload, aborting");
344 this->peer_id
= id_payload
->get_identification(id_payload
);
346 process_payloads(this, message
);
350 DBG1(DBG_IKE
, "received ME_CALLBACK for '%D'", this->peer_id
);
354 if (!this->connect_id
.ptr
)
356 DBG1(DBG_IKE
, "received ME_CONNECT without ME_CONNECTID notify, aborting");
357 this->invalid_syntax
= TRUE
;
361 if (!this->connect_key
.ptr
)
363 DBG1(DBG_IKE
, "received ME_CONNECT without ME_CONNECTKEY notify, aborting");
364 this->invalid_syntax
= TRUE
;
368 if (!this->remote_endpoints
->get_count(this->remote_endpoints
))
370 DBG1(DBG_IKE
, "received ME_CONNECT without any ME_ENDPOINT payloads, aborting");
371 this->invalid_syntax
= TRUE
;
375 DBG1(DBG_IKE
, "received ME_CONNECT");
385 * Implementation of task_t.build for responder
387 static status_t
build_r(private_ike_me_t
*this, message_t
*message
)
389 switch(message
->get_exchange_type(message
))
393 if (this->invalid_syntax
)
395 message
->add_notify(message
, TRUE
, INVALID_SYNTAX
, chunk_empty
);
401 charon
->connect_manager
->check_and_initiate(charon
->connect_manager
,
402 this->ike_sa
->get_id(this->ike_sa
),
403 this->ike_sa
->get_my_id(this->ike_sa
), this->peer_id
);
409 /* FIXME: handle result of set_responder_data
410 * as initiator, upon receiving a response from another peer,
411 * update the checklist and start sending checks */
412 charon
->connect_manager
->set_responder_data(charon
->connect_manager
,
413 this->connect_id
, this->connect_key
, this->remote_endpoints
);
417 /* FIXME: handle result of set_initiator_data
418 * as responder, create a checklist with the initiator's data */
419 charon
->connect_manager
->set_initiator_data(charon
->connect_manager
,
420 this->peer_id
, this->ike_sa
->get_my_id(this->ike_sa
),
421 this->connect_id
, this->connect_key
, this->remote_endpoints
,
423 if (this->ike_sa
->respond(this->ike_sa
, this->peer_id
,
424 this->connect_id
) != SUCCESS
)
438 * Implementation of task_t.process for initiator
440 static status_t
process_i(private_ike_me_t
*this, message_t
*message
)
442 switch(message
->get_exchange_type(message
))
446 process_payloads(this, message
);
448 if (!this->mediation
)
450 DBG1(DBG_IKE
, "server did not return a ME_MEDIATION, aborting");
458 process_payloads(this, message
);
459 /* FIXME: we should update the server reflexive endpoint somehow,
460 * if mobike notices a change */
461 endpoint_notify_t
*reflexive
;
462 if (this->remote_endpoints
->get_first(this->remote_endpoints
,
463 (void**)&reflexive
) == SUCCESS
&&
464 reflexive
->get_type(reflexive
) == SERVER_REFLEXIVE
)
465 { /* FIXME: should we accept this endpoint even if we did not send
467 host_t
*endpoint
= reflexive
->get_host(reflexive
);
469 this->ike_sa
->set_server_reflexive_host(this->ike_sa
, endpoint
->clone(endpoint
));
471 /* FIXME: what if it failed? e.g. AUTH failure */
472 SIG(CHILD_UP_SUCCESS
, "established mediation connection without CHILD_SA successfully");
478 process_payloads(this, message
);
482 DBG1(DBG_IKE
, "peer '%D' is not online", this->peer_id
);
483 /* FIXME: notify the mediated connection (job?) */
489 /* FIXME: handle result of set_responder_data.
490 * as responder, we update the checklist and start sending checks */
491 charon
->connect_manager
->set_responder_data(charon
->connect_manager
,
492 this->connect_id
, this->connect_key
, this->local_endpoints
);
496 /* FIXME: handle result of set_initiator_data
497 * as initiator, we create a checklist and set the initiator's data */
498 charon
->connect_manager
->set_initiator_data(charon
->connect_manager
,
499 this->ike_sa
->get_my_id(this->ike_sa
), this->peer_id
,
500 this->connect_id
, this->connect_key
, this->local_endpoints
,
502 /* FIXME: also start a timer for the whole transaction (maybe
503 * within the connect_manager?) */
515 * Implementation of task_t.build for initiator (mediation server)
517 static status_t
build_i_ms(private_ike_me_t
*this, message_t
*message
)
519 switch(message
->get_exchange_type(message
))
523 id_payload_t
*id_payload
= id_payload_create_from_identification(ID_PEER
, this->peer_id
);
524 message
->add_payload(message
, (payload_t
*)id_payload
);
528 message
->add_notify(message
, FALSE
, ME_CALLBACK
, chunk_empty
);
534 message
->add_notify(message
, FALSE
, ME_RESPONSE
, chunk_empty
);
536 message
->add_notify(message
, FALSE
, ME_CONNECTID
, this->connect_id
);
537 message
->add_notify(message
, FALSE
, ME_CONNECTKEY
, this->connect_key
);
539 add_endpoints_to_message(message
, this->remote_endpoints
);
551 * Implementation of task_t.process for responder (mediation server)
553 static status_t
process_r_ms(private_ike_me_t
*this, message_t
*message
)
555 switch(message
->get_exchange_type(message
))
559 /* FIXME: we should check for SA* and TS* payloads
560 * if any are there send NO_ADDITIONAL_SAS back and delete this SA */
561 process_payloads(this, message
);
562 return this->mediation ? NEED_MORE
: SUCCESS
;
566 /* FIXME: we should check whether the current peer_config is configured
567 * as mediation connection */
568 process_payloads(this, message
);
571 case CREATE_CHILD_SA
:
573 /* FIXME: if this is not to rekey the IKE SA we have to return a
574 * NO_ADDITIONAL_SAS and then delete the SA */
579 id_payload_t
*id_payload
;
580 id_payload
= (id_payload_t
*)message
->get_payload(message
, ID_PEER
);
583 DBG1(DBG_IKE
, "received ME_CONNECT without ID_PEER payload, aborting");
584 this->invalid_syntax
= TRUE
;
588 this->peer_id
= id_payload
->get_identification(id_payload
);
590 process_payloads(this, message
);
592 if (!this->connect_id
.ptr
)
594 DBG1(DBG_IKE
, "received ME_CONNECT without ME_CONNECTID notify, aborting");
595 this->invalid_syntax
= TRUE
;
599 if (!this->connect_key
.ptr
)
601 DBG1(DBG_IKE
, "received ME_CONNECT without ME_CONNECTKEY notify, aborting");
602 this->invalid_syntax
= TRUE
;
606 if (!this->remote_endpoints
->get_count(this->remote_endpoints
))
608 DBG1(DBG_IKE
, "received ME_CONNECT without any ME_ENDPOINT payloads, aborting");
609 this->invalid_syntax
= TRUE
;
622 * Implementation of task_t.build for responder (mediation server)
624 static status_t
build_r_ms(private_ike_me_t
*this, message_t
*message
)
626 switch(message
->get_exchange_type(message
))
630 message
->add_notify(message
, FALSE
, ME_MEDIATION
, chunk_empty
);
635 endpoint_notify_t
*endpoint
;
636 if (this->remote_endpoints
->get_first(this->remote_endpoints
, (void**)&endpoint
) == SUCCESS
&&
637 endpoint
->get_type(endpoint
) == SERVER_REFLEXIVE
)
639 host_t
*host
= this->ike_sa
->get_other_host(this->ike_sa
);
641 DBG2(DBG_IKE
, "received request for a server reflexive endpoint "
642 "sending: %#H", host
);
644 endpoint
= endpoint_notify_create_from_host(SERVER_REFLEXIVE
, host
, NULL
);
645 message
->add_payload(message
, (payload_t
*)endpoint
->build_notify(endpoint
));
646 endpoint
->destroy(endpoint
);
649 /* FIXME: we actually must delete any existing IKE_SAs with the same remote id */
650 this->ike_sa
->act_as_mediation_server(this->ike_sa
);
652 SIG(CHILD_UP_SUCCESS
, "established mediation connection without CHILD_SA successfully");
658 if (this->invalid_syntax
)
660 message
->add_notify(message
, TRUE
, INVALID_SYNTAX
, chunk_empty
);
664 ike_sa_id_t
*peer_sa
;
667 peer_sa
= charon
->mediation_manager
->check_and_register(charon
->mediation_manager
,
668 this->peer_id
, this->ike_sa
->get_other_id(this->ike_sa
));
672 peer_sa
= charon
->mediation_manager
->check(charon
->mediation_manager
,
678 /* the peer is not online */
679 message
->add_notify(message
, TRUE
, ME_CONNECT_FAILED
, chunk_empty
);
683 job_t
*job
= (job_t
*)mediation_job_create(this->peer_id
,
684 this->ike_sa
->get_other_id(this->ike_sa
), this->connect_id
,
685 this->connect_key
, this->remote_endpoints
, this->response
);
686 charon
->processor
->queue_job(charon
->processor
, job
);
697 * Implementation of task_t.process for initiator (mediation server)
699 static status_t
process_i_ms(private_ike_me_t
*this, message_t
*message
)
701 /* FIXME: theoretically we should be prepared to receive a ME_CONNECT_FAILED
702 * here if the responding peer is not able to proceed. in this case we shall
703 * notify the initiating peer with a ME_CONNECT request containing only a
704 * ME_CONNECT_FAILED */
709 * Implementation of ike_me.connect
711 static void me_connect(private_ike_me_t
*this, identification_t
*peer_id
)
713 this->peer_id
= peer_id
->clone(peer_id
);
717 * Implementation of ike_me.respond
719 static void me_respond(private_ike_me_t
*this, identification_t
*peer_id
,
722 this->peer_id
= peer_id
->clone(peer_id
);
723 this->connect_id
= chunk_clone(connect_id
);
724 this->response
= TRUE
;
728 * Implementation of ike_me.callback
730 static void me_callback(private_ike_me_t
*this, identification_t
*peer_id
)
732 this->peer_id
= peer_id
->clone(peer_id
);
733 this->callback
= TRUE
;
737 * Implementation of ike_me.relay
739 static void relay(private_ike_me_t
*this, identification_t
*requester
, chunk_t connect_id
,
740 chunk_t connect_key
, linked_list_t
*endpoints
, bool response
)
742 this->peer_id
= requester
->clone(requester
);
743 this->connect_id
= chunk_clone(connect_id
);
744 this->connect_key
= chunk_clone(connect_key
);
746 this->remote_endpoints
->destroy_offset(this->remote_endpoints
, offsetof(endpoint_notify_t
, destroy
));
747 this->remote_endpoints
= endpoints
->clone_offset(endpoints
, offsetof(endpoint_notify_t
, clone
));
749 this->response
= response
;
753 * Implementation of task_t.get_type
755 static task_type_t
get_type(private_ike_me_t
*this)
761 * Implementation of task_t.migrate
763 static void migrate(private_ike_me_t
*this, ike_sa_t
*ike_sa
)
765 this->ike_sa
= ike_sa
;
769 * Implementation of task_t.destroy
771 static void destroy(private_ike_me_t
*this)
773 DESTROY_IF(this->peer_id
);
775 chunk_free(&this->connect_id
);
776 chunk_free(&this->connect_key
);
778 this->local_endpoints
->destroy_offset(this->local_endpoints
, offsetof(endpoint_notify_t
, destroy
));
779 this->remote_endpoints
->destroy_offset(this->remote_endpoints
, offsetof(endpoint_notify_t
, destroy
));
781 DESTROY_IF(this->mediated_cfg
);
786 * Described in header.
788 ike_me_t
*ike_me_create(ike_sa_t
*ike_sa
, bool initiator
)
790 private_ike_me_t
*this = malloc_thing(private_ike_me_t
);
792 this->public.task
.get_type
= (task_type_t(*)(task_t
*))get_type
;
793 this->public.task
.migrate
= (void(*)(task_t
*,ike_sa_t
*))migrate
;
794 this->public.task
.destroy
= (void(*)(task_t
*))destroy
;
796 if (ike_sa
->is_ike_initiator(ike_sa
))
800 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_i
;
801 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_i
;
805 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_r
;
806 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_r
;
811 /* mediation server */
814 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_i_ms
;
815 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_i_ms
;
819 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_r_ms
;
820 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_r_ms
;
824 this->public.connect
= (void(*)(ike_me_t
*,identification_t
*))me_connect
;
825 this->public.respond
= (void(*)(ike_me_t
*,identification_t
*,chunk_t
))me_respond
;
826 this->public.callback
= (void(*)(ike_me_t
*,identification_t
*))me_callback
;
827 this->public.relay
= (void(*)(ike_me_t
*,identification_t
*,chunk_t
,chunk_t
,linked_list_t
*,bool))relay
;
829 this->ike_sa
= ike_sa
;
830 this->initiator
= initiator
;
832 this->peer_id
= NULL
;
833 this->connect_id
= chunk_empty
;
834 this->connect_key
= chunk_empty
;
835 this->local_endpoints
= linked_list_create();
836 this->remote_endpoints
= linked_list_create();
837 this->mediation
= FALSE
;
838 this->response
= FALSE
;
839 this->callback
= FALSE
;
840 this->failed
= FALSE
;
841 this->invalid_syntax
= FALSE
;
843 this->mediated_cfg
= NULL
;
845 return &this->public;