0d89c148ef35cc5b0fa56da83e061ff9f4da5c8a
[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 * wheter to enforce delete action policy
56 */
57 bool check_delete_action;
58
59 /**
60 * CHILD_SAs which get deleted
61 */
62 linked_list_t *child_sas;
63 };
64
65 /**
66 * build the delete payloads from the listed child_sas
67 */
68 static void build_payloads(private_child_delete_t *this, message_t *message)
69 {
70 delete_payload_t *ah = NULL, *esp = NULL;
71 iterator_t *iterator;
72 child_sa_t *child_sa;
73
74 iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
75 while (iterator->iterate(iterator, (void**)&child_sa))
76 {
77 protocol_id_t protocol = child_sa->get_protocol(child_sa);
78 u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
79
80 switch (protocol)
81 {
82 case PROTO_ESP:
83 if (esp == NULL)
84 {
85 esp = delete_payload_create(PROTO_ESP);
86 message->add_payload(message, (payload_t*)esp);
87 }
88 esp->add_spi(esp, spi);
89 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
90 protocol_id_names, protocol, ntohl(spi));
91 break;
92 case PROTO_AH:
93 if (ah == NULL)
94 {
95 ah = delete_payload_create(PROTO_AH);
96 message->add_payload(message, (payload_t*)ah);
97 }
98 ah->add_spi(ah, spi);
99 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
100 protocol_id_names, protocol, ntohl(spi));
101 break;
102 default:
103 break;
104 }
105 child_sa->set_state(child_sa, CHILD_DELETING);
106 }
107 iterator->destroy(iterator);
108 }
109
110 /**
111 * read in payloads and find the children to delete
112 */
113 static void process_payloads(private_child_delete_t *this, message_t *message)
114 {
115 enumerator_t *payloads;
116 iterator_t *spis;
117 payload_t *payload;
118 delete_payload_t *delete_payload;
119 u_int32_t *spi;
120 protocol_id_t protocol;
121 child_sa_t *child_sa;
122
123 payloads = message->create_payload_enumerator(message);
124 while (payloads->enumerate(payloads, &payload))
125 {
126 if (payload->get_type(payload) == DELETE)
127 {
128 delete_payload = (delete_payload_t*)payload;
129 protocol = delete_payload->get_protocol_id(delete_payload);
130 if (protocol != PROTO_ESP && protocol != PROTO_AH)
131 {
132 continue;
133 }
134 spis = delete_payload->create_spi_iterator(delete_payload);
135 while (spis->iterate(spis, (void**)&spi))
136 {
137 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
138 *spi, FALSE);
139 if (child_sa == NULL)
140 {
141 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, "
142 "but no such SA", protocol_id_names, protocol, ntohl(*spi));
143 continue;
144 }
145 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
146 protocol_id_names, protocol, ntohl(*spi));
147
148 switch (child_sa->get_state(child_sa))
149 {
150 case CHILD_REKEYING:
151 /* we reply as usual, rekeying will fail */
152 break;
153 case CHILD_DELETING:
154 /* we don't send back a delete if we initiated ourself */
155 if (!this->initiator)
156 {
157 this->ike_sa->destroy_child_sa(this->ike_sa,
158 protocol, *spi);
159 continue;
160 }
161 case CHILD_INSTALLED:
162 if (!this->initiator)
163 { /* reestablish installed children if required */
164 this->check_delete_action = TRUE;
165 }
166 default:
167 break;
168 }
169
170 this->child_sas->insert_last(this->child_sas, child_sa);
171 }
172 spis->destroy(spis);
173 }
174 }
175 payloads->destroy(payloads);
176 }
177
178 /**
179 * destroy the children listed in this->child_sas, reestablish by policy
180 */
181 static status_t destroy_and_reestablish(private_child_delete_t *this)
182 {
183 iterator_t *iterator;
184 child_sa_t *child_sa;
185 child_cfg_t *child_cfg;
186 protocol_id_t protocol;
187 u_int32_t spi;
188 status_t status = SUCCESS;
189
190 iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
191 while (iterator->iterate(iterator, (void**)&child_sa))
192 {
193 spi = child_sa->get_spi(child_sa, TRUE);
194 protocol = child_sa->get_protocol(child_sa);
195 child_cfg = child_sa->get_config(child_sa);
196 child_cfg->get_ref(child_cfg);
197 this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
198 if (this->check_delete_action)
199 { /* enforce child_cfg policy if deleted passively */
200 switch (child_cfg->get_close_action(child_cfg))
201 {
202 case ACTION_RESTART:
203 child_cfg->get_ref(child_cfg);
204 status = this->ike_sa->initiate(this->ike_sa, child_cfg, 0,
205 NULL, NULL);
206 break;
207 case ACTION_ROUTE:
208 charon->traps->install(charon->traps,
209 this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg);
210 break;
211 default:
212 break;
213 }
214 }
215 child_cfg->destroy(child_cfg);
216 if (status != SUCCESS)
217 {
218 break;
219 }
220 }
221 iterator->destroy(iterator);
222 return status;
223 }
224
225 /**
226 * send closing signals for all CHILD_SAs over the bus
227 */
228 static void log_children(private_child_delete_t *this)
229 {
230 iterator_t *iterator;
231 child_sa_t *child_sa;
232
233 iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
234 while (iterator->iterate(iterator, (void**)&child_sa))
235 {
236 DBG0(DBG_IKE, "closing CHILD_SA %s{%d} "
237 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
238 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
239 ntohl(child_sa->get_spi(child_sa, TRUE)),
240 ntohl(child_sa->get_spi(child_sa, FALSE)),
241 child_sa->get_traffic_selectors(child_sa, TRUE),
242 child_sa->get_traffic_selectors(child_sa, FALSE));
243 }
244 iterator->destroy(iterator);
245 }
246
247 /**
248 * Implementation of task_t.build for initiator
249 */
250 static status_t build_i(private_child_delete_t *this, message_t *message)
251 {
252 child_sa_t *child_sa;
253
254 child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
255 this->spi, TRUE);
256 if (!child_sa)
257 { /* child does not exist anymore */
258 return SUCCESS;
259 }
260 this->child_sas->insert_last(this->child_sas, child_sa);
261
262 log_children(this);
263 build_payloads(this, message);
264 return NEED_MORE;
265 }
266
267 /**
268 * Implementation of task_t.process for initiator
269 */
270 static status_t process_i(private_child_delete_t *this, message_t *message)
271 {
272 /* flush the list before adding new SAs */
273 this->child_sas->destroy(this->child_sas);
274 this->child_sas = linked_list_create();
275
276 process_payloads(this, message);
277 DBG1(DBG_IKE, "CHILD_SA closed");
278 return destroy_and_reestablish(this);
279 }
280
281 /**
282 * Implementation of task_t.process for initiator
283 */
284 static status_t process_r(private_child_delete_t *this, message_t *message)
285 {
286 process_payloads(this, message);
287 log_children(this);
288 return NEED_MORE;
289 }
290
291 /**
292 * Implementation of task_t.build for responder
293 */
294 static status_t build_r(private_child_delete_t *this, message_t *message)
295 {
296 /* if we are rekeying, we send an empty informational */
297 if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING)
298 {
299 build_payloads(this, message);
300 }
301 DBG1(DBG_IKE, "CHILD_SA closed");
302 return destroy_and_reestablish(this);
303 }
304
305 /**
306 * Implementation of task_t.get_type
307 */
308 static task_type_t get_type(private_child_delete_t *this)
309 {
310 return CHILD_DELETE;
311 }
312
313 /**
314 * Implementation of child_delete_t.get_child
315 */
316 static child_sa_t* get_child(private_child_delete_t *this)
317 {
318 child_sa_t *child_sa = NULL;
319 this->child_sas->get_first(this->child_sas, (void**)&child_sa);
320 return child_sa;
321 }
322
323 /**
324 * Implementation of task_t.migrate
325 */
326 static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa)
327 {
328 this->check_delete_action = FALSE;
329 this->ike_sa = ike_sa;
330
331 this->child_sas->destroy(this->child_sas);
332 this->child_sas = linked_list_create();
333 }
334
335 /**
336 * Implementation of task_t.destroy
337 */
338 static void destroy(private_child_delete_t *this)
339 {
340 this->child_sas->destroy(this->child_sas);
341 free(this);
342 }
343
344 /*
345 * Described in header.
346 */
347 child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
348 u_int32_t spi)
349 {
350 private_child_delete_t *this = malloc_thing(private_child_delete_t);
351
352 this->public.get_child = (child_sa_t*(*)(child_delete_t*))get_child;
353 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
354 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
355 this->public.task.destroy = (void(*)(task_t*))destroy;
356
357 this->ike_sa = ike_sa;
358 this->check_delete_action = FALSE;
359 this->child_sas = linked_list_create();
360 this->protocol = protocol;
361 this->spi = spi;
362
363 if (protocol != PROTO_NONE)
364 {
365 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
366 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
367 this->initiator = TRUE;
368 }
369 else
370 {
371 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
372 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
373 this->initiator = FALSE;
374 }
375 return &this->public;
376 }