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