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