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