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