]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/charon/sa/child_sa.c
(no commit message)
[people/ms/strongswan.git] / src / charon / sa / child_sa.c
CommitLineData
3ebebc5e
MW
1/**
2 * @file child_sa.c
3 *
4 * @brief Implementation of child_sa_t.
5 *
6 */
7
8/*
1396815a 9 * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
c71d53ba
MW
10 * Copyright (C) 2005-2006 Martin Willi
11 * Copyright (C) 2005 Jan Hutter
3ebebc5e
MW
12 * Hochschule fuer Technik Rapperswil
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 */
24
b92eef28 25#include "child_sa.h"
3ebebc5e 26
aeda79ff
MW
27#include <daemon.h>
28
3ebebc5e 29
bcb95ced
MW
30/**
31 * String mappings for child_sa_state_t.
32 */
33mapping_t child_sa_state_m[] = {
34 {CHILD_CREATED, "CREATED"},
35 {CHILD_INSTALLED, "INSTALLED"},
45f76a7d 36 {CHILD_ROUTED, "ROUTED"},
bcb95ced
MW
37 {CHILD_REKEYING, "REKEYING"},
38 {CHILD_DELETING, "DELETING"},
39 {MAPPING_END, NULL}
40};
41
16b9a73c 42typedef struct sa_policy_t sa_policy_t;
5d187bd2
MW
43
44/**
45 * Struct used to store information for a policy. This
46 * is needed since we must provide all this information
47 * for deleting a policy...
48 */
16b9a73c 49struct sa_policy_t {
92ee45a0
MW
50 /**
51 * Traffic selector for us
52 */
53 traffic_selector_t *my_ts;
5d187bd2
MW
54
55 /**
92ee45a0 56 * Traffic selector for other
5d187bd2 57 */
92ee45a0 58 traffic_selector_t *other_ts;
5d187bd2
MW
59};
60
3ebebc5e
MW
61typedef struct private_child_sa_t private_child_sa_t;
62
63/**
144f676c 64 * Private data of a child_sa_t object.
3ebebc5e
MW
65 */
66struct private_child_sa_t {
67 /**
144f676c 68 * Public interface of child_sa_t.
3ebebc5e
MW
69 */
70 child_sa_t public;
71
8d77edde
MW
72 struct {
73 /** address of peer */
74 host_t *addr;
75 /** actual used SPI, 0 if unused */
76 u_int32_t spi;
77 } me, other;
aeda79ff 78
3efbf983
MW
79 /**
80 * Allocated SPI for a ESP proposal candidates
81 */
82 u_int32_t alloc_esp_spi;
83
84 /**
85 * Allocated SPI for a AH proposal candidates
86 */
87 u_int32_t alloc_ah_spi;
88
aeda79ff 89 /**
8d77edde 90 * Protocol used to protect this SA, ESP|AH
aeda79ff 91 */
8d77edde 92 protocol_id_t protocol;
30b5b412
MW
93
94 /**
8d77edde 95 * List containing sa_policy_t objects
5d187bd2 96 */
8d77edde 97 linked_list_t *policies;
5d187bd2 98
8dfbe71b
MW
99 /**
100 * Seperate list for local traffic selectors
101 */
102 linked_list_t *my_ts;
103
104 /**
105 * Seperate list for remote traffic selectors
106 */
107 linked_list_t *other_ts;
108
5d187bd2 109 /**
8d77edde 110 * reqid used for this child_sa
5d187bd2 111 */
8d77edde 112 u_int32_t reqid;
5d187bd2 113
c0593835
MW
114 /**
115 * encryption algorithm used for this SA
116 */
117 algorithm_t encryption;
118
119 /**
120 * integrity protection algorithm used for this SA
121 */
122 algorithm_t integrity;
123
a2a3fb3e
MW
124 /**
125 * time, on which SA was installed
126 */
127 time_t install_time;
128
5d187bd2 129 /**
8d77edde 130 * Lifetime before rekeying
5d187bd2 131 */
8d77edde 132 u_int32_t soft_lifetime;
30b5b412 133
a527a426 134 /**
8d77edde 135 * Lifetime before delete
a527a426 136 */
8d77edde 137 u_int32_t hard_lifetime;
a527a426 138
bcb95ced
MW
139 /**
140 * state of the CHILD_SA
141 */
142 child_sa_state_t state;
143
695723d4 144 /**
abba7ecb 145 * transaction which is rekeying this CHILD_SA
695723d4 146 */
abba7ecb 147 void *rekeying_transaction;
1396815a
MW
148
149 /**
150 * Specifies if NAT traversal is used
151 */
152 bool use_natt;
695723d4 153
30b5b412
MW
154 /**
155 * CHILD_SAs own logger
156 */
157 logger_t *logger;
3ebebc5e
MW
158};
159
32b6500f
MW
160/**
161 * Implements child_sa_t.get_reqid
162 */
163static u_int32_t get_reqid(private_child_sa_t *this)
164{
165 return this->reqid;
166}
8d77edde
MW
167
168/**
169 * Implements child_sa_t.get_spi
170 */
171u_int32_t get_spi(private_child_sa_t *this, bool inbound)
172{
173 if (inbound)
174 {
175 return this->me.spi;
176 }
177 return this->other.spi;
178}
179
180/**
181 * Implements child_sa_t.get_protocol
182 */
183protocol_id_t get_protocol(private_child_sa_t *this)
184{
185 return this->protocol;
186}
32b6500f 187
bcb95ced
MW
188/**
189 * Implements child_sa_t.get_state
190 */
191static child_sa_state_t get_state(private_child_sa_t *this)
192{
193 return this->state;
194}
195
196/**
197 * Implements child_sa_t.set_state
198 */
199static void set_state(private_child_sa_t *this, child_sa_state_t state)
200{
201 this->state = state;
202}
203
1396815a
MW
204/**
205 * Allocate SPI for a single proposal
206 */
207static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal)
208{
209 protocol_id_t protocol = proposal->get_protocol(proposal);
210
211 if (protocol == PROTO_AH)
212 {
213 /* get a new spi for AH, if not already done */
214 if (this->alloc_ah_spi == 0)
215 {
216 if (charon->kernel_interface->get_spi(
217 charon->kernel_interface,
218 this->other.addr, this->me.addr,
219 PROTO_AH, this->reqid,
220 &this->alloc_ah_spi) != SUCCESS)
221 {
222 return FAILED;
223 }
224 }
225 proposal->set_spi(proposal, this->alloc_ah_spi);
226 }
227 if (protocol == PROTO_ESP)
228 {
229 /* get a new spi for ESP, if not already done */
230 if (this->alloc_esp_spi == 0)
231 {
232 if (charon->kernel_interface->get_spi(
233 charon->kernel_interface,
234 this->other.addr, this->me.addr,
235 PROTO_ESP, this->reqid,
236 &this->alloc_esp_spi) != SUCCESS)
237 {
238 return FAILED;
239 }
240 }
241 proposal->set_spi(proposal, this->alloc_esp_spi);
242 }
243 return SUCCESS;
244}
245
246
3ebebc5e 247/**
30b5b412 248 * Implements child_sa_t.alloc
3ebebc5e 249 */
30b5b412 250static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
3ebebc5e 251{
30b5b412
MW
252 iterator_t *iterator;
253 proposal_t *proposal;
30b5b412 254
3efbf983 255 /* iterator through proposals to update spis */
30b5b412
MW
256 iterator = proposals->create_iterator(proposals, TRUE);
257 while(iterator->has_next(iterator))
258 {
259 iterator->current(iterator, (void**)&proposal);
1396815a 260 if (alloc_proposal(this, proposal) != SUCCESS)
3efbf983 261 {
1396815a
MW
262 iterator->destroy(iterator);
263 return FAILED;
3efbf983 264 }
30b5b412
MW
265 }
266 iterator->destroy(iterator);
267 return SUCCESS;
3ebebc5e
MW
268}
269
30b5b412 270static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine)
3ebebc5e 271{
30b5b412 272 u_int32_t spi;
5c131a01
MW
273 algorithm_t *enc_algo, *int_algo;
274 algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0};
275 algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
30b5b412
MW
276 host_t *src;
277 host_t *dst;
1396815a 278 natt_conf_t *natt;
30b5b412 279 status_t status;
aeda79ff 280
8d77edde
MW
281 this->protocol = proposal->get_protocol(proposal);
282
283 /* now we have to decide which spi to use. Use self allocated, if "mine",
3efbf983
MW
284 * or the one in the proposal, if not "mine" (others). Additionally,
285 * source and dest host switch depending on the role */
8d77edde 286 if (mine)
aeda79ff 287 {
3efbf983
MW
288 /* if we have allocated SPIs for AH and ESP, we must delete the unused
289 * one. */
290 if (this->protocol == PROTO_ESP)
291 {
292 this->me.spi = this->alloc_esp_spi;
293 if (this->alloc_ah_spi)
294 {
295 charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr,
296 this->alloc_ah_spi, PROTO_AH);
297 }
298 }
299 else
300 {
301 this->me.spi = this->alloc_ah_spi;
302 if (this->alloc_esp_spi)
303 {
304 charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr,
305 this->alloc_esp_spi, PROTO_ESP);
306 }
307 }
8d77edde 308 spi = this->me.spi;
3efbf983
MW
309 dst = this->me.addr;
310 src = this->other.addr;
aeda79ff 311 }
8d77edde
MW
312 else
313 {
3efbf983
MW
314 this->other.spi = proposal->get_spi(proposal);
315 spi = this->other.spi;
316 src = this->me.addr;
317 dst = this->other.addr;
8d77edde
MW
318 }
319
1d390631 320 this->logger->log(this->logger, CONTROL|LEVEL1, "adding %s %s SA",
5c131a01
MW
321 mine ? "inbound" : "outbound",
322 mapping_find(protocol_id_m, this->protocol));
323
324 /* select encryption algo */
325 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_algo))
8d77edde 326 {
5c131a01
MW
327 this->logger->log(this->logger, CONTROL|LEVEL2, " using %s for encryption",
328 mapping_find(encryption_algorithm_m, enc_algo->algorithm));
8d77edde
MW
329 }
330 else
331 {
5c131a01 332 enc_algo = &enc_algo_none;
8d77edde
MW
333 }
334
5c131a01
MW
335 /* select integrity algo */
336 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_algo))
8d77edde 337 {
5c131a01
MW
338 this->logger->log(this->logger, CONTROL|LEVEL2, " using %s for integrity",
339 mapping_find(integrity_algorithm_m, int_algo->algorithm));
8d77edde
MW
340 }
341 else
342 {
5c131a01 343 int_algo = &int_algo_none;
8d77edde
MW
344 }
345
1396815a
MW
346 /* setup nat-t */
347 if (this->use_natt)
348 {
349 natt = alloca(sizeof(natt_conf_t));
350 natt->sport = src->get_port(src);
351 natt->dport = dst->get_port(dst);
352 }
353 else
354 {
355 natt = NULL;
356 }
357
358
5c131a01
MW
359 /* send SA down to the kernel */
360 this->logger->log(this->logger, CONTROL|LEVEL2,
361 " SPI 0x%.8x, src %s dst %s",
92ee45a0 362 ntohl(spi), src->get_string(src), dst->get_string(dst));
8d77edde 363 status = charon->kernel_interface->add_sa(charon->kernel_interface,
1396815a
MW
364 src, dst,
365 spi, this->protocol,
366 this->reqid,
698d7749 367 mine ? this->soft_lifetime : 0,
1396815a
MW
368 this->hard_lifetime,
369 enc_algo, int_algo,
370 prf_plus, natt, mine);
a2a3fb3e 371
c0593835
MW
372 this->encryption = *enc_algo;
373 this->integrity = *int_algo;
a2a3fb3e 374 this->install_time = time(NULL);
abba7ecb 375
8d77edde 376 return status;
30b5b412
MW
377}
378
379static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
380{
891dfaf9 381 u_int32_t outbound_spi, inbound_spi;
30b5b412 382
891dfaf9
MW
383 /* backup outbound spi, as alloc overwrites it */
384 outbound_spi = proposal->get_spi(proposal);
30b5b412 385
891dfaf9 386 /* get SPIs inbound SAs */
1396815a 387 if (alloc_proposal(this, proposal) != SUCCESS)
30b5b412 388 {
30b5b412
MW
389 return FAILED;
390 }
891dfaf9 391 inbound_spi = proposal->get_spi(proposal);
30b5b412 392
891dfaf9 393 /* install inbound SAs */
30b5b412
MW
394 if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
395 {
396 return FAILED;
397 }
a527a426 398
891dfaf9
MW
399 /* install outbound SAs, restore spi*/
400 proposal->set_spi(proposal, outbound_spi);
401 if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
402 {
403 return FAILED;
404 }
405 proposal->set_spi(proposal, inbound_spi);
406
bcb95ced
MW
407 this->state = CHILD_INSTALLED;
408
30b5b412
MW
409 return SUCCESS;
410}
411
412static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
413{
891dfaf9
MW
414 u_int32_t inbound_spi;
415
416 /* backup received spi, as install() overwrites it */
417 inbound_spi = proposal->get_spi(proposal);
418
419 /* install outbound SAs */
420 if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
30b5b412
MW
421 {
422 return FAILED;
423 }
891dfaf9
MW
424
425 /* restore spi */
426 proposal->set_spi(proposal, inbound_spi);
427 /* install inbound SAs */
428 if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
30b5b412
MW
429 {
430 return FAILED;
431 }
a527a426 432
bcb95ced
MW
433 this->state = CHILD_INSTALLED;
434
a527a426
MW
435 return SUCCESS;
436}
437
5d187bd2 438static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list)
a527a426 439{
5d187bd2
MW
440 iterator_t *my_iter, *other_iter;
441 traffic_selector_t *my_ts, *other_ts;
a527a426 442
5d187bd2
MW
443 /* iterate over both lists */
444 my_iter = my_ts_list->create_iterator(my_ts_list, TRUE);
445 other_iter = other_ts_list->create_iterator(other_ts_list, TRUE);
446 while (my_iter->has_next(my_iter))
a527a426 447 {
5d187bd2
MW
448 my_iter->current(my_iter, (void**)&my_ts);
449 other_iter->reset(other_iter);
450 while (other_iter->has_next(other_iter))
451 {
452 /* set up policies for every entry in my_ts_list to every entry in other_ts_list */
5d187bd2 453 status_t status;
92ee45a0 454 sa_policy_t *policy;
5d187bd2
MW
455
456 other_iter->current(other_iter, (void**)&other_ts);
457
92ee45a0
MW
458 if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts))
459 {
460 this->logger->log(this->logger, CONTROL|LEVEL1,
461 "CHILD_SA policy uses two different IP families, ignored");
462 continue;
463 }
464
5f0eb96f
MW
465 /* only set up policies if protocol matches, or if one is zero (any) */
466 if (my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts) &&
467 my_ts->get_protocol(my_ts) && other_ts->get_protocol(other_ts))
5d187bd2 468 {
92ee45a0 469 this->logger->log(this->logger, CONTROL|LEVEL1,
5f0eb96f 470 "CHILD_SA policy uses two different protocols, ignored");
5d187bd2
MW
471 continue;
472 }
5d187bd2 473
5d187bd2
MW
474 /* install 3 policies: out, in and forward */
475 status = charon->kernel_interface->add_policy(charon->kernel_interface,
92ee45a0
MW
476 this->me.addr, this->other.addr, my_ts, other_ts,
477 POLICY_OUT, this->protocol, this->reqid, FALSE);
478
5d187bd2 479 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
92ee45a0
MW
480 this->other.addr, this->me.addr, other_ts, my_ts,
481 POLICY_IN, this->protocol, this->reqid, FALSE);
482
5d187bd2 483 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
92ee45a0
MW
484 this->other.addr, this->me.addr, other_ts, my_ts,
485 POLICY_FWD, this->protocol, this->reqid, FALSE);
5d187bd2
MW
486
487 if (status != SUCCESS)
488 {
489 my_iter->destroy(my_iter);
490 other_iter->destroy(other_iter);
5d187bd2
MW
491 return status;
492 }
493
92ee45a0
MW
494 /* store policy to delete/update them later */
495 policy = malloc_thing(sa_policy_t);
496 policy->my_ts = my_ts->clone(my_ts);
497 policy->other_ts = other_ts->clone(other_ts);
498 this->policies->insert_last(this->policies, (void*)policy);
8dfbe71b
MW
499 /* add to separate list to query them via get_*_traffic_selectors() */
500 this->my_ts->insert_last(this->my_ts, (void*)policy->my_ts);
501 this->other_ts->insert_last(this->other_ts, (void*)policy->other_ts);
5d187bd2
MW
502 }
503 }
5d187bd2
MW
504 my_iter->destroy(my_iter);
505 other_iter->destroy(other_iter);
45f76a7d
MW
506
507 /* switch to routed state if no SAD entry set up */
508 if (this->state == CHILD_CREATED)
509 {
510 this->state = CHILD_ROUTED;
511 }
512
5d187bd2 513 return SUCCESS;
30b5b412
MW
514}
515
8dfbe71b
MW
516/**
517 * Implementation of child_sa_t.get_my_traffic_selectors.
518 */
519static linked_list_t *get_my_traffic_selectors(private_child_sa_t *this)
520{
521 return this->my_ts;
522}
523
524/**
525 * Implementation of child_sa_t.get_my_traffic_selectors.
526 */
527static linked_list_t *get_other_traffic_selectors(private_child_sa_t *this)
528{
529 return this->other_ts;
530}
531
695723d4 532/**
abba7ecb
MW
533 * Implementation of child_sa_t.set_rekeying_transaction.
534 */
535static void set_rekeying_transaction(private_child_sa_t *this, void *transaction)
536{
537 this->rekeying_transaction = transaction;
abba7ecb
MW
538}
539
540/**
541 * Implementation of child_sa_t.get_rekeying_transaction.
695723d4 542 */
abba7ecb 543static void* get_rekeying_transaction(private_child_sa_t *this)
695723d4 544{
abba7ecb
MW
545 return this->rekeying_transaction;
546}
547
2f89902d
MW
548/**
549 * Implementation of child_sa_t.get_use_time
550 */
551static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use_time)
552{
92ee45a0
MW
553 iterator_t *iterator;
554 sa_policy_t *policy;
fe04e93a 555 status_t status = FAILED;
2f89902d
MW
556
557 *use_time = UNDEFINED_TIME;
92ee45a0
MW
558
559 iterator = this->policies->create_iterator(this->policies, TRUE);
560 while (iterator->iterate(iterator, (void**)&policy))
aeeb4f4f 561 {
92ee45a0
MW
562 if (inbound)
563 {
564 time_t in = UNDEFINED_TIME, fwd = UNDEFINED_TIME;
565
566 status = charon->kernel_interface->query_policy(
567 charon->kernel_interface,
568 policy->other_ts, policy->my_ts,
569 POLICY_IN, (u_int32_t*)&in);
570 status |= charon->kernel_interface->query_policy(
571 charon->kernel_interface,
572 policy->other_ts, policy->my_ts,
573 POLICY_FWD, (u_int32_t*)&fwd);
574 *use_time = max(in, fwd);
575 }
576 else
577 {
578 status = charon->kernel_interface->query_policy(
579 charon->kernel_interface,
580 policy->my_ts, policy->other_ts,
581 POLICY_OUT, (u_int32_t*)use_time);
582 }
aeeb4f4f 583 }
92ee45a0 584 iterator->destroy(iterator);
aeeb4f4f 585 return status;
2f89902d
MW
586}
587
5f0eb96f
MW
588/**
589 * Implementation of child_sa_t.log_status.
590 */
591static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
592{
593 iterator_t *iterator;
594 char use_in_str[12] = "unused";
595 char use_out_str[12] = "unused";
596 char rekey_str[12] = "disabled";
c0593835
MW
597 char enc_str[32] = "";
598 char int_str[32] = "";
92ee45a0
MW
599 u_int32_t use_in, use_out, use_fwd, now, rekeying;
600 status_t status;
5f0eb96f
MW
601
602 if (logger == NULL)
603 {
604 logger = this->logger;
605 }
92ee45a0
MW
606 now = (u_int32_t)time(NULL);
607
45f76a7d 608 if (this->state == CHILD_INSTALLED)
c0593835 609 {
45f76a7d
MW
610 /* query SA times */
611 status = charon->kernel_interface->query_sa(charon->kernel_interface,
612 this->me.addr, this->me.spi, this->protocol, &use_in);
613 if (status == SUCCESS && use_in)
c0593835 614 {
45f76a7d
MW
615 snprintf(use_in_str, sizeof(use_in_str), "%ds", now - use_in);
616 }
617 status = charon->kernel_interface->query_sa(charon->kernel_interface,
618 this->other.addr, this->other.spi, this->protocol, &use_out);
619 if (status == SUCCESS && use_out)
620 {
621 snprintf(use_out_str, sizeof(use_out_str), "%ds", now - use_out);
622 }
623
624 /* calculate rekey times */
625 if (this->soft_lifetime)
626 {
627 rekeying = this->soft_lifetime - (now - this->install_time);
628 snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying);
629 }
630
631 /* algorithms used */
632 if (this->protocol == PROTO_ESP)
633 {
634 if (this->encryption.key_size)
635 {
636 snprintf(enc_str, sizeof(enc_str), "%s-%d,",
637 mapping_find(encryption_algorithm_m, this->encryption.algorithm),
638 this->encryption.key_size);
639 }
640 else
641 {
642 snprintf(enc_str, sizeof(enc_str), "%s,",
643 mapping_find(encryption_algorithm_m, this->encryption.algorithm));
644 }
645 }
646 if (this->integrity.key_size)
647 {
648 snprintf(int_str, sizeof(int_str), "%s-%d",
649 mapping_find(integrity_algorithm_m, this->integrity.algorithm),
650 this->integrity.key_size);
c0593835
MW
651 }
652 else
653 {
45f76a7d
MW
654 snprintf(int_str, sizeof(int_str), "%s",
655 mapping_find(integrity_algorithm_m, this->integrity.algorithm));
c0593835 656 }
45f76a7d
MW
657
658 logger->log(logger, CONTROL|LEVEL1,
659 " \"%s\": state: %s, reqid: %d, ",
660 name, mapping_find(child_sa_state_m, this->state), this->reqid);
661 logger->log(logger, CONTROL|LEVEL1,
662 " \"%s\": %s (%s%s), SPIs (in/out): 0x%x/0x%x",
663 name, this->protocol == PROTO_ESP ? "ESP" : "AH",
664 enc_str, int_str,
665 htonl(this->me.spi), htonl(this->other.spi));
666 logger->log(logger, CONTROL|LEVEL1,
667 " \"%s\": rekeying: %s, key age (in/out): %s/%s",
668 name, rekey_str, use_in_str, use_out_str);
c0593835
MW
669 }
670 else
671 {
45f76a7d
MW
672 logger->log(logger, CONTROL|LEVEL1, " \"%s\": state: %s, reqid: %d",
673 name, mapping_find(child_sa_state_m, this->state),
674 this->reqid);
c0593835
MW
675 }
676
5f0eb96f
MW
677 iterator = this->policies->create_iterator(this->policies, TRUE);
678 while (iterator->has_next(iterator))
679 {
680 sa_policy_t *policy;
92ee45a0
MW
681 char *my_str;
682 char *other_str;
683 char pol_in_str[12] = "unused";
684 char pol_out_str[12] = "unused";
685 char pol_fwd_str[12] = "unused";
5f0eb96f 686
92ee45a0 687 /* get ts strings */
5f0eb96f 688 iterator->current(iterator, (void**)&policy);
92ee45a0
MW
689 my_str = policy->my_ts->get_string(policy->my_ts);
690 other_str = policy->other_ts->get_string(policy->other_ts);
5f0eb96f 691
92ee45a0
MW
692 /* query policy times */
693 status = charon->kernel_interface->query_policy(charon->kernel_interface,
694 policy->other_ts, policy->my_ts, POLICY_IN, &use_in);
695 if (status == SUCCESS && use_in)
5f0eb96f 696 {
92ee45a0 697 snprintf(pol_in_str, sizeof(pol_in_str), "%ds", now - use_in);
5f0eb96f 698 }
92ee45a0
MW
699 status = charon->kernel_interface->query_policy(charon->kernel_interface,
700 policy->my_ts, policy->other_ts, POLICY_OUT, &use_out);
701 if (status == SUCCESS && use_out)
5f0eb96f 702 {
92ee45a0 703 snprintf(pol_out_str, sizeof(pol_out_str), "%ds", now - use_out);
5f0eb96f 704 }
92ee45a0
MW
705 status = charon->kernel_interface->query_policy(charon->kernel_interface,
706 policy->other_ts, policy->my_ts, POLICY_FWD, &use_fwd);
707 if (status == SUCCESS && use_fwd)
5f0eb96f 708 {
92ee45a0 709 snprintf(pol_fwd_str, sizeof(pol_fwd_str), "%ds", now - use_fwd);
5f0eb96f
MW
710 }
711
92ee45a0
MW
712 logger->log(logger, CONTROL,
713 " \"%s\": %s====%s, last use (in/out/fwd): %s/%s/%s",
714 name, my_str, other_str, pol_in_str, pol_out_str, pol_fwd_str);
5f0eb96f
MW
715 }
716 iterator->destroy(iterator);
717}
718
1396815a
MW
719/**
720 * Update the host adress/port of a SA
721 */
722static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other,
723 int my_changes, int other_changes, bool mine)
724{
725 host_t *src, *dst, *new_src, *new_dst;
726 int src_changes, dst_changes;
727 status_t status;
728 u_int32_t spi;
729
730 if (mine)
1396815a
MW
731 {
732 src = this->other.addr;
733 dst = this->me.addr;
734 new_src = new_other;
735 new_dst = new_me;
736 src_changes = other_changes;
737 dst_changes = my_changes;
738 spi = this->other.spi;
739 }
abba7ecb
MW
740 else
741 {
742 src = this->me.addr;
743 dst = this->other.addr;
744 new_src = new_me;
745 new_dst = new_other;
746 src_changes = my_changes;
747 dst_changes = other_changes;
748 spi = this->me.spi;
749 }
1396815a
MW
750
751 this->logger->log(this->logger, CONTROL|LEVEL1,
752 "updating %s SA 0x%x, from %s:%d..%s:%d to %s:%d..%s:%d",
753 mapping_find(protocol_id_m, this->protocol), ntohl(spi),
92ee45a0
MW
754 src->get_string(src), src->get_port(src),
755 dst->get_string(dst), dst->get_port(dst),
756 new_src->get_string(new_src), new_src->get_port(new_src),
757 new_dst->get_string(new_dst), new_dst->get_port(new_dst));
1396815a 758
92ee45a0
MW
759 status = charon->kernel_interface->update_sa(charon->kernel_interface,
760 dst, spi, this->protocol,
761 new_src, new_dst,
762 src_changes, dst_changes);
1396815a
MW
763
764 if (status != SUCCESS)
765 {
766 return FAILED;
767 }
768 return SUCCESS;
769}
770
771/**
772 * Update the host adress/port of a policy
773 */
774static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other)
775{
776 iterator_t *iterator;
777 sa_policy_t *policy;
778 status_t status;
779
780 iterator = this->policies->create_iterator(this->policies, TRUE);
781 while (iterator->iterate(iterator, (void**)&policy))
782 {
1396815a
MW
783 status = charon->kernel_interface->add_policy(
784 charon->kernel_interface,
785 new_me, new_other,
92ee45a0
MW
786 policy->my_ts, policy->other_ts,
787 POLICY_OUT, this->protocol, this->reqid, TRUE);
1396815a
MW
788
789 status |= charon->kernel_interface->add_policy(
790 charon->kernel_interface,
791 new_other, new_me,
92ee45a0
MW
792 policy->other_ts, policy->my_ts,
793 POLICY_IN, this->protocol, this->reqid, TRUE);
1396815a
MW
794
795 status |= charon->kernel_interface->add_policy(
796 charon->kernel_interface,
797 new_other, new_me,
92ee45a0
MW
798 policy->other_ts, policy->my_ts,
799 POLICY_FWD, this->protocol, this->reqid, TRUE);
aeeb4f4f 800
1396815a
MW
801 if (status != SUCCESS)
802 {
803 iterator->destroy(iterator);
804 return FAILED;
805 }
806 }
807 iterator->destroy(iterator);
92ee45a0 808
698d7749 809 return SUCCESS;
1396815a
MW
810}
811
812/**
813 * Implementation of child_sa_t.update_hosts.
814 */
815static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other,
92ee45a0 816 host_diff_t my_changes, host_diff_t other_changes)
1396815a 817{
abba7ecb 818 if (!my_changes && !other_changes)
1396815a
MW
819 {
820 return SUCCESS;
821 }
822
823 /* update our (initator) SAs */
824 if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, TRUE) != SUCCESS)
825 {
826 return FAILED;
827 }
828
829 /* update his (responder) SAs */
830 if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, FALSE) != SUCCESS)
831 {
832 return FAILED;
833 }
834
835 /* update policies */
836 if (my_changes & HOST_DIFF_ADDR || other_changes & HOST_DIFF_ADDR)
837 {
838 if (update_policy_hosts(this, new_me, new_other) != SUCCESS)
839 {
840 return FAILED;
841 }
842 }
843
844 /* update hosts */
845 if (my_changes)
846 {
847 this->me.addr->destroy(this->me.addr);
848 this->me.addr = new_me->clone(new_me);
849 }
850
851 if (other_changes)
852 {
853 this->other.addr->destroy(this->other.addr);
854 this->other.addr = new_other->clone(new_other);
855 }
856
857 return SUCCESS;
858}
859
30b5b412
MW
860/**
861 * Implementation of child_sa_t.destroy.
862 */
863static void destroy(private_child_sa_t *this)
864{
16b9a73c 865 sa_policy_t *policy;
5d187bd2
MW
866
867 /* delete SAs in the kernel, if they are set up */
3efbf983 868 if (this->me.spi)
5d187bd2
MW
869 {
870 charon->kernel_interface->del_sa(charon->kernel_interface,
695723d4 871 this->me.addr, this->me.spi, this->protocol);
3efbf983
MW
872 }
873 if (this->alloc_esp_spi && this->alloc_esp_spi != this->me.spi)
874 {
875 charon->kernel_interface->del_sa(charon->kernel_interface,
876 this->me.addr, this->alloc_esp_spi, PROTO_ESP);
877 }
878 if (this->alloc_ah_spi && this->alloc_ah_spi != this->me.spi)
879 {
880 charon->kernel_interface->del_sa(charon->kernel_interface,
881 this->me.addr, this->alloc_ah_spi, PROTO_AH);
882 }
883 if (this->other.spi)
884 {
5d187bd2 885 charon->kernel_interface->del_sa(charon->kernel_interface,
695723d4
MW
886 this->other.addr, this->other.spi, this->protocol);
887 }
888
889 /* delete all policies in the kernel */
890 while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
891 {
aeeb4f4f
MW
892 /* let rekeyed policies, as they are used by another child_sa */
893 charon->kernel_interface->del_policy(charon->kernel_interface,
92ee45a0
MW
894 policy->my_ts, policy->other_ts,
895 POLICY_OUT);
aeeb4f4f
MW
896
897 charon->kernel_interface->del_policy(charon->kernel_interface,
92ee45a0
MW
898 policy->other_ts, policy->my_ts,
899 POLICY_IN);
aeeb4f4f
MW
900
901 charon->kernel_interface->del_policy(charon->kernel_interface,
92ee45a0
MW
902 policy->other_ts, policy->my_ts,
903 POLICY_FWD);
904 policy->my_ts->destroy(policy->my_ts);
905 policy->other_ts->destroy(policy->other_ts);
695723d4 906 free(policy);
5d187bd2 907 }
695723d4 908 this->policies->destroy(this->policies);
abba7ecb 909
8dfbe71b
MW
910 this->my_ts->destroy(this->my_ts);
911 this->other_ts->destroy(this->other_ts);
abba7ecb
MW
912 this->me.addr->destroy(this->me.addr);
913 this->other.addr->destroy(this->other.addr);
5113680f 914 free(this);
30b5b412
MW
915}
916
917/*
918 * Described in header.
919 */
50f98119 920child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
1396815a
MW
921 u_int32_t soft_lifetime, u_int32_t hard_lifetime,
922 bool use_natt)
30b5b412 923{
1396815a 924 static u_int32_t reqid = REQID_START;
5113680f 925 private_child_sa_t *this = malloc_thing(private_child_sa_t);
30b5b412
MW
926
927 /* public functions */
32b6500f 928 this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
8d77edde
MW
929 this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
930 this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
30b5b412
MW
931 this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
932 this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
933 this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
92ee45a0 934 this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts;
5d187bd2 935 this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
8dfbe71b
MW
936 this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors;
937 this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors;
2f89902d 938 this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
abba7ecb
MW
939 this->public.set_rekeying_transaction = (void (*)(child_sa_t*,void*))set_rekeying_transaction;
940 this->public.get_rekeying_transaction = (void* (*)(child_sa_t*))get_rekeying_transaction;
bcb95ced
MW
941 this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
942 this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
e168ee17 943 this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status;
30b5b412
MW
944 this->public.destroy = (void(*)(child_sa_t*))destroy;
945
946 /* private data */
5113680f 947 this->logger = logger_manager->get_logger(logger_manager, CHILD_SA);
abba7ecb
MW
948 this->me.addr = me->clone(me);
949 this->other.addr = other->clone(other);
8d77edde
MW
950 this->me.spi = 0;
951 this->other.spi = 0;
3efbf983
MW
952 this->alloc_ah_spi = 0;
953 this->alloc_esp_spi = 0;
1396815a 954 this->use_natt = use_natt;
8d77edde
MW
955 this->soft_lifetime = soft_lifetime;
956 this->hard_lifetime = hard_lifetime;
bcb95ced 957 this->state = CHILD_CREATED;
50f98119
MW
958 /* reuse old reqid if we are rekeying an existing CHILD_SA */
959 this->reqid = rekey ? rekey : ++reqid;
c0593835
MW
960 this->encryption.algorithm = ENCR_UNDEFINED;
961 this->encryption.key_size = 0;
962 this->integrity.algorithm = AUTH_UNDEFINED;
963 this->encryption.key_size = 0;
5d187bd2 964 this->policies = linked_list_create();
8dfbe71b
MW
965 this->my_ts = linked_list_create();
966 this->other_ts = linked_list_create();
8d77edde 967 this->protocol = PROTO_NONE;
abba7ecb 968 this->rekeying_transaction = NULL;
3ebebc5e 969
1396815a 970 return &this->public;
3ebebc5e 971}