]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libcharon/sa/ikev2/tasks/child_delete.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libcharon / sa / ikev2 / tasks / child_delete.c
1 /*
2 * Copyright (C) 2009-2016 Tobias Brunner
3 * Copyright (C) 2006-2007 Martin Willi
4 *
5 * Copyright (C) secunet Security Networks AG
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "child_delete.h"
19
20 #include <daemon.h>
21 #include <encoding/payloads/delete_payload.h>
22 #include <processing/jobs/delete_child_sa_job.h>
23 #include <sa/ikev2/tasks/child_create.h>
24 #include <sa/ikev2/tasks/child_rekey.h>
25
26 #ifndef DELETE_REKEYED_DELAY
27 #define DELETE_REKEYED_DELAY 5
28 #endif
29
30 typedef struct private_child_delete_t private_child_delete_t;
31
32 /**
33 * Private members of a child_delete_t task.
34 */
35 struct private_child_delete_t {
36
37 /**
38 * Public methods and task_t interface.
39 */
40 child_delete_t public;
41
42 /**
43 * Assigned IKE_SA.
44 */
45 ike_sa_t *ike_sa;
46
47 /**
48 * Whether we are the initiator of the exchange
49 */
50 bool initiator;
51
52 /**
53 * Protocol of CHILD_SA to delete (as initiator)
54 */
55 protocol_id_t protocol;
56
57 /**
58 * Inbound SPI of CHILD_SA to delete (as initiator)
59 */
60 uint32_t spi;
61
62 /**
63 * CHILD_SA already expired (as initiator)
64 */
65 bool expired;
66
67 /**
68 * CHILD_SAs which get deleted, entry_t*
69 */
70 linked_list_t *child_sas;
71 };
72
73 /**
74 * Information about a deleted CHILD_SA
75 */
76 typedef struct {
77 /** Deleted CHILD_SA */
78 child_sa_t *child_sa;
79 /** Whether the CHILD_SA was rekeyed */
80 bool rekeyed;
81 /** Whether to enforce any delete action policy */
82 bool check_delete_action;
83 } entry_t;
84
85 CALLBACK(match_child, bool,
86 entry_t *entry, va_list args)
87 {
88 child_sa_t *child_sa;
89
90 VA_ARGS_VGET(args, child_sa);
91 return entry->child_sa == child_sa;
92 }
93
94 /**
95 * build the delete payloads from the listed child_sas
96 */
97 static void build_payloads(private_child_delete_t *this, message_t *message)
98 {
99 delete_payload_t *ah = NULL, *esp = NULL;
100 enumerator_t *enumerator;
101 entry_t *entry;
102 protocol_id_t protocol;
103 uint32_t spi;
104
105 enumerator = this->child_sas->create_enumerator(this->child_sas);
106 while (enumerator->enumerate(enumerator, (void**)&entry))
107 {
108 protocol = entry->child_sa->get_protocol(entry->child_sa);
109 spi = entry->child_sa->get_spi(entry->child_sa, TRUE);
110
111 switch (protocol)
112 {
113 case PROTO_ESP:
114 if (!esp)
115 {
116 esp = delete_payload_create(PLV2_DELETE, PROTO_ESP);
117 message->add_payload(message, (payload_t*)esp);
118 }
119 esp->add_spi(esp, spi);
120 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
121 protocol_id_names, protocol, ntohl(spi));
122 break;
123 case PROTO_AH:
124 if (ah == NULL)
125 {
126 ah = delete_payload_create(PLV2_DELETE, PROTO_AH);
127 message->add_payload(message, (payload_t*)ah);
128 }
129 ah->add_spi(ah, spi);
130 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
131 protocol_id_names, protocol, ntohl(spi));
132 break;
133 default:
134 break;
135 }
136 entry->child_sa->set_state(entry->child_sa, CHILD_DELETING);
137 }
138 enumerator->destroy(enumerator);
139 }
140
141 /**
142 * Check if the given CHILD_SA is the redundant SA created in a rekey collision.
143 */
144 static bool is_redundant(private_child_delete_t *this, child_sa_t *child)
145 {
146 enumerator_t *tasks;
147 task_t *task;
148
149 tasks = this->ike_sa->create_task_enumerator(this->ike_sa,
150 TASK_QUEUE_ACTIVE);
151 while (tasks->enumerate(tasks, &task))
152 {
153 if (task->get_type(task) == TASK_CHILD_REKEY)
154 {
155 child_rekey_t *rekey = (child_rekey_t*)task;
156
157 if (rekey->is_redundant(rekey, child))
158 {
159 tasks->destroy(tasks);
160 return TRUE;
161 }
162 }
163 }
164 tasks->destroy(tasks);
165 return FALSE;
166 }
167
168 /**
169 * Install the outbound CHILD_SA with the given SPI
170 */
171 static void install_outbound(private_child_delete_t *this,
172 protocol_id_t protocol, uint32_t spi)
173 {
174 child_sa_t *child_sa;
175 linked_list_t *my_ts, *other_ts;
176 status_t status;
177
178 if (!spi)
179 {
180 return;
181 }
182
183 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
184 spi, FALSE);
185 if (!child_sa)
186 {
187 DBG1(DBG_IKE, "CHILD_SA not found after rekeying");
188 return;
189 }
190 if (this->initiator && is_redundant(this, child_sa))
191 { /* if we won the rekey collision we don't want to install the
192 * redundant SA created by the peer */
193 return;
194 }
195
196 status = child_sa->install_outbound(child_sa);
197 if (status != SUCCESS)
198 {
199 DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel");
200 charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
201 child_sa);
202 /* FIXME: delete the new child_sa? */
203 return;
204 }
205
206 my_ts = linked_list_create_from_enumerator(
207 child_sa->create_ts_enumerator(child_sa, TRUE));
208 other_ts = linked_list_create_from_enumerator(
209 child_sa->create_ts_enumerator(child_sa, FALSE));
210
211 DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established "
212 "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
213 child_sa->get_name(child_sa),
214 child_sa->get_unique_id(child_sa),
215 ntohl(child_sa->get_spi(child_sa, TRUE)),
216 ntohl(child_sa->get_spi(child_sa, FALSE)),
217 my_ts, other_ts);
218
219 my_ts->destroy(my_ts);
220 other_ts->destroy(other_ts);
221 }
222
223 /**
224 * read in payloads and find the children to delete
225 */
226 static void process_payloads(private_child_delete_t *this, message_t *message)
227 {
228 enumerator_t *payloads, *spis;
229 payload_t *payload;
230 delete_payload_t *delete_payload;
231 uint32_t spi;
232 protocol_id_t protocol;
233 child_sa_t *child_sa;
234 entry_t *entry;
235
236 payloads = message->create_payload_enumerator(message);
237 while (payloads->enumerate(payloads, &payload))
238 {
239 if (payload->get_type(payload) == PLV2_DELETE)
240 {
241 delete_payload = (delete_payload_t*)payload;
242 protocol = delete_payload->get_protocol_id(delete_payload);
243 if (protocol != PROTO_ESP && protocol != PROTO_AH)
244 {
245 continue;
246 }
247 spis = delete_payload->create_spi_enumerator(delete_payload);
248 while (spis->enumerate(spis, &spi))
249 {
250 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
251 spi, FALSE);
252 if (!child_sa)
253 {
254 DBG1(DBG_IKE, "received DELETE for unknown %N CHILD_SA with"
255 " SPI %.8x", protocol_id_names, protocol, ntohl(spi));
256 continue;
257 }
258 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
259 protocol_id_names, protocol, ntohl(spi));
260
261 if (this->child_sas->find_first(this->child_sas, match_child,
262 NULL, child_sa))
263 {
264 continue;
265 }
266 INIT(entry,
267 .child_sa = child_sa
268 );
269 switch (child_sa->get_state(child_sa))
270 {
271 case CHILD_REKEYED:
272 entry->rekeyed = TRUE;
273 break;
274 case CHILD_DELETED:
275 /* already deleted but not yet destroyed, ignore */
276 case CHILD_DELETING:
277 /* we don't send back a delete if we already initiated
278 * a delete ourself */
279 if (!this->initiator)
280 {
281 free(entry);
282 continue;
283 }
284 break;
285 case CHILD_REKEYING:
286 /* we reply as usual, rekeying will fail */
287 case CHILD_INSTALLED:
288 if (!this->initiator)
289 {
290 if (is_redundant(this, child_sa))
291 {
292 entry->rekeyed = TRUE;
293 }
294 else
295 {
296 entry->check_delete_action = TRUE;
297 }
298 }
299 break;
300 default:
301 break;
302 }
303 this->child_sas->insert_last(this->child_sas, entry);
304 }
305 spis->destroy(spis);
306 }
307 }
308 payloads->destroy(payloads);
309 }
310
311 /**
312 * destroy the children listed in this->child_sas, reestablish by policy
313 */
314 static status_t destroy_and_reestablish(private_child_delete_t *this)
315 {
316 child_init_args_t args = {};
317 enumerator_t *enumerator;
318 entry_t *entry;
319 child_sa_t *child_sa;
320 child_cfg_t *child_cfg;
321 protocol_id_t protocol;
322 uint32_t spi;
323 action_t action;
324 status_t status = SUCCESS;
325 time_t now, expire;
326 u_int delay;
327
328 now = time_monotonic(NULL);
329 delay = lib->settings->get_int(lib->settings, "%s.delete_rekeyed_delay",
330 DELETE_REKEYED_DELAY, lib->ns);
331
332 enumerator = this->child_sas->create_enumerator(this->child_sas);
333 while (enumerator->enumerate(enumerator, (void**)&entry))
334 {
335 child_sa = entry->child_sa;
336 child_sa->set_state(child_sa, CHILD_DELETED);
337 /* signal child down event if we weren't rekeying */
338 protocol = child_sa->get_protocol(child_sa);
339 if (!entry->rekeyed)
340 {
341 charon->bus->child_updown(charon->bus, child_sa, FALSE);
342 }
343 else
344 {
345 /* the following two calls are only relevant as responder/loser of
346 * rekeyings as the initiator/winner already did this right after
347 * the rekeying was completed, either way, we delay destroying
348 * the CHILD_SA, by default, so we can process delayed packets */
349 install_outbound(this, protocol, child_sa->get_rekey_spi(child_sa));
350 child_sa->remove_outbound(child_sa);
351
352 expire = child_sa->get_lifetime(child_sa, TRUE);
353 if (delay && (!expire || ((now + delay) < expire)))
354 {
355 lib->scheduler->schedule_job(lib->scheduler,
356 (job_t*)delete_child_sa_job_create_id(
357 child_sa->get_unique_id(child_sa)), delay);
358 continue;
359 }
360 else if (now < expire)
361 { /* let it expire naturally */
362 continue;
363 }
364 /* no delay and no lifetime, destroy it immediately */
365 }
366 spi = child_sa->get_spi(child_sa, TRUE);
367 child_cfg = child_sa->get_config(child_sa);
368 child_cfg->get_ref(child_cfg);
369 args.reqid = child_sa->get_reqid(child_sa);
370 args.label = child_sa->get_label(child_sa);
371 if (args.label)
372 {
373 args.label = args.label->clone(args.label);
374 }
375 action = child_sa->get_close_action(child_sa);
376
377 this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
378
379 if (entry->check_delete_action)
380 { /* enforce child_cfg policy if deleted passively */
381 if (action & ACTION_TRAP)
382 {
383 charon->traps->install(charon->traps,
384 this->ike_sa->get_peer_cfg(this->ike_sa),
385 child_cfg);
386 }
387 if (action & ACTION_START)
388 {
389 child_cfg->get_ref(child_cfg);
390 status = this->ike_sa->initiate(this->ike_sa, child_cfg, &args);
391 }
392 }
393 child_cfg->destroy(child_cfg);
394 DESTROY_IF(args.label);
395 if (status != SUCCESS)
396 {
397 break;
398 }
399 }
400 enumerator->destroy(enumerator);
401 return status;
402 }
403
404 /**
405 * send closing signals for all CHILD_SAs over the bus
406 */
407 static void log_children(private_child_delete_t *this)
408 {
409 linked_list_t *my_ts, *other_ts;
410 enumerator_t *enumerator;
411 entry_t *entry;
412 child_sa_t *child_sa;
413 uint64_t bytes_in, bytes_out;
414
415 enumerator = this->child_sas->create_enumerator(this->child_sas);
416 while (enumerator->enumerate(enumerator, (void**)&entry))
417 {
418 child_sa = entry->child_sa;
419 my_ts = linked_list_create_from_enumerator(
420 child_sa->create_ts_enumerator(child_sa, TRUE));
421 other_ts = linked_list_create_from_enumerator(
422 child_sa->create_ts_enumerator(child_sa, FALSE));
423 if (this->expired)
424 {
425 DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
426 "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
427 child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
428 ntohl(child_sa->get_spi(child_sa, TRUE)),
429 ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
430 }
431 else
432 {
433 child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, NULL);
434 child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, NULL);
435
436 DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i "
437 "(%llu bytes) %.8x_o (%llu bytes) and TS %#R === %#R",
438 child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
439 ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
440 ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
441 my_ts, other_ts);
442 }
443 my_ts->destroy(my_ts);
444 other_ts->destroy(other_ts);
445 }
446 enumerator->destroy(enumerator);
447 }
448
449 METHOD(task_t, build_i, status_t,
450 private_child_delete_t *this, message_t *message)
451 {
452 child_sa_t *child_sa;
453 entry_t *entry;
454
455 child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
456 this->spi, TRUE);
457 if (!child_sa)
458 { /* check if it is an outbound sa */
459 child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
460 this->spi, FALSE);
461 if (!child_sa)
462 { /* child does not exist anymore */
463 return SUCCESS;
464 }
465 /* we work only with the inbound SPI */
466 this->spi = child_sa->get_spi(child_sa, TRUE);
467 }
468
469 if (this->expired && child_sa->get_state(child_sa) == CHILD_REKEYED)
470 { /* the peer was expected to delete this SA, but if we send a DELETE
471 * we might cause a collision there if the CREATE_CHILD_SA response
472 * is delayed (the peer wouldn't know if we deleted this SA due to an
473 * expire or because of a forced delete by the user and might then
474 * ignore the CREATE_CHILD_SA response once it arrives) */
475 child_sa->set_state(child_sa, CHILD_DELETED);
476 install_outbound(this, this->protocol,
477 child_sa->get_rekey_spi(child_sa));
478 }
479
480 if (child_sa->get_state(child_sa) == CHILD_DELETED)
481 { /* DELETEs for this CHILD_SA were already exchanged, but it was not yet
482 * destroyed to allow delayed packets to get processed */
483 this->ike_sa->destroy_child_sa(this->ike_sa, this->protocol, this->spi);
484 message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
485 return SUCCESS;
486 }
487
488 INIT(entry,
489 .child_sa = child_sa,
490 .rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYED,
491 );
492 this->child_sas->insert_last(this->child_sas, entry);
493 log_children(this);
494 build_payloads(this, message);
495
496 if (!entry->rekeyed && this->expired)
497 {
498 child_cfg_t *child_cfg;
499
500 DBG1(DBG_IKE, "scheduling CHILD_SA recreate after hard expire");
501 child_cfg = child_sa->get_config(child_sa);
502 this->ike_sa->queue_task(this->ike_sa, (task_t*)
503 child_create_create(this->ike_sa, child_cfg->get_ref(child_cfg),
504 FALSE, NULL, NULL));
505 }
506 return NEED_MORE;
507 }
508
509 METHOD(task_t, process_i, status_t,
510 private_child_delete_t *this, message_t *message)
511 {
512 process_payloads(this, message);
513 DBG1(DBG_IKE, "CHILD_SA closed");
514 return destroy_and_reestablish(this);
515 }
516
517 METHOD(task_t, process_r, status_t,
518 private_child_delete_t *this, message_t *message)
519 {
520 process_payloads(this, message);
521 log_children(this);
522 return NEED_MORE;
523 }
524
525 METHOD(task_t, build_r, status_t,
526 private_child_delete_t *this, message_t *message)
527 {
528 build_payloads(this, message);
529 DBG1(DBG_IKE, "CHILD_SA closed");
530 return destroy_and_reestablish(this);
531 }
532
533 METHOD(task_t, get_type, task_type_t,
534 private_child_delete_t *this)
535 {
536 return TASK_CHILD_DELETE;
537 }
538
539 METHOD(child_delete_t , get_child, child_sa_t*,
540 private_child_delete_t *this)
541 {
542 child_sa_t *child_sa = NULL;
543 entry_t *entry;
544
545 if (this->child_sas->get_first(this->child_sas, (void**)&entry) == SUCCESS)
546 {
547 child_sa = entry->child_sa;
548 }
549 return child_sa;
550 }
551
552 METHOD(task_t, migrate, void,
553 private_child_delete_t *this, ike_sa_t *ike_sa)
554 {
555 this->ike_sa = ike_sa;
556
557 this->child_sas->destroy_function(this->child_sas, free);
558 this->child_sas = linked_list_create();
559 }
560
561 METHOD(task_t, destroy, void,
562 private_child_delete_t *this)
563 {
564 this->child_sas->destroy_function(this->child_sas, free);
565 free(this);
566 }
567
568 /*
569 * Described in header.
570 */
571 child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
572 uint32_t spi, bool expired)
573 {
574 private_child_delete_t *this;
575
576 INIT(this,
577 .public = {
578 .task = {
579 .get_type = _get_type,
580 .migrate = _migrate,
581 .destroy = _destroy,
582 },
583 .get_child = _get_child,
584 },
585 .ike_sa = ike_sa,
586 .child_sas = linked_list_create(),
587 .protocol = protocol,
588 .spi = spi,
589 .expired = expired,
590 );
591
592 if (protocol != PROTO_NONE)
593 {
594 this->public.task.build = _build_i;
595 this->public.task.process = _process_i;
596 this->initiator = TRUE;
597 }
598 else
599 {
600 this->public.task.build = _build_r;
601 this->public.task.process = _process_r;
602 this->initiator = FALSE;
603 }
604 return &this->public;
605 }