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