ikev1: Don't trigger updown event and close action for redundant CHILD_SAs
[strongswan.git] / src / libcharon / sa / ikev1 / tasks / quick_delete.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
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 * Copyright (C) 2013 Oliver Smith
17 *
18 * Permission is hereby granted, free of charge, to any person obtaining a copy
19 * of this software and associated documentation files (the "Software"), to deal
20 * in the Software without restriction, including without limitation the rights
21 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22 * copies of the Software, and to permit persons to whom the Software is
23 * furnished to do so, subject to the following conditions:
24 *
25 * The above copyright notice and this permission notice shall be included in
26 * all copies or substantial portions of the Software.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34 * THE SOFTWARE.
35 */
36
37 #include "quick_delete.h"
38
39 #include <daemon.h>
40 #include <encoding/payloads/delete_payload.h>
41 #include <sa/ikev1/task_manager_v1.h>
42
43 typedef struct private_quick_delete_t private_quick_delete_t;
44
45 /**
46 * Private members of a quick_delete_t task.
47 */
48 struct private_quick_delete_t {
49
50 /**
51 * Public methods and task_t interface.
52 */
53 quick_delete_t public;
54
55 /**
56 * Assigned IKE_SA.
57 */
58 ike_sa_t *ike_sa;
59
60 /**
61 * Are we the initiator?
62 */
63 bool initiator;
64
65 /**
66 * Protocol of CHILD_SA to delete
67 */
68 protocol_id_t protocol;
69
70 /**
71 * Inbound SPI of CHILD_SA to delete
72 */
73 uint32_t spi;
74
75 /**
76 * Send delete even if SA does not exist
77 */
78 bool force;
79
80 /**
81 * SA already expired?
82 */
83 bool expired;
84 };
85
86 /**
87 * Delete the specified CHILD_SA, if found
88 */
89 static bool delete_child(private_quick_delete_t *this, protocol_id_t protocol,
90 uint32_t spi, bool remote_close)
91 {
92 uint64_t bytes_in, bytes_out;
93 child_sa_t *child_sa;
94 linked_list_t *my_ts, *other_ts;
95 child_cfg_t *child_cfg;
96 bool rekeyed;
97
98 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE);
99 if (!child_sa)
100 { /* fallback and check for outbound SA */
101 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE);
102 if (!child_sa)
103 {
104 return FALSE;
105 }
106 this->spi = spi = child_sa->get_spi(child_sa, TRUE);
107 }
108
109 rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYED;
110 if (!rekeyed)
111 {
112 rekeyed = ikev1_child_sa_is_redundant(this->ike_sa, child_sa, NULL);
113 }
114 child_sa->set_state(child_sa, CHILD_DELETING);
115
116 my_ts = linked_list_create_from_enumerator(
117 child_sa->create_ts_enumerator(child_sa, TRUE));
118 other_ts = linked_list_create_from_enumerator(
119 child_sa->create_ts_enumerator(child_sa, FALSE));
120 if (this->expired)
121 {
122 DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
123 "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
124 child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
125 ntohl(child_sa->get_spi(child_sa, TRUE)),
126 ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
127 }
128 else
129 {
130 child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, NULL);
131 child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, NULL);
132
133 DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs "
134 "%.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R === %#R",
135 child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
136 ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
137 ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
138 my_ts, other_ts);
139 }
140 my_ts->destroy(my_ts);
141 other_ts->destroy(other_ts);
142
143 child_sa->set_state(child_sa, CHILD_DELETED);
144 if (!rekeyed)
145 {
146 charon->bus->child_updown(charon->bus, child_sa, FALSE);
147
148 if (remote_close)
149 {
150 child_cfg = child_sa->get_config(child_sa);
151 child_cfg->get_ref(child_cfg);
152
153 switch (child_sa->get_close_action(child_sa))
154 {
155 case ACTION_RESTART:
156 child_cfg->get_ref(child_cfg);
157 this->ike_sa->initiate(this->ike_sa, child_cfg,
158 child_sa->get_reqid(child_sa), NULL, NULL);
159 break;
160 case ACTION_ROUTE:
161 charon->traps->install(charon->traps,
162 this->ike_sa->get_peer_cfg(this->ike_sa),
163 child_cfg);
164 break;
165 default:
166 break;
167 }
168 child_cfg->destroy(child_cfg);
169 }
170 }
171 this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
172
173 return TRUE;
174 }
175
176 METHOD(task_t, build_i, status_t,
177 private_quick_delete_t *this, message_t *message)
178 {
179 if (delete_child(this, this->protocol, this->spi, FALSE) || this->force)
180 {
181 delete_payload_t *delete_payload;
182
183 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
184 protocol_id_names, this->protocol, ntohl(this->spi));
185
186 delete_payload = delete_payload_create(PLV1_DELETE, this->protocol);
187 delete_payload->add_spi(delete_payload, this->spi);
188 message->add_payload(message, &delete_payload->payload_interface);
189
190 return SUCCESS;
191 }
192 this->ike_sa->flush_queue(this->ike_sa, TASK_QUEUE_ACTIVE);
193 return ALREADY_DONE;
194 }
195
196 METHOD(task_t, process_i, status_t,
197 private_quick_delete_t *this, message_t *message)
198 {
199 return FAILED;
200 }
201
202 METHOD(task_t, process_r, status_t,
203 private_quick_delete_t *this, message_t *message)
204 {
205 enumerator_t *payloads, *spis;
206 payload_t *payload;
207 delete_payload_t *delete_payload;
208 protocol_id_t protocol;
209 uint32_t spi;
210
211 payloads = message->create_payload_enumerator(message);
212 while (payloads->enumerate(payloads, &payload))
213 {
214 if (payload->get_type(payload) == PLV1_DELETE)
215 {
216 delete_payload = (delete_payload_t*)payload;
217 protocol = delete_payload->get_protocol_id(delete_payload);
218 if (protocol != PROTO_ESP && protocol != PROTO_AH)
219 {
220 continue;
221 }
222 spis = delete_payload->create_spi_enumerator(delete_payload);
223 while (spis->enumerate(spis, &spi))
224 {
225 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
226 protocol_id_names, protocol, ntohl(spi));
227 if (!delete_child(this, protocol, spi, TRUE))
228 {
229 DBG1(DBG_IKE, "CHILD_SA not found, ignored");
230 continue;
231 }
232 }
233 spis->destroy(spis);
234 }
235 }
236 payloads->destroy(payloads);
237
238 return SUCCESS;
239 }
240
241 METHOD(task_t, build_r, status_t,
242 private_quick_delete_t *this, message_t *message)
243 {
244 return FAILED;
245 }
246
247 METHOD(task_t, get_type, task_type_t,
248 private_quick_delete_t *this)
249 {
250 return TASK_QUICK_DELETE;
251 }
252
253 METHOD(task_t, migrate, void,
254 private_quick_delete_t *this, ike_sa_t *ike_sa)
255 {
256 this->ike_sa = ike_sa;
257 }
258
259 METHOD(task_t, destroy, void,
260 private_quick_delete_t *this)
261 {
262 free(this);
263 }
264
265 /*
266 * Described in header.
267 */
268 quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
269 uint32_t spi, bool force, bool expired)
270 {
271 private_quick_delete_t *this;
272
273 INIT(this,
274 .public = {
275 .task = {
276 .get_type = _get_type,
277 .migrate = _migrate,
278 .destroy = _destroy,
279 },
280 },
281 .ike_sa = ike_sa,
282 .protocol = protocol,
283 .spi = spi,
284 .force = force,
285 .expired = expired,
286 );
287
288 if (protocol != PROTO_NONE)
289 {
290 this->public.task.build = _build_i;
291 this->public.task.process = _process_i;
292 }
293 else
294 {
295 this->public.task.build = _build_r;
296 this->public.task.process = _process_r;
297 }
298 return &this->public;
299 }