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