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