make use of the new trap-manager
[strongswan.git] / src / charon / plugins / stroke / stroke_control.c
1 /*
2 * Copyright (C) 2008 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 "stroke_control.h"
17
18 #include <daemon.h>
19 #include <processing/jobs/delete_ike_sa_job.h>
20
21 typedef struct private_stroke_control_t private_stroke_control_t;
22
23 /**
24 * private data of stroke_control
25 */
26 struct private_stroke_control_t {
27
28 /**
29 * public functions
30 */
31 stroke_control_t public;
32 };
33
34
35 typedef struct stroke_log_info_t stroke_log_info_t;
36
37 /**
38 * helper struct to say what and where to log when using controller callback
39 */
40 struct stroke_log_info_t {
41
42 /**
43 * level to log up to
44 */
45 level_t level;
46
47 /**
48 * where to write log
49 */
50 FILE* out;
51 };
52
53 /**
54 * logging to the stroke interface
55 */
56 static bool stroke_log(stroke_log_info_t *info, debug_t group, level_t level,
57 ike_sa_t *ike_sa, char *format, va_list args)
58 {
59 if (level <= info->level)
60 {
61 if (vfprintf(info->out, format, args) < 0 ||
62 fprintf(info->out, "\n") < 0 ||
63 fflush(info->out) != 0)
64 {
65 return FALSE;
66 }
67 }
68 return TRUE;
69 }
70
71 /**
72 * get the child_cfg with the same name as the peer cfg
73 */
74 static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
75 {
76 child_cfg_t *current, *found = NULL;
77 enumerator_t *enumerator;
78
79 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
80 while (enumerator->enumerate(enumerator, &current))
81 {
82 if (streq(current->get_name(current), name))
83 {
84 found = current;
85 found->get_ref(found);
86 break;
87 }
88 }
89 enumerator->destroy(enumerator);
90 return found;
91 }
92
93 /**
94 * Implementation of stroke_control_t.initiate.
95 */
96 static void initiate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
97 {
98 peer_cfg_t *peer_cfg;
99 child_cfg_t *child_cfg;
100 stroke_log_info_t info;
101
102 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
103 msg->initiate.name);
104 if (peer_cfg == NULL)
105 {
106 DBG1(DBG_CFG, "no config named '%s'\n", msg->initiate.name);
107 return;
108 }
109 if (peer_cfg->get_ike_version(peer_cfg) != 2)
110 {
111 DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
112 peer_cfg->get_ike_version(peer_cfg));
113 peer_cfg->destroy(peer_cfg);
114 return;
115 }
116
117 child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
118 if (child_cfg == NULL)
119 {
120 DBG1(DBG_CFG, "no child config named '%s'\n", msg->initiate.name);
121 peer_cfg->destroy(peer_cfg);
122 return;
123 }
124
125 if (msg->output_verbosity < 0)
126 {
127 charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
128 NULL, NULL);
129 }
130 else
131 {
132 info.out = out;
133 info.level = msg->output_verbosity;
134 charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
135 (controller_cb_t)stroke_log, &info);
136 }
137 }
138
139 /**
140 * Implementation of stroke_control_t.terminate.
141 */
142 static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
143 {
144 char *string, *pos = NULL, *name = NULL;
145 u_int32_t id = 0;
146 bool child;
147 int len;
148 ike_sa_t *ike_sa;
149 enumerator_t *enumerator;
150 stroke_log_info_t info;
151
152 string = msg->terminate.name;
153
154 len = strlen(string);
155 if (len < 1)
156 {
157 DBG1(DBG_CFG, "error parsing string");
158 return;
159 }
160 switch (string[len-1])
161 {
162 case '}':
163 child = TRUE;
164 pos = strchr(string, '{');
165 break;
166 case ']':
167 child = FALSE;
168 pos = strchr(string, '[');
169 break;
170 default:
171 name = string;
172 child = FALSE;
173 break;
174 }
175
176 if (name)
177 {
178 /* is a single name */
179 }
180 else if (pos == string + len - 2)
181 { /* is name[] or name{} */
182 string[len-2] = '\0';
183 name = string;
184 }
185 else
186 { /* is name[123] or name{23} */
187 string[len-1] = '\0';
188 id = atoi(pos + 1);
189 if (id == 0)
190 {
191 DBG1(DBG_CFG, "error parsing string");
192 return;
193 }
194 }
195
196 info.out = out;
197 info.level = msg->output_verbosity;
198
199 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
200 while (enumerator->enumerate(enumerator, &ike_sa))
201 {
202 child_sa_t *child_sa;
203 iterator_t *children;
204
205 if (child)
206 {
207 children = ike_sa->create_child_sa_iterator(ike_sa);
208 while (children->iterate(children, (void**)&child_sa))
209 {
210 if ((name && streq(name, child_sa->get_name(child_sa))) ||
211 (id && id == child_sa->get_reqid(child_sa)))
212 {
213 id = child_sa->get_reqid(child_sa);
214 children->destroy(children);
215 enumerator->destroy(enumerator);
216
217 charon->controller->terminate_child(charon->controller, id,
218 (controller_cb_t)stroke_log, &info);
219 return;
220 }
221 }
222 children->destroy(children);
223 }
224 else if ((name && streq(name, ike_sa->get_name(ike_sa))) ||
225 (id && id == ike_sa->get_unique_id(ike_sa)))
226 {
227 id = ike_sa->get_unique_id(ike_sa);
228 /* unlock manager first */
229 enumerator->destroy(enumerator);
230
231 charon->controller->terminate_ike(charon->controller, id,
232 (controller_cb_t)stroke_log, &info);
233 return;
234 }
235
236 }
237 enumerator->destroy(enumerator);
238 DBG1(DBG_CFG, "no such SA found");
239 }
240
241 /**
242 * Implementation of stroke_control_t.terminate_srcip.
243 */
244 static void terminate_srcip(private_stroke_control_t *this,
245 stroke_msg_t *msg, FILE *out)
246 {
247 enumerator_t *enumerator;
248 ike_sa_t *ike_sa;
249 host_t *start = NULL, *end = NULL, *vip;
250 chunk_t chunk_start, chunk_end = chunk_empty, chunk_vip;
251
252 if (msg->terminate_srcip.start)
253 {
254 start = host_create_from_string(msg->terminate_srcip.start, 0);
255 }
256 if (!start)
257 {
258 DBG1(DBG_CFG, "invalid start address: %s", msg->terminate_srcip.start);
259 return;
260 }
261 chunk_start = start->get_address(start);
262 if (msg->terminate_srcip.end)
263 {
264 end = host_create_from_string(msg->terminate_srcip.end, 0);
265 if (!end)
266 {
267 DBG1(DBG_CFG, "invalid end address: %s", msg->terminate_srcip.end);
268 start->destroy(start);
269 return;
270 }
271 chunk_end = end->get_address(end);
272 }
273
274 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
275 while (enumerator->enumerate(enumerator, &ike_sa))
276 {
277 vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
278 if (!vip)
279 {
280 continue;
281 }
282 if (!end)
283 {
284 if (!vip->ip_equals(vip, start))
285 {
286 continue;
287 }
288 }
289 else
290 {
291 chunk_vip = vip->get_address(vip);
292 if (chunk_vip.len != chunk_start.len ||
293 chunk_vip.len != chunk_end.len ||
294 memcmp(chunk_vip.ptr, chunk_start.ptr, chunk_vip.len) < 0 ||
295 memcmp(chunk_vip.ptr, chunk_end.ptr, chunk_vip.len) > 0)
296 {
297 continue;
298 }
299 }
300
301 /* schedule delete asynchronously */
302 charon->processor->queue_job(charon->processor, (job_t*)
303 delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE));
304 }
305 enumerator->destroy(enumerator);
306 start->destroy(start);
307 DESTROY_IF(end);
308 }
309
310 /**
311 * Implementation of stroke_control_t.route.
312 */
313 static void route(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
314 {
315 peer_cfg_t *peer_cfg;
316 child_cfg_t *child_cfg;
317
318 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
319 msg->route.name);
320 if (peer_cfg == NULL)
321 {
322 fprintf(out, "no config named '%s'\n", msg->route.name);
323 return;
324 }
325 if (peer_cfg->get_ike_version(peer_cfg) != 2)
326 {
327 peer_cfg->destroy(peer_cfg);
328 return;
329 }
330
331 child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
332 if (child_cfg == NULL)
333 {
334 fprintf(out, "no child config named '%s'\n", msg->route.name);
335 peer_cfg->destroy(peer_cfg);
336 return;
337 }
338
339 if (charon->traps->install(charon->traps, peer_cfg, child_cfg))
340 {
341 fprintf(out, "configuration '%s' routed\n", msg->route.name);
342 }
343 else
344 {
345 fprintf(out, "routing configuration '%s' failed\n", msg->route.name);
346 }
347 peer_cfg->destroy(peer_cfg);
348 child_cfg->destroy(child_cfg);
349 }
350
351 /**
352 * Implementation of stroke_control_t.unroute.
353 */
354 static void unroute(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
355 {
356 child_sa_t *child_sa;
357 enumerator_t *enumerator;
358 u_int32_t id;
359
360 enumerator = charon->traps->create_enumerator(charon->traps);
361 while (enumerator->enumerate(enumerator, NULL, &child_sa))
362 {
363 if (streq(msg->unroute.name, child_sa->get_name(child_sa)))
364 {
365 id = child_sa->get_reqid(child_sa);
366 enumerator->destroy(enumerator);
367 charon->traps->uninstall(charon->traps, id);
368 fprintf(out, "configuration '%s' unrouted\n", msg->unroute.name);
369 return;
370 }
371 }
372 enumerator->destroy(enumerator);
373 fprintf(out, "configuration '%s' not found\n", msg->unroute.name);
374 }
375
376 /**
377 * Implementation of stroke_control_t.destroy
378 */
379 static void destroy(private_stroke_control_t *this)
380 {
381 free(this);
382 }
383
384 /*
385 * see header file
386 */
387 stroke_control_t *stroke_control_create()
388 {
389 private_stroke_control_t *this = malloc_thing(private_stroke_control_t);
390
391 this->public.initiate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))initiate;
392 this->public.terminate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate;
393 this->public.terminate_srcip = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate_srcip;
394 this->public.route = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))route;
395 this->public.unroute = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))unroute;
396 this->public.destroy = (void(*)(stroke_control_t*))destroy;
397
398 return &this->public;
399 }
400