payload: Use common prefixes for all payload type identifiers
[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 #include <sa/ikev2/tasks/child_create.h>
21
22
23 typedef struct private_child_delete_t private_child_delete_t;
24
25 /**
26 * Private members of a child_delete_t task.
27 */
28 struct private_child_delete_t {
29
30 /**
31 * Public methods and task_t interface.
32 */
33 child_delete_t public;
34
35 /**
36 * Assigned IKE_SA.
37 */
38 ike_sa_t *ike_sa;
39
40 /**
41 * Are we the initiator?
42 */
43 bool initiator;
44
45 /**
46 * Protocol of CHILD_SA to delete
47 */
48 protocol_id_t protocol;
49
50 /**
51 * Inbound SPI of CHILD_SA to delete
52 */
53 u_int32_t spi;
54
55 /**
56 * whether to enforce delete action policy
57 */
58 bool check_delete_action;
59
60 /**
61 * is this delete exchange following a rekey?
62 */
63 bool rekeyed;
64
65 /**
66 * CHILD_SA already expired?
67 */
68 bool expired;
69
70 /**
71 * CHILD_SAs which get deleted
72 */
73 linked_list_t *child_sas;
74 };
75
76 /**
77 * build the delete payloads from the listed child_sas
78 */
79 static void build_payloads(private_child_delete_t *this, message_t *message)
80 {
81 delete_payload_t *ah = NULL, *esp = NULL;
82 enumerator_t *enumerator;
83 child_sa_t *child_sa;
84
85 enumerator = this->child_sas->create_enumerator(this->child_sas);
86 while (enumerator->enumerate(enumerator, (void**)&child_sa))
87 {
88 protocol_id_t protocol = child_sa->get_protocol(child_sa);
89 u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
90
91 switch (protocol)
92 {
93 case PROTO_ESP:
94 if (esp == NULL)
95 {
96 esp = delete_payload_create(PLV2_DELETE, PROTO_ESP);
97 message->add_payload(message, (payload_t*)esp);
98 }
99 esp->add_spi(esp, spi);
100 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
101 protocol_id_names, protocol, ntohl(spi));
102 break;
103 case PROTO_AH:
104 if (ah == NULL)
105 {
106 ah = delete_payload_create(PLV2_DELETE, PROTO_AH);
107 message->add_payload(message, (payload_t*)ah);
108 }
109 ah->add_spi(ah, spi);
110 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
111 protocol_id_names, protocol, ntohl(spi));
112 break;
113 default:
114 break;
115 }
116 child_sa->set_state(child_sa, CHILD_DELETING);
117 }
118 enumerator->destroy(enumerator);
119 }
120
121 /**
122 * read in payloads and find the children to delete
123 */
124 static void process_payloads(private_child_delete_t *this, message_t *message)
125 {
126 enumerator_t *payloads, *spis;
127 payload_t *payload;
128 delete_payload_t *delete_payload;
129 u_int32_t spi;
130 protocol_id_t protocol;
131 child_sa_t *child_sa;
132
133 payloads = message->create_payload_enumerator(message);
134 while (payloads->enumerate(payloads, &payload))
135 {
136 if (payload->get_type(payload) == PLV2_DELETE)
137 {
138 delete_payload = (delete_payload_t*)payload;
139 protocol = delete_payload->get_protocol_id(delete_payload);
140 if (protocol != PROTO_ESP && protocol != PROTO_AH)
141 {
142 continue;
143 }
144 spis = delete_payload->create_spi_enumerator(delete_payload);
145 while (spis->enumerate(spis, &spi))
146 {
147 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
148 spi, FALSE);
149 if (child_sa == NULL)
150 {
151 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, "
152 "but no such SA", protocol_id_names, protocol, ntohl(spi));
153 continue;
154 }
155 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
156 protocol_id_names, protocol, ntohl(spi));
157
158 switch (child_sa->get_state(child_sa))
159 {
160 case CHILD_REKEYING:
161 this->rekeyed = TRUE;
162 /* we reply as usual, rekeying will fail */
163 break;
164 case CHILD_DELETING:
165 /* we don't send back a delete if we initiated ourself */
166 if (!this->initiator)
167 {
168 this->ike_sa->destroy_child_sa(this->ike_sa,
169 protocol, spi);
170 continue;
171 }
172 /* fall through */
173 case CHILD_INSTALLED:
174 if (!this->initiator)
175 { /* reestablish installed children if required */
176 this->check_delete_action = TRUE;
177 }
178 default:
179 break;
180 }
181 if (this->child_sas->find_first(this->child_sas, NULL,
182 (void**)&child_sa) != SUCCESS)
183 {
184 this->child_sas->insert_last(this->child_sas, child_sa);
185 }
186 }
187 spis->destroy(spis);
188 }
189 }
190 payloads->destroy(payloads);
191 }
192
193 /**
194 * destroy the children listed in this->child_sas, reestablish by policy
195 */
196 static status_t destroy_and_reestablish(private_child_delete_t *this)
197 {
198 enumerator_t *enumerator;
199 child_sa_t *child_sa;
200 child_cfg_t *child_cfg;
201 protocol_id_t protocol;
202 u_int32_t spi, reqid;
203 action_t action;
204 status_t status = SUCCESS;
205
206 enumerator = this->child_sas->create_enumerator(this->child_sas);
207 while (enumerator->enumerate(enumerator, (void**)&child_sa))
208 {
209 /* signal child down event if we are not rekeying */
210 if (!this->rekeyed)
211 {
212 charon->bus->child_updown(charon->bus, child_sa, FALSE);
213 }
214 spi = child_sa->get_spi(child_sa, TRUE);
215 reqid = child_sa->get_reqid(child_sa);
216 protocol = child_sa->get_protocol(child_sa);
217 child_cfg = child_sa->get_config(child_sa);
218 child_cfg->get_ref(child_cfg);
219 action = child_sa->get_close_action(child_sa);
220 this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
221 if (this->check_delete_action)
222 { /* enforce child_cfg policy if deleted passively */
223 switch (action)
224 {
225 case ACTION_RESTART:
226 child_cfg->get_ref(child_cfg);
227 status = this->ike_sa->initiate(this->ike_sa, child_cfg,
228 reqid, NULL, NULL);
229 break;
230 case ACTION_ROUTE:
231 charon->traps->install(charon->traps,
232 this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg,
233 reqid);
234 break;
235 default:
236 break;
237 }
238 }
239 child_cfg->destroy(child_cfg);
240 if (status != SUCCESS)
241 {
242 break;
243 }
244 }
245 enumerator->destroy(enumerator);
246 return status;
247 }
248
249 /**
250 * send closing signals for all CHILD_SAs over the bus
251 */
252 static void log_children(private_child_delete_t *this)
253 {
254 linked_list_t *my_ts, *other_ts;
255 enumerator_t *enumerator;
256 child_sa_t *child_sa;
257 u_int64_t bytes_in, bytes_out;
258
259 enumerator = this->child_sas->create_enumerator(this->child_sas);
260 while (enumerator->enumerate(enumerator, (void**)&child_sa))
261 {
262 my_ts = linked_list_create_from_enumerator(
263 child_sa->create_ts_enumerator(child_sa, TRUE));
264 other_ts = linked_list_create_from_enumerator(
265 child_sa->create_ts_enumerator(child_sa, FALSE));
266 if (this->expired)
267 {
268 DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
269 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
270 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
271 ntohl(child_sa->get_spi(child_sa, TRUE)),
272 ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
273 }
274 else
275 {
276 child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, NULL);
277 child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, NULL);
278
279 DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i "
280 "(%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
281 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
282 ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
283 ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
284 my_ts, other_ts);
285 }
286 my_ts->destroy(my_ts);
287 other_ts->destroy(other_ts);
288 }
289 enumerator->destroy(enumerator);
290 }
291
292 METHOD(task_t, build_i, status_t,
293 private_child_delete_t *this, message_t *message)
294 {
295 child_sa_t *child_sa;
296
297 child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
298 this->spi, TRUE);
299 if (!child_sa)
300 { /* check if it is an outbound sa */
301 child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
302 this->spi, FALSE);
303 if (!child_sa)
304 { /* child does not exist anymore */
305 return SUCCESS;
306 }
307 /* we work only with the inbound SPI */
308 this->spi = child_sa->get_spi(child_sa, TRUE);
309 }
310 this->child_sas->insert_last(this->child_sas, child_sa);
311 if (child_sa->get_state(child_sa) == CHILD_REKEYING)
312 {
313 this->rekeyed = TRUE;
314 }
315 log_children(this);
316 build_payloads(this, message);
317
318 if (!this->rekeyed && this->expired)
319 {
320 child_cfg_t *child_cfg;
321
322 DBG1(DBG_IKE, "scheduling CHILD_SA recreate after hard expire");
323 child_cfg = child_sa->get_config(child_sa);
324 this->ike_sa->queue_task(this->ike_sa, (task_t*)
325 child_create_create(this->ike_sa, child_cfg->get_ref(child_cfg),
326 FALSE, NULL, NULL));
327 }
328 return NEED_MORE;
329 }
330
331 METHOD(task_t, process_i, status_t,
332 private_child_delete_t *this, message_t *message)
333 {
334 process_payloads(this, message);
335 DBG1(DBG_IKE, "CHILD_SA closed");
336 return destroy_and_reestablish(this);
337 }
338
339 METHOD(task_t, process_r, status_t,
340 private_child_delete_t *this, message_t *message)
341 {
342 process_payloads(this, message);
343 log_children(this);
344 return NEED_MORE;
345 }
346
347 METHOD(task_t, build_r, status_t,
348 private_child_delete_t *this, message_t *message)
349 {
350 /* if we are rekeying, we send an empty informational */
351 if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING)
352 {
353 build_payloads(this, message);
354 }
355 DBG1(DBG_IKE, "CHILD_SA closed");
356 return destroy_and_reestablish(this);
357 }
358
359 METHOD(task_t, get_type, task_type_t,
360 private_child_delete_t *this)
361 {
362 return TASK_CHILD_DELETE;
363 }
364
365 METHOD(child_delete_t , get_child, child_sa_t*,
366 private_child_delete_t *this)
367 {
368 child_sa_t *child_sa = NULL;
369 this->child_sas->get_first(this->child_sas, (void**)&child_sa);
370 return child_sa;
371 }
372
373 METHOD(task_t, migrate, void,
374 private_child_delete_t *this, ike_sa_t *ike_sa)
375 {
376 this->check_delete_action = FALSE;
377 this->ike_sa = ike_sa;
378
379 this->child_sas->destroy(this->child_sas);
380 this->child_sas = linked_list_create();
381 }
382
383 METHOD(task_t, destroy, void,
384 private_child_delete_t *this)
385 {
386 this->child_sas->destroy(this->child_sas);
387 free(this);
388 }
389
390 /*
391 * Described in header.
392 */
393 child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
394 u_int32_t spi, bool expired)
395 {
396 private_child_delete_t *this;
397
398 INIT(this,
399 .public = {
400 .task = {
401 .get_type = _get_type,
402 .migrate = _migrate,
403 .destroy = _destroy,
404 },
405 .get_child = _get_child,
406 },
407 .ike_sa = ike_sa,
408 .child_sas = linked_list_create(),
409 .protocol = protocol,
410 .spi = spi,
411 .expired = expired,
412 );
413
414 if (protocol != PROTO_NONE)
415 {
416 this->public.task.build = _build_i;
417 this->public.task.process = _process_i;
418 this->initiator = TRUE;
419 }
420 else
421 {
422 this->public.task.build = _build_r;
423 this->public.task.process = _process_r;
424 this->initiator = FALSE;
425 }
426 return &this->public;
427 }