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