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