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