]>
Commit | Line | Data |
---|---|---|
3ebebc5e MW |
1 | /** |
2 | * @file child_sa.c | |
3 | * | |
4 | * @brief Implementation of child_sa_t. | |
5 | * | |
6 | */ | |
7 | ||
8 | /* | |
1396815a | 9 | * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger |
c71d53ba MW |
10 | * Copyright (C) 2005-2006 Martin Willi |
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 | ||
b92eef28 | 25 | #include "child_sa.h" |
3ebebc5e | 26 | |
aeda79ff MW |
27 | #include <daemon.h> |
28 | ||
3ebebc5e | 29 | |
bcb95ced MW |
30 | /** |
31 | * String mappings for child_sa_state_t. | |
32 | */ | |
33 | mapping_t child_sa_state_m[] = { | |
34 | {CHILD_CREATED, "CREATED"}, | |
35 | {CHILD_INSTALLED, "INSTALLED"}, | |
36 | {CHILD_REKEYING, "REKEYING"}, | |
37 | {CHILD_DELETING, "DELETING"}, | |
38 | {MAPPING_END, NULL} | |
39 | }; | |
40 | ||
16b9a73c | 41 | typedef struct sa_policy_t sa_policy_t; |
5d187bd2 MW |
42 | |
43 | /** | |
44 | * Struct used to store information for a policy. This | |
45 | * is needed since we must provide all this information | |
46 | * for deleting a policy... | |
47 | */ | |
16b9a73c | 48 | struct sa_policy_t { |
92ee45a0 MW |
49 | /** |
50 | * Traffic selector for us | |
51 | */ | |
52 | traffic_selector_t *my_ts; | |
5d187bd2 MW |
53 | |
54 | /** | |
92ee45a0 | 55 | * Traffic selector for other |
5d187bd2 | 56 | */ |
92ee45a0 | 57 | traffic_selector_t *other_ts; |
5d187bd2 MW |
58 | }; |
59 | ||
3ebebc5e MW |
60 | typedef struct private_child_sa_t private_child_sa_t; |
61 | ||
62 | /** | |
144f676c | 63 | * Private data of a child_sa_t object. |
3ebebc5e MW |
64 | */ |
65 | struct private_child_sa_t { | |
66 | /** | |
144f676c | 67 | * Public interface of child_sa_t. |
3ebebc5e MW |
68 | */ |
69 | child_sa_t public; | |
70 | ||
8d77edde MW |
71 | struct { |
72 | /** address of peer */ | |
73 | host_t *addr; | |
74 | /** actual used SPI, 0 if unused */ | |
75 | u_int32_t spi; | |
76 | } me, other; | |
aeda79ff | 77 | |
3efbf983 MW |
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 | ||
aeda79ff | 88 | /** |
8d77edde | 89 | * Protocol used to protect this SA, ESP|AH |
aeda79ff | 90 | */ |
8d77edde | 91 | protocol_id_t protocol; |
30b5b412 MW |
92 | |
93 | /** | |
8d77edde | 94 | * List containing sa_policy_t objects |
5d187bd2 | 95 | */ |
8d77edde | 96 | linked_list_t *policies; |
5d187bd2 | 97 | |
8dfbe71b MW |
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 | ||
5d187bd2 | 108 | /** |
8d77edde | 109 | * reqid used for this child_sa |
5d187bd2 | 110 | */ |
8d77edde | 111 | u_int32_t reqid; |
5d187bd2 | 112 | |
a2a3fb3e MW |
113 | /** |
114 | * time, on which SA was installed | |
115 | */ | |
116 | time_t install_time; | |
117 | ||
5d187bd2 | 118 | /** |
8d77edde | 119 | * Lifetime before rekeying |
5d187bd2 | 120 | */ |
8d77edde | 121 | u_int32_t soft_lifetime; |
30b5b412 | 122 | |
a527a426 | 123 | /** |
8d77edde | 124 | * Lifetime before delete |
a527a426 | 125 | */ |
8d77edde | 126 | u_int32_t hard_lifetime; |
a527a426 | 127 | |
bcb95ced MW |
128 | /** |
129 | * state of the CHILD_SA | |
130 | */ | |
131 | child_sa_state_t state; | |
132 | ||
695723d4 | 133 | /** |
abba7ecb | 134 | * transaction which is rekeying this CHILD_SA |
695723d4 | 135 | */ |
abba7ecb | 136 | void *rekeying_transaction; |
1396815a MW |
137 | |
138 | /** | |
139 | * Specifies if NAT traversal is used | |
140 | */ | |
141 | bool use_natt; | |
695723d4 | 142 | |
30b5b412 MW |
143 | /** |
144 | * CHILD_SAs own logger | |
145 | */ | |
146 | logger_t *logger; | |
3ebebc5e MW |
147 | }; |
148 | ||
32b6500f MW |
149 | /** |
150 | * Implements child_sa_t.get_reqid | |
151 | */ | |
152 | static u_int32_t get_reqid(private_child_sa_t *this) | |
153 | { | |
154 | return this->reqid; | |
155 | } | |
8d77edde MW |
156 | |
157 | /** | |
158 | * Implements child_sa_t.get_spi | |
159 | */ | |
160 | u_int32_t get_spi(private_child_sa_t *this, bool inbound) | |
161 | { | |
162 | if (inbound) | |
163 | { | |
164 | return this->me.spi; | |
165 | } | |
166 | return this->other.spi; | |
167 | } | |
168 | ||
169 | /** | |
170 | * Implements child_sa_t.get_protocol | |
171 | */ | |
172 | protocol_id_t get_protocol(private_child_sa_t *this) | |
173 | { | |
174 | return this->protocol; | |
175 | } | |
32b6500f | 176 | |
bcb95ced MW |
177 | /** |
178 | * Implements child_sa_t.get_state | |
179 | */ | |
180 | static child_sa_state_t get_state(private_child_sa_t *this) | |
181 | { | |
182 | return this->state; | |
183 | } | |
184 | ||
185 | /** | |
186 | * Implements child_sa_t.set_state | |
187 | */ | |
188 | static void set_state(private_child_sa_t *this, child_sa_state_t state) | |
189 | { | |
190 | this->state = state; | |
191 | } | |
192 | ||
1396815a MW |
193 | /** |
194 | * Allocate SPI for a single proposal | |
195 | */ | |
196 | static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal) | |
197 | { | |
198 | protocol_id_t protocol = proposal->get_protocol(proposal); | |
199 | ||
200 | if (protocol == PROTO_AH) | |
201 | { | |
202 | /* get a new spi for AH, if not already done */ | |
203 | if (this->alloc_ah_spi == 0) | |
204 | { | |
205 | if (charon->kernel_interface->get_spi( | |
206 | charon->kernel_interface, | |
207 | this->other.addr, this->me.addr, | |
208 | PROTO_AH, this->reqid, | |
209 | &this->alloc_ah_spi) != SUCCESS) | |
210 | { | |
211 | return FAILED; | |
212 | } | |
213 | } | |
214 | proposal->set_spi(proposal, this->alloc_ah_spi); | |
215 | } | |
216 | if (protocol == PROTO_ESP) | |
217 | { | |
218 | /* get a new spi for ESP, if not already done */ | |
219 | if (this->alloc_esp_spi == 0) | |
220 | { | |
221 | if (charon->kernel_interface->get_spi( | |
222 | charon->kernel_interface, | |
223 | this->other.addr, this->me.addr, | |
224 | PROTO_ESP, this->reqid, | |
225 | &this->alloc_esp_spi) != SUCCESS) | |
226 | { | |
227 | return FAILED; | |
228 | } | |
229 | } | |
230 | proposal->set_spi(proposal, this->alloc_esp_spi); | |
231 | } | |
232 | return SUCCESS; | |
233 | } | |
234 | ||
235 | ||
3ebebc5e | 236 | /** |
30b5b412 | 237 | * Implements child_sa_t.alloc |
3ebebc5e | 238 | */ |
30b5b412 | 239 | static status_t alloc(private_child_sa_t *this, linked_list_t *proposals) |
3ebebc5e | 240 | { |
30b5b412 MW |
241 | iterator_t *iterator; |
242 | proposal_t *proposal; | |
30b5b412 | 243 | |
3efbf983 | 244 | /* iterator through proposals to update spis */ |
30b5b412 MW |
245 | iterator = proposals->create_iterator(proposals, TRUE); |
246 | while(iterator->has_next(iterator)) | |
247 | { | |
248 | iterator->current(iterator, (void**)&proposal); | |
1396815a | 249 | if (alloc_proposal(this, proposal) != SUCCESS) |
3efbf983 | 250 | { |
1396815a MW |
251 | iterator->destroy(iterator); |
252 | return FAILED; | |
3efbf983 | 253 | } |
30b5b412 MW |
254 | } |
255 | iterator->destroy(iterator); | |
256 | return SUCCESS; | |
3ebebc5e MW |
257 | } |
258 | ||
30b5b412 | 259 | static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine) |
3ebebc5e | 260 | { |
30b5b412 | 261 | u_int32_t spi; |
5c131a01 MW |
262 | algorithm_t *enc_algo, *int_algo; |
263 | algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0}; | |
264 | algorithm_t int_algo_none = {AUTH_UNDEFINED, 0}; | |
30b5b412 MW |
265 | host_t *src; |
266 | host_t *dst; | |
1396815a | 267 | natt_conf_t *natt; |
30b5b412 | 268 | status_t status; |
aeda79ff | 269 | |
8d77edde MW |
270 | this->protocol = proposal->get_protocol(proposal); |
271 | ||
272 | /* now we have to decide which spi to use. Use self allocated, if "mine", | |
3efbf983 MW |
273 | * or the one in the proposal, if not "mine" (others). Additionally, |
274 | * source and dest host switch depending on the role */ | |
8d77edde | 275 | if (mine) |
aeda79ff | 276 | { |
3efbf983 MW |
277 | /* if we have allocated SPIs for AH and ESP, we must delete the unused |
278 | * one. */ | |
279 | if (this->protocol == PROTO_ESP) | |
280 | { | |
281 | this->me.spi = this->alloc_esp_spi; | |
282 | if (this->alloc_ah_spi) | |
283 | { | |
284 | charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, | |
285 | this->alloc_ah_spi, PROTO_AH); | |
286 | } | |
287 | } | |
288 | else | |
289 | { | |
290 | this->me.spi = this->alloc_ah_spi; | |
291 | if (this->alloc_esp_spi) | |
292 | { | |
293 | charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, | |
294 | this->alloc_esp_spi, PROTO_ESP); | |
295 | } | |
296 | } | |
8d77edde | 297 | spi = this->me.spi; |
3efbf983 MW |
298 | dst = this->me.addr; |
299 | src = this->other.addr; | |
aeda79ff | 300 | } |
8d77edde MW |
301 | else |
302 | { | |
3efbf983 MW |
303 | this->other.spi = proposal->get_spi(proposal); |
304 | spi = this->other.spi; | |
305 | src = this->me.addr; | |
306 | dst = this->other.addr; | |
8d77edde MW |
307 | } |
308 | ||
1d390631 | 309 | this->logger->log(this->logger, CONTROL|LEVEL1, "adding %s %s SA", |
5c131a01 MW |
310 | mine ? "inbound" : "outbound", |
311 | mapping_find(protocol_id_m, this->protocol)); | |
312 | ||
313 | /* select encryption algo */ | |
314 | if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_algo)) | |
8d77edde | 315 | { |
5c131a01 MW |
316 | this->logger->log(this->logger, CONTROL|LEVEL2, " using %s for encryption", |
317 | mapping_find(encryption_algorithm_m, enc_algo->algorithm)); | |
8d77edde MW |
318 | } |
319 | else | |
320 | { | |
5c131a01 | 321 | enc_algo = &enc_algo_none; |
8d77edde MW |
322 | } |
323 | ||
5c131a01 MW |
324 | /* select integrity algo */ |
325 | if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_algo)) | |
8d77edde | 326 | { |
5c131a01 MW |
327 | this->logger->log(this->logger, CONTROL|LEVEL2, " using %s for integrity", |
328 | mapping_find(integrity_algorithm_m, int_algo->algorithm)); | |
8d77edde MW |
329 | } |
330 | else | |
331 | { | |
5c131a01 | 332 | int_algo = &int_algo_none; |
8d77edde MW |
333 | } |
334 | ||
1396815a MW |
335 | /* setup nat-t */ |
336 | if (this->use_natt) | |
337 | { | |
338 | natt = alloca(sizeof(natt_conf_t)); | |
339 | natt->sport = src->get_port(src); | |
340 | natt->dport = dst->get_port(dst); | |
341 | } | |
342 | else | |
343 | { | |
344 | natt = NULL; | |
345 | } | |
346 | ||
347 | ||
5c131a01 MW |
348 | /* send SA down to the kernel */ |
349 | this->logger->log(this->logger, CONTROL|LEVEL2, | |
350 | " SPI 0x%.8x, src %s dst %s", | |
92ee45a0 | 351 | ntohl(spi), src->get_string(src), dst->get_string(dst)); |
8d77edde | 352 | status = charon->kernel_interface->add_sa(charon->kernel_interface, |
1396815a MW |
353 | src, dst, |
354 | spi, this->protocol, | |
355 | this->reqid, | |
698d7749 | 356 | mine ? this->soft_lifetime : 0, |
1396815a MW |
357 | this->hard_lifetime, |
358 | enc_algo, int_algo, | |
359 | prf_plus, natt, mine); | |
a2a3fb3e MW |
360 | |
361 | this->install_time = time(NULL); | |
abba7ecb | 362 | |
8d77edde | 363 | return status; |
30b5b412 MW |
364 | } |
365 | ||
366 | static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus) | |
367 | { | |
891dfaf9 | 368 | u_int32_t outbound_spi, inbound_spi; |
30b5b412 | 369 | |
891dfaf9 MW |
370 | /* backup outbound spi, as alloc overwrites it */ |
371 | outbound_spi = proposal->get_spi(proposal); | |
30b5b412 | 372 | |
891dfaf9 | 373 | /* get SPIs inbound SAs */ |
1396815a | 374 | if (alloc_proposal(this, proposal) != SUCCESS) |
30b5b412 | 375 | { |
30b5b412 MW |
376 | return FAILED; |
377 | } | |
891dfaf9 | 378 | inbound_spi = proposal->get_spi(proposal); |
30b5b412 | 379 | |
891dfaf9 | 380 | /* install inbound SAs */ |
30b5b412 MW |
381 | if (install(this, proposal, prf_plus, TRUE) != SUCCESS) |
382 | { | |
383 | return FAILED; | |
384 | } | |
a527a426 | 385 | |
891dfaf9 MW |
386 | /* install outbound SAs, restore spi*/ |
387 | proposal->set_spi(proposal, outbound_spi); | |
388 | if (install(this, proposal, prf_plus, FALSE) != SUCCESS) | |
389 | { | |
390 | return FAILED; | |
391 | } | |
392 | proposal->set_spi(proposal, inbound_spi); | |
393 | ||
bcb95ced MW |
394 | this->state = CHILD_INSTALLED; |
395 | ||
30b5b412 MW |
396 | return SUCCESS; |
397 | } | |
398 | ||
399 | static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus) | |
400 | { | |
891dfaf9 MW |
401 | u_int32_t inbound_spi; |
402 | ||
403 | /* backup received spi, as install() overwrites it */ | |
404 | inbound_spi = proposal->get_spi(proposal); | |
405 | ||
406 | /* install outbound SAs */ | |
407 | if (install(this, proposal, prf_plus, FALSE) != SUCCESS) | |
30b5b412 MW |
408 | { |
409 | return FAILED; | |
410 | } | |
891dfaf9 MW |
411 | |
412 | /* restore spi */ | |
413 | proposal->set_spi(proposal, inbound_spi); | |
414 | /* install inbound SAs */ | |
415 | if (install(this, proposal, prf_plus, TRUE) != SUCCESS) | |
30b5b412 MW |
416 | { |
417 | return FAILED; | |
418 | } | |
a527a426 | 419 | |
bcb95ced MW |
420 | this->state = CHILD_INSTALLED; |
421 | ||
a527a426 MW |
422 | return SUCCESS; |
423 | } | |
424 | ||
5d187bd2 | 425 | static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list) |
a527a426 | 426 | { |
5d187bd2 MW |
427 | iterator_t *my_iter, *other_iter; |
428 | traffic_selector_t *my_ts, *other_ts; | |
a527a426 | 429 | |
5d187bd2 MW |
430 | /* iterate over both lists */ |
431 | my_iter = my_ts_list->create_iterator(my_ts_list, TRUE); | |
432 | other_iter = other_ts_list->create_iterator(other_ts_list, TRUE); | |
433 | while (my_iter->has_next(my_iter)) | |
a527a426 | 434 | { |
5d187bd2 MW |
435 | my_iter->current(my_iter, (void**)&my_ts); |
436 | other_iter->reset(other_iter); | |
437 | while (other_iter->has_next(other_iter)) | |
438 | { | |
439 | /* set up policies for every entry in my_ts_list to every entry in other_ts_list */ | |
5d187bd2 | 440 | status_t status; |
92ee45a0 | 441 | sa_policy_t *policy; |
5d187bd2 MW |
442 | |
443 | other_iter->current(other_iter, (void**)&other_ts); | |
444 | ||
92ee45a0 MW |
445 | if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts)) |
446 | { | |
447 | this->logger->log(this->logger, CONTROL|LEVEL1, | |
448 | "CHILD_SA policy uses two different IP families, ignored"); | |
449 | continue; | |
450 | } | |
451 | ||
5f0eb96f MW |
452 | /* only set up policies if protocol matches, or if one is zero (any) */ |
453 | if (my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts) && | |
454 | my_ts->get_protocol(my_ts) && other_ts->get_protocol(other_ts)) | |
5d187bd2 | 455 | { |
92ee45a0 | 456 | this->logger->log(this->logger, CONTROL|LEVEL1, |
5f0eb96f | 457 | "CHILD_SA policy uses two different protocols, ignored"); |
5d187bd2 MW |
458 | continue; |
459 | } | |
5d187bd2 | 460 | |
5d187bd2 MW |
461 | /* install 3 policies: out, in and forward */ |
462 | status = charon->kernel_interface->add_policy(charon->kernel_interface, | |
92ee45a0 MW |
463 | this->me.addr, this->other.addr, my_ts, other_ts, |
464 | POLICY_OUT, this->protocol, this->reqid, FALSE); | |
465 | ||
5d187bd2 | 466 | status |= charon->kernel_interface->add_policy(charon->kernel_interface, |
92ee45a0 MW |
467 | this->other.addr, this->me.addr, other_ts, my_ts, |
468 | POLICY_IN, this->protocol, this->reqid, FALSE); | |
469 | ||
5d187bd2 | 470 | status |= charon->kernel_interface->add_policy(charon->kernel_interface, |
92ee45a0 MW |
471 | this->other.addr, this->me.addr, other_ts, my_ts, |
472 | POLICY_FWD, this->protocol, this->reqid, FALSE); | |
5d187bd2 MW |
473 | |
474 | if (status != SUCCESS) | |
475 | { | |
476 | my_iter->destroy(my_iter); | |
477 | other_iter->destroy(other_iter); | |
5d187bd2 MW |
478 | return status; |
479 | } | |
480 | ||
92ee45a0 MW |
481 | /* store policy to delete/update them later */ |
482 | policy = malloc_thing(sa_policy_t); | |
483 | policy->my_ts = my_ts->clone(my_ts); | |
484 | policy->other_ts = other_ts->clone(other_ts); | |
485 | this->policies->insert_last(this->policies, (void*)policy); | |
8dfbe71b MW |
486 | /* add to separate list to query them via get_*_traffic_selectors() */ |
487 | this->my_ts->insert_last(this->my_ts, (void*)policy->my_ts); | |
488 | this->other_ts->insert_last(this->other_ts, (void*)policy->other_ts); | |
5d187bd2 MW |
489 | } |
490 | } | |
5d187bd2 MW |
491 | my_iter->destroy(my_iter); |
492 | other_iter->destroy(other_iter); | |
493 | return SUCCESS; | |
30b5b412 MW |
494 | } |
495 | ||
8dfbe71b MW |
496 | /** |
497 | * Implementation of child_sa_t.get_my_traffic_selectors. | |
498 | */ | |
499 | static linked_list_t *get_my_traffic_selectors(private_child_sa_t *this) | |
500 | { | |
501 | return this->my_ts; | |
502 | } | |
503 | ||
504 | /** | |
505 | * Implementation of child_sa_t.get_my_traffic_selectors. | |
506 | */ | |
507 | static linked_list_t *get_other_traffic_selectors(private_child_sa_t *this) | |
508 | { | |
509 | return this->other_ts; | |
510 | } | |
511 | ||
695723d4 | 512 | /** |
abba7ecb MW |
513 | * Implementation of child_sa_t.set_rekeying_transaction. |
514 | */ | |
515 | static void set_rekeying_transaction(private_child_sa_t *this, void *transaction) | |
516 | { | |
517 | this->rekeying_transaction = transaction; | |
abba7ecb MW |
518 | } |
519 | ||
520 | /** | |
521 | * Implementation of child_sa_t.get_rekeying_transaction. | |
695723d4 | 522 | */ |
abba7ecb | 523 | static void* get_rekeying_transaction(private_child_sa_t *this) |
695723d4 | 524 | { |
abba7ecb MW |
525 | return this->rekeying_transaction; |
526 | } | |
527 | ||
2f89902d MW |
528 | /** |
529 | * Implementation of child_sa_t.get_use_time | |
530 | */ | |
531 | static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use_time) | |
532 | { | |
92ee45a0 MW |
533 | iterator_t *iterator; |
534 | sa_policy_t *policy; | |
2f89902d MW |
535 | status_t status; |
536 | ||
537 | *use_time = UNDEFINED_TIME; | |
92ee45a0 MW |
538 | |
539 | iterator = this->policies->create_iterator(this->policies, TRUE); | |
540 | while (iterator->iterate(iterator, (void**)&policy)) | |
aeeb4f4f | 541 | { |
92ee45a0 MW |
542 | if (inbound) |
543 | { | |
544 | time_t in = UNDEFINED_TIME, fwd = UNDEFINED_TIME; | |
545 | ||
546 | status = charon->kernel_interface->query_policy( | |
547 | charon->kernel_interface, | |
548 | policy->other_ts, policy->my_ts, | |
549 | POLICY_IN, (u_int32_t*)&in); | |
550 | status |= charon->kernel_interface->query_policy( | |
551 | charon->kernel_interface, | |
552 | policy->other_ts, policy->my_ts, | |
553 | POLICY_FWD, (u_int32_t*)&fwd); | |
554 | *use_time = max(in, fwd); | |
555 | } | |
556 | else | |
557 | { | |
558 | status = charon->kernel_interface->query_policy( | |
559 | charon->kernel_interface, | |
560 | policy->my_ts, policy->other_ts, | |
561 | POLICY_OUT, (u_int32_t*)use_time); | |
562 | } | |
aeeb4f4f | 563 | } |
92ee45a0 | 564 | iterator->destroy(iterator); |
aeeb4f4f | 565 | return status; |
2f89902d MW |
566 | } |
567 | ||
5f0eb96f MW |
568 | /** |
569 | * Implementation of child_sa_t.log_status. | |
570 | */ | |
571 | static void log_status(private_child_sa_t *this, logger_t *logger, char* name) | |
572 | { | |
573 | iterator_t *iterator; | |
574 | char use_in_str[12] = "unused"; | |
575 | char use_out_str[12] = "unused"; | |
576 | char rekey_str[12] = "disabled"; | |
92ee45a0 MW |
577 | u_int32_t use_in, use_out, use_fwd, now, rekeying; |
578 | status_t status; | |
5f0eb96f MW |
579 | |
580 | if (logger == NULL) | |
581 | { | |
582 | logger = this->logger; | |
583 | } | |
92ee45a0 MW |
584 | now = (u_int32_t)time(NULL); |
585 | ||
586 | /* query SA times */ | |
587 | status = charon->kernel_interface->query_sa(charon->kernel_interface, | |
588 | this->me.addr, this->me.spi, this->protocol, &use_in); | |
589 | if (status == SUCCESS && use_in) | |
5f0eb96f | 590 | { |
92ee45a0 | 591 | snprintf(use_in_str, sizeof(use_in_str), "%ds", now - use_in); |
5f0eb96f | 592 | } |
92ee45a0 MW |
593 | status = charon->kernel_interface->query_sa(charon->kernel_interface, |
594 | this->other.addr, this->other.spi, this->protocol, &use_out); | |
595 | if (status == SUCCESS && use_out) | |
5f0eb96f | 596 | { |
92ee45a0 | 597 | snprintf(use_out_str, sizeof(use_out_str), "%ds", now - use_out); |
5f0eb96f | 598 | } |
92ee45a0 MW |
599 | |
600 | /* calculate rekey times */ | |
5f0eb96f MW |
601 | if (this->soft_lifetime) |
602 | { | |
603 | rekeying = this->soft_lifetime - (now - this->install_time); | |
604 | snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying); | |
605 | } | |
606 | ||
92ee45a0 | 607 | logger->log(logger, CONTROL|LEVEL1, |
5f0eb96f MW |
608 | " \"%s\": using %s, SPIs (in/out): 0x%x/0x%x, reqid: %d", |
609 | name, | |
610 | this->protocol == PROTO_ESP ? "ESP" : "AH", | |
611 | htonl(this->me.spi), htonl(this->other.spi), | |
612 | this->reqid); | |
92ee45a0 MW |
613 | logger->log(logger, CONTROL|LEVEL1, |
614 | " \"%s\": state: %s, rekeying: %s, key age (in/out): %s/%s", | |
bcb95ced MW |
615 | name, mapping_find(child_sa_state_m, this->state), |
616 | rekey_str, use_in_str, use_out_str); | |
5f0eb96f MW |
617 | |
618 | iterator = this->policies->create_iterator(this->policies, TRUE); | |
619 | while (iterator->has_next(iterator)) | |
620 | { | |
621 | sa_policy_t *policy; | |
92ee45a0 MW |
622 | char *my_str; |
623 | char *other_str; | |
624 | char pol_in_str[12] = "unused"; | |
625 | char pol_out_str[12] = "unused"; | |
626 | char pol_fwd_str[12] = "unused"; | |
5f0eb96f | 627 | |
92ee45a0 | 628 | /* get ts strings */ |
5f0eb96f | 629 | iterator->current(iterator, (void**)&policy); |
92ee45a0 MW |
630 | my_str = policy->my_ts->get_string(policy->my_ts); |
631 | other_str = policy->other_ts->get_string(policy->other_ts); | |
5f0eb96f | 632 | |
92ee45a0 MW |
633 | /* query policy times */ |
634 | status = charon->kernel_interface->query_policy(charon->kernel_interface, | |
635 | policy->other_ts, policy->my_ts, POLICY_IN, &use_in); | |
636 | if (status == SUCCESS && use_in) | |
5f0eb96f | 637 | { |
92ee45a0 | 638 | snprintf(pol_in_str, sizeof(pol_in_str), "%ds", now - use_in); |
5f0eb96f | 639 | } |
92ee45a0 MW |
640 | status = charon->kernel_interface->query_policy(charon->kernel_interface, |
641 | policy->my_ts, policy->other_ts, POLICY_OUT, &use_out); | |
642 | if (status == SUCCESS && use_out) | |
5f0eb96f | 643 | { |
92ee45a0 | 644 | snprintf(pol_out_str, sizeof(pol_out_str), "%ds", now - use_out); |
5f0eb96f | 645 | } |
92ee45a0 MW |
646 | status = charon->kernel_interface->query_policy(charon->kernel_interface, |
647 | policy->other_ts, policy->my_ts, POLICY_FWD, &use_fwd); | |
648 | if (status == SUCCESS && use_fwd) | |
5f0eb96f | 649 | { |
92ee45a0 | 650 | snprintf(pol_fwd_str, sizeof(pol_fwd_str), "%ds", now - use_fwd); |
5f0eb96f MW |
651 | } |
652 | ||
92ee45a0 MW |
653 | logger->log(logger, CONTROL, |
654 | " \"%s\": %s====%s, last use (in/out/fwd): %s/%s/%s", | |
655 | name, my_str, other_str, pol_in_str, pol_out_str, pol_fwd_str); | |
5f0eb96f MW |
656 | } |
657 | iterator->destroy(iterator); | |
658 | } | |
659 | ||
1396815a MW |
660 | /** |
661 | * Update the host adress/port of a SA | |
662 | */ | |
663 | static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other, | |
664 | int my_changes, int other_changes, bool mine) | |
665 | { | |
666 | host_t *src, *dst, *new_src, *new_dst; | |
667 | int src_changes, dst_changes; | |
668 | status_t status; | |
669 | u_int32_t spi; | |
670 | ||
671 | if (mine) | |
1396815a MW |
672 | { |
673 | src = this->other.addr; | |
674 | dst = this->me.addr; | |
675 | new_src = new_other; | |
676 | new_dst = new_me; | |
677 | src_changes = other_changes; | |
678 | dst_changes = my_changes; | |
679 | spi = this->other.spi; | |
680 | } | |
abba7ecb MW |
681 | else |
682 | { | |
683 | src = this->me.addr; | |
684 | dst = this->other.addr; | |
685 | new_src = new_me; | |
686 | new_dst = new_other; | |
687 | src_changes = my_changes; | |
688 | dst_changes = other_changes; | |
689 | spi = this->me.spi; | |
690 | } | |
1396815a MW |
691 | |
692 | this->logger->log(this->logger, CONTROL|LEVEL1, | |
693 | "updating %s SA 0x%x, from %s:%d..%s:%d to %s:%d..%s:%d", | |
694 | mapping_find(protocol_id_m, this->protocol), ntohl(spi), | |
92ee45a0 MW |
695 | src->get_string(src), src->get_port(src), |
696 | dst->get_string(dst), dst->get_port(dst), | |
697 | new_src->get_string(new_src), new_src->get_port(new_src), | |
698 | new_dst->get_string(new_dst), new_dst->get_port(new_dst)); | |
1396815a | 699 | |
92ee45a0 MW |
700 | status = charon->kernel_interface->update_sa(charon->kernel_interface, |
701 | dst, spi, this->protocol, | |
702 | new_src, new_dst, | |
703 | src_changes, dst_changes); | |
1396815a MW |
704 | |
705 | if (status != SUCCESS) | |
706 | { | |
707 | return FAILED; | |
708 | } | |
709 | return SUCCESS; | |
710 | } | |
711 | ||
712 | /** | |
713 | * Update the host adress/port of a policy | |
714 | */ | |
715 | static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other) | |
716 | { | |
717 | iterator_t *iterator; | |
718 | sa_policy_t *policy; | |
719 | status_t status; | |
720 | ||
721 | iterator = this->policies->create_iterator(this->policies, TRUE); | |
722 | while (iterator->iterate(iterator, (void**)&policy)) | |
723 | { | |
1396815a MW |
724 | status = charon->kernel_interface->add_policy( |
725 | charon->kernel_interface, | |
726 | new_me, new_other, | |
92ee45a0 MW |
727 | policy->my_ts, policy->other_ts, |
728 | POLICY_OUT, this->protocol, this->reqid, TRUE); | |
1396815a MW |
729 | |
730 | status |= charon->kernel_interface->add_policy( | |
731 | charon->kernel_interface, | |
732 | new_other, new_me, | |
92ee45a0 MW |
733 | policy->other_ts, policy->my_ts, |
734 | POLICY_IN, this->protocol, this->reqid, TRUE); | |
1396815a MW |
735 | |
736 | status |= charon->kernel_interface->add_policy( | |
737 | charon->kernel_interface, | |
738 | new_other, new_me, | |
92ee45a0 MW |
739 | policy->other_ts, policy->my_ts, |
740 | POLICY_FWD, this->protocol, this->reqid, TRUE); | |
aeeb4f4f | 741 | |
1396815a MW |
742 | if (status != SUCCESS) |
743 | { | |
744 | iterator->destroy(iterator); | |
745 | return FAILED; | |
746 | } | |
747 | } | |
748 | iterator->destroy(iterator); | |
92ee45a0 | 749 | |
698d7749 | 750 | return SUCCESS; |
1396815a MW |
751 | } |
752 | ||
753 | /** | |
754 | * Implementation of child_sa_t.update_hosts. | |
755 | */ | |
756 | static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other, | |
92ee45a0 | 757 | host_diff_t my_changes, host_diff_t other_changes) |
1396815a | 758 | { |
abba7ecb | 759 | if (!my_changes && !other_changes) |
1396815a MW |
760 | { |
761 | return SUCCESS; | |
762 | } | |
763 | ||
764 | /* update our (initator) SAs */ | |
765 | if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, TRUE) != SUCCESS) | |
766 | { | |
767 | return FAILED; | |
768 | } | |
769 | ||
770 | /* update his (responder) SAs */ | |
771 | if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, FALSE) != SUCCESS) | |
772 | { | |
773 | return FAILED; | |
774 | } | |
775 | ||
776 | /* update policies */ | |
777 | if (my_changes & HOST_DIFF_ADDR || other_changes & HOST_DIFF_ADDR) | |
778 | { | |
779 | if (update_policy_hosts(this, new_me, new_other) != SUCCESS) | |
780 | { | |
781 | return FAILED; | |
782 | } | |
783 | } | |
784 | ||
785 | /* update hosts */ | |
786 | if (my_changes) | |
787 | { | |
788 | this->me.addr->destroy(this->me.addr); | |
789 | this->me.addr = new_me->clone(new_me); | |
790 | } | |
791 | ||
792 | if (other_changes) | |
793 | { | |
794 | this->other.addr->destroy(this->other.addr); | |
795 | this->other.addr = new_other->clone(new_other); | |
796 | } | |
797 | ||
798 | return SUCCESS; | |
799 | } | |
800 | ||
30b5b412 MW |
801 | /** |
802 | * Implementation of child_sa_t.destroy. | |
803 | */ | |
804 | static void destroy(private_child_sa_t *this) | |
805 | { | |
16b9a73c | 806 | sa_policy_t *policy; |
5d187bd2 MW |
807 | |
808 | /* delete SAs in the kernel, if they are set up */ | |
3efbf983 | 809 | if (this->me.spi) |
5d187bd2 MW |
810 | { |
811 | charon->kernel_interface->del_sa(charon->kernel_interface, | |
695723d4 | 812 | this->me.addr, this->me.spi, this->protocol); |
3efbf983 MW |
813 | } |
814 | if (this->alloc_esp_spi && this->alloc_esp_spi != this->me.spi) | |
815 | { | |
816 | charon->kernel_interface->del_sa(charon->kernel_interface, | |
817 | this->me.addr, this->alloc_esp_spi, PROTO_ESP); | |
818 | } | |
819 | if (this->alloc_ah_spi && this->alloc_ah_spi != this->me.spi) | |
820 | { | |
821 | charon->kernel_interface->del_sa(charon->kernel_interface, | |
822 | this->me.addr, this->alloc_ah_spi, PROTO_AH); | |
823 | } | |
824 | if (this->other.spi) | |
825 | { | |
5d187bd2 | 826 | charon->kernel_interface->del_sa(charon->kernel_interface, |
695723d4 MW |
827 | this->other.addr, this->other.spi, this->protocol); |
828 | } | |
829 | ||
830 | /* delete all policies in the kernel */ | |
831 | while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS) | |
832 | { | |
aeeb4f4f MW |
833 | /* let rekeyed policies, as they are used by another child_sa */ |
834 | charon->kernel_interface->del_policy(charon->kernel_interface, | |
92ee45a0 MW |
835 | policy->my_ts, policy->other_ts, |
836 | POLICY_OUT); | |
aeeb4f4f MW |
837 | |
838 | charon->kernel_interface->del_policy(charon->kernel_interface, | |
92ee45a0 MW |
839 | policy->other_ts, policy->my_ts, |
840 | POLICY_IN); | |
aeeb4f4f MW |
841 | |
842 | charon->kernel_interface->del_policy(charon->kernel_interface, | |
92ee45a0 MW |
843 | policy->other_ts, policy->my_ts, |
844 | POLICY_FWD); | |
845 | policy->my_ts->destroy(policy->my_ts); | |
846 | policy->other_ts->destroy(policy->other_ts); | |
695723d4 | 847 | free(policy); |
5d187bd2 | 848 | } |
695723d4 | 849 | this->policies->destroy(this->policies); |
abba7ecb | 850 | |
8dfbe71b MW |
851 | this->my_ts->destroy(this->my_ts); |
852 | this->other_ts->destroy(this->other_ts); | |
abba7ecb MW |
853 | this->me.addr->destroy(this->me.addr); |
854 | this->other.addr->destroy(this->other.addr); | |
5113680f | 855 | free(this); |
30b5b412 MW |
856 | } |
857 | ||
858 | /* | |
859 | * Described in header. | |
860 | */ | |
50f98119 | 861 | child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, |
1396815a MW |
862 | u_int32_t soft_lifetime, u_int32_t hard_lifetime, |
863 | bool use_natt) | |
30b5b412 | 864 | { |
1396815a | 865 | static u_int32_t reqid = REQID_START; |
5113680f | 866 | private_child_sa_t *this = malloc_thing(private_child_sa_t); |
30b5b412 MW |
867 | |
868 | /* public functions */ | |
32b6500f | 869 | this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid; |
8d77edde MW |
870 | this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi; |
871 | this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol; | |
30b5b412 MW |
872 | this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; |
873 | this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add; | |
874 | this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update; | |
92ee45a0 | 875 | this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts; |
5d187bd2 | 876 | this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies; |
8dfbe71b MW |
877 | this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors; |
878 | this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors; | |
2f89902d | 879 | this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; |
abba7ecb MW |
880 | this->public.set_rekeying_transaction = (void (*)(child_sa_t*,void*))set_rekeying_transaction; |
881 | this->public.get_rekeying_transaction = (void* (*)(child_sa_t*))get_rekeying_transaction; | |
bcb95ced MW |
882 | this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state; |
883 | this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state; | |
e168ee17 | 884 | this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status; |
30b5b412 MW |
885 | this->public.destroy = (void(*)(child_sa_t*))destroy; |
886 | ||
887 | /* private data */ | |
5113680f | 888 | this->logger = logger_manager->get_logger(logger_manager, CHILD_SA); |
abba7ecb MW |
889 | this->me.addr = me->clone(me); |
890 | this->other.addr = other->clone(other); | |
8d77edde MW |
891 | this->me.spi = 0; |
892 | this->other.spi = 0; | |
3efbf983 MW |
893 | this->alloc_ah_spi = 0; |
894 | this->alloc_esp_spi = 0; | |
1396815a | 895 | this->use_natt = use_natt; |
8d77edde MW |
896 | this->soft_lifetime = soft_lifetime; |
897 | this->hard_lifetime = hard_lifetime; | |
bcb95ced | 898 | this->state = CHILD_CREATED; |
50f98119 MW |
899 | /* reuse old reqid if we are rekeying an existing CHILD_SA */ |
900 | this->reqid = rekey ? rekey : ++reqid; | |
5d187bd2 | 901 | this->policies = linked_list_create(); |
8dfbe71b MW |
902 | this->my_ts = linked_list_create(); |
903 | this->other_ts = linked_list_create(); | |
8d77edde | 904 | this->protocol = PROTO_NONE; |
abba7ecb | 905 | this->rekeying_transaction = NULL; |
3ebebc5e | 906 | |
1396815a | 907 | return &this->public; |
3ebebc5e | 908 | } |