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