Moving charon to libcharon.
[strongswan.git] / src / libcharon / 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, all = FALSE;
147 int len;
148 ike_sa_t *ike_sa;
149 enumerator_t *enumerator;
150 linked_list_t *ike_list, *child_list;
151 stroke_log_info_t info;
152 uintptr_t del;
153
154 string = msg->terminate.name;
155
156 len = strlen(string);
157 if (len < 1)
158 {
159 DBG1(DBG_CFG, "error parsing string");
160 return;
161 }
162 switch (string[len-1])
163 {
164 case '}':
165 child = TRUE;
166 pos = strchr(string, '{');
167 break;
168 case ']':
169 child = FALSE;
170 pos = strchr(string, '[');
171 break;
172 default:
173 name = string;
174 child = FALSE;
175 break;
176 }
177
178 if (name)
179 {
180 /* is a single name */
181 }
182 else if (pos == string + len - 2)
183 { /* is name[] or name{} */
184 string[len-2] = '\0';
185 name = string;
186 }
187 else
188 {
189 if (*(pos + 1) == '*')
190 { /* is name[*] */
191 all = TRUE;
192 *pos = '\0';
193 name = string;
194 }
195 else
196 { /* is name[123] or name{23} */
197 id = atoi(pos + 1);
198 if (id == 0)
199 {
200 DBG1(DBG_CFG, "error parsing string");
201 return;
202 }
203 }
204 }
205
206 info.out = out;
207 info.level = msg->output_verbosity;
208
209 if (id)
210 {
211 if (child)
212 {
213 charon->controller->terminate_child(charon->controller, id,
214 (controller_cb_t)stroke_log, &info);
215 }
216 else
217 {
218 charon->controller->terminate_ike(charon->controller, id,
219 (controller_cb_t)stroke_log, &info);
220 }
221 return;
222 }
223
224 ike_list = linked_list_create();
225 child_list = linked_list_create();
226 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
227 while (enumerator->enumerate(enumerator, &ike_sa))
228 {
229 child_sa_t *child_sa;
230 iterator_t *children;
231
232 if (child)
233 {
234 children = ike_sa->create_child_sa_iterator(ike_sa);
235 while (children->iterate(children, (void**)&child_sa))
236 {
237 if (streq(name, child_sa->get_name(child_sa)))
238 {
239 child_list->insert_last(child_list,
240 (void*)(uintptr_t)child_sa->get_reqid(child_sa));
241 if (!all)
242 {
243 break;
244 }
245 }
246 }
247 children->destroy(children);
248 if (child_list->get_count(child_list) && !all)
249 {
250 break;
251 }
252 }
253 else if (streq(name, ike_sa->get_name(ike_sa)))
254 {
255 ike_list->insert_last(ike_list,
256 (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
257 if (!all)
258 {
259 break;
260 }
261 }
262 }
263 enumerator->destroy(enumerator);
264
265 enumerator = child_list->create_enumerator(child_list);
266 while (enumerator->enumerate(enumerator, &del))
267 {
268 charon->controller->terminate_child(charon->controller, del,
269 (controller_cb_t)stroke_log, &info);
270 }
271 enumerator->destroy(enumerator);
272
273 enumerator = ike_list->create_enumerator(ike_list);
274 while (enumerator->enumerate(enumerator, &del))
275 {
276 charon->controller->terminate_ike(charon->controller, del,
277 (controller_cb_t)stroke_log, &info);
278 }
279 enumerator->destroy(enumerator);
280
281 if (child_list->get_count(child_list) == 0 &&
282 ike_list->get_count(ike_list) == 0)
283 {
284 DBG1(DBG_CFG, "no %s_SA named '%s' found",
285 child ? "CHILD" : "IKE", name);
286 }
287 ike_list->destroy(ike_list);
288 child_list->destroy(child_list);
289 }
290
291 /**
292 * Implementation of stroke_control_t.terminate_srcip.
293 */
294 static void terminate_srcip(private_stroke_control_t *this,
295 stroke_msg_t *msg, FILE *out)
296 {
297 enumerator_t *enumerator;
298 ike_sa_t *ike_sa;
299 host_t *start = NULL, *end = NULL, *vip;
300 chunk_t chunk_start, chunk_end = chunk_empty, chunk_vip;
301
302 if (msg->terminate_srcip.start)
303 {
304 start = host_create_from_string(msg->terminate_srcip.start, 0);
305 }
306 if (!start)
307 {
308 DBG1(DBG_CFG, "invalid start address: %s", msg->terminate_srcip.start);
309 return;
310 }
311 chunk_start = start->get_address(start);
312 if (msg->terminate_srcip.end)
313 {
314 end = host_create_from_string(msg->terminate_srcip.end, 0);
315 if (!end)
316 {
317 DBG1(DBG_CFG, "invalid end address: %s", msg->terminate_srcip.end);
318 start->destroy(start);
319 return;
320 }
321 chunk_end = end->get_address(end);
322 }
323
324 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
325 while (enumerator->enumerate(enumerator, &ike_sa))
326 {
327 vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
328 if (!vip)
329 {
330 continue;
331 }
332 if (!end)
333 {
334 if (!vip->ip_equals(vip, start))
335 {
336 continue;
337 }
338 }
339 else
340 {
341 chunk_vip = vip->get_address(vip);
342 if (chunk_vip.len != chunk_start.len ||
343 chunk_vip.len != chunk_end.len ||
344 memcmp(chunk_vip.ptr, chunk_start.ptr, chunk_vip.len) < 0 ||
345 memcmp(chunk_vip.ptr, chunk_end.ptr, chunk_vip.len) > 0)
346 {
347 continue;
348 }
349 }
350
351 /* schedule delete asynchronously */
352 charon->processor->queue_job(charon->processor, (job_t*)
353 delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE));
354 }
355 enumerator->destroy(enumerator);
356 start->destroy(start);
357 DESTROY_IF(end);
358 }
359
360 /**
361 * Implementation of stroke_control_t.purge_ike
362 */
363 static void purge_ike(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
364 {
365 enumerator_t *enumerator;
366 iterator_t *iterator;
367 ike_sa_t *ike_sa;
368 child_sa_t *child_sa;
369 linked_list_t *list;
370 uintptr_t del;
371 stroke_log_info_t info;
372
373 info.out = out;
374 info.level = msg->output_verbosity;
375
376 list = linked_list_create();
377 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
378 while (enumerator->enumerate(enumerator, &ike_sa))
379 {
380 iterator = ike_sa->create_child_sa_iterator(ike_sa);
381 if (!iterator->iterate(iterator, (void**)&child_sa))
382 {
383 list->insert_last(list,
384 (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
385 }
386 iterator->destroy(iterator);
387 }
388 enumerator->destroy(enumerator);
389
390 enumerator = list->create_enumerator(list);
391 while (enumerator->enumerate(enumerator, &del))
392 {
393 charon->controller->terminate_ike(charon->controller, del,
394 (controller_cb_t)stroke_log, &info);
395 }
396 enumerator->destroy(enumerator);
397 list->destroy(list);
398 }
399
400 /**
401 * Implementation of stroke_control_t.route.
402 */
403 static void route(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
404 {
405 peer_cfg_t *peer_cfg;
406 child_cfg_t *child_cfg;
407
408 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
409 msg->route.name);
410 if (peer_cfg == NULL)
411 {
412 fprintf(out, "no config named '%s'\n", msg->route.name);
413 return;
414 }
415 if (peer_cfg->get_ike_version(peer_cfg) != 2)
416 {
417 peer_cfg->destroy(peer_cfg);
418 return;
419 }
420
421 child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
422 if (child_cfg == NULL)
423 {
424 fprintf(out, "no child config named '%s'\n", msg->route.name);
425 peer_cfg->destroy(peer_cfg);
426 return;
427 }
428
429 if (charon->traps->install(charon->traps, peer_cfg, child_cfg))
430 {
431 fprintf(out, "configuration '%s' routed\n", msg->route.name);
432 }
433 else
434 {
435 fprintf(out, "routing configuration '%s' failed\n", msg->route.name);
436 }
437 peer_cfg->destroy(peer_cfg);
438 child_cfg->destroy(child_cfg);
439 }
440
441 /**
442 * Implementation of stroke_control_t.unroute.
443 */
444 static void unroute(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
445 {
446 child_sa_t *child_sa;
447 enumerator_t *enumerator;
448 u_int32_t id;
449
450 enumerator = charon->traps->create_enumerator(charon->traps);
451 while (enumerator->enumerate(enumerator, NULL, &child_sa))
452 {
453 if (streq(msg->unroute.name, child_sa->get_name(child_sa)))
454 {
455 id = child_sa->get_reqid(child_sa);
456 enumerator->destroy(enumerator);
457 charon->traps->uninstall(charon->traps, id);
458 fprintf(out, "configuration '%s' unrouted\n", msg->unroute.name);
459 return;
460 }
461 }
462 enumerator->destroy(enumerator);
463 fprintf(out, "configuration '%s' not found\n", msg->unroute.name);
464 }
465
466 /**
467 * Implementation of stroke_control_t.destroy
468 */
469 static void destroy(private_stroke_control_t *this)
470 {
471 free(this);
472 }
473
474 /*
475 * see header file
476 */
477 stroke_control_t *stroke_control_create()
478 {
479 private_stroke_control_t *this = malloc_thing(private_stroke_control_t);
480
481 this->public.initiate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))initiate;
482 this->public.terminate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate;
483 this->public.terminate_srcip = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate_srcip;
484 this->public.purge_ike = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))purge_ike;
485 this->public.route = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))route;
486 this->public.unroute = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))unroute;
487 this->public.destroy = (void(*)(stroke_control_t*))destroy;
488
489 return &this->public;
490 }
491