refactored and cleaned up child_sa interface
[strongswan.git] / src / charon / sa / child_sa.c
1 /*
2 * Copyright (C) 2006-2008 Tobias Brunner
3 * Copyright (C) 2005-2008 Martin Willi
4 * Copyright (C) 2006 Daniel Roethlisberger
5 * Copyright (C) 2005 Jan Hutter
6 * Hochschule fuer Technik Rapperswil
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * $Id$
19 */
20
21 #define _GNU_SOURCE
22 #include "child_sa.h"
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27
28 #include <daemon.h>
29
30 ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
31 "CREATED",
32 "ROUTED",
33 "INSTALLING",
34 "INSTALLED",
35 "UPDATING",
36 "REKEYING",
37 "DELETING",
38 "DESTROYING",
39 );
40
41 typedef struct private_child_sa_t private_child_sa_t;
42
43 /**
44 * Private data of a child_sa_t object.
45 */
46 struct private_child_sa_t {
47 /**
48 * Public interface of child_sa_t.
49 */
50 child_sa_t public;
51
52 /**
53 * address of us
54 */
55 host_t *my_addr;
56
57 /**
58 * address of remote
59 */
60 host_t *other_addr;
61
62 /**
63 * our actually used SPI, 0 if unused
64 */
65 u_int32_t my_spi;
66
67 /**
68 * others used SPI, 0 if unused
69 */
70 u_int32_t other_spi;
71
72 /**
73 * our Compression Parameter Index (CPI) used, 0 if unused
74 */
75 u_int16_t my_cpi;
76
77 /**
78 * others Compression Parameter Index (CPI) used, 0 if unused
79 */
80 u_int16_t other_cpi;
81
82 /**
83 * List for local traffic selectors
84 */
85 linked_list_t *my_ts;
86
87 /**
88 * List for remote traffic selectors
89 */
90 linked_list_t *other_ts;
91
92 /**
93 * Protocol used to protect this SA, ESP|AH
94 */
95 protocol_id_t protocol;
96
97 /**
98 * reqid used for this child_sa
99 */
100 u_int32_t reqid;
101
102 /**
103 * absolute time when rekeying is scheduled
104 */
105 time_t rekey_time;
106
107 /**
108 * absolute time when the SA expires
109 */
110 time_t expire_time;
111
112 /**
113 * state of the CHILD_SA
114 */
115 child_sa_state_t state;
116
117 /**
118 * Specifies if UDP encapsulation is enabled (NAT traversal)
119 */
120 bool encap;
121
122 /**
123 * Specifies the IPComp transform used (IPCOMP_NONE if disabled)
124 */
125 ipcomp_transform_t ipcomp;
126
127 /**
128 * mode this SA uses, tunnel/transport
129 */
130 ipsec_mode_t mode;
131
132 /**
133 * selected proposal
134 */
135 proposal_t *proposal;
136
137 /**
138 * config used to create this child
139 */
140 child_cfg_t *config;
141 };
142
143 /**
144 * Implementation of child_sa_t.get_name
145 */
146 static char *get_name(private_child_sa_t *this)
147 {
148 return this->config->get_name(this->config);
149 }
150
151 /**
152 * Implements child_sa_t.get_reqid
153 */
154 static u_int32_t get_reqid(private_child_sa_t *this)
155 {
156 return this->reqid;
157 }
158
159 /**
160 * Implements child_sa_t.get_config
161 */
162 static child_cfg_t* get_config(private_child_sa_t *this)
163 {
164 return this->config;
165 }
166
167 /**
168 * Implements child_sa_t.set_state
169 */
170 static void set_state(private_child_sa_t *this, child_sa_state_t state)
171 {
172 charon->bus->child_state_change(charon->bus, &this->public, state);
173 this->state = state;
174 }
175
176 /**
177 * Implements child_sa_t.get_state
178 */
179 static child_sa_state_t get_state(private_child_sa_t *this)
180 {
181 return this->state;
182 }
183
184 /**
185 * Implements child_sa_t.get_spi
186 */
187 u_int32_t get_spi(private_child_sa_t *this, bool inbound)
188 {
189 return inbound ? this->my_spi : this->other_spi;
190 }
191
192 /**
193 * Implements child_sa_t.get_cpi
194 */
195 u_int16_t get_cpi(private_child_sa_t *this, bool inbound)
196 {
197 return inbound ? this->my_cpi : this->other_cpi;
198 }
199
200 /**
201 * Implements child_sa_t.get_protocol
202 */
203 protocol_id_t get_protocol(private_child_sa_t *this)
204 {
205 return this->protocol;
206 }
207
208 /**
209 * Implementation of child_sa_t.set_protocol
210 */
211 static void set_protocol(private_child_sa_t *this, protocol_id_t protocol)
212 {
213 this->protocol = protocol;
214 }
215
216 /**
217 * Implementation of child_sa_t.get_mode
218 */
219 static ipsec_mode_t get_mode(private_child_sa_t *this)
220 {
221 return this->mode;
222 }
223
224 /**
225 * Implementation of child_sa_t.set_mode
226 */
227 static void set_mode(private_child_sa_t *this, ipsec_mode_t mode)
228 {
229 this->mode = mode;
230 }
231
232 /**
233 * Implementation of child_sa_t.has_encap
234 */
235 static bool has_encap(private_child_sa_t *this)
236 {
237 return this->encap;
238 }
239
240 /**
241 * Implementation of child_sa_t.get_ipcomp
242 */
243 static ipcomp_transform_t get_ipcomp(private_child_sa_t *this)
244 {
245 return this->ipcomp;
246 }
247
248 /**
249 * Implementation of child_sa_t.set_ipcomp.
250 */
251 static void set_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp)
252 {
253 this->ipcomp = ipcomp;
254 }
255
256 /**
257 * Implementation of child_sa_t.get_proposal
258 */
259 static proposal_t* get_proposal(private_child_sa_t *this)
260 {
261 return this->proposal;
262 }
263
264 /**
265 * Implementation of child_sa_t.set_proposal
266 */
267 static void set_proposal(private_child_sa_t *this, proposal_t *proposal)
268 {
269 this->proposal = proposal->clone(proposal);
270 }
271
272 /**
273 * Implementation of child_sa_t.get_traffic_selectors.
274 */
275 static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local)
276 {
277 return local ? this->my_ts : this->other_ts;
278 }
279
280 typedef struct policy_enumerator_t policy_enumerator_t;
281
282 /**
283 * Private policy enumerator
284 */
285 struct policy_enumerator_t {
286 /** implements enumerator_t */
287 enumerator_t public;
288 /** enumerator over own TS */
289 enumerator_t *mine;
290 /** enumerator over others TS */
291 enumerator_t *other;
292 /** list of others TS, to recreate enumerator */
293 linked_list_t *list;
294 /** currently enumerating TS for "me" side */
295 traffic_selector_t *ts;
296 };
297
298 /**
299 * enumerator function of create_policy_enumerator()
300 */
301 static bool policy_enumerate(policy_enumerator_t *this,
302 traffic_selector_t **my_out, traffic_selector_t **other_out)
303 {
304 traffic_selector_t *other_ts;
305
306 while (this->ts || this->mine->enumerate(this->mine, &this->ts))
307 {
308 if (!this->other->enumerate(this->other, &other_ts))
309 { /* end of others list, restart with new of mine */
310 this->other->destroy(this->other);
311 this->other = this->list->create_enumerator(this->list);
312 this->ts = NULL;
313 continue;
314 }
315 if (this->ts->get_type(this->ts) != other_ts->get_type(other_ts))
316 { /* family mismatch */
317 continue;
318 }
319 if (this->ts->get_protocol(this->ts) &&
320 other_ts->get_protocol(other_ts) &&
321 this->ts->get_protocol(this->ts) != other_ts->get_protocol(other_ts))
322 { /* protocol mismatch */
323 continue;
324 }
325 *my_out = this->ts;
326 *other_out = other_ts;
327 return TRUE;
328 }
329 return FALSE;
330 }
331
332 /**
333 * destroy function of create_policy_enumerator()
334 */
335 static void policy_destroy(policy_enumerator_t *this)
336 {
337 this->mine->destroy(this->mine);
338 this->other->destroy(this->other);
339 free(this);
340 }
341
342 /**
343 * Implementation of child_sa_t.create_policy_enumerator
344 */
345 static enumerator_t* create_policy_enumerator(private_child_sa_t *this)
346 {
347 policy_enumerator_t *e = malloc_thing(policy_enumerator_t);
348
349 e->public.enumerate = (void*)policy_enumerate;
350 e->public.destroy = (void*)policy_destroy;
351 e->mine = this->my_ts->create_enumerator(this->my_ts);
352 e->other = this->other_ts->create_enumerator(this->other_ts);
353 e->list = this->other_ts;
354 e->ts = NULL;
355
356 return &e->public;
357 }
358
359 /**
360 * Implementation of child_sa_t.get_usetime
361 */
362 static u_int32_t get_usetime(private_child_sa_t *this, bool inbound)
363 {
364 enumerator_t *enumerator;
365 traffic_selector_t *my_ts, *other_ts;
366 u_int32_t last_use = 0;
367
368 enumerator = create_policy_enumerator(this);
369 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
370 {
371 u_int32_t in, out, fwd;
372
373 if (inbound)
374 {
375 if (charon->kernel_interface->query_policy(charon->kernel_interface,
376 other_ts, my_ts, POLICY_IN, &in) == SUCCESS)
377 {
378 last_use = max(last_use, in);
379 }
380 if (this->mode != MODE_TRANSPORT)
381 {
382 if (charon->kernel_interface->query_policy(charon->kernel_interface,
383 other_ts, my_ts, POLICY_FWD, &fwd) == SUCCESS)
384 {
385 last_use = max(last_use, fwd);
386 }
387 }
388 }
389 else
390 {
391 if (charon->kernel_interface->query_policy(charon->kernel_interface,
392 my_ts, other_ts, POLICY_OUT, &out) == SUCCESS)
393 {
394 last_use = max(last_use, out);
395 }
396 }
397 }
398 enumerator->destroy(enumerator);
399 return last_use;
400 }
401
402 /**
403 * Implementation of child_sa_t.get_lifetime
404 */
405 static u_int32_t get_lifetime(private_child_sa_t *this, bool hard)
406 {
407 return hard ? this->expire_time : this->rekey_time;
408 }
409
410 /**
411 * Implementation of child_sa_t.alloc_spi
412 */
413 static u_int32_t alloc_spi(private_child_sa_t *this, protocol_id_t protocol)
414 {
415 switch (protocol)
416 {
417 case PROTO_AH:
418 if (charon->kernel_interface->get_spi(charon->kernel_interface,
419 this->other_addr, this->my_addr, PROTO_AH,
420 this->reqid, &this->my_spi) == SUCCESS)
421 {
422 return this->my_spi;
423 }
424 break;
425 case PROTO_ESP:
426 if (charon->kernel_interface->get_spi(charon->kernel_interface,
427 this->other_addr, this->my_addr, PROTO_ESP,
428 this->reqid, &this->my_spi) == SUCCESS)
429 {
430 return this->my_spi;
431 }
432 break;
433 default:
434 break;
435 }
436 return 0;
437 }
438
439 /**
440 * Implementation of child_sa_t.alloc_cpi
441 */
442 static u_int16_t alloc_cpi(private_child_sa_t *this)
443 {
444 if (charon->kernel_interface->get_cpi(charon->kernel_interface,
445 this->other_addr, this->my_addr, this->reqid,
446 &this->my_cpi) == SUCCESS)
447 {
448 return this->my_cpi;
449 }
450 return 0;
451 }
452
453 /**
454 * Implementation of child_sa_t.install
455 */
456 static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ,
457 u_int32_t spi, u_int16_t cpi, bool inbound)
458 {
459 u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
460 u_int32_t soft, hard, now;
461 host_t *src, *dst;
462 status_t status;
463 bool update = FALSE;
464
465 /* now we have to decide which spi to use. Use self allocated, if "in",
466 * or the one in the proposal, if not "in" (others). Additionally,
467 * source and dest host switch depending on the role */
468 if (inbound)
469 {
470 dst = this->my_addr;
471 src = this->other_addr;
472 if (this->my_spi == spi)
473 { /* alloc_spi has been called, do an SA update */
474 update = TRUE;
475 }
476 this->my_spi = spi;
477 this->my_cpi = cpi;
478 }
479 else
480 {
481 src = this->my_addr;
482 dst = this->other_addr;
483 this->other_spi = spi;
484 this->other_cpi = cpi;
485 }
486
487 DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound",
488 protocol_id_names, this->protocol);
489
490 /* send SA down to the kernel */
491 DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
492
493 this->proposal->get_algorithm(this->proposal, ENCRYPTION_ALGORITHM,
494 &enc_alg, &size);
495 this->proposal->get_algorithm(this->proposal, INTEGRITY_ALGORITHM,
496 &int_alg, &size);
497
498 soft = this->config->get_lifetime(this->config, TRUE);
499 hard = this->config->get_lifetime(this->config, FALSE);
500
501 status = charon->kernel_interface->add_sa(charon->kernel_interface,
502 src, dst, spi, this->protocol, this->reqid,
503 inbound ? soft : 0, hard, enc_alg, encr, int_alg, integ,
504 this->mode, this->ipcomp, cpi, this->encap, update);
505
506 now = time(NULL);
507 this->rekey_time = now + soft;
508 this->expire_time = now + hard;
509 return status;
510 }
511
512 /**
513 * Implementation of child_sa_t.add_policies
514 */
515 static status_t add_policies(private_child_sa_t *this,
516 linked_list_t *my_ts_list, linked_list_t *other_ts_list)
517 {
518 enumerator_t *enumerator;
519 traffic_selector_t *my_ts, *other_ts;
520 status_t status = SUCCESS;
521 bool routed = (this->state == CHILD_CREATED);
522
523 /* apply traffic selectors */
524 enumerator = my_ts_list->create_enumerator(my_ts_list);
525 while (enumerator->enumerate(enumerator, &my_ts))
526 {
527 this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts));
528 }
529 enumerator->destroy(enumerator);
530 enumerator = other_ts_list->create_enumerator(other_ts_list);
531 while (enumerator->enumerate(enumerator, &other_ts))
532 {
533 this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts));
534 }
535 enumerator->destroy(enumerator);
536
537 if (this->config->install_policy(this->config))
538 {
539 /* enumerate pairs of traffic selectors */
540 enumerator = create_policy_enumerator(this);
541 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
542 {
543 /* install 3 policies: out, in and forward */
544 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
545 this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT,
546 this->other_spi, this->protocol, this->reqid, this->mode,
547 this->ipcomp, this->other_cpi, routed);
548
549 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
550 this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN,
551 this->my_spi, this->protocol, this->reqid, this->mode,
552 this->ipcomp, this->my_cpi, routed);
553 if (this->mode != MODE_TRANSPORT)
554 {
555 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
556 this->other_addr, this->my_addr, other_ts, my_ts, POLICY_FWD,
557 this->my_spi, this->protocol, this->reqid, this->mode,
558 this->ipcomp, this->my_cpi, routed);
559 }
560
561 if (status != SUCCESS)
562 {
563 break;
564 }
565 }
566 enumerator->destroy(enumerator);
567 }
568
569 if (status == SUCCESS && this->state == CHILD_CREATED)
570 { /* switch to routed state if no SAD entry set up */
571 set_state(this, CHILD_ROUTED);
572 }
573 return status;
574 }
575
576 /**
577 * Implementation of child_sa_t.update.
578 */
579 static status_t update(private_child_sa_t *this, host_t *me, host_t *other,
580 host_t *vip, bool encap)
581 {
582 child_sa_state_t old;
583 bool transport_proxy_mode;
584
585 /* anything changed at all? */
586 if (me->equals(me, this->my_addr) &&
587 other->equals(other, this->other_addr) && this->encap == encap)
588 {
589 return SUCCESS;
590 }
591
592 old = this->state;
593 set_state(this, CHILD_UPDATING);
594 transport_proxy_mode = this->config->use_proxy_mode(this->config) &&
595 this->mode == MODE_TRANSPORT;
596
597 if (!transport_proxy_mode)
598 {
599 /* update our (initator) SA */
600 if (this->my_spi)
601 {
602 if (charon->kernel_interface->update_sa(charon->kernel_interface,
603 this->my_spi, this->protocol,
604 this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0,
605 this->other_addr, this->my_addr, other, me,
606 this->encap, encap) == NOT_SUPPORTED)
607 {
608 return NOT_SUPPORTED;
609 }
610 }
611
612 /* update his (responder) SA */
613 if (this->other_spi)
614 {
615 if (charon->kernel_interface->update_sa(charon->kernel_interface,
616 this->other_spi, this->protocol,
617 this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0,
618 this->my_addr, this->other_addr, me, other,
619 this->encap, encap) == NOT_SUPPORTED)
620 {
621 return NOT_SUPPORTED;
622 }
623 }
624 }
625
626 if (this->config->install_policy(this->config))
627 {
628 /* update policies */
629 if (!me->ip_equals(me, this->my_addr) ||
630 !other->ip_equals(other, this->other_addr))
631 {
632 enumerator_t *enumerator;
633 traffic_selector_t *my_ts, *other_ts;
634
635 /* always use high priorities, as hosts getting updated are INSTALLED */
636 enumerator = create_policy_enumerator(this);
637 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
638 {
639 /* remove old policies first */
640 charon->kernel_interface->del_policy(charon->kernel_interface,
641 my_ts, other_ts, POLICY_OUT, FALSE);
642 charon->kernel_interface->del_policy(charon->kernel_interface,
643 other_ts, my_ts, POLICY_IN, FALSE);
644 if (this->mode != MODE_TRANSPORT)
645 {
646 charon->kernel_interface->del_policy(charon->kernel_interface,
647 other_ts, my_ts, POLICY_FWD, FALSE);
648 }
649
650 /* check whether we have to update a "dynamic" traffic selector */
651 if (!me->ip_equals(me, this->my_addr) &&
652 my_ts->is_host(my_ts, this->my_addr))
653 {
654 my_ts->set_address(my_ts, me);
655 }
656 if (!other->ip_equals(other, this->other_addr) &&
657 other_ts->is_host(other_ts, this->other_addr))
658 {
659 other_ts->set_address(other_ts, other);
660 }
661
662 /* we reinstall the virtual IP to handle interface roaming
663 * correctly */
664 if (vip)
665 {
666 charon->kernel_interface->del_ip(charon->kernel_interface, vip);
667 charon->kernel_interface->add_ip(charon->kernel_interface, vip, me);
668 }
669
670 /* reinstall updated policies */
671 charon->kernel_interface->add_policy(charon->kernel_interface,
672 me, other, my_ts, other_ts, POLICY_OUT, this->other_spi,
673 this->protocol, this->reqid, this->mode, this->ipcomp,
674 this->other_cpi, FALSE);
675 charon->kernel_interface->add_policy(charon->kernel_interface,
676 other, me, other_ts, my_ts, POLICY_IN, this->my_spi,
677 this->protocol, this->reqid, this->mode, this->ipcomp,
678 this->my_cpi, FALSE);
679 if (this->mode != MODE_TRANSPORT)
680 {
681 charon->kernel_interface->add_policy(charon->kernel_interface,
682 other, me, other_ts, my_ts, POLICY_FWD, this->my_spi,
683 this->protocol, this->reqid, this->mode, this->ipcomp,
684 this->my_cpi, FALSE);
685 }
686 }
687 enumerator->destroy(enumerator);
688 }
689 }
690
691 if (!transport_proxy_mode)
692 {
693 /* apply hosts */
694 if (!me->equals(me, this->my_addr))
695 {
696 this->my_addr->destroy(this->my_addr);
697 this->my_addr = me->clone(me);
698 }
699 if (!other->equals(other, this->other_addr))
700 {
701 this->other_addr->destroy(this->other_addr);
702 this->other_addr = other->clone(other);
703 }
704 }
705
706 this->encap = encap;
707 set_state(this, old);
708
709 return SUCCESS;
710 }
711
712 /**
713 * Implementation of child_sa_t.destroy.
714 */
715 static void destroy(private_child_sa_t *this)
716 {
717 enumerator_t *enumerator;
718 traffic_selector_t *my_ts, *other_ts;
719 bool unrouted = (this->state == CHILD_ROUTED);
720
721 set_state(this, CHILD_DESTROYING);
722
723 /* delete SAs in the kernel, if they are set up */
724 if (this->my_spi)
725 {
726 charon->kernel_interface->del_sa(charon->kernel_interface,
727 this->my_addr, this->my_spi, this->protocol,
728 this->my_cpi);
729 }
730 if (this->other_spi)
731 {
732 charon->kernel_interface->del_sa(charon->kernel_interface,
733 this->other_addr, this->other_spi, this->protocol,
734 this->other_cpi);
735 }
736
737 if (this->config->install_policy(this->config))
738 {
739 /* delete all policies in the kernel */
740 enumerator = create_policy_enumerator(this);
741 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
742 {
743 charon->kernel_interface->del_policy(charon->kernel_interface,
744 my_ts, other_ts, POLICY_OUT, unrouted);
745 charon->kernel_interface->del_policy(charon->kernel_interface,
746 other_ts, my_ts, POLICY_IN, unrouted);
747 if (this->mode != MODE_TRANSPORT)
748 {
749 charon->kernel_interface->del_policy(charon->kernel_interface,
750 other_ts, my_ts, POLICY_FWD, unrouted);
751 }
752 }
753 enumerator->destroy(enumerator);
754 }
755
756 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
757 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
758 this->my_addr->destroy(this->my_addr);
759 this->other_addr->destroy(this->other_addr);
760 DESTROY_IF(this->proposal);
761 this->config->destroy(this->config);
762 free(this);
763 }
764
765 /*
766 * Described in header.
767 */
768 child_sa_t * child_sa_create(host_t *me, host_t* other,
769 child_cfg_t *config, u_int32_t rekey, bool encap)
770 {
771 static u_int32_t reqid = 0;
772 private_child_sa_t *this = malloc_thing(private_child_sa_t);
773
774 /* public functions */
775 this->public.get_name = (char*(*)(child_sa_t*))get_name;
776 this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
777 this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config;
778 this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
779 this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
780 this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
781 this->public.get_cpi = (u_int16_t(*)(child_sa_t*, bool))get_cpi;
782 this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
783 this->public.set_protocol = (void(*)(child_sa_t*, protocol_id_t protocol))set_protocol;
784 this->public.get_mode = (ipsec_mode_t(*)(child_sa_t*))get_mode;
785 this->public.set_mode = (void(*)(child_sa_t*, ipsec_mode_t mode))set_mode;
786 this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal;
787 this->public.set_proposal = (void(*)(child_sa_t*, proposal_t *proposal))set_proposal;
788 this->public.get_lifetime = (u_int32_t(*)(child_sa_t*, bool))get_lifetime;
789 this->public.get_usetime = (u_int32_t(*)(child_sa_t*, bool))get_usetime;
790 this->public.has_encap = (bool(*)(child_sa_t*))has_encap;
791 this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp;
792 this->public.set_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t))set_ipcomp;
793 this->public.alloc_spi = (u_int32_t(*)(child_sa_t*, protocol_id_t protocol))alloc_spi;
794 this->public.alloc_cpi = (u_int16_t(*)(child_sa_t*))alloc_cpi;
795 this->public.install = (status_t(*)(child_sa_t*, chunk_t encr, chunk_t integ, u_int32_t spi, u_int16_t cpi, bool inbound))install;
796 this->public.update = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update;
797 this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
798 this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
799 this->public.create_policy_enumerator = (enumerator_t*(*)(child_sa_t*))create_policy_enumerator;
800 this->public.destroy = (void(*)(child_sa_t*))destroy;
801
802 /* private data */
803 this->my_addr = me->clone(me);
804 this->other_addr = other->clone(other);
805 this->my_spi = 0;
806 this->other_spi = 0;
807 this->my_cpi = 0;
808 this->other_cpi = 0;
809 this->encap = encap;
810 this->ipcomp = IPCOMP_NONE;
811 this->state = CHILD_CREATED;
812 /* reuse old reqid if we are rekeying an existing CHILD_SA */
813 this->reqid = rekey ? rekey : ++reqid;
814 this->my_ts = linked_list_create();
815 this->other_ts = linked_list_create();
816 this->protocol = PROTO_NONE;
817 this->mode = MODE_TUNNEL;
818 this->proposal = NULL;
819 this->config = config;
820 config->get_ref(config);
821
822 /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
823 if (config->get_mode(config) == MODE_TRANSPORT &&
824 config->use_proxy_mode(config))
825 {
826 ts_type_t type;
827 int family;
828 chunk_t addr;
829 host_t *host;
830 enumerator_t *enumerator;
831 linked_list_t *my_ts_list, *other_ts_list;
832 traffic_selector_t *my_ts, *other_ts;
833
834 this->mode = MODE_TRANSPORT;
835
836 my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me);
837 enumerator = my_ts_list->create_enumerator(my_ts_list);
838 if (enumerator->enumerate(enumerator, &my_ts))
839 {
840 if (my_ts->is_host(my_ts, NULL) &&
841 !my_ts->is_host(my_ts, this->my_addr))
842 {
843 type = my_ts->get_type(my_ts);
844 family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
845 addr = my_ts->get_from_address(my_ts);
846 host = host_create_from_chunk(family, addr, 0);
847 free(addr.ptr);
848 DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H",
849 this->my_addr, host);
850 this->my_addr->destroy(this->my_addr);
851 this->my_addr = host;
852 }
853 }
854 enumerator->destroy(enumerator);
855 my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy));
856
857 other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other);
858 enumerator = other_ts_list->create_enumerator(other_ts_list);
859 if (enumerator->enumerate(enumerator, &other_ts))
860 {
861 if (other_ts->is_host(other_ts, NULL) &&
862 !other_ts->is_host(other_ts, this->other_addr))
863 {
864 type = other_ts->get_type(other_ts);
865 family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
866 addr = other_ts->get_from_address(other_ts);
867 host = host_create_from_chunk(family, addr, 0);
868 free(addr.ptr);
869 DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H",
870 this->other_addr, host);
871 this->other_addr->destroy(this->other_addr);
872 this->other_addr = host;
873 }
874 }
875 enumerator->destroy(enumerator);
876 other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy));
877 }
878
879 return &this->public;
880 }