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