6669f38c06f11faa6d4585f27230a693bb855f34
[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 #include <processing/jobs/rekey_ike_sa_job.h>
21 #include <processing/jobs/rekey_child_sa_job.h>
22
23 typedef struct private_stroke_control_t private_stroke_control_t;
24
25 /**
26 * private data of stroke_control
27 */
28 struct private_stroke_control_t {
29
30 /**
31 * public functions
32 */
33 stroke_control_t public;
34 };
35
36
37 typedef struct stroke_log_info_t stroke_log_info_t;
38
39 /**
40 * helper struct to say what and where to log when using controller callback
41 */
42 struct stroke_log_info_t {
43
44 /**
45 * level to log up to
46 */
47 level_t level;
48
49 /**
50 * where to write log
51 */
52 FILE* out;
53 };
54
55 /**
56 * logging to the stroke interface
57 */
58 static bool stroke_log(stroke_log_info_t *info, debug_t group, level_t level,
59 ike_sa_t *ike_sa, char *format, va_list args)
60 {
61 if (level <= info->level)
62 {
63 if (vfprintf(info->out, format, args) < 0 ||
64 fprintf(info->out, "\n") < 0 ||
65 fflush(info->out) != 0)
66 {
67 return FALSE;
68 }
69 }
70 return TRUE;
71 }
72
73 /**
74 * get the child_cfg with the same name as the peer cfg
75 */
76 static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
77 {
78 child_cfg_t *current, *found = NULL;
79 enumerator_t *enumerator;
80
81 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
82 while (enumerator->enumerate(enumerator, &current))
83 {
84 if (streq(current->get_name(current), name))
85 {
86 found = current;
87 found->get_ref(found);
88 break;
89 }
90 }
91 enumerator->destroy(enumerator);
92 return found;
93 }
94
95 /**
96 * Handles all connections that must be either started or routed
97 * Currently only for connections stored in an SQL database
98 * Connection defined in ipsec.conf are started via stroke commands
99 */
100 static void start_all_connections(void)
101 {
102 enumerator_t *enumerator, *children;
103 peer_cfg_t *peer_cfg;
104 child_cfg_t *child_cfg;
105 char *name;
106
107 enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
108 NULL, NULL, NULL, NULL);
109 while (enumerator->enumerate(enumerator, &peer_cfg))
110 {
111 if (peer_cfg->get_ike_version(peer_cfg) != 2)
112 {
113 continue;
114 }
115
116 children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
117 while (children->enumerate(children, &child_cfg))
118 {
119 name = child_cfg->get_name(child_cfg);
120
121 switch (child_cfg->get_start_action(child_cfg))
122 {
123 case ACTION_RESTART:
124 charon->controller->initiate(charon->controller,
125 peer_cfg->get_ref(peer_cfg),
126 child_cfg->get_ref(child_cfg),
127 NULL, NULL);
128 break;
129 case ACTION_ROUTE:
130 if (charon->traps->install(charon->traps, peer_cfg, child_cfg))
131 {
132 DBG1(DBG_CFG, "configuration '%s' routed", name);
133 }
134 else
135 {
136 DBG1(DBG_CFG, "routing configuration '%s' failed", name);
137 }
138 break;
139 case ACTION_NONE:
140 break;
141 }
142 }
143 children->destroy(children);
144 }
145 enumerator->destroy(enumerator);
146 }
147
148 /**
149 * Implementation of stroke_control_t.initiate.
150 */
151 static void initiate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
152 {
153 peer_cfg_t *peer_cfg;
154 child_cfg_t *child_cfg;
155 stroke_log_info_t info;
156
157 if (streq(msg->initiate.name, "%startall"))
158 {
159 start_all_connections();
160 return;
161 }
162
163 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
164 msg->initiate.name);
165 if (peer_cfg == NULL)
166 {
167 DBG1(DBG_CFG, "no config named '%s'\n", msg->initiate.name);
168 return;
169 }
170 if (peer_cfg->get_ike_version(peer_cfg) != 2)
171 {
172 DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
173 peer_cfg->get_ike_version(peer_cfg));
174 peer_cfg->destroy(peer_cfg);
175 return;
176 }
177
178 child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
179 if (child_cfg == NULL)
180 {
181 DBG1(DBG_CFG, "no child config named '%s'\n", msg->initiate.name);
182 peer_cfg->destroy(peer_cfg);
183 return;
184 }
185
186 if (msg->output_verbosity < 0)
187 {
188 charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
189 NULL, NULL);
190 }
191 else
192 {
193 info.out = out;
194 info.level = msg->output_verbosity;
195 charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
196 (controller_cb_t)stroke_log, &info);
197 }
198 }
199
200 /**
201 * Parse a terminate/rekey specifier
202 */
203 static bool parse_specifier(char *string, u_int32_t *id,
204 char **name, bool *child, bool *all)
205 {
206 int len;
207 char *pos = NULL;
208
209 *id = 0;
210 *name = NULL;
211 *all = FALSE;
212
213 len = strlen(string);
214 if (len < 1)
215 {
216 return FALSE;
217 }
218 switch (string[len-1])
219 {
220 case '}':
221 *child = TRUE;
222 pos = strchr(string, '{');
223 break;
224 case ']':
225 *child = FALSE;
226 pos = strchr(string, '[');
227 break;
228 default:
229 *name = string;
230 *child = FALSE;
231 break;
232 }
233
234 if (*name)
235 {
236 /* is a single name */
237 }
238 else if (pos == string + len - 2)
239 { /* is name[] or name{} */
240 string[len-2] = '\0';
241 *name = string;
242 }
243 else
244 {
245 if (!pos)
246 {
247 return FALSE;
248 }
249 if (*(pos + 1) == '*')
250 { /* is name[*] */
251 *all = TRUE;
252 *pos = '\0';
253 *name = string;
254 }
255 else
256 { /* is name[123] or name{23} */
257 *id = atoi(pos + 1);
258 if (*id == 0)
259 {
260 return FALSE;
261 }
262 }
263 }
264 return TRUE;
265 }
266
267 /**
268 * Implementation of stroke_control_t.terminate.
269 */
270 static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
271 {
272 char *name;
273 u_int32_t id;
274 bool child, all;
275 ike_sa_t *ike_sa;
276 enumerator_t *enumerator;
277 linked_list_t *ike_list, *child_list;
278 stroke_log_info_t info;
279 uintptr_t del;
280
281 if (!parse_specifier(msg->terminate.name, &id, &name, &child, &all))
282 {
283 DBG1(DBG_CFG, "error parsing specifier string");
284 return;
285 }
286
287 info.out = out;
288 info.level = msg->output_verbosity;
289
290 if (id)
291 {
292 if (child)
293 {
294 charon->controller->terminate_child(charon->controller, id,
295 (controller_cb_t)stroke_log, &info);
296 }
297 else
298 {
299 charon->controller->terminate_ike(charon->controller, id,
300 (controller_cb_t)stroke_log, &info);
301 }
302 return;
303 }
304
305 ike_list = linked_list_create();
306 child_list = linked_list_create();
307 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
308 while (enumerator->enumerate(enumerator, &ike_sa))
309 {
310 child_sa_t *child_sa;
311 iterator_t *children;
312
313 if (child)
314 {
315 children = ike_sa->create_child_sa_iterator(ike_sa);
316 while (children->iterate(children, (void**)&child_sa))
317 {
318 if (streq(name, child_sa->get_name(child_sa)))
319 {
320 child_list->insert_last(child_list,
321 (void*)(uintptr_t)child_sa->get_reqid(child_sa));
322 if (!all)
323 {
324 break;
325 }
326 }
327 }
328 children->destroy(children);
329 if (child_list->get_count(child_list) && !all)
330 {
331 break;
332 }
333 }
334 else if (streq(name, ike_sa->get_name(ike_sa)))
335 {
336 ike_list->insert_last(ike_list,
337 (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
338 if (!all)
339 {
340 break;
341 }
342 }
343 }
344 enumerator->destroy(enumerator);
345
346 enumerator = child_list->create_enumerator(child_list);
347 while (enumerator->enumerate(enumerator, &del))
348 {
349 charon->controller->terminate_child(charon->controller, del,
350 (controller_cb_t)stroke_log, &info);
351 }
352 enumerator->destroy(enumerator);
353
354 enumerator = ike_list->create_enumerator(ike_list);
355 while (enumerator->enumerate(enumerator, &del))
356 {
357 charon->controller->terminate_ike(charon->controller, del,
358 (controller_cb_t)stroke_log, &info);
359 }
360 enumerator->destroy(enumerator);
361
362 if (child_list->get_count(child_list) == 0 &&
363 ike_list->get_count(ike_list) == 0)
364 {
365 DBG1(DBG_CFG, "no %s_SA named '%s' found",
366 child ? "CHILD" : "IKE", name);
367 }
368 ike_list->destroy(ike_list);
369 child_list->destroy(child_list);
370 }
371
372 /**
373 * Implementation of stroke_control_t.rekey.
374 */
375 static void rekey(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
376 {
377 char *name;
378 u_int32_t id;
379 bool child, all, finished = FALSE;
380 ike_sa_t *ike_sa;
381 enumerator_t *enumerator;
382
383 if (!parse_specifier(msg->terminate.name, &id, &name, &child, &all))
384 {
385 DBG1(DBG_CFG, "error parsing specifier string");
386 return;
387 }
388 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
389 while (enumerator->enumerate(enumerator, &ike_sa))
390 {
391 child_sa_t *child_sa;
392 iterator_t *children;
393
394 if (child)
395 {
396 children = ike_sa->create_child_sa_iterator(ike_sa);
397 while (children->iterate(children, (void**)&child_sa))
398 {
399 if ((name && streq(name, child_sa->get_name(child_sa))) ||
400 (id && id == child_sa->get_reqid(child_sa)))
401 {
402 lib->processor->queue_job(lib->processor,
403 (job_t*)rekey_child_sa_job_create(
404 child_sa->get_reqid(child_sa),
405 child_sa->get_protocol(child_sa),
406 child_sa->get_spi(child_sa, TRUE)));
407 if (!all)
408 {
409 finished = TRUE;
410 break;
411 }
412 }
413 }
414 children->destroy(children);
415 }
416 else if ((name && streq(name, ike_sa->get_name(ike_sa))) ||
417 (id && id == ike_sa->get_unique_id(ike_sa)))
418 {
419 lib->processor->queue_job(lib->processor,
420 (job_t*)rekey_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE));
421 if (!all)
422 {
423 finished = TRUE;
424 }
425 }
426 if (finished)
427 {
428 break;
429 }
430 }
431 enumerator->destroy(enumerator);
432 }
433
434 /**
435 * Implementation of stroke_control_t.terminate_srcip.
436 */
437 static void terminate_srcip(private_stroke_control_t *this,
438 stroke_msg_t *msg, FILE *out)
439 {
440 enumerator_t *enumerator;
441 ike_sa_t *ike_sa;
442 host_t *start = NULL, *end = NULL, *vip;
443 chunk_t chunk_start, chunk_end = chunk_empty, chunk_vip;
444
445 if (msg->terminate_srcip.start)
446 {
447 start = host_create_from_string(msg->terminate_srcip.start, 0);
448 }
449 if (!start)
450 {
451 DBG1(DBG_CFG, "invalid start address: %s", msg->terminate_srcip.start);
452 return;
453 }
454 chunk_start = start->get_address(start);
455 if (msg->terminate_srcip.end)
456 {
457 end = host_create_from_string(msg->terminate_srcip.end, 0);
458 if (!end)
459 {
460 DBG1(DBG_CFG, "invalid end address: %s", msg->terminate_srcip.end);
461 start->destroy(start);
462 return;
463 }
464 chunk_end = end->get_address(end);
465 }
466
467 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
468 while (enumerator->enumerate(enumerator, &ike_sa))
469 {
470 vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
471 if (!vip)
472 {
473 continue;
474 }
475 if (!end)
476 {
477 if (!vip->ip_equals(vip, start))
478 {
479 continue;
480 }
481 }
482 else
483 {
484 chunk_vip = vip->get_address(vip);
485 if (chunk_vip.len != chunk_start.len ||
486 chunk_vip.len != chunk_end.len ||
487 memcmp(chunk_vip.ptr, chunk_start.ptr, chunk_vip.len) < 0 ||
488 memcmp(chunk_vip.ptr, chunk_end.ptr, chunk_vip.len) > 0)
489 {
490 continue;
491 }
492 }
493
494 /* schedule delete asynchronously */
495 lib->processor->queue_job(lib->processor, (job_t*)
496 delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE));
497 }
498 enumerator->destroy(enumerator);
499 start->destroy(start);
500 DESTROY_IF(end);
501 }
502
503 /**
504 * Implementation of stroke_control_t.purge_ike
505 */
506 static void purge_ike(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
507 {
508 enumerator_t *enumerator;
509 iterator_t *iterator;
510 ike_sa_t *ike_sa;
511 child_sa_t *child_sa;
512 linked_list_t *list;
513 uintptr_t del;
514 stroke_log_info_t info;
515
516 info.out = out;
517 info.level = msg->output_verbosity;
518
519 list = linked_list_create();
520 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
521 while (enumerator->enumerate(enumerator, &ike_sa))
522 {
523 iterator = ike_sa->create_child_sa_iterator(ike_sa);
524 if (!iterator->iterate(iterator, (void**)&child_sa))
525 {
526 list->insert_last(list,
527 (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
528 }
529 iterator->destroy(iterator);
530 }
531 enumerator->destroy(enumerator);
532
533 enumerator = list->create_enumerator(list);
534 while (enumerator->enumerate(enumerator, &del))
535 {
536 charon->controller->terminate_ike(charon->controller, del,
537 (controller_cb_t)stroke_log, &info);
538 }
539 enumerator->destroy(enumerator);
540 list->destroy(list);
541 }
542
543 /**
544 * Implementation of stroke_control_t.route.
545 */
546 static void route(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
547 {
548 peer_cfg_t *peer_cfg;
549 child_cfg_t *child_cfg;
550
551 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
552 msg->route.name);
553 if (peer_cfg == NULL)
554 {
555 fprintf(out, "no config named '%s'\n", msg->route.name);
556 return;
557 }
558 if (peer_cfg->get_ike_version(peer_cfg) != 2)
559 {
560 peer_cfg->destroy(peer_cfg);
561 return;
562 }
563
564 child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
565 if (child_cfg == NULL)
566 {
567 fprintf(out, "no child config named '%s'\n", msg->route.name);
568 peer_cfg->destroy(peer_cfg);
569 return;
570 }
571
572 if (charon->traps->install(charon->traps, peer_cfg, child_cfg))
573 {
574 fprintf(out, "configuration '%s' routed\n", msg->route.name);
575 }
576 else
577 {
578 fprintf(out, "routing configuration '%s' failed\n", msg->route.name);
579 }
580 peer_cfg->destroy(peer_cfg);
581 child_cfg->destroy(child_cfg);
582 }
583
584 /**
585 * Implementation of stroke_control_t.unroute.
586 */
587 static void unroute(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
588 {
589 child_sa_t *child_sa;
590 enumerator_t *enumerator;
591 u_int32_t id;
592
593 enumerator = charon->traps->create_enumerator(charon->traps);
594 while (enumerator->enumerate(enumerator, NULL, &child_sa))
595 {
596 if (streq(msg->unroute.name, child_sa->get_name(child_sa)))
597 {
598 id = child_sa->get_reqid(child_sa);
599 enumerator->destroy(enumerator);
600 charon->traps->uninstall(charon->traps, id);
601 fprintf(out, "configuration '%s' unrouted\n", msg->unroute.name);
602 return;
603 }
604 }
605 enumerator->destroy(enumerator);
606 fprintf(out, "configuration '%s' not found\n", msg->unroute.name);
607 }
608
609 /**
610 * Implementation of stroke_control_t.destroy
611 */
612 static void destroy(private_stroke_control_t *this)
613 {
614 free(this);
615 }
616
617 /*
618 * see header file
619 */
620 stroke_control_t *stroke_control_create()
621 {
622 private_stroke_control_t *this = malloc_thing(private_stroke_control_t);
623
624 this->public.initiate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))initiate;
625 this->public.terminate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate;
626 this->public.terminate_srcip = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate_srcip;
627 this->public.rekey = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))rekey;
628 this->public.purge_ike = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))purge_ike;
629 this->public.route = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))route;
630 this->public.unroute = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))unroute;
631 this->public.destroy = (void(*)(stroke_control_t*))destroy;
632
633 return &this->public;
634 }
635