Support arbitrary suffixes for actions, same action multiple times
[strongswan.git] / src / conftest / actions.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 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 #include "actions.h"
17 #include "conftest.h"
18
19 #include <daemon.h>
20 #include <processing/jobs/callback_job.h>
21 #include <processing/jobs/rekey_ike_sa_job.h>
22 #include <processing/jobs/rekey_child_sa_job.h>
23 #include <processing/jobs/send_dpd_job.h>
24
25 typedef struct private_actions_t private_actions_t;
26
27 /**
28 * Private data of an actions_t object.
29 */
30 struct private_actions_t {
31
32 /**
33 * Public actions_t interface.
34 */
35 actions_t public;
36 };
37
38 /**
39 * Initiate a CHILD_SA
40 */
41 static job_requeue_t initiate(char *config)
42 {
43 peer_cfg_t *peer_cfg;
44 child_cfg_t *child_cfg = NULL, *current;
45 enumerator_t *enumerator;
46
47 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, config);
48 if (!peer_cfg)
49 {
50 DBG1(DBG_CFG, "initiating '%s' failed, config not found");
51 return JOB_REQUEUE_NONE;
52 }
53 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
54 while (enumerator->enumerate(enumerator, &current))
55 {
56 if (streq(current->get_name(current), config))
57 {
58 child_cfg = current;
59 child_cfg->get_ref(child_cfg);
60 break;
61 }
62 }
63 enumerator->destroy(enumerator);
64 if (child_cfg)
65 {
66 DBG1(DBG_CFG, "initiating IKE_SA for CHILD_SA config '%s'", config);
67 charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
68 NULL, NULL);
69 }
70 else
71 {
72 DBG1(DBG_CFG, "initiating '%s' failed, CHILD_SA config not found",
73 config);
74 }
75
76 return JOB_REQUEUE_NONE;
77 }
78
79 /**
80 * Rekey an IKE_SA
81 */
82 static job_requeue_t rekey_ike(char *config)
83 {
84 enumerator_t *enumerator;
85 job_t *job = NULL;
86 ike_sa_t *ike_sa;
87
88 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
89 while (enumerator->enumerate(enumerator, &ike_sa))
90 {
91 if (strcaseeq(config, ike_sa->get_name(ike_sa)))
92 {
93 job = (job_t*)rekey_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE);
94 break;
95 }
96 }
97 enumerator->destroy(enumerator);
98
99 if (job)
100 {
101 DBG1(DBG_CFG, "starting rekey of IKE_SA '%s'", config);
102 lib->processor->queue_job(lib->processor, job);
103 }
104 else
105 {
106 DBG1(DBG_CFG, "rekeying '%s' failed, IKE_SA not found", config);
107 }
108 return JOB_REQUEUE_NONE;
109 }
110
111 /**
112 * Rekey an CHILD_SA
113 */
114 static job_requeue_t rekey_child(char *config)
115 {
116 enumerator_t *enumerator;
117 iterator_t *children;
118 ike_sa_t *ike_sa;
119 child_sa_t *child_sa;
120 u_int32_t reqid = 0, spi = 0;
121 protocol_id_t proto = PROTO_ESP;
122
123 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
124 while (enumerator->enumerate(enumerator, &ike_sa))
125 {
126 children = ike_sa->create_child_sa_iterator(ike_sa);
127 while (children->iterate(children, (void**)&child_sa))
128 {
129 if (streq(config, child_sa->get_name(child_sa)))
130 {
131 reqid = child_sa->get_reqid(child_sa);
132 proto = child_sa->get_protocol(child_sa);
133 spi = child_sa->get_spi(child_sa, TRUE);
134 break;
135 }
136 }
137 children->destroy(children);
138 }
139 enumerator->destroy(enumerator);
140 if (reqid)
141 {
142 DBG1(DBG_CFG, "starting rekey of CHILD_SA '%s'", config);
143 lib->processor->queue_job(lib->processor,
144 (job_t*)rekey_child_sa_job_create(reqid, proto, spi));
145 }
146 else
147 {
148 DBG1(DBG_CFG, "rekeying '%s' failed, CHILD_SA not found", config);
149 }
150 return JOB_REQUEUE_NONE;
151 }
152
153 /**
154 * Do a liveness check
155 */
156 static job_requeue_t liveness(char *config)
157 {
158 enumerator_t *enumerator;
159 job_t *job = NULL;
160 ike_sa_t *ike_sa;
161
162 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
163 while (enumerator->enumerate(enumerator, &ike_sa))
164 {
165 if (strcaseeq(config, ike_sa->get_name(ike_sa)))
166 {
167 job = (job_t*)send_dpd_job_create(ike_sa->get_id(ike_sa));
168 break;
169 }
170 }
171 enumerator->destroy(enumerator);
172
173 if (job)
174 {
175 DBG1(DBG_CFG, "starting liveness check of IKE_SA '%s'", config);
176 lib->processor->queue_job(lib->processor, job);
177 }
178 else
179 {
180 DBG1(DBG_CFG, "liveness check for '%s' failed, IKE_SA not found", config);
181 }
182 return JOB_REQUEUE_NONE;
183 }
184
185 /**
186 * Close an IKE_SA with all CHILD_SAs
187 */
188 static job_requeue_t close_ike(char *config)
189 {
190 enumerator_t *enumerator;
191 ike_sa_t *ike_sa;
192 int id = 0;
193
194 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
195 while (enumerator->enumerate(enumerator, &ike_sa))
196 {
197 if (strcaseeq(config, ike_sa->get_name(ike_sa)))
198 {
199 id = ike_sa->get_unique_id(ike_sa);
200 break;
201 }
202 }
203 enumerator->destroy(enumerator);
204 if (id)
205 {
206 DBG1(DBG_CFG, "closing IKE_SA '%s'", config);
207 charon->controller->terminate_ike(charon->controller, id, NULL, NULL);
208 }
209 else
210 {
211 DBG1(DBG_CFG, "unable to close IKE_SA '%s', not found", config);
212 }
213 return JOB_REQUEUE_NONE;
214 }
215
216 /**
217 * Close a CHILD_SAs
218 */
219 static job_requeue_t close_child(char *config)
220 {
221 enumerator_t *enumerator;
222 iterator_t *children;
223 ike_sa_t *ike_sa;
224 child_sa_t *child_sa;
225 int id = 0;
226
227 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
228 while (enumerator->enumerate(enumerator, &ike_sa))
229 {
230
231 children = ike_sa->create_child_sa_iterator(ike_sa);
232 while (children->iterate(children, (void**)&child_sa))
233 {
234 if (streq(config, child_sa->get_name(child_sa)))
235 {
236 id = child_sa->get_reqid(child_sa);
237 break;
238 }
239 }
240 children->destroy(children);
241 }
242 enumerator->destroy(enumerator);
243 if (id)
244 {
245 DBG1(DBG_CFG, "closing CHILD_SA '%s'", config);
246 charon->controller->terminate_child(charon->controller, id, NULL, NULL);
247 }
248 else
249 {
250 DBG1(DBG_CFG, "unable to close CHILD_SA '%s', not found", config);
251 }
252 return JOB_REQUEUE_NONE;
253 }
254
255 /**
256 * Load a single action
257 */
258 static void load_action(settings_t *settings, char *action)
259 {
260 static struct {
261 char *name;
262 callback_job_cb_t cb;
263 } actions[] = {
264 {"initiate", (void*)initiate},
265 {"rekey_ike", (void*)rekey_ike},
266 {"rekey_child", (void*)rekey_child},
267 {"liveness", (void*)liveness},
268 {"close_ike", (void*)close_ike},
269 {"close_child", (void*)close_child},
270 };
271 bool found = FALSE;
272 int i;
273
274 for (i = 0; i < countof(actions); i++)
275 {
276 if (strncasecmp(actions[i].name, action, strlen(actions[i].name)) == 0)
277 {
278 int delay;
279 char *config;
280
281 found = TRUE;
282 delay = settings->get_int(settings, "actions.%s.delay", 0, action);
283 config = settings->get_str(settings, "actions.%s.config",
284 NULL, action);
285 if (!config)
286 {
287 DBG1(DBG_CFG, "no config defined for action '%s'", action);
288 break;
289 }
290 lib->scheduler->schedule_job(lib->scheduler,
291 (job_t*)callback_job_create(actions[i].cb, config, NULL, NULL),
292 delay);
293 }
294 }
295 if (!found)
296 {
297 DBG1(DBG_CFG, "unknown action '%s', skipped", action);
298 }
299 }
300
301 /**
302 * Load configured actions
303 */
304 static void load_actions(settings_t *settings)
305 {
306 enumerator_t *enumerator;
307 char *action;
308
309 enumerator = settings->create_section_enumerator(settings, "actions");
310 while (enumerator->enumerate(enumerator, &action))
311 {
312 load_action(settings, action);
313 }
314 enumerator->destroy(enumerator);
315 }
316
317 METHOD(actions_t, destroy, void,
318 private_actions_t *this)
319 {
320 free(this);
321 }
322
323 /**
324 * See header
325 */
326 actions_t *actions_create()
327 {
328 private_actions_t *this;
329
330 INIT(this,
331 .public = {
332 .destroy = _destroy,
333 },
334 );
335
336 load_actions(conftest->test);
337
338 return &this->public;
339 }