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