Separated libcharon/sa directory with ikev1 and ikev2 subfolders
[strongswan.git] / src / libcharon / sa / ikev2 / tasks / child_delete.c
1 /*
2 * Copyright (C) 2006-2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "child_delete.h"
17
18 #include <daemon.h>
19 #include <encoding/payloads/delete_payload.h>
20
21
22 typedef struct private_child_delete_t private_child_delete_t;
23
24 /**
25 * Private members of a child_delete_t task.
26 */
27 struct private_child_delete_t {
28
29 /**
30 * Public methods and task_t interface.
31 */
32 child_delete_t public;
33
34 /**
35 * Assigned IKE_SA.
36 */
37 ike_sa_t *ike_sa;
38
39 /**
40 * Are we the initiator?
41 */
42 bool initiator;
43
44 /**
45 * Protocol of CHILD_SA to delete
46 */
47 protocol_id_t protocol;
48
49 /**
50 * Inbound SPI of CHILD_SA to delete
51 */
52 u_int32_t spi;
53
54 /**
55 * whether to enforce delete action policy
56 */
57 bool check_delete_action;
58
59 /**
60 * is this delete exchange following a rekey?
61 */
62 bool rekeyed;
63
64 /**
65 * CHILD_SAs which get deleted
66 */
67 linked_list_t *child_sas;
68 };
69
70 /**
71 * build the delete payloads from the listed child_sas
72 */
73 static void build_payloads(private_child_delete_t *this, message_t *message)
74 {
75 delete_payload_t *ah = NULL, *esp = NULL;
76 enumerator_t *enumerator;
77 child_sa_t *child_sa;
78
79 enumerator = this->child_sas->create_enumerator(this->child_sas);
80 while (enumerator->enumerate(enumerator, (void**)&child_sa))
81 {
82 protocol_id_t protocol = child_sa->get_protocol(child_sa);
83 u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
84
85 switch (protocol)
86 {
87 case PROTO_ESP:
88 if (esp == NULL)
89 {
90 esp = delete_payload_create(DELETE, PROTO_ESP);
91 message->add_payload(message, (payload_t*)esp);
92 }
93 esp->add_spi(esp, spi);
94 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
95 protocol_id_names, protocol, ntohl(spi));
96 break;
97 case PROTO_AH:
98 if (ah == NULL)
99 {
100 ah = delete_payload_create(DELETE, PROTO_AH);
101 message->add_payload(message, (payload_t*)ah);
102 }
103 ah->add_spi(ah, spi);
104 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
105 protocol_id_names, protocol, ntohl(spi));
106 break;
107 default:
108 break;
109 }
110 child_sa->set_state(child_sa, CHILD_DELETING);
111 }
112 enumerator->destroy(enumerator);
113 }
114
115 /**
116 * read in payloads and find the children to delete
117 */
118 static void process_payloads(private_child_delete_t *this, message_t *message)
119 {
120 enumerator_t *payloads, *spis;
121 payload_t *payload;
122 delete_payload_t *delete_payload;
123 u_int32_t spi;
124 protocol_id_t protocol;
125 child_sa_t *child_sa;
126
127 payloads = message->create_payload_enumerator(message);
128 while (payloads->enumerate(payloads, &payload))
129 {
130 if (payload->get_type(payload) == DELETE)
131 {
132 delete_payload = (delete_payload_t*)payload;
133 protocol = delete_payload->get_protocol_id(delete_payload);
134 if (protocol != PROTO_ESP && protocol != PROTO_AH)
135 {
136 continue;
137 }
138 spis = delete_payload->create_spi_enumerator(delete_payload);
139 while (spis->enumerate(spis, &spi))
140 {
141 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
142 spi, FALSE);
143 if (child_sa == NULL)
144 {
145 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, "
146 "but no such SA", protocol_id_names, protocol, ntohl(spi));
147 continue;
148 }
149 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
150 protocol_id_names, protocol, ntohl(spi));
151
152 switch (child_sa->get_state(child_sa))
153 {
154 case CHILD_REKEYING:
155 this->rekeyed = TRUE;
156 /* we reply as usual, rekeying will fail */
157 break;
158 case CHILD_DELETING:
159 /* we don't send back a delete if we initiated ourself */
160 if (!this->initiator)
161 {
162 this->ike_sa->destroy_child_sa(this->ike_sa,
163 protocol, spi);
164 continue;
165 }
166 /* fall through */
167 case CHILD_INSTALLED:
168 if (!this->initiator)
169 { /* reestablish installed children if required */
170 this->check_delete_action = TRUE;
171 }
172 default:
173 break;
174 }
175
176 this->child_sas->insert_last(this->child_sas, child_sa);
177 }
178 spis->destroy(spis);
179 }
180 }
181 payloads->destroy(payloads);
182 }
183
184 /**
185 * destroy the children listed in this->child_sas, reestablish by policy
186 */
187 static status_t destroy_and_reestablish(private_child_delete_t *this)
188 {
189 enumerator_t *enumerator;
190 child_sa_t *child_sa;
191 child_cfg_t *child_cfg;
192 protocol_id_t protocol;
193 u_int32_t spi;
194 action_t action;
195 status_t status = SUCCESS;
196
197 enumerator = this->child_sas->create_enumerator(this->child_sas);
198 while (enumerator->enumerate(enumerator, (void**)&child_sa))
199 {
200 /* signal child down event if we are not rekeying */
201 if (!this->rekeyed)
202 {
203 charon->bus->child_updown(charon->bus, child_sa, FALSE);
204 }
205 spi = child_sa->get_spi(child_sa, TRUE);
206 protocol = child_sa->get_protocol(child_sa);
207 child_cfg = child_sa->get_config(child_sa);
208 child_cfg->get_ref(child_cfg);
209 action = child_sa->get_close_action(child_sa);
210 this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
211 if (this->check_delete_action)
212 { /* enforce child_cfg policy if deleted passively */
213 switch (action)
214 {
215 case ACTION_RESTART:
216 child_cfg->get_ref(child_cfg);
217 status = this->ike_sa->initiate(this->ike_sa, child_cfg, 0,
218 NULL, NULL);
219 break;
220 case ACTION_ROUTE:
221 charon->traps->install(charon->traps,
222 this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg);
223 break;
224 default:
225 break;
226 }
227 }
228 child_cfg->destroy(child_cfg);
229 if (status != SUCCESS)
230 {
231 break;
232 }
233 }
234 enumerator->destroy(enumerator);
235 return status;
236 }
237
238 /**
239 * send closing signals for all CHILD_SAs over the bus
240 */
241 static void log_children(private_child_delete_t *this)
242 {
243 enumerator_t *enumerator;
244 child_sa_t *child_sa;
245 u_int64_t bytes_in, bytes_out;
246
247 enumerator = this->child_sas->create_enumerator(this->child_sas);
248 while (enumerator->enumerate(enumerator, (void**)&child_sa))
249 {
250 child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in);
251 child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out);
252
253 DBG0(DBG_IKE, "closing CHILD_SA %s{%d} "
254 "with SPIs %.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
255 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
256 ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
257 ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
258 child_sa->get_traffic_selectors(child_sa, TRUE),
259 child_sa->get_traffic_selectors(child_sa, FALSE));
260 }
261 enumerator->destroy(enumerator);
262 }
263
264 METHOD(task_t, build_i, status_t,
265 private_child_delete_t *this, message_t *message)
266 {
267 child_sa_t *child_sa;
268
269 child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
270 this->spi, TRUE);
271 if (!child_sa)
272 { /* check if it is an outbound sa */
273 child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
274 this->spi, FALSE);
275 if (!child_sa)
276 { /* child does not exist anymore */
277 return SUCCESS;
278 }
279 /* we work only with the inbound SPI */
280 this->spi = child_sa->get_spi(child_sa, TRUE);
281 }
282 this->child_sas->insert_last(this->child_sas, child_sa);
283 if (child_sa->get_state(child_sa) == CHILD_REKEYING)
284 {
285 this->rekeyed = TRUE;
286 }
287 log_children(this);
288 build_payloads(this, message);
289 return NEED_MORE;
290 }
291
292 METHOD(task_t, process_i, status_t,
293 private_child_delete_t *this, message_t *message)
294 {
295 /* flush the list before adding new SAs */
296 this->child_sas->destroy(this->child_sas);
297 this->child_sas = linked_list_create();
298
299 process_payloads(this, message);
300 DBG1(DBG_IKE, "CHILD_SA closed");
301 return destroy_and_reestablish(this);
302 }
303
304 METHOD(task_t, process_r, status_t,
305 private_child_delete_t *this, message_t *message)
306 {
307 process_payloads(this, message);
308 log_children(this);
309 return NEED_MORE;
310 }
311
312 METHOD(task_t, build_r, status_t,
313 private_child_delete_t *this, message_t *message)
314 {
315 /* if we are rekeying, we send an empty informational */
316 if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING)
317 {
318 build_payloads(this, message);
319 }
320 DBG1(DBG_IKE, "CHILD_SA closed");
321 return destroy_and_reestablish(this);
322 }
323
324 METHOD(task_t, get_type, task_type_t,
325 private_child_delete_t *this)
326 {
327 return TASK_CHILD_DELETE;
328 }
329
330 METHOD(child_delete_t , get_child, child_sa_t*,
331 private_child_delete_t *this)
332 {
333 child_sa_t *child_sa = NULL;
334 this->child_sas->get_first(this->child_sas, (void**)&child_sa);
335 return child_sa;
336 }
337
338 METHOD(task_t, migrate, void,
339 private_child_delete_t *this, ike_sa_t *ike_sa)
340 {
341 this->check_delete_action = FALSE;
342 this->ike_sa = ike_sa;
343
344 this->child_sas->destroy(this->child_sas);
345 this->child_sas = linked_list_create();
346 }
347
348 METHOD(task_t, destroy, void,
349 private_child_delete_t *this)
350 {
351 this->child_sas->destroy(this->child_sas);
352 free(this);
353 }
354
355 /*
356 * Described in header.
357 */
358 child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
359 u_int32_t spi)
360 {
361 private_child_delete_t *this;
362
363 INIT(this,
364 .public = {
365 .task = {
366 .get_type = _get_type,
367 .migrate = _migrate,
368 .destroy = _destroy,
369 },
370 .get_child = _get_child,
371 },
372 .ike_sa = ike_sa,
373 .child_sas = linked_list_create(),
374 .protocol = protocol,
375 .spi = spi,
376 );
377
378 if (protocol != PROTO_NONE)
379 {
380 this->public.task.build = _build_i;
381 this->public.task.process = _process_i;
382 this->initiator = TRUE;
383 }
384 else
385 {
386 this->public.task.build = _build_r;
387 this->public.task.process = _process_r;
388 this->initiator = FALSE;
389 }
390 return &this->public;
391 }