]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/sa/child_sa.c
support of xfrm marks for IKEv2
[thirdparty/strongswan.git] / src / libcharon / sa / child_sa.c
CommitLineData
3ebebc5e 1/*
cb123493 2 * Copyright (C) 2006-2009 Tobias Brunner
a985db3f 3 * Copyright (C) 2005-2008 Martin Willi
d4aad554 4 * Copyright (C) 2006 Daniel Roethlisberger
c71d53ba 5 * Copyright (C) 2005 Jan Hutter
3ebebc5e
MW
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
60356f33 19#define _GNU_SOURCE
b92eef28 20#include "child_sa.h"
3ebebc5e 21
a095243f 22#include <stdio.h>
4c23a8c9 23#include <string.h>
e13389a7 24#include <time.h>
4c23a8c9 25
aeda79ff
MW
26#include <daemon.h>
27
a985db3f 28ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
60356f33
MW
29 "CREATED",
30 "ROUTED",
ea625fab 31 "INSTALLING",
60356f33 32 "INSTALLED",
ad3af574 33 "UPDATING",
60356f33
MW
34 "REKEYING",
35 "DELETING",
a985db3f 36 "DESTROYING",
60356f33 37);
bcb95ced 38
3ebebc5e
MW
39typedef struct private_child_sa_t private_child_sa_t;
40
41/**
7b8bae99 42 * Private data of a child_sa_t object.
3ebebc5e
MW
43 */
44struct private_child_sa_t {
45 /**
144f676c 46 * Public interface of child_sa_t.
3ebebc5e
MW
47 */
48 child_sa_t public;
7daf5226 49
80853d84
MW
50 /**
51 * address of us
52 */
53 host_t *my_addr;
7daf5226 54
3efbf983 55 /**
80853d84 56 * address of remote
3efbf983 57 */
80853d84 58 host_t *other_addr;
7daf5226 59
3efbf983 60 /**
80853d84 61 * our actually used SPI, 0 if unused
3efbf983 62 */
80853d84 63 u_int32_t my_spi;
7daf5226 64
aeda79ff 65 /**
80853d84 66 * others used SPI, 0 if unused
aeda79ff 67 */
80853d84 68 u_int32_t other_spi;
7daf5226 69
8dfbe71b 70 /**
80853d84 71 * our Compression Parameter Index (CPI) used, 0 if unused
8dfbe71b 72 */
80853d84 73 u_int16_t my_cpi;
7daf5226 74
8dfbe71b 75 /**
80853d84 76 * others Compression Parameter Index (CPI) used, 0 if unused
8dfbe71b 77 */
80853d84 78 u_int16_t other_cpi;
7daf5226 79
5d187bd2 80 /**
80853d84 81 * List for local traffic selectors
5d187bd2 82 */
80853d84 83 linked_list_t *my_ts;
7daf5226 84
80853d84
MW
85 /**
86 * List for remote traffic selectors
87 */
88 linked_list_t *other_ts;
7daf5226 89
c0593835 90 /**
80853d84 91 * Protocol used to protect this SA, ESP|AH
c0593835 92 */
80853d84 93 protocol_id_t protocol;
7daf5226 94
3c7e72f5 95 /**
80853d84 96 * reqid used for this child_sa
3c7e72f5 97 */
80853d84 98 u_int32_t reqid;
7daf5226 99
ee26c537
AS
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
a2a3fb3e 110 /**
6e10aead 111 * absolute time when rekeying is scheduled
a2a3fb3e 112 */
6e10aead 113 time_t rekey_time;
7daf5226 114
e70d5576 115 /**
6e10aead 116 * absolute time when the SA expires
e70d5576 117 */
6e10aead 118 time_t expire_time;
7daf5226 119
bcb95ced
MW
120 /**
121 * state of the CHILD_SA
122 */
123 child_sa_state_t state;
fff4ee8a 124
1239c6f4 125 /**
fc2d1c42 126 * Specifies if UDP encapsulation is enabled (NAT traversal)
1239c6f4 127 */
fc2d1c42 128 bool encap;
7daf5226 129
d4aad554
TB
130 /**
131 * Specifies the IPComp transform used (IPCOMP_NONE if disabled)
132 */
133 ipcomp_transform_t ipcomp;
7daf5226 134
7652be89
MW
135 /**
136 * mode this SA uses, tunnel/transport
137 */
a341a68f 138 ipsec_mode_t mode;
7daf5226 139
4c401ea2
MW
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
80853d84 150 /**
7b3814f7
MW
151 * selected proposal
152 */
153 proposal_t *proposal;
7daf5226 154
c60c7694 155 /**
e0fe7651 156 * config used to create this child
c60c7694 157 */
e0fe7651 158 child_cfg_t *config;
3f720dc7
AS
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;
3ebebc5e
MW
179};
180
e517b4b1 181/**
d487b4b7 182 * Implementation of child_sa_t.get_name
9be547c0
MW
183 */
184static char *get_name(private_child_sa_t *this)
185{
e0fe7651 186 return this->config->get_name(this->config);
9be547c0
MW
187}
188
32b6500f
MW
189/**
190 * Implements child_sa_t.get_reqid
191 */
192static u_int32_t get_reqid(private_child_sa_t *this)
193{
194 return this->reqid;
195}
3aaf7908
MW
196
197/**
198 * Implements child_sa_t.get_config
199 */
200static child_cfg_t* get_config(private_child_sa_t *this)
201{
202 return this->config;
203}
204
205/**
206 * Implements child_sa_t.set_state
207 */
208static void set_state(private_child_sa_t *this, child_sa_state_t state)
209{
210 charon->bus->child_state_change(charon->bus, &this->public, state);
211 this->state = state;
212}
213
214/**
215 * Implements child_sa_t.get_state
216 */
217static child_sa_state_t get_state(private_child_sa_t *this)
218{
219 return this->state;
220}
221
8d77edde
MW
222/**
223 * Implements child_sa_t.get_spi
224 */
225u_int32_t get_spi(private_child_sa_t *this, bool inbound)
226{
80853d84 227 return inbound ? this->my_spi : this->other_spi;
8d77edde
MW
228}
229
66da78b4
AS
230/**
231 * Implements child_sa_t.get_cpi
232 */
233u_int16_t get_cpi(private_child_sa_t *this, bool inbound)
234{
80853d84 235 return inbound ? this->my_cpi : this->other_cpi;
66da78b4
AS
236}
237
8d77edde
MW
238/**
239 * Implements child_sa_t.get_protocol
240 */
241protocol_id_t get_protocol(private_child_sa_t *this)
242{
243 return this->protocol;
244}
32b6500f 245
3aaf7908
MW
246/**
247 * Implementation of child_sa_t.set_protocol
248 */
249static void set_protocol(private_child_sa_t *this, protocol_id_t protocol)
250{
251 this->protocol = protocol;
252}
253
80853d84
MW
254/**
255 * Implementation of child_sa_t.get_mode
256 */
257static ipsec_mode_t get_mode(private_child_sa_t *this)
258{
259 return this->mode;
260}
261
3aaf7908
MW
262/**
263 * Implementation of child_sa_t.set_mode
264 */
265static void set_mode(private_child_sa_t *this, ipsec_mode_t mode)
266{
267 this->mode = mode;
268}
269
82d20c05
MW
270/**
271 * Implementation of child_sa_t.has_encap
272 */
273static bool has_encap(private_child_sa_t *this)
274{
275 return this->encap;
276}
277
278/**
279 * Implementation of child_sa_t.get_ipcomp
280 */
281static ipcomp_transform_t get_ipcomp(private_child_sa_t *this)
282{
283 return this->ipcomp;
284}
285
bcb95ced 286/**
3aaf7908 287 * Implementation of child_sa_t.set_ipcomp.
bcb95ced 288 */
3aaf7908 289static void set_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp)
bcb95ced 290{
3aaf7908 291 this->ipcomp = ipcomp;
bcb95ced
MW
292}
293
4c401ea2
MW
294/**
295 * Implementation of child_sa_t.set_close_action.
296 */
297static void set_close_action(private_child_sa_t *this, action_t action)
298{
299 this->close_action = action;
300}
301
302/**
303 * Implementation of child_sa_t.get_close_action.
304 */
305static action_t get_close_action(private_child_sa_t *this)
306{
307 return this->close_action;
308}
309
310/**
311 * Implementation of child_sa_t.set_dpd_action.
312 */
313static void set_dpd_action(private_child_sa_t *this, action_t action)
314{
315 this->dpd_action = action;
316}
317
318/**
319 * Implementation of child_sa_t.get_dpd_action.
320 */
321static action_t get_dpd_action(private_child_sa_t *this)
322{
323 return this->dpd_action;
324}
325
c60c7694 326/**
3aaf7908 327 * Implementation of child_sa_t.get_proposal
c60c7694 328 */
3aaf7908 329static proposal_t* get_proposal(private_child_sa_t *this)
c60c7694 330{
3aaf7908
MW
331 return this->proposal;
332}
333
334/**
335 * Implementation of child_sa_t.set_proposal
336 */
337static void set_proposal(private_child_sa_t *this, proposal_t *proposal)
338{
339 this->proposal = proposal->clone(proposal);
340}
341
342/**
343 * Implementation of child_sa_t.get_traffic_selectors.
344 */
345static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local)
346{
347 return local ? this->my_ts : this->other_ts;
c60c7694
MW
348}
349
1df106bf
MW
350typedef struct policy_enumerator_t policy_enumerator_t;
351
352/**
353 * Private policy enumerator
354 */
355struct policy_enumerator_t {
356 /** implements enumerator_t */
357 enumerator_t public;
358 /** enumerator over own TS */
359 enumerator_t *mine;
360 /** enumerator over others TS */
361 enumerator_t *other;
362 /** list of others TS, to recreate enumerator */
363 linked_list_t *list;
6df2837a
MW
364 /** currently enumerating TS for "me" side */
365 traffic_selector_t *ts;
1df106bf
MW
366};
367
368/**
369 * enumerator function of create_policy_enumerator()
370 */
371static bool policy_enumerate(policy_enumerator_t *this,
372 traffic_selector_t **my_out, traffic_selector_t **other_out)
373{
6df2837a 374 traffic_selector_t *other_ts;
7daf5226 375
6df2837a 376 while (this->ts || this->mine->enumerate(this->mine, &this->ts))
1df106bf 377 {
6df2837a
MW
378 if (!this->other->enumerate(this->other, &other_ts))
379 { /* end of others list, restart with new of mine */
380 this->other->destroy(this->other);
381 this->other = this->list->create_enumerator(this->list);
382 this->ts = NULL;
383 continue;
384 }
385 if (this->ts->get_type(this->ts) != other_ts->get_type(other_ts))
386 { /* family mismatch */
387 continue;
388 }
389 if (this->ts->get_protocol(this->ts) &&
390 other_ts->get_protocol(other_ts) &&
391 this->ts->get_protocol(this->ts) != other_ts->get_protocol(other_ts))
392 { /* protocol mismatch */
393 continue;
1df106bf 394 }
6df2837a
MW
395 *my_out = this->ts;
396 *other_out = other_ts;
397 return TRUE;
1df106bf
MW
398 }
399 return FALSE;
400}
401
402/**
403 * destroy function of create_policy_enumerator()
404 */
405static void policy_destroy(policy_enumerator_t *this)
406{
407 this->mine->destroy(this->mine);
408 this->other->destroy(this->other);
409 free(this);
410}
411
412/**
413 * Implementation of child_sa_t.create_policy_enumerator
414 */
415static enumerator_t* create_policy_enumerator(private_child_sa_t *this)
416{
417 policy_enumerator_t *e = malloc_thing(policy_enumerator_t);
7daf5226 418
1df106bf
MW
419 e->public.enumerate = (void*)policy_enumerate;
420 e->public.destroy = (void*)policy_destroy;
421 e->mine = this->my_ts->create_enumerator(this->my_ts);
422 e->other = this->other_ts->create_enumerator(this->other_ts);
423 e->list = this->other_ts;
6df2837a 424 e->ts = NULL;
7daf5226 425
1df106bf
MW
426 return &e->public;
427}
428
dd83c6d4
TB
429/**
430 * update the cached usebytes
431 * returns SUCCESS if the usebytes have changed, FAILED if not or no SPIs
432 * are available, and NOT_SUPPORTED if the kernel interface does not support
99dd4291 433 * querying the usebytes.
dd83c6d4 434 */
c3a78360 435static status_t update_usebytes(private_child_sa_t *this, bool inbound)
dd83c6d4
TB
436{
437 status_t status = FAILED;
438 u_int64_t bytes;
7daf5226 439
dd83c6d4
TB
440 if (inbound)
441 {
442 if (this->my_spi)
443 {
ee26c537 444 status = charon->kernel_interface->query_sa(charon->kernel_interface,
dd83c6d4 445 this->other_addr, this->my_addr,
ee26c537
AS
446 this->my_spi, this->protocol,
447 this->mark_in, &bytes);
dd83c6d4
TB
448 if (status == SUCCESS)
449 {
450 if (bytes > this->my_usebytes)
451 {
452 this->my_usebytes = bytes;
453 return SUCCESS;
454 }
455 return FAILED;
456 }
457 }
458 }
459 else
460 {
461 if (this->other_spi)
462 {
ee26c537 463 status = charon->kernel_interface->query_sa(charon->kernel_interface,
dd83c6d4 464 this->my_addr, this->other_addr,
ee26c537
AS
465 this->other_spi, this->protocol,
466 this->mark_out, &bytes);
dd83c6d4
TB
467 if (status == SUCCESS)
468 {
469 if (bytes > this->other_usebytes)
470 {
471 this->other_usebytes = bytes;
472 return SUCCESS;
473 }
474 return FAILED;
475 }
476 }
477 }
478 return status;
479}
480
a3ce4bc2 481/**
c3a78360 482 * updates the cached usetime
a3ce4bc2 483 */
c3a78360 484static void update_usetime(private_child_sa_t *this, bool inbound)
a3ce4bc2 485{
1df106bf 486 enumerator_t *enumerator;
6e10aead
MW
487 traffic_selector_t *my_ts, *other_ts;
488 u_int32_t last_use = 0;
7daf5226 489
1df106bf
MW
490 enumerator = create_policy_enumerator(this);
491 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
a3ce4bc2 492 {
6e10aead 493 u_int32_t in, out, fwd;
7daf5226 494
dd83c6d4 495 if (inbound)
a3ce4bc2 496 {
6e10aead 497 if (charon->kernel_interface->query_policy(charon->kernel_interface,
ee26c537 498 other_ts, my_ts, POLICY_IN, this->mark_in, &in) == SUCCESS)
6e10aead
MW
499 {
500 last_use = max(last_use, in);
501 }
ce42db09 502 if (this->mode != MODE_TRANSPORT)
6e10aead 503 {
d487b4b7 504 if (charon->kernel_interface->query_policy(charon->kernel_interface,
ee26c537 505 other_ts, my_ts, POLICY_FWD, this->mark_in, &fwd) == SUCCESS)
d487b4b7
AS
506 {
507 last_use = max(last_use, fwd);
508 }
6e10aead 509 }
a3ce4bc2 510 }
6e10aead 511 else
a3ce4bc2 512 {
6e10aead 513 if (charon->kernel_interface->query_policy(charon->kernel_interface,
ee26c537 514 my_ts, other_ts, POLICY_OUT, this->mark_out, &out) == SUCCESS)
6e10aead
MW
515 {
516 last_use = max(last_use, out);
517 }
a3ce4bc2
MW
518 }
519 }
1df106bf 520 enumerator->destroy(enumerator);
99dd4291
AS
521
522 if (last_use == 0)
523 {
524 return;
525 }
3f720dc7
AS
526 if (inbound)
527 {
528 this->my_usetime = last_use;
529 }
530 else
531 {
532 this->other_usetime = last_use;
533 }
6e10aead
MW
534}
535
2ad51539 536/**
c3a78360 537 * Implementation of child_sa_t.get_usestats
2ad51539 538 */
c3a78360
TB
539static void get_usestats(private_child_sa_t *this, bool inbound,
540 time_t *time, u_int64_t *bytes)
2ad51539 541{
c3a78360 542 if (update_usebytes(this, inbound) != FAILED)
99dd4291
AS
543 {
544 /* there was traffic since last update or the kernel interface
545 * does not support querying the number of usebytes.
546 */
c3a78360
TB
547 update_usetime(this, inbound);
548 }
549 if (time)
550 {
551 *time = inbound ? this->my_usetime : this->other_usetime;
552 }
553 if (bytes)
554 {
555 *bytes = inbound ? this->my_usebytes : this->other_usebytes;
556 }
2ad51539
AS
557}
558
6e10aead
MW
559/**
560 * Implementation of child_sa_t.get_lifetime
561 */
e3c7e729 562static time_t get_lifetime(private_child_sa_t *this, bool hard)
6e10aead 563{
80853d84 564 return hard ? this->expire_time : this->rekey_time;
a3ce4bc2
MW
565}
566
bcb95ced 567/**
3aaf7908 568 * Implementation of child_sa_t.alloc_spi
1396815a 569 */
3aaf7908 570static u_int32_t alloc_spi(private_child_sa_t *this, protocol_id_t protocol)
1396815a 571{
64e8ca28
MW
572 if (charon->kernel_interface->get_spi(charon->kernel_interface,
573 this->other_addr, this->my_addr, protocol,
3aaf7908 574 this->reqid, &this->my_spi) == SUCCESS)
64e8ca28
MW
575 {
576 return this->my_spi;
1396815a 577 }
3aaf7908 578 return 0;
1396815a
MW
579}
580
3ebebc5e 581/**
3aaf7908 582 * Implementation of child_sa_t.alloc_cpi
3ebebc5e 583 */
3aaf7908 584static u_int16_t alloc_cpi(private_child_sa_t *this)
3ebebc5e 585{
3aaf7908
MW
586 if (charon->kernel_interface->get_cpi(charon->kernel_interface,
587 this->other_addr, this->my_addr, this->reqid,
588 &this->my_cpi) == SUCCESS)
30b5b412 589 {
3aaf7908 590 return this->my_cpi;
30b5b412 591 }
3aaf7908 592 return 0;
3ebebc5e
MW
593}
594
80853d84 595/**
3aaf7908 596 * Implementation of child_sa_t.install
80853d84 597 */
3aaf7908 598static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ,
6ec949e0
MW
599 u_int32_t spi, u_int16_t cpi, bool inbound,
600 linked_list_t *my_ts, linked_list_t *other_ts)
3ebebc5e 601{
80853d84 602 u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
6ec949e0 603 traffic_selector_t *src_ts = NULL, *dst_ts = NULL;
cb123493
TB
604 time_t now;
605 lifetime_cfg_t *lifetime;
e517b4b1 606 host_t *src, *dst;
30b5b412 607 status_t status;
3aaf7908 608 bool update = FALSE;
7daf5226 609
80853d84
MW
610 /* now we have to decide which spi to use. Use self allocated, if "in",
611 * or the one in the proposal, if not "in" (others). Additionally,
3efbf983 612 * source and dest host switch depending on the role */
3aaf7908 613 if (inbound)
aeda79ff 614 {
80853d84
MW
615 dst = this->my_addr;
616 src = this->other_addr;
3aaf7908
MW
617 if (this->my_spi == spi)
618 { /* alloc_spi has been called, do an SA update */
619 update = TRUE;
620 }
621 this->my_spi = spi;
622 this->my_cpi = cpi;
aeda79ff 623 }
8d77edde
MW
624 else
625 {
80853d84
MW
626 src = this->my_addr;
627 dst = this->other_addr;
3aaf7908
MW
628 this->other_spi = spi;
629 this->other_cpi = cpi;
8d77edde 630 }
7daf5226 631
3aaf7908 632 DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound",
60356f33 633 protocol_id_names, this->protocol);
7daf5226 634
5c131a01 635 /* send SA down to the kernel */
b83806d8 636 DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
7daf5226 637
3aaf7908
MW
638 this->proposal->get_algorithm(this->proposal, ENCRYPTION_ALGORITHM,
639 &enc_alg, &size);
640 this->proposal->get_algorithm(this->proposal, INTEGRITY_ALGORITHM,
641 &int_alg, &size);
7daf5226 642
cb123493 643 lifetime = this->config->get_lifetime(this->config);
7daf5226 644
6180a558 645 now = time_monotonic(NULL);
e75f4237 646 if (lifetime->time.rekey)
37974979 647 {
e75f4237 648 this->rekey_time = now + lifetime->time.rekey;
37974979 649 }
e75f4237 650 if (lifetime->time.life)
37974979 651 {
e75f4237 652 this->expire_time = now + lifetime->time.life;
cb123493 653 }
7daf5226 654
e75f4237 655 if (!lifetime->time.jitter && !inbound)
cb123493 656 { /* avoid triggering multiple rekey events */
e75f4237 657 lifetime->time.rekey = 0;
37974979 658 }
7daf5226 659
6ec949e0
MW
660 if (this->mode == MODE_BEET)
661 {
662 /* BEET requires the bound address from the traffic selectors.
663 * TODO: We add just the first traffic selector for now, as the
664 * kernel accepts a single TS per SA only */
665 if (inbound)
666 {
667 my_ts->get_first(my_ts, (void**)&dst_ts);
668 other_ts->get_first(other_ts, (void**)&src_ts);
669 }
670 else
671 {
672 my_ts->get_first(my_ts, (void**)&src_ts);
673 other_ts->get_first(other_ts, (void**)&dst_ts);
674 }
675 }
676
cb123493 677 status = charon->kernel_interface->add_sa(charon->kernel_interface,
ee26c537
AS
678 src, dst, spi, this->protocol, this->reqid,
679 inbound ? this->mark_in : this->mark_out,
680 lifetime, enc_alg, encr, int_alg, integ, this->mode,
681 this->ipcomp, cpi, this->encap, update, src_ts, dst_ts);
7daf5226 682
cb123493 683 free(lifetime);
7daf5226 684
8d77edde 685 return status;
30b5b412
MW
686}
687
80853d84
MW
688/**
689 * Implementation of child_sa_t.add_policies
690 */
7652be89 691static status_t add_policies(private_child_sa_t *this,
3aaf7908 692 linked_list_t *my_ts_list, linked_list_t *other_ts_list)
a527a426 693{
1df106bf 694 enumerator_t *enumerator;
5d187bd2 695 traffic_selector_t *my_ts, *other_ts;
1df106bf 696 status_t status = SUCCESS;
ea625fab 697 bool routed = (this->state == CHILD_CREATED);
7daf5226 698
1df106bf
MW
699 /* apply traffic selectors */
700 enumerator = my_ts_list->create_enumerator(my_ts_list);
701 while (enumerator->enumerate(enumerator, &my_ts))
a527a426 702 {
1df106bf
MW
703 this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts));
704 }
705 enumerator->destroy(enumerator);
706 enumerator = other_ts_list->create_enumerator(other_ts_list);
707 while (enumerator->enumerate(enumerator, &other_ts))
708 {
709 this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts));
710 }
711 enumerator->destroy(enumerator);
7daf5226 712
d487b4b7 713 if (this->config->install_policy(this->config))
1df106bf 714 {
d487b4b7
AS
715 /* enumerate pairs of traffic selectors */
716 enumerator = create_policy_enumerator(this);
717 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
718 {
719 /* install 3 policies: out, in and forward */
720 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
721 this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT,
ee26c537
AS
722 this->other_spi, this->protocol, this->reqid, this->mark_out,
723 this->mode, this->ipcomp, this->other_cpi, routed);
7daf5226 724
d487b4b7
AS
725 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
726 this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN,
ee26c537
AS
727 this->my_spi, this->protocol, this->reqid, this->mark_in,
728 this->mode, this->ipcomp, this->my_cpi, routed);
3aaf7908 729 if (this->mode != MODE_TRANSPORT)
d487b4b7
AS
730 {
731 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
ea625fab 732 this->other_addr, this->my_addr, other_ts, my_ts, POLICY_FWD,
ee26c537
AS
733 this->my_spi, this->protocol, this->reqid, this->mark_in,
734 this->mode, this->ipcomp, this->my_cpi, routed);
d487b4b7 735 }
7daf5226 736
d487b4b7
AS
737 if (status != SUCCESS)
738 {
739 break;
740 }
5d187bd2 741 }
d487b4b7 742 enumerator->destroy(enumerator);
5d187bd2 743 }
7daf5226 744
3aaf7908
MW
745 if (status == SUCCESS && this->state == CHILD_CREATED)
746 { /* switch to routed state if no SAD entry set up */
747 set_state(this, CHILD_ROUTED);
45f76a7d 748 }
1df106bf 749 return status;
30b5b412
MW
750}
751
8dfbe71b 752/**
3aaf7908 753 * Implementation of child_sa_t.update.
8dfbe71b 754 */
3aaf7908 755static status_t update(private_child_sa_t *this, host_t *me, host_t *other,
dd83c6d4 756 host_t *vip, bool encap)
1396815a 757{
ad3af574 758 child_sa_state_t old;
08c6ed9f 759 bool transport_proxy_mode;
7daf5226 760
2b3100b5 761 /* anything changed at all? */
dd83c6d4 762 if (me->equals(me, this->my_addr) &&
80853d84 763 other->equals(other, this->other_addr) && this->encap == encap)
1396815a
MW
764 {
765 return SUCCESS;
766 }
7daf5226 767
ad3af574
MW
768 old = this->state;
769 set_state(this, CHILD_UPDATING);
08c6ed9f
AS
770 transport_proxy_mode = this->config->use_proxy_mode(this->config) &&
771 this->mode == MODE_TRANSPORT;
7daf5226 772
08c6ed9f 773 if (!transport_proxy_mode)
ea625fab 774 {
7a915d62
AS
775 /* update our (initator) SA */
776 if (this->my_spi)
777 {
778 if (charon->kernel_interface->update_sa(charon->kernel_interface,
779 this->my_spi, this->protocol,
780 this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0,
781 this->other_addr, this->my_addr, other, me,
ee26c537 782 this->encap, encap, this->mark_in) == NOT_SUPPORTED)
7a915d62
AS
783 {
784 return NOT_SUPPORTED;
785 }
786 }
7daf5226 787
7a915d62
AS
788 /* update his (responder) SA */
789 if (this->other_spi)
790 {
791 if (charon->kernel_interface->update_sa(charon->kernel_interface,
792 this->other_spi, this->protocol,
b9b8a98f 793 this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0,
7a915d62 794 this->my_addr, this->other_addr, me, other,
ee26c537 795 this->encap, encap, this->mark_out) == NOT_SUPPORTED)
7a915d62
AS
796 {
797 return NOT_SUPPORTED;
798 }
799 }
ea625fab 800 }
7daf5226 801
d487b4b7 802 if (this->config->install_policy(this->config))
1396815a 803 {
d487b4b7
AS
804 /* update policies */
805 if (!me->ip_equals(me, this->my_addr) ||
806 !other->ip_equals(other, this->other_addr))
1396815a 807 {
d487b4b7
AS
808 enumerator_t *enumerator;
809 traffic_selector_t *my_ts, *other_ts;
7daf5226 810
d487b4b7
AS
811 /* always use high priorities, as hosts getting updated are INSTALLED */
812 enumerator = create_policy_enumerator(this);
813 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
814 {
815 /* remove old policies first */
816 charon->kernel_interface->del_policy(charon->kernel_interface,
ee26c537 817 my_ts, other_ts, POLICY_OUT, this->mark_out, FALSE);
d487b4b7 818 charon->kernel_interface->del_policy(charon->kernel_interface,
ee26c537 819 other_ts, my_ts, POLICY_IN, this->mark_in, FALSE);
ce42db09 820 if (this->mode != MODE_TRANSPORT)
d487b4b7
AS
821 {
822 charon->kernel_interface->del_policy(charon->kernel_interface,
ee26c537 823 other_ts, my_ts, POLICY_FWD, this->mark_in, FALSE);
d487b4b7 824 }
7daf5226 825
d487b4b7
AS
826 /* check whether we have to update a "dynamic" traffic selector */
827 if (!me->ip_equals(me, this->my_addr) &&
828 my_ts->is_host(my_ts, this->my_addr))
829 {
830 my_ts->set_address(my_ts, me);
831 }
832 if (!other->ip_equals(other, this->other_addr) &&
833 other_ts->is_host(other_ts, this->other_addr))
834 {
835 other_ts->set_address(other_ts, other);
836 }
7daf5226 837
d487b4b7
AS
838 /* we reinstall the virtual IP to handle interface roaming
839 * correctly */
840 if (vip)
841 {
842 charon->kernel_interface->del_ip(charon->kernel_interface, vip);
843 charon->kernel_interface->add_ip(charon->kernel_interface, vip, me);
844 }
7daf5226 845
d487b4b7
AS
846 /* reinstall updated policies */
847 charon->kernel_interface->add_policy(charon->kernel_interface,
ea625fab 848 me, other, my_ts, other_ts, POLICY_OUT, this->other_spi,
ee26c537
AS
849 this->protocol, this->reqid, this->mark_out, this->mode,
850 this->ipcomp, this->other_cpi, FALSE);
dd83c6d4 851 charon->kernel_interface->add_policy(charon->kernel_interface,
ea625fab 852 other, me, other_ts, my_ts, POLICY_IN, this->my_spi,
ee26c537
AS
853 this->protocol, this->reqid, this->mark_in, this->mode,
854 this->ipcomp, this->my_cpi, FALSE);
ce42db09 855 if (this->mode != MODE_TRANSPORT)
d487b4b7
AS
856 {
857 charon->kernel_interface->add_policy(charon->kernel_interface,
ea625fab 858 other, me, other_ts, my_ts, POLICY_FWD, this->my_spi,
ee26c537
AS
859 this->protocol, this->reqid, this->mark_in, this->mode,
860 this->ipcomp, this->my_cpi, FALSE);
d487b4b7
AS
861 }
862 }
863 enumerator->destroy(enumerator);
1396815a
MW
864 }
865 }
7a915d62 866
08c6ed9f
AS
867 if (!transport_proxy_mode)
868 {
869 /* apply hosts */
870 if (!me->equals(me, this->my_addr))
871 {
872 this->my_addr->destroy(this->my_addr);
873 this->my_addr = me->clone(me);
874 }
875 if (!other->equals(other, this->other_addr))
876 {
877 this->other_addr->destroy(this->other_addr);
878 this->other_addr = other->clone(other);
879 }
880 }
881
ea625fab 882 this->encap = encap;
ad3af574 883 set_state(this, old);
7a915d62 884
1396815a
MW
885 return SUCCESS;
886}
887
30b5b412
MW
888/**
889 * Implementation of child_sa_t.destroy.
890 */
891static void destroy(private_child_sa_t *this)
892{
1df106bf
MW
893 enumerator_t *enumerator;
894 traffic_selector_t *my_ts, *other_ts;
ea625fab 895 bool unrouted = (this->state == CHILD_ROUTED);
7daf5226 896
a985db3f 897 set_state(this, CHILD_DESTROYING);
7daf5226 898
5d187bd2 899 /* delete SAs in the kernel, if they are set up */
80853d84 900 if (this->my_spi)
5d187bd2 901 {
1bc0b4f7
MW
902 /* if CHILD was not established, use PROTO_ESP used during alloc_spi().
903 * TODO: For AH support, we have to store protocol specific SPI.s */
904 if (this->protocol == PROTO_NONE)
905 {
906 this->protocol = PROTO_ESP;
907 }
5d187bd2 908 charon->kernel_interface->del_sa(charon->kernel_interface,
d24a74c5 909 this->other_addr, this->my_addr, this->my_spi,
ee26c537 910 this->protocol, this->my_cpi, this->mark_in);
3efbf983 911 }
80853d84 912 if (this->other_spi)
3efbf983 913 {
5d187bd2 914 charon->kernel_interface->del_sa(charon->kernel_interface,
d24a74c5 915 this->my_addr, this->other_addr, this->other_spi,
ee26c537 916 this->protocol, this->other_cpi, this->mark_out);
d4aad554 917 }
7daf5226 918
d487b4b7 919 if (this->config->install_policy(this->config))
695723d4 920 {
d487b4b7
AS
921 /* delete all policies in the kernel */
922 enumerator = create_policy_enumerator(this);
923 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
924 {
925 charon->kernel_interface->del_policy(charon->kernel_interface,
ee26c537 926 my_ts, other_ts, POLICY_OUT, this->mark_out, unrouted);
d487b4b7 927 charon->kernel_interface->del_policy(charon->kernel_interface,
ee26c537 928 other_ts, my_ts, POLICY_IN, this->mark_in, unrouted);
ce42db09 929 if (this->mode != MODE_TRANSPORT)
d487b4b7
AS
930 {
931 charon->kernel_interface->del_policy(charon->kernel_interface,
ee26c537 932 other_ts, my_ts, POLICY_FWD, this->mark_in, unrouted);
d487b4b7
AS
933 }
934 }
935 enumerator->destroy(enumerator);
5d187bd2 936 }
7daf5226 937
1df106bf
MW
938 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
939 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
80853d84
MW
940 this->my_addr->destroy(this->my_addr);
941 this->other_addr->destroy(this->other_addr);
942 DESTROY_IF(this->proposal);
e0fe7651 943 this->config->destroy(this->config);
5113680f 944 free(this);
30b5b412
MW
945}
946
947/*
948 * Described in header.
949 */
c60c7694 950child_sa_t * child_sa_create(host_t *me, host_t* other,
fc2d1c42 951 child_cfg_t *config, u_int32_t rekey, bool encap)
30b5b412 952{
c60c7694 953 static u_int32_t reqid = 0;
5113680f 954 private_child_sa_t *this = malloc_thing(private_child_sa_t);
30b5b412
MW
955
956 /* public functions */
9be547c0 957 this->public.get_name = (char*(*)(child_sa_t*))get_name;
32b6500f 958 this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
3aaf7908
MW
959 this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config;
960 this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
961 this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
8d77edde 962 this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
66da78b4 963 this->public.get_cpi = (u_int16_t(*)(child_sa_t*, bool))get_cpi;
8d77edde 964 this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
3aaf7908 965 this->public.set_protocol = (void(*)(child_sa_t*, protocol_id_t protocol))set_protocol;
6e10aead 966 this->public.get_mode = (ipsec_mode_t(*)(child_sa_t*))get_mode;
3aaf7908
MW
967 this->public.set_mode = (void(*)(child_sa_t*, ipsec_mode_t mode))set_mode;
968 this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal;
969 this->public.set_proposal = (void(*)(child_sa_t*, proposal_t *proposal))set_proposal;
e3c7e729 970 this->public.get_lifetime = (time_t(*)(child_sa_t*, bool))get_lifetime;
c3a78360 971 this->public.get_usestats = (void(*)(child_sa_t*,bool,time_t*,u_int64_t*))get_usestats;
3aaf7908
MW
972 this->public.has_encap = (bool(*)(child_sa_t*))has_encap;
973 this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp;
974 this->public.set_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t))set_ipcomp;
4c401ea2
MW
975 this->public.get_close_action = (action_t(*)(child_sa_t*))get_close_action;
976 this->public.set_close_action = (void(*)(child_sa_t*,action_t))set_close_action;
977 this->public.get_dpd_action = (action_t(*)(child_sa_t*))get_dpd_action;
978 this->public.set_dpd_action = (void(*)(child_sa_t*,action_t))set_dpd_action;
3aaf7908
MW
979 this->public.alloc_spi = (u_int32_t(*)(child_sa_t*, protocol_id_t protocol))alloc_spi;
980 this->public.alloc_cpi = (u_int16_t(*)(child_sa_t*))alloc_cpi;
6ec949e0 981 this->public.install = (status_t(*)(child_sa_t*, chunk_t encr, chunk_t integ, u_int32_t spi, u_int16_t cpi, bool inbound, linked_list_t *my_ts_list, linked_list_t *other_ts_list))install;
3aaf7908
MW
982 this->public.update = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update;
983 this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
e0fe7651 984 this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
1df106bf 985 this->public.create_policy_enumerator = (enumerator_t*(*)(child_sa_t*))create_policy_enumerator;
30b5b412 986 this->public.destroy = (void(*)(child_sa_t*))destroy;
7daf5226 987
30b5b412 988 /* private data */
80853d84
MW
989 this->my_addr = me->clone(me);
990 this->other_addr = other->clone(other);
991 this->my_spi = 0;
80853d84 992 this->other_spi = 0;
3aaf7908 993 this->my_cpi = 0;
80853d84 994 this->other_cpi = 0;
fc2d1c42 995 this->encap = encap;
d4aad554 996 this->ipcomp = IPCOMP_NONE;
bcb95ced 997 this->state = CHILD_CREATED;
3f720dc7
AS
998 this->my_usetime = 0;
999 this->other_usetime = 0;
1000 this->my_usebytes = 0;
1001 this->other_usebytes = 0;
8dfbe71b
MW
1002 this->my_ts = linked_list_create();
1003 this->other_ts = linked_list_create();
8d77edde 1004 this->protocol = PROTO_NONE;
7652be89 1005 this->mode = MODE_TUNNEL;
4c401ea2
MW
1006 this->close_action = config->get_close_action(config);
1007 this->dpd_action = config->get_dpd_action(config);
80853d84 1008 this->proposal = NULL;
37974979
MW
1009 this->rekey_time = 0;
1010 this->expire_time = 0;
e0fe7651
MW
1011 this->config = config;
1012 config->get_ref(config);
71a66a62 1013 this->reqid = config->get_reqid(config);
ee26c537
AS
1014 this->mark_in = config->get_mark(config, TRUE);
1015 this->mark_out = config->get_mark(config, FALSE);
1016
71a66a62
RB
1017 if (!this->reqid)
1018 {
1019 /* reuse old reqid if we are rekeying an existing CHILD_SA */
1020 this->reqid = rekey ? rekey : ++reqid;
1021 }
7daf5226 1022
dd83c6d4 1023 /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
d487b4b7 1024 if (config->get_mode(config) == MODE_TRANSPORT &&
323f9f99 1025 config->use_proxy_mode(config))
d487b4b7
AS
1026 {
1027 ts_type_t type;
1028 int family;
1029 chunk_t addr;
1030 host_t *host;
1031 enumerator_t *enumerator;
1032 linked_list_t *my_ts_list, *other_ts_list;
1033 traffic_selector_t *my_ts, *other_ts;
7daf5226 1034
d487b4b7 1035 this->mode = MODE_TRANSPORT;
7daf5226 1036
d487b4b7
AS
1037 my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me);
1038 enumerator = my_ts_list->create_enumerator(my_ts_list);
1039 if (enumerator->enumerate(enumerator, &my_ts))
1040 {
1041 if (my_ts->is_host(my_ts, NULL) &&
1042 !my_ts->is_host(my_ts, this->my_addr))
1043 {
1044 type = my_ts->get_type(my_ts);
1045 family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
1046 addr = my_ts->get_from_address(my_ts);
1047 host = host_create_from_chunk(family, addr, 0);
1048 free(addr.ptr);
1049 DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H",
dd83c6d4 1050 this->my_addr, host);
d487b4b7
AS
1051 this->my_addr->destroy(this->my_addr);
1052 this->my_addr = host;
1053 }
1054 }
1055 enumerator->destroy(enumerator);
1056 my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy));
7daf5226 1057
d487b4b7
AS
1058 other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other);
1059 enumerator = other_ts_list->create_enumerator(other_ts_list);
1060 if (enumerator->enumerate(enumerator, &other_ts))
1061 {
1062 if (other_ts->is_host(other_ts, NULL) &&
1063 !other_ts->is_host(other_ts, this->other_addr))
1064 {
1065 type = other_ts->get_type(other_ts);
1066 family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
1067 addr = other_ts->get_from_address(other_ts);
1068 host = host_create_from_chunk(family, addr, 0);
1069 free(addr.ptr);
1070 DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H",
dd83c6d4 1071 this->other_addr, host);
d487b4b7
AS
1072 this->other_addr->destroy(this->other_addr);
1073 this->other_addr = host;
1074 }
1075 }
1076 enumerator->destroy(enumerator);
1077 other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy));
1078 }
7daf5226 1079
1396815a 1080 return &this->public;
3ebebc5e 1081}