a7e7505a19a9a133825333169b67c8e94e70e539
[strongswan.git] / src / libcharon / sa / ikev2 / tasks / ike_me.c
1 /*
2 * Copyright (C) 2007-2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "ike_me.h"
17
18 #include <string.h>
19
20 #include <hydra.h>
21 #include <daemon.h>
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>
27
28 #define ME_CONNECTID_LEN 4
29 #define ME_CONNECTKEY_LEN 16
30
31 typedef struct private_ike_me_t private_ike_me_t;
32
33 /**
34 * Private members of a ike_me_t task.
35 */
36 struct private_ike_me_t {
37
38 /**
39 * Public methods and task_t interface.
40 */
41 ike_me_t public;
42
43 /**
44 * Assigned IKE_SA.
45 */
46 ike_sa_t *ike_sa;
47
48 /**
49 * Are we the initiator?
50 */
51 bool initiator;
52
53 /**
54 * Is this a mediation connection?
55 */
56 bool mediation;
57
58 /**
59 * Is this the response from another peer?
60 */
61 bool response;
62
63 /**
64 * Gathered endpoints
65 */
66 linked_list_t *local_endpoints;
67
68 /**
69 * Parsed endpoints
70 */
71 linked_list_t *remote_endpoints;
72
73 /**
74 * Did the peer request a callback?
75 */
76 bool callback;
77
78 /**
79 * Did the connect fail?
80 */
81 bool failed;
82
83 /**
84 * Was there anything wrong with the payloads?
85 */
86 bool invalid_syntax;
87
88 /**
89 * The requested peer
90 */
91 identification_t *peer_id;
92 /**
93 * Received ID used for connectivity checks
94 */
95 chunk_t connect_id;
96
97 /**
98 * Received key used for connectivity checks
99 */
100 chunk_t connect_key;
101
102 /**
103 * Peer config of the mediated connection
104 */
105 peer_cfg_t *mediated_cfg;
106
107 };
108
109 /**
110 * Adds a list of endpoints as notifies to a given message
111 */
112 static void add_endpoints_to_message(message_t *message, linked_list_t *endpoints)
113 {
114 enumerator_t *enumerator;
115 endpoint_notify_t *endpoint;
116
117 enumerator = endpoints->create_enumerator(endpoints);
118 while (enumerator->enumerate(enumerator, (void**)&endpoint))
119 {
120 message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint));
121 }
122 enumerator->destroy(enumerator);
123 }
124
125 /**
126 * Gathers endpoints and adds them to the current message
127 */
128 static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message)
129 {
130 enumerator_t *enumerator;
131 host_t *addr, *host;
132 u_int16_t port;
133
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);
137
138 enumerator = hydra->kernel_interface->create_address_enumerator(
139 hydra->kernel_interface, ADDR_TYPE_REGULAR);
140 while (enumerator->enumerate(enumerator, (void**)&addr))
141 {
142 host = addr->clone(addr);
143 host->set_port(host, port);
144
145 this->local_endpoints->insert_last(this->local_endpoints,
146 endpoint_notify_create_from_host(HOST, host, NULL));
147
148 host->destroy(host);
149 }
150 enumerator->destroy(enumerator);
151
152 host = this->ike_sa->get_server_reflexive_host(this->ike_sa);
153 if (host)
154 {
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)));
158 }
159
160 add_endpoints_to_message(message, this->local_endpoints);
161 }
162
163 /**
164 * read notifys from message and evaluate them
165 */
166 static void process_payloads(private_ike_me_t *this, message_t *message)
167 {
168 enumerator_t *enumerator;
169 payload_t *payload;
170
171 enumerator = message->create_payload_enumerator(message);
172 while (enumerator->enumerate(enumerator, &payload))
173 {
174 if (payload->get_type(payload) != PLV2_NOTIFY)
175 {
176 continue;
177 }
178
179 notify_payload_t *notify = (notify_payload_t*)payload;
180
181 switch (notify->get_notify_type(notify))
182 {
183 case ME_CONNECT_FAILED:
184 {
185 DBG2(DBG_IKE, "received ME_CONNECT_FAILED notify");
186 this->failed = TRUE;
187 break;
188 }
189 case ME_MEDIATION:
190 {
191 DBG2(DBG_IKE, "received ME_MEDIATION notify");
192 this->mediation = TRUE;
193 break;
194 }
195 case ME_ENDPOINT:
196 {
197 endpoint_notify_t *endpoint;
198 endpoint = endpoint_notify_create_from_payload(notify);
199 if (!endpoint)
200 {
201 DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify");
202 break;
203 }
204 DBG1(DBG_IKE, "received %N ME_ENDPOINT %#H",
205 me_endpoint_type_names, endpoint->get_type(endpoint),
206 endpoint->get_host(endpoint));
207
208 this->remote_endpoints->insert_last(this->remote_endpoints,
209 endpoint);
210 break;
211 }
212 case ME_CALLBACK:
213 {
214 DBG2(DBG_IKE, "received ME_CALLBACK notify");
215 this->callback = TRUE;
216 break;
217 }
218 case ME_CONNECTID:
219 {
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);
223 break;
224 }
225 case ME_CONNECTKEY:
226 {
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);
230 break;
231 }
232 case ME_RESPONSE:
233 {
234 DBG2(DBG_IKE, "received ME_RESPONSE notify");
235 this->response = TRUE;
236 break;
237 }
238 default:
239 break;
240 }
241 }
242 enumerator->destroy(enumerator);
243 }
244
245 METHOD(task_t, build_i, status_t,
246 private_ike_me_t *this, message_t *message)
247 {
248 switch(message->get_exchange_type(message))
249 {
250 case IKE_SA_INIT:
251 {
252 peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
253 if (peer_cfg->is_mediation(peer_cfg))
254 {
255 DBG2(DBG_IKE, "adding ME_MEDIATION");
256 message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty);
257 }
258 else
259 {
260 return SUCCESS;
261 }
262 break;
263 }
264 case IKE_AUTH:
265 {
266 if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE))
267 {
268 endpoint_notify_t *endpoint;
269 endpoint = endpoint_notify_create_from_host(SERVER_REFLEXIVE,
270 NULL, NULL);
271 message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint));
272 endpoint->destroy(endpoint);
273 }
274 break;
275 }
276 case ME_CONNECT:
277 {
278 rng_t *rng;
279 id_payload_t *id_payload;
280 id_payload = id_payload_create_from_identification(PLV2_ID_PEER,
281 this->peer_id);
282 message->add_payload(message, (payload_t*)id_payload);
283
284 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
285 if (!rng)
286 {
287 DBG1(DBG_IKE, "unable to generate connect ID for ME_CONNECT");
288 return FAILED;
289 }
290 if (!this->response)
291 {
292 /* only the initiator creates a connect ID. the responder
293 * returns the connect ID that it received from the initiator */
294 if (!rng->allocate_bytes(rng, ME_CONNECTID_LEN,
295 &this->connect_id))
296 {
297 DBG1(DBG_IKE, "unable to generate ID for ME_CONNECT");
298 rng->destroy(rng);
299 return FAILED;
300 }
301 }
302 if (!rng->allocate_bytes(rng, ME_CONNECTKEY_LEN,
303 &this->connect_key))
304 {
305 DBG1(DBG_IKE, "unable to generate connect key for ME_CONNECT");
306 rng->destroy(rng);
307 return FAILED;
308 }
309 rng->destroy(rng);
310
311 message->add_notify(message, FALSE, ME_CONNECTID, this->connect_id);
312 message->add_notify(message, FALSE, ME_CONNECTKEY, this->connect_key);
313
314 if (this->response)
315 {
316 message->add_notify(message, FALSE, ME_RESPONSE, chunk_empty);
317 }
318 else
319 {
320 /* FIXME: should we make this configurable? */
321 message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty);
322 }
323
324 gather_and_add_endpoints(this, message);
325
326 break;
327 }
328 default:
329 break;
330 }
331 return NEED_MORE;
332 }
333
334 METHOD(task_t, process_r, status_t,
335 private_ike_me_t *this, message_t *message)
336 {
337 switch(message->get_exchange_type(message))
338 {
339 case ME_CONNECT:
340 {
341 id_payload_t *id_payload;
342 id_payload = (id_payload_t*)message->get_payload(message, PLV2_ID_PEER);
343 if (!id_payload)
344 {
345 DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload"
346 ", aborting");
347 break;
348 }
349 this->peer_id = id_payload->get_identification(id_payload);
350
351 process_payloads(this, message);
352
353 if (this->callback)
354 {
355 DBG1(DBG_IKE, "received ME_CALLBACK for '%Y'", this->peer_id);
356 break;
357 }
358
359 if (!this->connect_id.ptr)
360 {
361 DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify"
362 ", aborting");
363 this->invalid_syntax = TRUE;
364 break;
365 }
366
367 if (!this->connect_key.ptr)
368 {
369 DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY "
370 "notify, aborting");
371 this->invalid_syntax = TRUE;
372 break;
373 }
374
375 if (!this->remote_endpoints->get_count(this->remote_endpoints))
376 {
377 DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT "
378 "payloads, aborting");
379 this->invalid_syntax = TRUE;
380 break;
381 }
382
383 DBG1(DBG_IKE, "received ME_CONNECT");
384 break;
385 }
386 default:
387 break;
388 }
389 return NEED_MORE;
390 }
391
392 METHOD(task_t, build_r, status_t,
393 private_ike_me_t *this, message_t *message)
394 {
395 switch(message->get_exchange_type(message))
396 {
397 case ME_CONNECT:
398 {
399 if (this->invalid_syntax)
400 {
401 message->add_notify(message, TRUE, INVALID_SYNTAX, chunk_empty);
402 break;
403 }
404
405 if (this->callback)
406 {
407 /* we got a callback from the mediation server, initiate the
408 * queued mediated connecction */
409 charon->connect_manager->check_and_initiate(
410 charon->connect_manager,
411 this->ike_sa->get_id(this->ike_sa),
412 this->ike_sa->get_my_id(this->ike_sa), this->peer_id);
413 return SUCCESS;
414 }
415
416 if (this->response)
417 {
418 /* FIXME: handle result of set_responder_data
419 * as initiator, upon receiving a response from another peer,
420 * update the checklist and start sending checks */
421 charon->connect_manager->set_responder_data(
422 charon->connect_manager,
423 this->connect_id, this->connect_key,
424 this->remote_endpoints);
425 }
426 else
427 {
428 /* FIXME: handle result of set_initiator_data
429 * as responder, create a checklist with the initiator's data */
430 charon->connect_manager->set_initiator_data(
431 charon->connect_manager,
432 this->peer_id, this->ike_sa->get_my_id(this->ike_sa),
433 this->connect_id, this->connect_key,
434 this->remote_endpoints, FALSE);
435 if (this->ike_sa->respond(this->ike_sa, this->peer_id,
436 this->connect_id) != SUCCESS)
437 {
438 return FAILED;
439 }
440 }
441 break;
442 }
443 default:
444 break;
445 }
446 return SUCCESS;
447 }
448
449 METHOD(task_t, process_i, status_t,
450 private_ike_me_t *this, message_t *message)
451 {
452 switch(message->get_exchange_type(message))
453 {
454 case IKE_SA_INIT:
455 {
456 process_payloads(this, message);
457 if (!this->mediation)
458 {
459 DBG1(DBG_IKE, "server did not return a ME_MEDIATION, aborting");
460 return FAILED;
461 }
462 /* if we are on a mediation connection we switch to port 4500 even
463 * if no NAT is detected. */
464 this->ike_sa->float_ports(this->ike_sa);
465 return NEED_MORE;
466 }
467 case IKE_AUTH:
468 {
469 process_payloads(this, message);
470 /* FIXME: we should update the server reflexive endpoint somehow,
471 * if mobike notices a change */
472 endpoint_notify_t *reflexive;
473 if (this->remote_endpoints->get_first(this->remote_endpoints,
474 (void**)&reflexive) == SUCCESS &&
475 reflexive->get_type(reflexive) == SERVER_REFLEXIVE)
476 { /* FIXME: should we accept this endpoint even if we did not send
477 * a request? */
478 host_t *endpoint = reflexive->get_host(reflexive);
479 endpoint = endpoint->clone(endpoint);
480 this->ike_sa->set_server_reflexive_host(this->ike_sa, endpoint);
481 }
482 break;
483 }
484 case ME_CONNECT:
485 {
486 process_payloads(this, message);
487
488 if (this->failed)
489 {
490 DBG1(DBG_IKE, "peer '%Y' is not online", this->peer_id);
491 /* FIXME: notify the mediated connection (job?) */
492 }
493 else
494 {
495 if (this->response)
496 {
497 /* FIXME: handle result of set_responder_data. */
498 /* as responder, we update the checklist and start sending
499 * checks */
500 charon->connect_manager->set_responder_data(
501 charon->connect_manager, this->connect_id,
502 this->connect_key, this->local_endpoints);
503 }
504 else
505 {
506 /* FIXME: handle result of set_initiator_data */
507 /* as initiator, we create a checklist and set the
508 * initiator's data */
509 charon->connect_manager->set_initiator_data(
510 charon->connect_manager,
511 this->ike_sa->get_my_id(this->ike_sa),
512 this->peer_id, this->connect_id, this->connect_key,
513 this->local_endpoints, TRUE);
514 /* FIXME: also start a timer for the whole transaction
515 * (maybe within the connect_manager?) */
516 }
517 }
518 break;
519 }
520 default:
521 break;
522 }
523 return SUCCESS;
524 }
525
526 /**
527 * For mediation server
528 */
529 METHOD(task_t, build_i_ms, status_t,
530 private_ike_me_t *this, message_t *message)
531 {
532 switch(message->get_exchange_type(message))
533 {
534 case ME_CONNECT:
535 {
536 id_payload_t *id_payload;
537 id_payload = id_payload_create_from_identification(PLV2_ID_PEER,
538 this->peer_id);
539 message->add_payload(message, (payload_t*)id_payload);
540
541 if (this->callback)
542 {
543 message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty);
544 }
545 else
546 {
547 if (this->response)
548 {
549 message->add_notify(message, FALSE, ME_RESPONSE,
550 chunk_empty);
551 }
552 message->add_notify(message, FALSE, ME_CONNECTID,
553 this->connect_id);
554 message->add_notify(message, FALSE, ME_CONNECTKEY,
555 this->connect_key);
556 add_endpoints_to_message(message, this->remote_endpoints);
557 }
558 break;
559 }
560 default:
561 break;
562 }
563 return NEED_MORE;
564 }
565
566 /**
567 * For mediation server
568 */
569 METHOD(task_t, process_r_ms, status_t,
570 private_ike_me_t *this, message_t *message)
571 {
572 switch(message->get_exchange_type(message))
573 {
574 case IKE_SA_INIT:
575 {
576 /* FIXME: we should check for SA* and TS* payloads. if there are
577 * any, send NO_ADDITIONAL_SAS back and delete this SA */
578 process_payloads(this, message);
579 return this->mediation ? NEED_MORE : SUCCESS;
580 }
581 case IKE_AUTH:
582 {
583 /* FIXME: we should check whether the current peer_config is
584 * configured as mediation connection */
585 process_payloads(this, message);
586 break;
587 }
588 case CREATE_CHILD_SA:
589 {
590 /* FIXME: if this is not to rekey the IKE SA we have to return a
591 * NO_ADDITIONAL_SAS and then delete the SA */
592 break;
593 }
594 case ME_CONNECT:
595 {
596 id_payload_t *id_payload;
597 id_payload = (id_payload_t*)message->get_payload(message, PLV2_ID_PEER);
598 if (!id_payload)
599 {
600 DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload"
601 ", aborting");
602 this->invalid_syntax = TRUE;
603 break;
604 }
605 this->peer_id = id_payload->get_identification(id_payload);
606
607 process_payloads(this, message);
608
609 if (!this->connect_id.ptr)
610 {
611 DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify"
612 ", aborting");
613 this->invalid_syntax = TRUE;
614 break;
615 }
616
617 if (!this->connect_key.ptr)
618 {
619 DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY notify"
620 ", aborting");
621 this->invalid_syntax = TRUE;
622 break;
623 }
624
625 if (!this->remote_endpoints->get_count(this->remote_endpoints))
626 {
627 DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT "
628 "payloads, aborting");
629 this->invalid_syntax = TRUE;
630 break;
631 }
632 break;
633 }
634 default:
635 break;
636 }
637 return NEED_MORE;
638 }
639
640 /**
641 * For mediation server
642 */
643 METHOD(task_t, build_r_ms, status_t,
644 private_ike_me_t *this, message_t *message)
645 {
646 switch(message->get_exchange_type(message))
647 {
648 case IKE_SA_INIT:
649 {
650 message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty);
651 return NEED_MORE;
652 }
653 case IKE_AUTH:
654 {
655 endpoint_notify_t *endpoint;
656 if (this->remote_endpoints->get_first(this->remote_endpoints,
657 (void**)&endpoint) == SUCCESS &&
658 endpoint->get_type(endpoint) == SERVER_REFLEXIVE)
659 {
660 host_t *host = this->ike_sa->get_other_host(this->ike_sa);
661 DBG2(DBG_IKE, "received request for a server reflexive "
662 "endpoint sending: %#H", host);
663 endpoint = endpoint_notify_create_from_host(SERVER_REFLEXIVE,
664 host, NULL);
665 message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint));
666 endpoint->destroy(endpoint);
667 }
668 this->ike_sa->act_as_mediation_server(this->ike_sa);
669 break;
670 }
671 case ME_CONNECT:
672 {
673 if (this->invalid_syntax)
674 {
675 message->add_notify(message, TRUE, INVALID_SYNTAX, chunk_empty);
676 break;
677 }
678
679 ike_sa_id_t *peer_sa;
680 if (this->callback)
681 {
682 peer_sa = charon->mediation_manager->check_and_register(
683 charon->mediation_manager, this->peer_id,
684 this->ike_sa->get_other_id(this->ike_sa));
685 }
686 else
687 {
688 peer_sa = charon->mediation_manager->check(
689 charon->mediation_manager, this->peer_id);
690 }
691
692 if (!peer_sa)
693 {
694 /* the peer is not online */
695 message->add_notify(message, TRUE, ME_CONNECT_FAILED,
696 chunk_empty);
697 break;
698 }
699
700 job_t *job = (job_t*)mediation_job_create(this->peer_id,
701 this->ike_sa->get_other_id(this->ike_sa), this->connect_id,
702 this->connect_key, this->remote_endpoints, this->response);
703 lib->processor->queue_job(lib->processor, job);
704 break;
705 }
706 default:
707 break;
708 }
709 return SUCCESS;
710 }
711
712 /**
713 * For mediation server
714 */
715 METHOD(task_t, process_i_ms, status_t,
716 private_ike_me_t *this, message_t *message)
717 {
718 /* FIXME: theoretically we should be prepared to receive a ME_CONNECT_FAILED
719 * here if the responding peer is not able to proceed. in this case we shall
720 * notify the initiating peer with a ME_CONNECT request containing only a
721 * ME_CONNECT_FAILED */
722 return SUCCESS;
723 }
724
725 METHOD(ike_me_t, me_connect, void,
726 private_ike_me_t *this, identification_t *peer_id)
727 {
728 this->peer_id = peer_id->clone(peer_id);
729 }
730
731 METHOD(ike_me_t, me_respond, void,
732 private_ike_me_t *this, identification_t *peer_id, chunk_t connect_id)
733 {
734 this->peer_id = peer_id->clone(peer_id);
735 this->connect_id = chunk_clone(connect_id);
736 this->response = TRUE;
737 }
738
739 METHOD(ike_me_t, me_callback, void,
740 private_ike_me_t *this, identification_t *peer_id)
741 {
742 this->peer_id = peer_id->clone(peer_id);
743 this->callback = TRUE;
744 }
745
746 METHOD(ike_me_t, relay, void,
747 private_ike_me_t *this, identification_t *requester, chunk_t connect_id,
748 chunk_t connect_key, linked_list_t *endpoints, bool response)
749 {
750 this->peer_id = requester->clone(requester);
751 this->connect_id = chunk_clone(connect_id);
752 this->connect_key = chunk_clone(connect_key);
753
754 this->remote_endpoints->destroy_offset(this->remote_endpoints,
755 offsetof(endpoint_notify_t, destroy));
756 this->remote_endpoints = endpoints->clone_offset(endpoints,
757 offsetof(endpoint_notify_t, clone));
758
759 this->response = response;
760 }
761
762 METHOD(task_t, get_type, task_type_t,
763 private_ike_me_t *this)
764 {
765 return TASK_IKE_ME;
766 }
767
768 METHOD(task_t, migrate, void,
769 private_ike_me_t *this, ike_sa_t *ike_sa)
770 {
771 this->ike_sa = ike_sa;
772 }
773
774 METHOD(task_t, destroy, void,
775 private_ike_me_t *this)
776 {
777 DESTROY_IF(this->peer_id);
778
779 chunk_free(&this->connect_id);
780 chunk_free(&this->connect_key);
781
782 this->local_endpoints->destroy_offset(this->local_endpoints,
783 offsetof(endpoint_notify_t, destroy));
784 this->remote_endpoints->destroy_offset(this->remote_endpoints,
785 offsetof(endpoint_notify_t, destroy));
786
787 DESTROY_IF(this->mediated_cfg);
788 free(this);
789 }
790
791 /*
792 * Described in header.
793 */
794 ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator)
795 {
796 private_ike_me_t *this;
797
798 INIT(this,
799 .public = {
800 .task = {
801 .get_type = _get_type,
802 .migrate = _migrate,
803 .destroy = _destroy,
804 },
805 .connect = _me_connect,
806 .respond = _me_respond,
807 .callback = _me_callback,
808 .relay = _relay,
809 },
810 .ike_sa = ike_sa,
811 .initiator = initiator,
812 .local_endpoints = linked_list_create(),
813 .remote_endpoints = linked_list_create(),
814 );
815
816 if (ike_sa->has_condition(ike_sa, COND_ORIGINAL_INITIATOR))
817 {
818 if (initiator)
819 {
820 this->public.task.build = _build_i;
821 this->public.task.process = _process_i;
822 }
823 else
824 {
825 this->public.task.build = _build_r;
826 this->public.task.process = _process_r;
827 }
828 }
829 else
830 {
831 /* mediation server */
832 if (initiator)
833 {
834 this->public.task.build = _build_i_ms;
835 this->public.task.process = _process_i_ms;
836 }
837 else
838 {
839 this->public.task.build = _build_r_ms;
840 this->public.task.process = _process_r_ms;
841 }
842 }
843
844 return &this->public;
845 }