af3f276a1b3ca1d179ea6332bd4b6c0ef913f47f
[strongswan.git] / src / charon / sa / 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 iterator_t *iterator;
77 child_sa_t *child_sa;
78
79 iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
80 while (iterator->iterate(iterator, (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(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(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 iterator->destroy(iterator);
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;
121 iterator_t *spis;
122 payload_t *payload;
123 delete_payload_t *delete_payload;
124 u_int32_t *spi;
125 protocol_id_t protocol;
126 child_sa_t *child_sa;
127
128 payloads = message->create_payload_enumerator(message);
129 while (payloads->enumerate(payloads, &payload))
130 {
131 if (payload->get_type(payload) == DELETE)
132 {
133 delete_payload = (delete_payload_t*)payload;
134 protocol = delete_payload->get_protocol_id(delete_payload);
135 if (protocol != PROTO_ESP && protocol != PROTO_AH)
136 {
137 continue;
138 }
139 spis = delete_payload->create_spi_iterator(delete_payload);
140 while (spis->iterate(spis, (void**)&spi))
141 {
142 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
143 *spi, FALSE);
144 if (child_sa == NULL)
145 {
146 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, "
147 "but no such SA", protocol_id_names, protocol, ntohl(*spi));
148 continue;
149 }
150 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
151 protocol_id_names, protocol, ntohl(*spi));
152
153 switch (child_sa->get_state(child_sa))
154 {
155 case CHILD_REKEYING:
156 this->rekeyed = TRUE;
157 /* we reply as usual, rekeying will fail */
158 break;
159 case CHILD_DELETING:
160 /* we don't send back a delete if we initiated ourself */
161 if (!this->initiator)
162 {
163 this->ike_sa->destroy_child_sa(this->ike_sa,
164 protocol, *spi);
165 continue;
166 }
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 iterator_t *iterator;
190 child_sa_t *child_sa;
191 child_cfg_t *child_cfg;
192 protocol_id_t protocol;
193 u_int32_t spi;
194 status_t status = SUCCESS;
195
196 iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
197 while (iterator->iterate(iterator, (void**)&child_sa))
198 {
199 /* signal child down event if we are not rekeying */
200 if (!this->rekeyed)
201 {
202 charon->bus->child_updown(charon->bus, child_sa, FALSE);
203 }
204 spi = child_sa->get_spi(child_sa, TRUE);
205 protocol = child_sa->get_protocol(child_sa);
206 child_cfg = child_sa->get_config(child_sa);
207 child_cfg->get_ref(child_cfg);
208 this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
209 if (this->check_delete_action)
210 { /* enforce child_cfg policy if deleted passively */
211 switch (child_cfg->get_close_action(child_cfg))
212 {
213 case ACTION_RESTART:
214 child_cfg->get_ref(child_cfg);
215 status = this->ike_sa->initiate(this->ike_sa, child_cfg, 0,
216 NULL, NULL);
217 break;
218 case ACTION_ROUTE:
219 charon->traps->install(charon->traps,
220 this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg);
221 break;
222 default:
223 break;
224 }
225 }
226 child_cfg->destroy(child_cfg);
227 if (status != SUCCESS)
228 {
229 break;
230 }
231 }
232 iterator->destroy(iterator);
233 return status;
234 }
235
236 /**
237 * send closing signals for all CHILD_SAs over the bus
238 */
239 static void log_children(private_child_delete_t *this)
240 {
241 iterator_t *iterator;
242 child_sa_t *child_sa;
243 u_int64_t bytes_in, bytes_out;
244
245 iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
246 while (iterator->iterate(iterator, (void**)&child_sa))
247 {
248 child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in);
249 child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out);
250
251 DBG0(DBG_IKE, "closing CHILD_SA %s{%d} "
252 "with SPIs %.8x_i (%lu bytes) %.8x_o (%lu bytes) and TS %#R=== %#R",
253 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
254 ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
255 ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
256 child_sa->get_traffic_selectors(child_sa, TRUE),
257 child_sa->get_traffic_selectors(child_sa, FALSE));
258 }
259 iterator->destroy(iterator);
260 }
261
262 /**
263 * Implementation of task_t.build for initiator
264 */
265 static status_t build_i(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 { /* child does not exist anymore */
273 return SUCCESS;
274 }
275 this->child_sas->insert_last(this->child_sas, child_sa);
276 if (child_sa->get_state(child_sa) == CHILD_REKEYING)
277 {
278 this->rekeyed = TRUE;
279 }
280 log_children(this);
281 build_payloads(this, message);
282 return NEED_MORE;
283 }
284
285 /**
286 * Implementation of task_t.process for initiator
287 */
288 static status_t process_i(private_child_delete_t *this, message_t *message)
289 {
290 /* flush the list before adding new SAs */
291 this->child_sas->destroy(this->child_sas);
292 this->child_sas = linked_list_create();
293
294 process_payloads(this, message);
295 DBG1(DBG_IKE, "CHILD_SA closed");
296 return destroy_and_reestablish(this);
297 }
298
299 /**
300 * Implementation of task_t.process for initiator
301 */
302 static status_t process_r(private_child_delete_t *this, message_t *message)
303 {
304 process_payloads(this, message);
305 log_children(this);
306 return NEED_MORE;
307 }
308
309 /**
310 * Implementation of task_t.build for responder
311 */
312 static status_t build_r(private_child_delete_t *this, message_t *message)
313 {
314 /* if we are rekeying, we send an empty informational */
315 if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING)
316 {
317 build_payloads(this, message);
318 }
319 DBG1(DBG_IKE, "CHILD_SA closed");
320 return destroy_and_reestablish(this);
321 }
322
323 /**
324 * Implementation of task_t.get_type
325 */
326 static task_type_t get_type(private_child_delete_t *this)
327 {
328 return CHILD_DELETE;
329 }
330
331 /**
332 * Implementation of child_delete_t.get_child
333 */
334 static child_sa_t* get_child(private_child_delete_t *this)
335 {
336 child_sa_t *child_sa = NULL;
337 this->child_sas->get_first(this->child_sas, (void**)&child_sa);
338 return child_sa;
339 }
340
341 /**
342 * Implementation of task_t.migrate
343 */
344 static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa)
345 {
346 this->check_delete_action = FALSE;
347 this->ike_sa = ike_sa;
348
349 this->child_sas->destroy(this->child_sas);
350 this->child_sas = linked_list_create();
351 }
352
353 /**
354 * Implementation of task_t.destroy
355 */
356 static void destroy(private_child_delete_t *this)
357 {
358 this->child_sas->destroy(this->child_sas);
359 free(this);
360 }
361
362 /*
363 * Described in header.
364 */
365 child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
366 u_int32_t spi)
367 {
368 private_child_delete_t *this = malloc_thing(private_child_delete_t);
369
370 this->public.get_child = (child_sa_t*(*)(child_delete_t*))get_child;
371 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
372 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
373 this->public.task.destroy = (void(*)(task_t*))destroy;
374
375 this->ike_sa = ike_sa;
376 this->check_delete_action = FALSE;
377 this->child_sas = linked_list_create();
378 this->protocol = protocol;
379 this->spi = spi;
380 this->rekeyed = FALSE;
381
382 if (protocol != PROTO_NONE)
383 {
384 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
385 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
386 this->initiator = TRUE;
387 }
388 else
389 {
390 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
391 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
392 this->initiator = FALSE;
393 }
394 return &this->public;
395 }