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