Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/tasks/child_delete.c, revision 1.1.1.1
1.1 misho 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: if (!spi)
178: {
179: return;
180: }
181:
182: child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
183: spi, FALSE);
184: if (!child_sa)
185: {
186: DBG1(DBG_IKE, "CHILD_SA not found after rekeying");
187: return;
188: }
189: if (this->initiator && is_redundant(this, child_sa))
190: { /* if we won the rekey collision we don't want to install the
191: * redundant SA created by the peer */
192: return;
193: }
194:
195: status = child_sa->install_outbound(child_sa);
196: if (status != SUCCESS)
197: {
198: DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel");
199: charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
200: child_sa);
201: /* FIXME: delete the new child_sa? */
202: return;
203: }
204:
205: my_ts = linked_list_create_from_enumerator(
206: child_sa->create_ts_enumerator(child_sa, TRUE));
207: other_ts = linked_list_create_from_enumerator(
208: child_sa->create_ts_enumerator(child_sa, FALSE));
209:
210: DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established "
211: "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
212: child_sa->get_name(child_sa),
213: child_sa->get_unique_id(child_sa),
214: ntohl(child_sa->get_spi(child_sa, TRUE)),
215: ntohl(child_sa->get_spi(child_sa, FALSE)),
216: my_ts, other_ts);
217:
218: my_ts->destroy(my_ts);
219: other_ts->destroy(other_ts);
220: }
221:
222: /**
223: * read in payloads and find the children to delete
224: */
225: static void process_payloads(private_child_delete_t *this, message_t *message)
226: {
227: enumerator_t *payloads, *spis;
228: payload_t *payload;
229: delete_payload_t *delete_payload;
230: uint32_t spi;
231: protocol_id_t protocol;
232: child_sa_t *child_sa;
233: entry_t *entry;
234:
235: payloads = message->create_payload_enumerator(message);
236: while (payloads->enumerate(payloads, &payload))
237: {
238: if (payload->get_type(payload) == PLV2_DELETE)
239: {
240: delete_payload = (delete_payload_t*)payload;
241: protocol = delete_payload->get_protocol_id(delete_payload);
242: if (protocol != PROTO_ESP && protocol != PROTO_AH)
243: {
244: continue;
245: }
246: spis = delete_payload->create_spi_enumerator(delete_payload);
247: while (spis->enumerate(spis, &spi))
248: {
249: child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
250: spi, FALSE);
251: if (!child_sa)
252: {
253: DBG1(DBG_IKE, "received DELETE for unknown %N CHILD_SA with"
254: " SPI %.8x", protocol_id_names, protocol, ntohl(spi));
255: continue;
256: }
257: DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
258: protocol_id_names, protocol, ntohl(spi));
259:
260: if (this->child_sas->find_first(this->child_sas, match_child,
261: NULL, child_sa))
262: {
263: continue;
264: }
265: INIT(entry,
266: .child_sa = child_sa
267: );
268: switch (child_sa->get_state(child_sa))
269: {
270: case CHILD_REKEYED:
271: entry->rekeyed = TRUE;
272: break;
273: case CHILD_DELETED:
274: /* already deleted but not yet destroyed, ignore */
275: case CHILD_DELETING:
276: /* we don't send back a delete if we already initiated
277: * a delete ourself */
278: if (!this->initiator)
279: {
280: free(entry);
281: continue;
282: }
283: break;
284: case CHILD_REKEYING:
285: /* we reply as usual, rekeying will fail */
286: case CHILD_INSTALLED:
287: if (!this->initiator)
288: {
289: if (is_redundant(this, child_sa))
290: {
291: entry->rekeyed = TRUE;
292: }
293: else
294: {
295: entry->check_delete_action = TRUE;
296: }
297: }
298: break;
299: default:
300: break;
301: }
302: this->child_sas->insert_last(this->child_sas, entry);
303: }
304: spis->destroy(spis);
305: }
306: }
307: payloads->destroy(payloads);
308: }
309:
310: /**
311: * destroy the children listed in this->child_sas, reestablish by policy
312: */
313: static status_t destroy_and_reestablish(private_child_delete_t *this)
314: {
315: enumerator_t *enumerator;
316: entry_t *entry;
317: child_sa_t *child_sa;
318: child_cfg_t *child_cfg;
319: protocol_id_t protocol;
320: uint32_t spi, reqid;
321: action_t action;
322: status_t status = SUCCESS;
323: time_t now, expire;
324: u_int delay;
325:
326: now = time_monotonic(NULL);
327: delay = lib->settings->get_int(lib->settings, "%s.delete_rekeyed_delay",
328: DELETE_REKEYED_DELAY, lib->ns);
329:
330: enumerator = this->child_sas->create_enumerator(this->child_sas);
331: while (enumerator->enumerate(enumerator, (void**)&entry))
332: {
333: child_sa = entry->child_sa;
334: child_sa->set_state(child_sa, CHILD_DELETED);
335: /* signal child down event if we weren't rekeying */
336: protocol = child_sa->get_protocol(child_sa);
337: if (!entry->rekeyed)
338: {
339: charon->bus->child_updown(charon->bus, child_sa, FALSE);
340: }
341: else
342: {
343: install_outbound(this, protocol, child_sa->get_rekey_spi(child_sa));
344: /* for rekeyed CHILD_SAs we uninstall the outbound SA but don't
345: * immediately destroy it, by default, so we can process delayed
346: * packets */
347: child_sa->remove_outbound(child_sa);
348: expire = child_sa->get_lifetime(child_sa, TRUE);
349: if (delay && (!expire || ((now + delay) < expire)))
350: {
351: lib->scheduler->schedule_job(lib->scheduler,
352: (job_t*)delete_child_sa_job_create_id(
353: child_sa->get_unique_id(child_sa)), delay);
354: continue;
355: }
356: else if (now < expire)
357: { /* let it expire naturally */
358: continue;
359: }
360: /* no delay and no lifetime, destroy it immediately */
361: }
362: spi = child_sa->get_spi(child_sa, TRUE);
363: reqid = child_sa->get_reqid(child_sa);
364: child_cfg = child_sa->get_config(child_sa);
365: child_cfg->get_ref(child_cfg);
366: action = child_sa->get_close_action(child_sa);
367:
368: this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
369:
370: if (entry->check_delete_action)
371: { /* enforce child_cfg policy if deleted passively */
372: switch (action)
373: {
374: case ACTION_RESTART:
375: child_cfg->get_ref(child_cfg);
376: status = this->ike_sa->initiate(this->ike_sa, child_cfg,
377: reqid, NULL, NULL);
378: break;
379: case ACTION_ROUTE:
380: charon->traps->install(charon->traps,
381: this->ike_sa->get_peer_cfg(this->ike_sa),
382: child_cfg);
383: break;
384: default:
385: break;
386: }
387: }
388: child_cfg->destroy(child_cfg);
389: if (status != SUCCESS)
390: {
391: break;
392: }
393: }
394: enumerator->destroy(enumerator);
395: return status;
396: }
397:
398: /**
399: * send closing signals for all CHILD_SAs over the bus
400: */
401: static void log_children(private_child_delete_t *this)
402: {
403: linked_list_t *my_ts, *other_ts;
404: enumerator_t *enumerator;
405: entry_t *entry;
406: child_sa_t *child_sa;
407: uint64_t bytes_in, bytes_out;
408:
409: enumerator = this->child_sas->create_enumerator(this->child_sas);
410: while (enumerator->enumerate(enumerator, (void**)&entry))
411: {
412: child_sa = entry->child_sa;
413: my_ts = linked_list_create_from_enumerator(
414: child_sa->create_ts_enumerator(child_sa, TRUE));
415: other_ts = linked_list_create_from_enumerator(
416: child_sa->create_ts_enumerator(child_sa, FALSE));
417: if (this->expired)
418: {
419: DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
420: "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
421: child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
422: ntohl(child_sa->get_spi(child_sa, TRUE)),
423: ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
424: }
425: else
426: {
427: child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, NULL);
428: child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, NULL);
429:
430: DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i "
431: "(%llu bytes) %.8x_o (%llu bytes) and TS %#R === %#R",
432: child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
433: ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
434: ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
435: my_ts, other_ts);
436: }
437: my_ts->destroy(my_ts);
438: other_ts->destroy(other_ts);
439: }
440: enumerator->destroy(enumerator);
441: }
442:
443: METHOD(task_t, build_i, status_t,
444: private_child_delete_t *this, message_t *message)
445: {
446: child_sa_t *child_sa;
447: entry_t *entry;
448:
449: child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
450: this->spi, TRUE);
451: if (!child_sa)
452: { /* check if it is an outbound sa */
453: child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
454: this->spi, FALSE);
455: if (!child_sa)
456: { /* child does not exist anymore */
457: return SUCCESS;
458: }
459: /* we work only with the inbound SPI */
460: this->spi = child_sa->get_spi(child_sa, TRUE);
461: }
462:
463: if (this->expired && child_sa->get_state(child_sa) == CHILD_REKEYED)
464: { /* the peer was expected to delete this SA, but if we send a DELETE
465: * we might cause a collision there if the CREATE_CHILD_SA response
466: * is delayed (the peer wouldn't know if we deleted this SA due to an
467: * expire or because of a forced delete by the user and might then
468: * ignore the CREATE_CHILD_SA response once it arrives) */
469: child_sa->set_state(child_sa, CHILD_DELETED);
470: install_outbound(this, this->protocol,
471: child_sa->get_rekey_spi(child_sa));
472: }
473:
474: if (child_sa->get_state(child_sa) == CHILD_DELETED)
475: { /* DELETEs for this CHILD_SA were already exchanged, but it was not yet
476: * destroyed to allow delayed packets to get processed */
477: this->ike_sa->destroy_child_sa(this->ike_sa, this->protocol, this->spi);
478: message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
479: return SUCCESS;
480: }
481:
482: INIT(entry,
483: .child_sa = child_sa,
484: .rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYED,
485: );
486: this->child_sas->insert_last(this->child_sas, entry);
487: log_children(this);
488: build_payloads(this, message);
489:
490: if (!entry->rekeyed && this->expired)
491: {
492: child_cfg_t *child_cfg;
493:
494: DBG1(DBG_IKE, "scheduling CHILD_SA recreate after hard expire");
495: child_cfg = child_sa->get_config(child_sa);
496: this->ike_sa->queue_task(this->ike_sa, (task_t*)
497: child_create_create(this->ike_sa, child_cfg->get_ref(child_cfg),
498: FALSE, NULL, NULL));
499: }
500: return NEED_MORE;
501: }
502:
503: METHOD(task_t, process_i, status_t,
504: private_child_delete_t *this, message_t *message)
505: {
506: process_payloads(this, message);
507: DBG1(DBG_IKE, "CHILD_SA closed");
508: return destroy_and_reestablish(this);
509: }
510:
511: METHOD(task_t, process_r, status_t,
512: private_child_delete_t *this, message_t *message)
513: {
514: process_payloads(this, message);
515: log_children(this);
516: return NEED_MORE;
517: }
518:
519: METHOD(task_t, build_r, status_t,
520: private_child_delete_t *this, message_t *message)
521: {
522: build_payloads(this, message);
523: DBG1(DBG_IKE, "CHILD_SA closed");
524: return destroy_and_reestablish(this);
525: }
526:
527: METHOD(task_t, get_type, task_type_t,
528: private_child_delete_t *this)
529: {
530: return TASK_CHILD_DELETE;
531: }
532:
533: METHOD(child_delete_t , get_child, child_sa_t*,
534: private_child_delete_t *this)
535: {
536: child_sa_t *child_sa = NULL;
537: entry_t *entry;
538:
539: if (this->child_sas->get_first(this->child_sas, (void**)&entry) == SUCCESS)
540: {
541: child_sa = entry->child_sa;
542: }
543: return child_sa;
544: }
545:
546: METHOD(task_t, migrate, void,
547: private_child_delete_t *this, ike_sa_t *ike_sa)
548: {
549: this->ike_sa = ike_sa;
550:
551: this->child_sas->destroy_function(this->child_sas, free);
552: this->child_sas = linked_list_create();
553: }
554:
555: METHOD(task_t, destroy, void,
556: private_child_delete_t *this)
557: {
558: this->child_sas->destroy_function(this->child_sas, free);
559: free(this);
560: }
561:
562: /*
563: * Described in header.
564: */
565: child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
566: uint32_t spi, bool expired)
567: {
568: private_child_delete_t *this;
569:
570: INIT(this,
571: .public = {
572: .task = {
573: .get_type = _get_type,
574: .migrate = _migrate,
575: .destroy = _destroy,
576: },
577: .get_child = _get_child,
578: },
579: .ike_sa = ike_sa,
580: .child_sas = linked_list_create(),
581: .protocol = protocol,
582: .spi = spi,
583: .expired = expired,
584: );
585:
586: if (protocol != PROTO_NONE)
587: {
588: this->public.task.build = _build_i;
589: this->public.task.process = _process_i;
590: this->initiator = TRUE;
591: }
592: else
593: {
594: this->public.task.build = _build_r;
595: this->public.task.process = _process_r;
596: this->initiator = FALSE;
597: }
598: return &this->public;
599: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>