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