]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/charon/sa/child_sa.c
restructured file layout
[people/ms/strongswan.git] / src / charon / sa / child_sa.c
CommitLineData
3ebebc5e
MW
1/**
2 * @file child_sa.c
3 *
4 * @brief Implementation of child_sa_t.
5 *
6 */
7
8/*
c60c7694 9 * Copyright (C) 2005-2007 Martin Willi
1396815a 10 * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
c71d53ba 11 * Copyright (C) 2005 Jan Hutter
3ebebc5e
MW
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
60356f33 25#define _GNU_SOURCE
b92eef28 26#include "child_sa.h"
3ebebc5e 27
a095243f 28#include <stdio.h>
4c23a8c9 29#include <string.h>
60356f33 30#include <printf.h>
4c23a8c9 31
aeda79ff
MW
32#include <daemon.h>
33
60356f33
MW
34ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DELETING,
35 "CREATED",
36 "ROUTED",
37 "INSTALLED",
38 "REKEYING",
39 "DELETING",
40);
bcb95ced 41
16b9a73c 42typedef struct sa_policy_t sa_policy_t;
5d187bd2
MW
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 */
16b9a73c 49struct sa_policy_t {
92ee45a0
MW
50 /**
51 * Traffic selector for us
52 */
53 traffic_selector_t *my_ts;
5d187bd2
MW
54
55 /**
92ee45a0 56 * Traffic selector for other
5d187bd2 57 */
92ee45a0 58 traffic_selector_t *other_ts;
5d187bd2
MW
59};
60
3ebebc5e
MW
61typedef struct private_child_sa_t private_child_sa_t;
62
63/**
fff4ee8a 64 * Private data of a child_sa_t \ 1bject.
3ebebc5e
MW
65 */
66struct private_child_sa_t {
67 /**
144f676c 68 * Public interface of child_sa_t.
3ebebc5e
MW
69 */
70 child_sa_t public;
71
8d77edde
MW
72 struct {
73 /** address of peer */
74 host_t *addr;
d7934d0c
MW
75 /** id of peer */
76 identification_t *id;
8d77edde
MW
77 /** actual used SPI, 0 if unused */
78 u_int32_t spi;
79 } me, other;
aeda79ff 80
3efbf983
MW
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
aeda79ff 91 /**
8d77edde 92 * Protocol used to protect this SA, ESP|AH
aeda79ff 93 */
8d77edde 94 protocol_id_t protocol;
30b5b412
MW
95
96 /**
8d77edde 97 * List containing sa_policy_t objects
5d187bd2 98 */
8d77edde 99 linked_list_t *policies;
5d187bd2 100
8dfbe71b
MW
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
5d187bd2 111 /**
8d77edde 112 * reqid used for this child_sa
5d187bd2 113 */
8d77edde 114 u_int32_t reqid;
5d187bd2 115
c0593835
MW
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
a2a3fb3e
MW
126 /**
127 * time, on which SA was installed
128 */
129 time_t install_time;
130
e70d5576
MW
131 /**
132 * absolute time when rekeying is sceduled
133 */
134 time_t rekey_time;
135
bcb95ced
MW
136 /**
137 * state of the CHILD_SA
138 */
139 child_sa_state_t state;
fff4ee8a 140
1239c6f4 141 /**
d7934d0c 142 * Specifies if NAT traversal is used
1239c6f4 143 */
d7934d0c 144 bool use_natt;
7652be89
MW
145
146 /**
147 * mode this SA uses, tunnel/transport
148 */
149 mode_t mode;
c60c7694 150
8f031473
MW
151 /**
152 * virtual IP assinged to local host
153 */
154 host_t *virtual_ip;
155
c60c7694 156 /**
e0fe7651 157 * config used to create this child
c60c7694 158 */
e0fe7651 159 child_cfg_t *config;
3ebebc5e
MW
160};
161
9be547c0
MW
162/**
163 * Implementation of child_sa_t.get_name.
164 */
165static char *get_name(private_child_sa_t *this)
166{
e0fe7651 167 return this->config->get_name(this->config);
9be547c0
MW
168}
169
32b6500f
MW
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}
8d77edde
MW
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}
32b6500f 197
bcb95ced
MW
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
c60c7694 206/**
e0fe7651 207 * Implements child_sa_t.get_config
c60c7694 208 */
e0fe7651 209static child_cfg_t* get_config(private_child_sa_t *this)
c60c7694 210{
e0fe7651 211 return this->config;
c60c7694
MW
212}
213
d7934d0c
MW
214/**
215 * Run the up/down script
216 */
217static void updown(private_child_sa_t *this, bool up)
218{
191a26a6 219 sa_policy_t *policy;
d7934d0c 220 iterator_t *iterator;
c60c7694 221 char *script;
d7934d0c 222
e0fe7651 223 script = this->config->get_updown(this->config);
c60c7694
MW
224
225 if (script == NULL)
d7934d0c
MW
226 {
227 return;
228 }
229
230 iterator = this->policies->create_iterator(this->policies, TRUE);
191a26a6 231 while (iterator->iterate(iterator, (void**)&policy))
d7934d0c 232 {
d7934d0c
MW
233 char command[1024];
234 char *ifname = NULL;
d7934d0c 235 char *my_client, *other_client, *my_client_mask, *other_client_mask;
8f031473 236 char *pos, *virtual_ip;
d7934d0c
MW
237 FILE *shell;
238
d7934d0c 239 /* get subnet/bits from string */
60356f33 240 asprintf(&my_client, "%R", policy->my_ts);
d7934d0c
MW
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 }
60356f33 249 asprintf(&other_client, "%R", policy->other_ts);
d7934d0c
MW
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 }
9b1f4540 258
8f031473
MW
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 }
9b1f4540 268
373b8a60
MW
269 ifname = charon->kernel_interface->get_interface(charon->kernel_interface,
270 this->me.addr);
d7934d0c
MW
271
272 /* build the command with all env variables.
9b1f4540
AS
273 * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing
274 */
d7934d0c
MW
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' "
47f50278
MW
282 "PLUTO_ME='%H' "
283 "PLUTO_MY_ID='%D' "
d7934d0c
MW
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' "
47f50278
MW
289 "PLUTO_PEER='%H' "
290 "PLUTO_PEER_ID='%D' "
d7934d0c
MW
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' "
fff4ee8a 296 "%s"
9b1f4540 297 "%s"
d7934d0c
MW
298 "%s",
299 up ? "up" : "down",
60356f33
MW
300 policy->my_ts->is_host(policy->my_ts,
301 this->me.addr) ? "-host" : "-client",
d7934d0c 302 this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6",
e0fe7651 303 this->config->get_name(this->config),
373b8a60 304 ifname ? ifname : "(unknown)",
d7934d0c 305 this->reqid,
47f50278
MW
306 this->me.addr,
307 this->me.id,
d7934d0c
MW
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),
47f50278
MW
312 this->other.addr,
313 this->other.id,
d7934d0c
MW
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),
9b1f4540 318 virtual_ip,
e0fe7651 319 this->config->get_hostaccess(this->config) ?
9b1f4540
AS
320 "PLUTO_HOST_ACCESS='1' " : "",
321 script);
d7934d0c
MW
322 free(ifname);
323 free(my_client);
324 free(other_client);
9b1f4540 325 free(virtual_ip);
d7934d0c
MW
326
327 shell = popen(command, "r");
328
329 if (shell == NULL)
330 {
c60c7694 331 DBG1(DBG_CHD, "could not execute updown script '%s'", script);
d7934d0c
MW
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 {
b83806d8 343 DBG1(DBG_CHD, "error reading output from updown script");
d7934d0c
MW
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 }
b83806d8 358 DBG1(DBG_CHD, "updown: %s", resp);
d7934d0c
MW
359 }
360 }
361 pclose(shell);
362 }
363 iterator->destroy(iterator);
364}
365
bcb95ced
MW
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;
d7934d0c
MW
372 if (state == CHILD_INSTALLED)
373 {
374 updown(this, TRUE);
375 }
bcb95ced
MW
376}
377
1396815a
MW
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
3ebebc5e 421/**
30b5b412 422 * Implements child_sa_t.alloc
3ebebc5e 423 */
30b5b412 424static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
3ebebc5e 425{
30b5b412
MW
426 iterator_t *iterator;
427 proposal_t *proposal;
30b5b412 428
3efbf983 429 /* iterator through proposals to update spis */
30b5b412 430 iterator = proposals->create_iterator(proposals, TRUE);
191a26a6 431 while(iterator->iterate(iterator, (void**)&proposal))
30b5b412 432 {
1396815a 433 if (alloc_proposal(this, proposal) != SUCCESS)
3efbf983 434 {
1396815a
MW
435 iterator->destroy(iterator);
436 return FAILED;
3efbf983 437 }
30b5b412
MW
438 }
439 iterator->destroy(iterator);
440 return SUCCESS;
3ebebc5e
MW
441}
442
7652be89
MW
443static status_t install(private_child_sa_t *this, proposal_t *proposal,
444 mode_t mode, prf_plus_t *prf_plus, bool mine)
3ebebc5e 445{
c60c7694 446 u_int32_t spi, soft, hard;;
5c131a01
MW
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};
30b5b412
MW
450 host_t *src;
451 host_t *dst;
1396815a 452 natt_conf_t *natt;
30b5b412 453 status_t status;
aeda79ff 454
8d77edde
MW
455 this->protocol = proposal->get_protocol(proposal);
456
457 /* now we have to decide which spi to use. Use self allocated, if "mine",
3efbf983
MW
458 * or the one in the proposal, if not "mine" (others). Additionally,
459 * source and dest host switch depending on the role */
8d77edde 460 if (mine)
aeda79ff 461 {
3efbf983
MW
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 }
8d77edde 482 spi = this->me.spi;
3efbf983
MW
483 dst = this->me.addr;
484 src = this->other.addr;
aeda79ff 485 }
8d77edde
MW
486 else
487 {
3efbf983
MW
488 this->other.spi = proposal->get_spi(proposal);
489 spi = this->other.spi;
490 src = this->me.addr;
491 dst = this->other.addr;
8d77edde
MW
492 }
493
b83806d8 494 DBG2(DBG_CHD, "adding %s %N SA", mine ? "inbound" : "outbound",
60356f33 495 protocol_id_names, this->protocol);
5c131a01
MW
496
497 /* select encryption algo */
498 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_algo))
8d77edde 499 {
b83806d8 500 DBG2(DBG_CHD, " using %N for encryption",
60356f33 501 encryption_algorithm_names, enc_algo->algorithm);
8d77edde
MW
502 }
503 else
504 {
5c131a01 505 enc_algo = &enc_algo_none;
8d77edde
MW
506 }
507
5c131a01
MW
508 /* select integrity algo */
509 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_algo))
8d77edde 510 {
b83806d8 511 DBG2(DBG_CHD, " using %N for integrity",
60356f33 512 integrity_algorithm_names, int_algo->algorithm);
8d77edde
MW
513 }
514 else
515 {
5c131a01 516 int_algo = &int_algo_none;
8d77edde
MW
517 }
518
1396815a
MW
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
e0fe7651
MW
531 soft = this->config->get_lifetime(this->config, TRUE);
532 hard = this->config->get_lifetime(this->config, FALSE);
1396815a 533
5c131a01 534 /* send SA down to the kernel */
b83806d8 535 DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
8d77edde 536 status = charon->kernel_interface->add_sa(charon->kernel_interface,
c60c7694
MW
537 src, dst, spi, this->protocol,
538 this->reqid, mine ? soft : 0,
539 hard, enc_algo, int_algo,
7652be89 540 prf_plus, natt, mode, mine);
a2a3fb3e 541
c0593835
MW
542 this->encryption = *enc_algo;
543 this->integrity = *int_algo;
a2a3fb3e 544 this->install_time = time(NULL);
e70d5576 545 this->rekey_time = soft;
abba7ecb 546
8d77edde 547 return status;
30b5b412
MW
548}
549
7652be89
MW
550static status_t add(private_child_sa_t *this, proposal_t *proposal,
551 mode_t mode, prf_plus_t *prf_plus)
30b5b412 552{
891dfaf9 553 u_int32_t outbound_spi, inbound_spi;
30b5b412 554
891dfaf9
MW
555 /* backup outbound spi, as alloc overwrites it */
556 outbound_spi = proposal->get_spi(proposal);
30b5b412 557
891dfaf9 558 /* get SPIs inbound SAs */
1396815a 559 if (alloc_proposal(this, proposal) != SUCCESS)
30b5b412 560 {
30b5b412
MW
561 return FAILED;
562 }
891dfaf9 563 inbound_spi = proposal->get_spi(proposal);
30b5b412 564
891dfaf9 565 /* install inbound SAs */
7652be89 566 if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS)
30b5b412
MW
567 {
568 return FAILED;
569 }
a527a426 570
891dfaf9
MW
571 /* install outbound SAs, restore spi*/
572 proposal->set_spi(proposal, outbound_spi);
7652be89 573 if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
891dfaf9
MW
574 {
575 return FAILED;
576 }
577 proposal->set_spi(proposal, inbound_spi);
578
30b5b412
MW
579 return SUCCESS;
580}
581
7652be89
MW
582static status_t update(private_child_sa_t *this, proposal_t *proposal,
583 mode_t mode, prf_plus_t *prf_plus)
30b5b412 584{
891dfaf9
MW
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 */
7652be89 591 if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
30b5b412
MW
592 {
593 return FAILED;
594 }
891dfaf9
MW
595
596 /* restore spi */
597 proposal->set_spi(proposal, inbound_spi);
598 /* install inbound SAs */
7652be89 599 if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS)
30b5b412
MW
600 {
601 return FAILED;
602 }
a527a426
MW
603
604 return SUCCESS;
605}
606
7652be89
MW
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)
a527a426 610{
5d187bd2
MW
611 iterator_t *my_iter, *other_iter;
612 traffic_selector_t *my_ts, *other_ts;
a095243f
MW
613 /* use low prio for ROUTED policies */
614 bool high_prio = (this->state != CHILD_CREATED);
a527a426 615
5d187bd2
MW
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);
191a26a6 619 while (my_iter->iterate(my_iter, (void**)&my_ts))
a527a426 620 {
5d187bd2 621 other_iter->reset(other_iter);
191a26a6 622 while (other_iter->iterate(other_iter, (void**)&other_ts))
5d187bd2
MW
623 {
624 /* set up policies for every entry in my_ts_list to every entry in other_ts_list */
5d187bd2 625 status_t status;
92ee45a0 626 sa_policy_t *policy;
5d187bd2 627
92ee45a0
MW
628 if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts))
629 {
b83806d8 630 DBG2(DBG_CHD,
60356f33 631 "CHILD_SA policy uses two different IP families, ignored");
92ee45a0
MW
632 continue;
633 }
634
5f0eb96f
MW
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))
5d187bd2 638 {
b83806d8 639 DBG2(DBG_CHD,
60356f33 640 "CHILD_SA policy uses two different protocols, ignored");
5d187bd2
MW
641 continue;
642 }
5d187bd2 643
5d187bd2
MW
644 /* install 3 policies: out, in and forward */
645 status = charon->kernel_interface->add_policy(charon->kernel_interface,
7652be89
MW
646 this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT,
647 this->protocol, this->reqid, high_prio, mode, FALSE);
92ee45a0 648
5d187bd2 649 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
7652be89
MW
650 this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN,
651 this->protocol, this->reqid, high_prio, mode, FALSE);
92ee45a0 652
5d187bd2 653 status |= charon->kernel_interface->add_policy(charon->kernel_interface,
7652be89
MW
654 this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD,
655 this->protocol, this->reqid, high_prio, mode, FALSE);
5d187bd2
MW
656
657 if (status != SUCCESS)
658 {
659 my_iter->destroy(my_iter);
660 other_iter->destroy(other_iter);
5d187bd2
MW
661 return status;
662 }
663
92ee45a0
MW
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);
e0fe7651 668 this->policies->insert_last(this->policies, policy);
8dfbe71b 669 /* add to separate list to query them via get_*_traffic_selectors() */
e0fe7651
MW
670 this->my_ts->insert_last(this->my_ts, policy->my_ts);
671 this->other_ts->insert_last(this->other_ts, policy->other_ts);
5d187bd2
MW
672 }
673 }
5d187bd2
MW
674 my_iter->destroy(my_iter);
675 other_iter->destroy(other_iter);
45f76a7d
MW
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 }
7652be89
MW
682 /* needed to update hosts */
683 this->mode = mode;
5d187bd2 684 return SUCCESS;
30b5b412
MW
685}
686
8dfbe71b 687/**
e0fe7651 688 * Implementation of child_sa_t.get_traffic_selectors.
8dfbe71b 689 */
e0fe7651 690static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local)
8dfbe71b 691{
e0fe7651
MW
692 if (local)
693 {
694 return this->my_ts;
695 }
8dfbe71b
MW
696 return this->other_ts;
697}
698
2f89902d
MW
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{
92ee45a0
MW
704 iterator_t *iterator;
705 sa_policy_t *policy;
fe04e93a 706 status_t status = FAILED;
2f89902d
MW
707
708 *use_time = UNDEFINED_TIME;
92ee45a0
MW
709
710 iterator = this->policies->create_iterator(this->policies, TRUE);
711 while (iterator->iterate(iterator, (void**)&policy))
aeeb4f4f 712 {
92ee45a0
MW
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 }
aeeb4f4f 734 }
92ee45a0 735 iterator->destroy(iterator);
aeeb4f4f 736 return status;
2f89902d
MW
737}
738
5f0eb96f 739/**
60356f33 740 * output handler in printf()
5f0eb96f 741 */
60356f33
MW
742static int print(FILE *stream, const struct printf_info *info,
743 const void *const *args)
5f0eb96f 744{
60356f33 745 private_child_sa_t *this = *((private_child_sa_t**)(args[0]));
5f0eb96f 746 iterator_t *iterator;
60356f33 747 sa_policy_t *policy;
e70d5576 748 u_int32_t now, rekeying;
a40926c7 749 u_int32_t use, use_in, use_fwd;
92ee45a0 750 status_t status;
e706c7f1 751 size_t written = 0;
5f0eb96f 752
60356f33 753 if (this == NULL)
5f0eb96f 754 {
60356f33 755 return fprintf(stream, "(null)");
5f0eb96f 756 }
60356f33 757
39a268b8 758 now = time(NULL);
92ee45a0 759
c60c7694 760 written += fprintf(stream, "%12s{%d}: %N, %N",
e0fe7651 761 this->config->get_name(this->config), this->reqid,
c60c7694 762 child_sa_state_names, this->state,
21f42524 763 mode_names, this->mode);
60356f33 764
45f76a7d 765 if (this->state == CHILD_INSTALLED)
c0593835 766 {
efa0ed68 767 written += fprintf(stream, ", %N SPIs: 0x%0x_i 0x%0x_o",
e706c7f1
MW
768 protocol_id_names, this->protocol,
769 htonl(this->me.spi), htonl(this->other.spi));
45f76a7d 770
60356f33 771 if (info->alt)
45f76a7d 772 {
c60c7694 773 written += fprintf(stream, "\n%12s{%d}: ",
e0fe7651 774 this->config->get_name(this->config),
c60c7694 775 this->reqid);
60356f33
MW
776
777 if (this->protocol == PROTO_ESP)
45f76a7d 778 {
e706c7f1
MW
779 written += fprintf(stream, "%N", encryption_algorithm_names,
780 this->encryption.algorithm);
60356f33
MW
781
782 if (this->encryption.key_size)
783 {
e706c7f1 784 written += fprintf(stream, "-%d", this->encryption.key_size);
60356f33 785 }
e706c7f1 786 written += fprintf(stream, "/");
60356f33
MW
787 }
788
e706c7f1
MW
789 written += fprintf(stream, "%N", integrity_algorithm_names,
790 this->integrity.algorithm);
60356f33
MW
791 if (this->integrity.key_size)
792 {
e706c7f1 793 written += fprintf(stream, "-%d", this->integrity.key_size);
60356f33 794 }
efa0ed68 795 written += fprintf(stream, ", rekeying ");
60356f33
MW
796
797 /* calculate rekey times */
e70d5576 798 if (this->rekey_time)
60356f33 799 {
e70d5576 800 rekeying = this->install_time + this->rekey_time - now;
efa0ed68 801 written += fprintf(stream, "in %ds", rekeying);
45f76a7d
MW
802 }
803 else
804 {
e706c7f1 805 written += fprintf(stream, "disabled");
45f76a7d
MW
806 }
807 }
c0593835 808 }
5f0eb96f 809 iterator = this->policies->create_iterator(this->policies, TRUE);
60356f33 810 while (iterator->iterate(iterator, (void**)&policy))
5f0eb96f 811 {
c60c7694 812 written += fprintf(stream, "\n%12s{%d}: %R===%R, last use: ",
e0fe7651 813 this->config->get_name(this->config), this->reqid,
c60c7694 814 policy->my_ts, policy->other_ts);
5f0eb96f 815
a40926c7
AS
816 /* query time of last policy use */
817
818 /* inbound: POLICY_IN or POLICY_FWD */
92ee45a0 819 status = charon->kernel_interface->query_policy(charon->kernel_interface,
a40926c7
AS
820 policy->other_ts, policy->my_ts, POLICY_IN, &use_in);
821 use_in = (status == SUCCESS)? use_in : 0;
92ee45a0 822 status = charon->kernel_interface->query_policy(charon->kernel_interface,
a40926c7
AS
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)
60356f33 827 {
a40926c7 828 written += fprintf(stream, "%ds_i ", now - use);
60356f33
MW
829 }
830 else
5f0eb96f 831 {
a40926c7 832 written += fprintf(stream, "no_i ");
5f0eb96f 833 }
a40926c7
AS
834
835 /* outbound: POLICY_OUT */
92ee45a0 836 status = charon->kernel_interface->query_policy(charon->kernel_interface,
a40926c7 837 policy->my_ts, policy->other_ts, POLICY_OUT, &use);
60356f33 838 if (status == SUCCESS && use)
5f0eb96f 839 {
a40926c7 840 written += fprintf(stream, "%ds_o ", now - use);
60356f33
MW
841 }
842 else
843 {
a40926c7 844 written += fprintf(stream, "no_o ");
5f0eb96f 845 }
5f0eb96f
MW
846 }
847 iterator->destroy(iterator);
e706c7f1 848 return written;
60356f33
MW
849}
850
60356f33
MW
851/**
852 * register printf() handlers
853 */
854static void __attribute__ ((constructor))print_register()
855{
db7ef624 856 register_printf_function(PRINTF_CHILD_SA, print, arginfo_ptr);
5f0eb96f
MW
857}
858
1396815a
MW
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)
1396815a
MW
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 }
abba7ecb
MW
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 }
1396815a 890
b83806d8 891 DBG2(DBG_CHD, "updating %N SA 0x%x, from %#H..#H to %#H..%#H",
60356f33 892 protocol_id_names, this->protocol, ntohl(spi), src, dst, new_src, new_dst);
1396815a 893
92ee45a0
MW
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);
1396815a
MW
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;
a095243f 914 /* we always use high priorities, as hosts getting updated are INSTALLED */
1396815a
MW
915
916 iterator = this->policies->create_iterator(this->policies, TRUE);
917 while (iterator->iterate(iterator, (void**)&policy))
918 {
1396815a
MW
919 status = charon->kernel_interface->add_policy(
920 charon->kernel_interface,
921 new_me, new_other,
92ee45a0 922 policy->my_ts, policy->other_ts,
7652be89 923 POLICY_OUT, this->protocol, this->reqid, TRUE, this->mode, TRUE);
1396815a
MW
924
925 status |= charon->kernel_interface->add_policy(
926 charon->kernel_interface,
927 new_other, new_me,
92ee45a0 928 policy->other_ts, policy->my_ts,
7652be89 929 POLICY_IN, this->protocol, this->reqid, TRUE, this->mode, TRUE);
1396815a
MW
930
931 status |= charon->kernel_interface->add_policy(
932 charon->kernel_interface,
933 new_other, new_me,
92ee45a0 934 policy->other_ts, policy->my_ts,
7652be89 935 POLICY_FWD, this->protocol, this->reqid, TRUE, this->mode, TRUE);
aeeb4f4f 936
1396815a
MW
937 if (status != SUCCESS)
938 {
939 iterator->destroy(iterator);
940 return FAILED;
941 }
942 }
943 iterator->destroy(iterator);
92ee45a0 944
698d7749 945 return SUCCESS;
1396815a
MW
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,
92ee45a0 952 host_diff_t my_changes, host_diff_t other_changes)
1396815a 953{
abba7ecb 954 if (!my_changes && !other_changes)
1396815a
MW
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
8f031473
MW
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
30b5b412
MW
1004/**
1005 * Implementation of child_sa_t.destroy.
1006 */
1007static void destroy(private_child_sa_t *this)
1008{
16b9a73c 1009 sa_policy_t *policy;
5d187bd2 1010
d7934d0c
MW
1011 if (this->state == CHILD_DELETING || this->state == CHILD_INSTALLED)
1012 {
1013 updown(this, FALSE);
1014 }
1015
5d187bd2 1016 /* delete SAs in the kernel, if they are set up */
3efbf983 1017 if (this->me.spi)
5d187bd2
MW
1018 {
1019 charon->kernel_interface->del_sa(charon->kernel_interface,
695723d4 1020 this->me.addr, this->me.spi, this->protocol);
3efbf983
MW
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 {
5d187bd2 1034 charon->kernel_interface->del_sa(charon->kernel_interface,
695723d4
MW
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 {
aeeb4f4f
MW
1041 /* let rekeyed policies, as they are used by another child_sa */
1042 charon->kernel_interface->del_policy(charon->kernel_interface,
92ee45a0
MW
1043 policy->my_ts, policy->other_ts,
1044 POLICY_OUT);
aeeb4f4f
MW
1045
1046 charon->kernel_interface->del_policy(charon->kernel_interface,
92ee45a0
MW
1047 policy->other_ts, policy->my_ts,
1048 POLICY_IN);
aeeb4f4f
MW
1049
1050 charon->kernel_interface->del_policy(charon->kernel_interface,
92ee45a0
MW
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);
695723d4 1055 free(policy);
5d187bd2 1056 }
695723d4 1057 this->policies->destroy(this->policies);
abba7ecb 1058
8dfbe71b
MW
1059 this->my_ts->destroy(this->my_ts);
1060 this->other_ts->destroy(this->other_ts);
abba7ecb
MW
1061 this->me.addr->destroy(this->me.addr);
1062 this->other.addr->destroy(this->other.addr);
d7934d0c
MW
1063 this->me.id->destroy(this->me.id);
1064 this->other.id->destroy(this->other.id);
e0fe7651 1065 this->config->destroy(this->config);
8f031473 1066 DESTROY_IF(this->virtual_ip);
5113680f 1067 free(this);
30b5b412
MW
1068}
1069
1070/*
1071 * Described in header.
1072 */
c60c7694 1073child_sa_t * child_sa_create(host_t *me, host_t* other,
d7934d0c 1074 identification_t *my_id, identification_t *other_id,
e0fe7651 1075 child_cfg_t *config, u_int32_t rekey, bool use_natt)
30b5b412 1076{
c60c7694 1077 static u_int32_t reqid = 0;
5113680f 1078 private_child_sa_t *this = malloc_thing(private_child_sa_t);
30b5b412
MW
1079
1080 /* public functions */
9be547c0 1081 this->public.get_name = (char*(*)(child_sa_t*))get_name;
32b6500f 1082 this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
8d77edde
MW
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;
30b5b412 1085 this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
7652be89
MW
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;
92ee45a0 1088 this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts;
7652be89 1089 this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies;
e0fe7651 1090 this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
2f89902d 1091 this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
bcb95ced
MW
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;
e0fe7651 1094 this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config;
8f031473 1095 this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip;
30b5b412
MW
1096 this->public.destroy = (void(*)(child_sa_t*))destroy;
1097
1098 /* private data */
abba7ecb
MW
1099 this->me.addr = me->clone(me);
1100 this->other.addr = other->clone(other);
d7934d0c
MW
1101 this->me.id = my_id->clone(my_id);
1102 this->other.id = other_id->clone(other_id);
8d77edde
MW
1103 this->me.spi = 0;
1104 this->other.spi = 0;
3efbf983
MW
1105 this->alloc_ah_spi = 0;
1106 this->alloc_esp_spi = 0;
1396815a 1107 this->use_natt = use_natt;
bcb95ced 1108 this->state = CHILD_CREATED;
50f98119
MW
1109 /* reuse old reqid if we are rekeying an existing CHILD_SA */
1110 this->reqid = rekey ? rekey : ++reqid;
c0593835
MW
1111 this->encryption.algorithm = ENCR_UNDEFINED;
1112 this->encryption.key_size = 0;
1113 this->integrity.algorithm = AUTH_UNDEFINED;
1114 this->encryption.key_size = 0;
5d187bd2 1115 this->policies = linked_list_create();
8dfbe71b
MW
1116 this->my_ts = linked_list_create();
1117 this->other_ts = linked_list_create();
8d77edde 1118 this->protocol = PROTO_NONE;
7652be89 1119 this->mode = MODE_TUNNEL;
8f031473 1120 this->virtual_ip = NULL;
e0fe7651
MW
1121 this->config = config;
1122 config->get_ref(config);
3ebebc5e 1123
1396815a 1124 return &this->public;
3ebebc5e 1125}