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
22 #include <config/peer_cfg.h>
23 #include <encoding/payloads/id_payload.h>
24 #include <encoding/payloads/notify_payload.h>
25 #include <encoding/payloads/endpoint_notify.h>
26 #include <processing/jobs/mediation_job.h>
28 #define ME_CONNECTID_LEN 4
29 #define ME_CONNECTKEY_LEN 16
31 typedef struct private_ike_me_t private_ike_me_t
;
34 * Private members of a ike_me_t task.
36 struct private_ike_me_t
{
39 * Public methods and task_t interface.
49 * Are we the initiator?
54 * Is this a mediation connection?
59 * Is this the response from another peer?
66 linked_list_t
*local_endpoints
;
71 linked_list_t
*remote_endpoints
;
74 * Did the peer request a callback?
79 * Did the connect fail?
84 * Was there anything wrong with the payloads?
91 identification_t
*peer_id
;
93 * Received ID used for connectivity checks
98 * Received key used for connectivity checks
103 * Peer config of the mediated connection
105 peer_cfg_t
*mediated_cfg
;
110 * Adds a list of endpoints as notifies to a given message
112 static void add_endpoints_to_message(message_t
*message
, linked_list_t
*endpoints
)
114 enumerator_t
*enumerator
;
115 endpoint_notify_t
*endpoint
;
117 enumerator
= endpoints
->create_enumerator(endpoints
);
118 while (enumerator
->enumerate(enumerator
, (void**)&endpoint
))
120 message
->add_payload(message
, (payload_t
*)endpoint
->build_notify(endpoint
));
122 enumerator
->destroy(enumerator
);
126 * Gathers endpoints and adds them to the current message
128 static void gather_and_add_endpoints(private_ike_me_t
*this, message_t
*message
)
130 enumerator_t
*enumerator
;
134 /* get the port that is used to communicate with the ms */
135 host
= this->ike_sa
->get_my_host(this->ike_sa
);
136 port
= host
->get_port(host
);
138 enumerator
= hydra
->kernel_interface
->create_address_enumerator(
139 hydra
->kernel_interface
, FALSE
, FALSE
);
140 while (enumerator
->enumerate(enumerator
, (void**)&addr
))
142 host
= addr
->clone(addr
);
143 host
->set_port(host
, port
);
145 this->local_endpoints
->insert_last(this->local_endpoints
,
146 endpoint_notify_create_from_host(HOST
, host
, NULL
));
150 enumerator
->destroy(enumerator
);
152 host
= this->ike_sa
->get_server_reflexive_host(this->ike_sa
);
155 this->local_endpoints
->insert_last(this->local_endpoints
,
156 endpoint_notify_create_from_host(SERVER_REFLEXIVE
, host
,
157 this->ike_sa
->get_my_host(this->ike_sa
)));
160 add_endpoints_to_message(message
, this->local_endpoints
);
164 * read notifys from message and evaluate them
166 static void process_payloads(private_ike_me_t
*this, message_t
*message
)
168 enumerator_t
*enumerator
;
171 enumerator
= message
->create_payload_enumerator(message
);
172 while (enumerator
->enumerate(enumerator
, &payload
))
174 if (payload
->get_type(payload
) != NOTIFY
)
179 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
181 switch (notify
->get_notify_type(notify
))
183 case ME_CONNECT_FAILED
:
185 DBG2(DBG_IKE
, "received ME_CONNECT_FAILED notify");
191 DBG2(DBG_IKE
, "received ME_MEDIATION notify");
192 this->mediation
= TRUE
;
197 endpoint_notify_t
*endpoint
;
198 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",
205 me_endpoint_type_names
, endpoint
->get_type(endpoint
),
206 endpoint
->get_host(endpoint
));
208 this->remote_endpoints
->insert_last(this->remote_endpoints
,
214 DBG2(DBG_IKE
, "received ME_CALLBACK notify");
215 this->callback
= TRUE
;
220 chunk_free(&this->connect_id
);
221 this->connect_id
= chunk_clone(notify
->get_notification_data(notify
));
222 DBG2(DBG_IKE
, "received ME_CONNECTID %#B", &this->connect_id
);
227 chunk_free(&this->connect_key
);
228 this->connect_key
= chunk_clone(notify
->get_notification_data(notify
));
229 DBG4(DBG_IKE
, "received ME_CONNECTKEY %#B", &this->connect_key
);
234 DBG2(DBG_IKE
, "received ME_RESPONSE notify");
235 this->response
= TRUE
;
242 enumerator
->destroy(enumerator
);
245 METHOD(task_t
, build_i
, status_t
,
246 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
;
269 endpoint
= endpoint_notify_create_from_host(SERVER_REFLEXIVE
,
271 message
->add_payload(message
, (payload_t
*)endpoint
->build_notify(endpoint
));
272 endpoint
->destroy(endpoint
);
279 id_payload_t
*id_payload
;
280 id_payload
= id_payload_create_from_identification(ID_PEER
,
282 message
->add_payload(message
, (payload_t
*)id_payload
);
284 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_STRONG
);
287 DBG1(DBG_IKE
, "unable to generate connect ID for ME_CONNECT");
292 /* only the initiator creates a connect ID. the responder
293 * returns the connect ID that it received from the initiator */
294 rng
->allocate_bytes(rng
, ME_CONNECTID_LEN
, &this->connect_id
);
296 rng
->allocate_bytes(rng
, ME_CONNECTKEY_LEN
, &this->connect_key
);
299 message
->add_notify(message
, FALSE
, ME_CONNECTID
, this->connect_id
);
300 message
->add_notify(message
, FALSE
, ME_CONNECTKEY
, this->connect_key
);
304 message
->add_notify(message
, FALSE
, ME_RESPONSE
, chunk_empty
);
308 /* FIXME: should we make this configurable? */
309 message
->add_notify(message
, FALSE
, ME_CALLBACK
, chunk_empty
);
312 gather_and_add_endpoints(this, message
);
322 METHOD(task_t
, process_r
, status_t
,
323 private_ike_me_t
*this, message_t
*message
)
325 switch(message
->get_exchange_type(message
))
329 id_payload_t
*id_payload
;
330 id_payload
= (id_payload_t
*)message
->get_payload(message
, ID_PEER
);
333 DBG1(DBG_IKE
, "received ME_CONNECT without ID_PEER payload"
337 this->peer_id
= id_payload
->get_identification(id_payload
);
339 process_payloads(this, message
);
343 DBG1(DBG_IKE
, "received ME_CALLBACK for '%Y'", this->peer_id
);
347 if (!this->connect_id
.ptr
)
349 DBG1(DBG_IKE
, "received ME_CONNECT without ME_CONNECTID notify"
351 this->invalid_syntax
= TRUE
;
355 if (!this->connect_key
.ptr
)
357 DBG1(DBG_IKE
, "received ME_CONNECT without ME_CONNECTKEY "
359 this->invalid_syntax
= TRUE
;
363 if (!this->remote_endpoints
->get_count(this->remote_endpoints
))
365 DBG1(DBG_IKE
, "received ME_CONNECT without any ME_ENDPOINT "
366 "payloads, aborting");
367 this->invalid_syntax
= TRUE
;
371 DBG1(DBG_IKE
, "received ME_CONNECT");
380 METHOD(task_t
, build_r
, status_t
,
381 private_ike_me_t
*this, message_t
*message
)
383 switch(message
->get_exchange_type(message
))
387 if (this->invalid_syntax
)
389 message
->add_notify(message
, TRUE
, INVALID_SYNTAX
, chunk_empty
);
395 /* we got a callback from the mediation server, initiate the
396 * queued mediated connecction */
397 charon
->connect_manager
->check_and_initiate(
398 charon
->connect_manager
,
399 this->ike_sa
->get_id(this->ike_sa
),
400 this->ike_sa
->get_my_id(this->ike_sa
), this->peer_id
);
406 /* FIXME: handle result of set_responder_data
407 * as initiator, upon receiving a response from another peer,
408 * update the checklist and start sending checks */
409 charon
->connect_manager
->set_responder_data(
410 charon
->connect_manager
,
411 this->connect_id
, this->connect_key
,
412 this->remote_endpoints
);
416 /* FIXME: handle result of set_initiator_data
417 * as responder, create a checklist with the initiator's data */
418 charon
->connect_manager
->set_initiator_data(
419 charon
->connect_manager
,
420 this->peer_id
, this->ike_sa
->get_my_id(this->ike_sa
),
421 this->connect_id
, this->connect_key
,
422 this->remote_endpoints
, FALSE
);
423 if (this->ike_sa
->respond(this->ike_sa
, this->peer_id
,
424 this->connect_id
) != SUCCESS
)
437 METHOD(task_t
, process_i
, status_t
,
438 private_ike_me_t
*this, message_t
*message
)
440 switch(message
->get_exchange_type(message
))
444 process_payloads(this, message
);
445 if (!this->mediation
)
447 DBG1(DBG_IKE
, "server did not return a ME_MEDIATION, aborting");
450 /* if we are on a mediation connection we switch to port 4500 even
451 * if no NAT is detected. */
452 this->ike_sa
->float_ports(this->ike_sa
);
457 process_payloads(this, message
);
458 /* FIXME: we should update the server reflexive endpoint somehow,
459 * if mobike notices a change */
460 endpoint_notify_t
*reflexive
;
461 if (this->remote_endpoints
->get_first(this->remote_endpoints
,
462 (void**)&reflexive
) == SUCCESS
&&
463 reflexive
->get_type(reflexive
) == SERVER_REFLEXIVE
)
464 { /* FIXME: should we accept this endpoint even if we did not send
466 host_t
*endpoint
= reflexive
->get_host(reflexive
);
467 endpoint
= endpoint
->clone(endpoint
);
468 this->ike_sa
->set_server_reflexive_host(this->ike_sa
, endpoint
);
474 process_payloads(this, message
);
478 DBG1(DBG_IKE
, "peer '%Y' is not online", this->peer_id
);
479 /* FIXME: notify the mediated connection (job?) */
485 /* FIXME: handle result of set_responder_data. */
486 /* as responder, we update the checklist and start sending
488 charon
->connect_manager
->set_responder_data(
489 charon
->connect_manager
, this->connect_id
,
490 this->connect_key
, this->local_endpoints
);
494 /* FIXME: handle result of set_initiator_data */
495 /* as initiator, we create a checklist and set the
496 * initiator's data */
497 charon
->connect_manager
->set_initiator_data(
498 charon
->connect_manager
,
499 this->ike_sa
->get_my_id(this->ike_sa
),
500 this->peer_id
, this->connect_id
, this->connect_key
,
501 this->local_endpoints
, TRUE
);
502 /* FIXME: also start a timer for the whole transaction
503 * (maybe within the connect_manager?) */
515 * For mediation server
517 METHOD(task_t
, build_i_ms
, status_t
,
518 private_ike_me_t
*this, message_t
*message
)
520 switch(message
->get_exchange_type(message
))
524 id_payload_t
*id_payload
;
525 id_payload
= id_payload_create_from_identification(ID_PEER
,
527 message
->add_payload(message
, (payload_t
*)id_payload
);
531 message
->add_notify(message
, FALSE
, ME_CALLBACK
, chunk_empty
);
537 message
->add_notify(message
, FALSE
, ME_RESPONSE
,
540 message
->add_notify(message
, FALSE
, ME_CONNECTID
,
542 message
->add_notify(message
, FALSE
, ME_CONNECTKEY
,
544 add_endpoints_to_message(message
, this->remote_endpoints
);
555 * For mediation server
557 METHOD(task_t
, process_r_ms
, status_t
,
558 private_ike_me_t
*this, message_t
*message
)
560 switch(message
->get_exchange_type(message
))
564 /* FIXME: we should check for SA* and TS* payloads. if there are
565 * any, send NO_ADDITIONAL_SAS back and delete this SA */
566 process_payloads(this, message
);
567 return this->mediation ? NEED_MORE
: SUCCESS
;
571 /* FIXME: we should check whether the current peer_config is
572 * configured as mediation connection */
573 process_payloads(this, message
);
576 case CREATE_CHILD_SA
:
578 /* FIXME: if this is not to rekey the IKE SA we have to return a
579 * NO_ADDITIONAL_SAS and then delete the SA */
584 id_payload_t
*id_payload
;
585 id_payload
= (id_payload_t
*)message
->get_payload(message
, ID_PEER
);
588 DBG1(DBG_IKE
, "received ME_CONNECT without ID_PEER payload"
590 this->invalid_syntax
= TRUE
;
593 this->peer_id
= id_payload
->get_identification(id_payload
);
595 process_payloads(this, message
);
597 if (!this->connect_id
.ptr
)
599 DBG1(DBG_IKE
, "received ME_CONNECT without ME_CONNECTID notify"
601 this->invalid_syntax
= TRUE
;
605 if (!this->connect_key
.ptr
)
607 DBG1(DBG_IKE
, "received ME_CONNECT without ME_CONNECTKEY notify"
609 this->invalid_syntax
= TRUE
;
613 if (!this->remote_endpoints
->get_count(this->remote_endpoints
))
615 DBG1(DBG_IKE
, "received ME_CONNECT without any ME_ENDPOINT "
616 "payloads, aborting");
617 this->invalid_syntax
= TRUE
;
629 * For mediation server
631 METHOD(task_t
, build_r_ms
, status_t
,
632 private_ike_me_t
*this, message_t
*message
)
634 switch(message
->get_exchange_type(message
))
638 message
->add_notify(message
, FALSE
, ME_MEDIATION
, chunk_empty
);
643 endpoint_notify_t
*endpoint
;
644 if (this->remote_endpoints
->get_first(this->remote_endpoints
,
645 (void**)&endpoint
) == SUCCESS
&&
646 endpoint
->get_type(endpoint
) == SERVER_REFLEXIVE
)
648 host_t
*host
= this->ike_sa
->get_other_host(this->ike_sa
);
649 DBG2(DBG_IKE
, "received request for a server reflexive "
650 "endpoint sending: %#H", host
);
651 endpoint
= endpoint_notify_create_from_host(SERVER_REFLEXIVE
,
653 message
->add_payload(message
, (payload_t
*)endpoint
->build_notify(endpoint
));
654 endpoint
->destroy(endpoint
);
656 this->ike_sa
->act_as_mediation_server(this->ike_sa
);
661 if (this->invalid_syntax
)
663 message
->add_notify(message
, TRUE
, INVALID_SYNTAX
, chunk_empty
);
667 ike_sa_id_t
*peer_sa
;
670 peer_sa
= charon
->mediation_manager
->check_and_register(
671 charon
->mediation_manager
, this->peer_id
,
672 this->ike_sa
->get_other_id(this->ike_sa
));
676 peer_sa
= charon
->mediation_manager
->check(
677 charon
->mediation_manager
, this->peer_id
);
682 /* the peer is not online */
683 message
->add_notify(message
, TRUE
, ME_CONNECT_FAILED
,
688 job_t
*job
= (job_t
*)mediation_job_create(this->peer_id
,
689 this->ike_sa
->get_other_id(this->ike_sa
), this->connect_id
,
690 this->connect_key
, this->remote_endpoints
, this->response
);
691 lib
->processor
->queue_job(lib
->processor
, job
);
701 * For mediation server
703 METHOD(task_t
, process_i_ms
, status_t
,
704 private_ike_me_t
*this, message_t
*message
)
706 /* FIXME: theoretically we should be prepared to receive a ME_CONNECT_FAILED
707 * here if the responding peer is not able to proceed. in this case we shall
708 * notify the initiating peer with a ME_CONNECT request containing only a
709 * ME_CONNECT_FAILED */
713 METHOD(ike_me_t
, me_connect
, void,
714 private_ike_me_t
*this, identification_t
*peer_id
)
716 this->peer_id
= peer_id
->clone(peer_id
);
719 METHOD(ike_me_t
, me_respond
, void,
720 private_ike_me_t
*this, identification_t
*peer_id
, chunk_t connect_id
)
722 this->peer_id
= peer_id
->clone(peer_id
);
723 this->connect_id
= chunk_clone(connect_id
);
724 this->response
= TRUE
;
727 METHOD(ike_me_t
, me_callback
, void,
728 private_ike_me_t
*this, identification_t
*peer_id
)
730 this->peer_id
= peer_id
->clone(peer_id
);
731 this->callback
= TRUE
;
734 METHOD(ike_me_t
, relay
, void,
735 private_ike_me_t
*this, identification_t
*requester
, chunk_t connect_id
,
736 chunk_t connect_key
, linked_list_t
*endpoints
, bool response
)
738 this->peer_id
= requester
->clone(requester
);
739 this->connect_id
= chunk_clone(connect_id
);
740 this->connect_key
= chunk_clone(connect_key
);
742 this->remote_endpoints
->destroy_offset(this->remote_endpoints
,
743 offsetof(endpoint_notify_t
, destroy
));
744 this->remote_endpoints
= endpoints
->clone_offset(endpoints
,
745 offsetof(endpoint_notify_t
, clone
));
747 this->response
= response
;
750 METHOD(task_t
, get_type
, task_type_t
,
751 private_ike_me_t
*this)
756 METHOD(task_t
, migrate
, void,
757 private_ike_me_t
*this, ike_sa_t
*ike_sa
)
759 this->ike_sa
= ike_sa
;
762 METHOD(tast_t
, destroy
, void,
763 private_ike_me_t
*this)
765 DESTROY_IF(this->peer_id
);
767 chunk_free(&this->connect_id
);
768 chunk_free(&this->connect_key
);
770 this->local_endpoints
->destroy_offset(this->local_endpoints
,
771 offsetof(endpoint_notify_t
, destroy
));
772 this->remote_endpoints
->destroy_offset(this->remote_endpoints
,
773 offsetof(endpoint_notify_t
, destroy
));
775 DESTROY_IF(this->mediated_cfg
);
780 * Described in header.
782 ike_me_t
*ike_me_create(ike_sa_t
*ike_sa
, bool initiator
)
784 private_ike_me_t
*this;
789 .get_type
= _get_type
,
793 .connect
= _me_connect
,
794 .respond
= _me_respond
,
795 .callback
= _me_callback
,
799 .initiator
= initiator
,
800 .local_endpoints
= linked_list_create(),
801 .remote_endpoints
= linked_list_create(),
804 if (ike_sa
->has_condition(ike_sa
, COND_ORIGINAL_INITIATOR
))
808 this->public.task
.build
= _build_i
;
809 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_i
;
813 this->public.task
.build
= _build_r
;
814 this->public.task
.process
= _process_r
;
819 /* mediation server */
822 this->public.task
.build
= _build_i_ms
;
823 this->public.task
.process
= _process_i_ms
;
827 this->public.task
.build
= _build_r_ms
;
828 this->public.task
.process
= _process_r_ms
;
832 return &this->public;