merging kernel_klips plugin back into trunk
[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_TUNNEL)
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 status = charon->kernel_interface->add_sa(charon->kernel_interface,
501 src, dst, spi, this->protocol, this->reqid,
502 in ? soft : 0, hard, enc_alg, encr, int_alg, integ,
503 mode, this->ipcomp, in ? this->my_cpi : this->other_cpi,
504 this->encap, in);
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
514 */
515 static status_t add(private_child_sa_t *this,
516 proposal_t *proposal, ipsec_mode_t mode,
517 chunk_t integ_in, chunk_t integ_out,
518 chunk_t encr_in, chunk_t encr_out)
519 {
520 this->proposal = proposal->clone(proposal);
521 this->protocol = proposal->get_protocol(proposal);
522
523 /* get SPIs for inbound SAs, write to proposal */
524 if (alloc_proposal(this, proposal) != SUCCESS)
525 {
526 return FAILED;
527 }
528 /* install inbound SAs using allocated SPI */
529 if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS)
530 {
531 return FAILED;
532 }
533 /* install outbound SAs using received SPI*/
534 if (install(this, this->proposal, mode, integ_out, encr_out, FALSE) != SUCCESS)
535 {
536 return FAILED;
537 }
538 return SUCCESS;
539 }
540
541 /**
542 * Implementation of child_sa_t.update
543 */
544 static status_t update(private_child_sa_t *this,
545 proposal_t *proposal, ipsec_mode_t mode,
546 chunk_t integ_in, chunk_t integ_out,
547 chunk_t encr_in, chunk_t encr_out)
548 {
549 this->proposal = proposal->clone(proposal);
550 this->protocol = proposal->get_protocol(proposal);
551
552 /* install outbound SAs */
553 if (install(this, proposal, mode, integ_out, encr_out, FALSE) != SUCCESS)
554 {
555 return FAILED;
556 }
557 /* install inbound SAs */
558 if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS)
559 {
560 return FAILED;
561 }
562 return SUCCESS;
563 }
564
565 /**
566 * Implementation of child_sa_t.get_proposal
567 */
568 static proposal_t* get_proposal(private_child_sa_t *this)
569 {
570 return this->proposal;
571 }
572
573 /**
574 * Implementation of child_sa_t.add_policies
575 */
576 static status_t add_policies(private_child_sa_t *this,
577 linked_list_t *my_ts_list, linked_list_t *other_ts_list,
578 ipsec_mode_t mode, protocol_id_t proto)
579 {
580 enumerator_t *enumerator;
581 traffic_selector_t *my_ts, *other_ts;
582 status_t status = SUCCESS;
583 bool routed = (this->state == CHILD_CREATED);
584
585 if (this->protocol == PROTO_NONE)
586 { /* update if not set yet */
587 this->protocol = proto;
588 }
589
590 /* apply traffic selectors */
591 enumerator = my_ts_list->create_enumerator(my_ts_list);
592 while (enumerator->enumerate(enumerator, &my_ts))
593 {
594 this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts));
595 }
596 enumerator->destroy(enumerator);
597 enumerator = other_ts_list->create_enumerator(other_ts_list);
598 while (enumerator->enumerate(enumerator, &other_ts))
599 {
600 this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts));
601 }
602 enumerator->destroy(enumerator);
603
604 if (this->config->install_policy(this->config))
605 {
606 /* enumerate pairs of traffic selectors */
607 enumerator = create_policy_enumerator(this);
608 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
609 {
610 /* install 3 policies: out, in and forward */
611 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
612 this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT,
613 this->other_spi, this->protocol, this->reqid, mode, this->ipcomp,
614 this->other_cpi, routed);
615
616 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
617 this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN,
618 this->my_spi, this->protocol, this->reqid, mode, this->ipcomp,
619 this->my_cpi, routed);
620
621 if (mode == MODE_TUNNEL)
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
685 /* update his (responder) SA */
686 if (charon->kernel_interface->update_sa(charon->kernel_interface, this->other_spi,
687 this->protocol, this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0,
688 this->my_addr, this->other_addr, me, other,
689 this->encap, encap) == NOT_SUPPORTED)
690 {
691 return NOT_SUPPORTED;
692 }
693
694 if (this->config->install_policy(this->config))
695 {
696 /* update policies */
697 if (!me->ip_equals(me, this->my_addr) ||
698 !other->ip_equals(other, this->other_addr))
699 {
700 enumerator_t *enumerator;
701 traffic_selector_t *my_ts, *other_ts;
702
703 /* always use high priorities, as hosts getting updated are INSTALLED */
704 enumerator = create_policy_enumerator(this);
705 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
706 {
707 /* remove old policies first */
708 charon->kernel_interface->del_policy(charon->kernel_interface,
709 my_ts, other_ts, POLICY_OUT, FALSE);
710 charon->kernel_interface->del_policy(charon->kernel_interface,
711 other_ts, my_ts, POLICY_IN, FALSE);
712 if (this->mode == MODE_TUNNEL)
713 {
714 charon->kernel_interface->del_policy(charon->kernel_interface,
715 other_ts, my_ts, POLICY_FWD, FALSE);
716 }
717
718 /* check whether we have to update a "dynamic" traffic selector */
719 if (!me->ip_equals(me, this->my_addr) &&
720 my_ts->is_host(my_ts, this->my_addr))
721 {
722 my_ts->set_address(my_ts, me);
723 }
724 if (!other->ip_equals(other, this->other_addr) &&
725 other_ts->is_host(other_ts, this->other_addr))
726 {
727 other_ts->set_address(other_ts, other);
728 }
729
730 /* we reinstall the virtual IP to handle interface roaming
731 * correctly */
732 if (vip)
733 {
734 charon->kernel_interface->del_ip(charon->kernel_interface, vip);
735 charon->kernel_interface->add_ip(charon->kernel_interface, vip, me);
736 }
737
738 /* reinstall updated policies */
739 charon->kernel_interface->add_policy(charon->kernel_interface,
740 me, other, my_ts, other_ts, POLICY_OUT, this->other_spi,
741 this->protocol, this->reqid, this->mode, this->ipcomp,
742 this->other_cpi, FALSE);
743 charon->kernel_interface->add_policy(charon->kernel_interface,
744 other, me, other_ts, my_ts, POLICY_IN, this->my_spi,
745 this->protocol, this->reqid, this->mode, this->ipcomp,
746 this->my_cpi, FALSE);
747 if (this->mode == MODE_TUNNEL)
748 {
749 charon->kernel_interface->add_policy(charon->kernel_interface,
750 other, me, other_ts, my_ts, POLICY_FWD, this->my_spi,
751 this->protocol, this->reqid, this->mode, this->ipcomp,
752 this->my_cpi, FALSE);
753 }
754 }
755 enumerator->destroy(enumerator);
756 }
757 }
758
759 /* apply hosts */
760 if (!this->config->use_proxy_mode(this->config) || this->mode != MODE_TRANSPORT)
761 {
762 if (!me->equals(me, this->my_addr))
763 {
764 this->my_addr->destroy(this->my_addr);
765 this->my_addr = me->clone(me);
766 }
767 if (!other->equals(other, this->other_addr))
768 {
769 this->other_addr->destroy(this->other_addr);
770 this->other_addr = other->clone(other);
771 }
772 }
773 this->encap = encap;
774
775 set_state(this, old);
776
777 return SUCCESS;
778 }
779
780 /**
781 * Implementation of child_sa_t.activate_ipcomp.
782 */
783 static void activate_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp,
784 u_int16_t other_cpi)
785 {
786 this->ipcomp = ipcomp;
787 this->other_cpi = other_cpi;
788 }
789
790 /**
791 * Implementation of child_sa_t.allocate_cpi.
792 */
793 static u_int16_t allocate_cpi(private_child_sa_t *this)
794 {
795 if (!this->cpi_allocated)
796 {
797 charon->kernel_interface->get_cpi(charon->kernel_interface,
798 this->other_addr, this->my_addr, this->reqid, &this->my_cpi);
799 this->cpi_allocated = TRUE;
800 }
801 return this->my_cpi;
802 }
803
804 /**
805 * Implementation of child_sa_t.destroy.
806 */
807 static void destroy(private_child_sa_t *this)
808 {
809 enumerator_t *enumerator;
810 traffic_selector_t *my_ts, *other_ts;
811 bool unrouted = (this->state == CHILD_ROUTED);
812
813 set_state(this, CHILD_DESTROYING);
814
815 /* delete SAs in the kernel, if they are set up */
816 if (this->my_spi)
817 {
818 charon->kernel_interface->del_sa(charon->kernel_interface,
819 this->my_addr, this->my_spi, this->protocol,
820 this->my_cpi);
821 }
822 if (this->alloc_esp_spi && this->alloc_esp_spi != this->my_spi)
823 {
824 charon->kernel_interface->del_sa(charon->kernel_interface,
825 this->my_addr, this->alloc_esp_spi, PROTO_ESP, 0);
826 }
827 if (this->alloc_ah_spi && this->alloc_ah_spi != this->my_spi)
828 {
829 charon->kernel_interface->del_sa(charon->kernel_interface,
830 this->my_addr, this->alloc_ah_spi, PROTO_AH, 0);
831 }
832 if (this->other_spi)
833 {
834 charon->kernel_interface->del_sa(charon->kernel_interface,
835 this->other_addr, this->other_spi, this->protocol,
836 this->other_cpi);
837 }
838
839 if (this->config->install_policy(this->config))
840 {
841 /* delete all policies in the kernel */
842 enumerator = create_policy_enumerator(this);
843 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
844 {
845 charon->kernel_interface->del_policy(charon->kernel_interface,
846 my_ts, other_ts, POLICY_OUT, unrouted);
847 charon->kernel_interface->del_policy(charon->kernel_interface,
848 other_ts, my_ts, POLICY_IN, unrouted);
849 if (this->mode == MODE_TUNNEL)
850 {
851 charon->kernel_interface->del_policy(charon->kernel_interface,
852 other_ts, my_ts, POLICY_FWD, unrouted);
853 }
854 }
855 enumerator->destroy(enumerator);
856 }
857
858 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
859 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
860 this->my_addr->destroy(this->my_addr);
861 this->other_addr->destroy(this->other_addr);
862 DESTROY_IF(this->proposal);
863 this->config->destroy(this->config);
864 free(this);
865 }
866
867 /*
868 * Described in header.
869 */
870 child_sa_t * child_sa_create(host_t *me, host_t* other,
871 child_cfg_t *config, u_int32_t rekey, bool encap)
872 {
873 static u_int32_t reqid = 0;
874 private_child_sa_t *this = malloc_thing(private_child_sa_t);
875
876 /* public functions */
877 this->public.get_name = (char*(*)(child_sa_t*))get_name;
878 this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
879 this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
880 this->public.get_cpi = (u_int16_t(*)(child_sa_t*, bool))get_cpi;
881 this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
882 this->public.get_mode = (ipsec_mode_t(*)(child_sa_t*))get_mode;
883 this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp;
884 this->public.has_encap = (bool(*)(child_sa_t*))has_encap;
885 this->public.get_lifetime = (u_int32_t(*)(child_sa_t*, bool))get_lifetime;
886 this->public.get_usetime = (u_int32_t(*)(child_sa_t*, bool))get_usetime;
887 this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
888 this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))add;
889 this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))update;
890 this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal;
891 this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update_hosts;
892 this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,ipsec_mode_t,protocol_id_t))add_policies;
893 this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
894 this->public.create_policy_enumerator = (enumerator_t*(*)(child_sa_t*))create_policy_enumerator;
895 this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
896 this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
897 this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config;
898 this->public.activate_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t,u_int16_t))activate_ipcomp;
899 this->public.allocate_cpi = (u_int16_t(*)(child_sa_t*))allocate_cpi;
900 this->public.destroy = (void(*)(child_sa_t*))destroy;
901
902 /* private data */
903 this->my_addr = me->clone(me);
904 this->other_addr = other->clone(other);
905 this->my_spi = 0;
906 this->my_cpi = 0;
907 this->other_spi = 0;
908 this->other_cpi = 0;
909 this->alloc_ah_spi = 0;
910 this->alloc_esp_spi = 0;
911 this->encap = encap;
912 this->cpi_allocated = FALSE;
913 this->ipcomp = IPCOMP_NONE;
914 this->state = CHILD_CREATED;
915 /* reuse old reqid if we are rekeying an existing CHILD_SA */
916 this->reqid = rekey ? rekey : ++reqid;
917 this->my_ts = linked_list_create();
918 this->other_ts = linked_list_create();
919 this->protocol = PROTO_NONE;
920 this->mode = MODE_TUNNEL;
921 this->proposal = NULL;
922 this->config = config;
923 config->get_ref(config);
924
925 /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
926 if (config->get_mode(config) == MODE_TRANSPORT &&
927 config->use_proxy_mode(config))
928 {
929 ts_type_t type;
930 int family;
931 chunk_t addr;
932 host_t *host;
933 enumerator_t *enumerator;
934 linked_list_t *my_ts_list, *other_ts_list;
935 traffic_selector_t *my_ts, *other_ts;
936
937 this->mode = MODE_TRANSPORT;
938
939 my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me);
940 enumerator = my_ts_list->create_enumerator(my_ts_list);
941 if (enumerator->enumerate(enumerator, &my_ts))
942 {
943 if (my_ts->is_host(my_ts, NULL) &&
944 !my_ts->is_host(my_ts, this->my_addr))
945 {
946 type = my_ts->get_type(my_ts);
947 family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
948 addr = my_ts->get_from_address(my_ts);
949 host = host_create_from_chunk(family, addr, 0);
950 free(addr.ptr);
951 DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H",
952 this->my_addr, host);
953 this->my_addr->destroy(this->my_addr);
954 this->my_addr = host;
955 }
956 }
957 enumerator->destroy(enumerator);
958 my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy));
959
960 other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other);
961 enumerator = other_ts_list->create_enumerator(other_ts_list);
962 if (enumerator->enumerate(enumerator, &other_ts))
963 {
964 if (other_ts->is_host(other_ts, NULL) &&
965 !other_ts->is_host(other_ts, this->other_addr))
966 {
967 type = other_ts->get_type(other_ts);
968 family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
969 addr = other_ts->get_from_address(other_ts);
970 host = host_create_from_chunk(family, addr, 0);
971 free(addr.ptr);
972 DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H",
973 this->other_addr, host);
974 this->other_addr->destroy(this->other_addr);
975 this->other_addr = host;
976 }
977 }
978 enumerator->destroy(enumerator);
979 other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy));
980 }
981
982 return &this->public;
983 }
984