]>
Commit | Line | Data |
---|---|---|
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 |
34 | ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DELETING, |
35 | "CREATED", | |
36 | "ROUTED", | |
37 | "INSTALLED", | |
38 | "REKEYING", | |
39 | "DELETING", | |
40 | ); | |
bcb95ced | 41 | |
16b9a73c | 42 | typedef 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 | 49 | struct 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 |
61 | typedef struct private_child_sa_t private_child_sa_t; |
62 | ||
63 | /** | |
fff4ee8a | 64 | * Private data of a child_sa_t \ 1bject. |
3ebebc5e MW |
65 | */ |
66 | struct 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 | */ | |
165 | static 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 | */ | |
173 | static 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 | */ | |
181 | u_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 | */ | |
193 | protocol_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 | */ | |
201 | static 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 | 209 | static 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 | */ | |
217 | static 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 | */ | |
369 | static 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 | */ | |
381 | static 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 | 424 | static 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 |
443 | static 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 |
550 | static 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 |
582 | static 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 |
607 | static 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 | 690 | static 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 | */ | |
702 | static 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 |
742 | static 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 | */ | |
854 | static 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 | */ | |
862 | static 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 | */ | |
909 | static 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 | */ | |
951 | static 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 | */ | |
999 | static 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 | */ | |
1007 | static 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 | 1073 | child_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 | } |