2 * Copyright (C) 2013-2015 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
5 * Copyright (C) secunet Security Networks AG
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include "stroke_control.h"
22 #include <processing/jobs/delete_ike_sa_job.h>
23 #include <processing/jobs/rekey_ike_sa_job.h>
24 #include <processing/jobs/rekey_child_sa_job.h>
26 typedef struct private_stroke_control_t private_stroke_control_t
;
29 * private data of stroke_control
31 struct private_stroke_control_t
{
36 stroke_control_t
public;
39 * Timeout for stroke commands, im ms
45 typedef struct stroke_log_info_t stroke_log_info_t
;
48 * helper struct to say what and where to log when using controller callback
50 struct stroke_log_info_t
{
64 * logging to the stroke interface
66 static bool stroke_log(stroke_log_info_t
*info
, debug_t group
, level_t level
,
67 ike_sa_t
*ike_sa
, char *message
)
69 if (level
<= info
->level
)
71 if (fprintf(info
->out
, "%s", message
) < 0 ||
72 fprintf(info
->out
, "\n") < 0 ||
73 fflush(info
->out
) != 0)
82 * get the child_cfg with the same name as the peer cfg
84 static child_cfg_t
* get_child_from_peer(peer_cfg_t
*peer_cfg
, char *name
)
86 child_cfg_t
*current
, *found
= NULL
;
87 enumerator_t
*enumerator
;
89 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
90 while (enumerator
->enumerate(enumerator
, ¤t
))
92 if (streq(current
->get_name(current
), name
))
95 found
->get_ref(found
);
99 enumerator
->destroy(enumerator
);
104 * call the charon controller to initiate the connection
106 static void charon_initiate(private_stroke_control_t
*this, peer_cfg_t
*peer_cfg
,
107 child_cfg_t
*child_cfg
, stroke_msg_t
*msg
, FILE *out
)
109 if (msg
->output_verbosity
< 0)
111 charon
->controller
->initiate(charon
->controller
, peer_cfg
, child_cfg
,
112 NULL
, NULL
, 0, FALSE
);
116 stroke_log_info_t info
= { msg
->output_verbosity
, out
};
119 status
= charon
->controller
->initiate(charon
->controller
,
120 peer_cfg
, child_cfg
, (controller_cb_t
)stroke_log
,
121 &info
, this->timeout
, FALSE
);
125 fprintf(out
, "connection '%s' established successfully\n",
129 fprintf(out
, "connection '%s' not established after %dms, "
130 "detaching\n", msg
->initiate
.name
, this->timeout
);
134 fprintf(out
, "establishing connection '%s' failed\n",
141 METHOD(stroke_control_t
, initiate
, void,
142 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
144 child_cfg_t
*child_cfg
= NULL
;
145 peer_cfg_t
*peer_cfg
;
146 enumerator_t
*enumerator
;
149 peer_cfg
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
,
153 child_cfg
= get_child_from_peer(peer_cfg
, msg
->initiate
.name
);
154 if (child_cfg
== NULL
)
156 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
157 while (enumerator
->enumerate(enumerator
, &child_cfg
))
160 charon_initiate(this, peer_cfg
->get_ref(peer_cfg
),
161 child_cfg
->get_ref(child_cfg
), msg
, out
);
163 enumerator
->destroy(enumerator
);
167 DBG1(DBG_CFG
, "no child config named '%s'", msg
->initiate
.name
);
168 fprintf(out
, "no child config named '%s'\n", msg
->initiate
.name
);
170 peer_cfg
->destroy(peer_cfg
);
176 enumerator
= charon
->backends
->create_peer_cfg_enumerator(
177 charon
->backends
, NULL
, NULL
, NULL
, NULL
, IKE_ANY
);
178 while (enumerator
->enumerate(enumerator
, &peer_cfg
))
180 child_cfg
= get_child_from_peer(peer_cfg
, msg
->initiate
.name
);
183 peer_cfg
->get_ref(peer_cfg
);
187 enumerator
->destroy(enumerator
);
189 if (child_cfg
== NULL
)
191 DBG1(DBG_CFG
, "no config named '%s'", msg
->initiate
.name
);
192 fprintf(out
, "no config named '%s'\n", msg
->initiate
.name
);
196 charon_initiate(this, peer_cfg
, child_cfg
, msg
, out
);
200 * Parse a terminate/rekey specifier
202 static bool parse_specifier(char *string
, uint32_t *id
,
203 char **name
, bool *child
, bool *all
)
212 len
= strlen(string
);
217 switch (string
[len
-1])
221 pos
= strchr(string
, '{');
225 pos
= strchr(string
, '[');
235 /* is a single name */
237 else if (pos
== string
+ len
- 2)
238 { /* is name[] or name{} */
239 string
[len
-2] = '\0';
248 if (*(pos
+ 1) == '*')
255 { /* is name[123] or name{23} */
267 * Report the result of a terminate() call to console
269 static void report_terminate_status(private_stroke_control_t
*this,
270 status_t status
, FILE *out
, uint32_t id
, bool child
)
272 char *prefix
, *postfix
;
276 prefix
= "CHILD_SA {";
288 fprintf(out
, "%s%d%s closed successfully\n", prefix
, id
, postfix
);
291 fprintf(out
, "%s%d%s not closed after %dms, detaching\n",
292 prefix
, id
, postfix
, this->timeout
);
296 fprintf(out
, "closing %s%d%s failed\n", prefix
, id
, postfix
);
302 * Call the charon controller to terminate a CHILD_SA
304 static void charon_terminate(private_stroke_control_t
*this, uint32_t id
,
305 stroke_msg_t
*msg
, FILE *out
, bool child
)
307 if (msg
->output_verbosity
>= 0)
309 stroke_log_info_t info
= { msg
->output_verbosity
, out
};
314 status
= charon
->controller
->terminate_child(charon
->controller
, id
,
315 (controller_cb_t
)stroke_log
, &info
, this->timeout
);
319 status
= charon
->controller
->terminate_ike(charon
->controller
, id
,
320 FALSE
, (controller_cb_t
)stroke_log
, &info
,
323 report_terminate_status(this, status
, out
, id
, child
);
327 charon
->controller
->terminate_child(charon
->controller
, id
,
332 charon
->controller
->terminate_ike(charon
->controller
, id
, FALSE
,
337 METHOD(stroke_control_t
, terminate
, void,
338 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
344 enumerator_t
*enumerator
;
345 linked_list_t
*ike_list
, *child_list
;
348 if (!parse_specifier(msg
->terminate
.name
, &id
, &name
, &child
, &all
))
350 DBG1(DBG_CFG
, "error parsing specifier string");
356 return charon_terminate(this, id
, msg
, out
, child
);
359 ike_list
= linked_list_create();
360 child_list
= linked_list_create();
361 enumerator
= charon
->controller
->create_ike_sa_enumerator(
362 charon
->controller
, TRUE
);
363 while (enumerator
->enumerate(enumerator
, &ike_sa
))
365 child_sa_t
*child_sa
;
366 enumerator_t
*children
;
370 children
= ike_sa
->create_child_sa_enumerator(ike_sa
);
371 while (children
->enumerate(children
, (void**)&child_sa
))
373 if (streq(name
, child_sa
->get_name(child_sa
)))
375 child_list
->insert_last(child_list
,
376 (void*)(uintptr_t)child_sa
->get_unique_id(child_sa
));
383 children
->destroy(children
);
384 if (child_list
->get_count(child_list
) && !all
)
389 else if (streq(name
, ike_sa
->get_name(ike_sa
)))
391 ike_list
->insert_last(ike_list
,
392 (void*)(uintptr_t)ike_sa
->get_unique_id(ike_sa
));
399 enumerator
->destroy(enumerator
);
401 enumerator
= child_list
->create_enumerator(child_list
);
402 while (enumerator
->enumerate(enumerator
, &del
))
404 charon_terminate(this, del
, msg
, out
, TRUE
);
406 enumerator
->destroy(enumerator
);
408 enumerator
= ike_list
->create_enumerator(ike_list
);
409 while (enumerator
->enumerate(enumerator
, &del
))
411 charon_terminate(this, del
, msg
, out
, FALSE
);
413 enumerator
->destroy(enumerator
);
415 if (child_list
->get_count(child_list
) == 0 &&
416 ike_list
->get_count(ike_list
) == 0)
418 DBG1(DBG_CFG
, "no %s_SA named '%s' found",
419 child
? "CHILD" : "IKE", name
);
421 ike_list
->destroy(ike_list
);
422 child_list
->destroy(child_list
);
425 METHOD(stroke_control_t
, rekey
, void,
426 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
430 bool child
, all
, finished
= FALSE
;
432 enumerator_t
*enumerator
;
434 if (!parse_specifier(msg
->terminate
.name
, &id
, &name
, &child
, &all
))
436 DBG1(DBG_CFG
, "error parsing specifier string");
439 enumerator
= charon
->controller
->create_ike_sa_enumerator(
440 charon
->controller
, TRUE
);
441 while (enumerator
->enumerate(enumerator
, &ike_sa
))
443 child_sa_t
*child_sa
;
444 enumerator_t
*children
;
448 children
= ike_sa
->create_child_sa_enumerator(ike_sa
);
449 while (children
->enumerate(children
, (void**)&child_sa
))
451 if ((name
&& streq(name
, child_sa
->get_name(child_sa
))) ||
452 (id
&& id
== child_sa
->get_unique_id(child_sa
)))
454 lib
->processor
->queue_job(lib
->processor
,
455 (job_t
*)rekey_child_sa_job_create(
456 child_sa
->get_protocol(child_sa
),
457 child_sa
->get_spi(child_sa
, TRUE
),
458 ike_sa
->get_my_host(ike_sa
)));
466 children
->destroy(children
);
468 else if ((name
&& streq(name
, ike_sa
->get_name(ike_sa
))) ||
469 (id
&& id
== ike_sa
->get_unique_id(ike_sa
)))
471 lib
->processor
->queue_job(lib
->processor
,
472 (job_t
*)rekey_ike_sa_job_create(ike_sa
->get_id(ike_sa
), FALSE
));
483 enumerator
->destroy(enumerator
);
486 METHOD(stroke_control_t
, terminate_srcip
, void,
487 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
489 enumerator_t
*enumerator
, *vips
;
491 host_t
*start
= NULL
, *end
= NULL
, *vip
;
492 chunk_t chunk_start
, chunk_end
= chunk_empty
, chunk
;
494 if (msg
->terminate_srcip
.start
)
496 start
= host_create_from_string(msg
->terminate_srcip
.start
, 0);
500 DBG1(DBG_CFG
, "invalid start address: %s", msg
->terminate_srcip
.start
);
503 chunk_start
= start
->get_address(start
);
504 if (msg
->terminate_srcip
.end
)
506 end
= host_create_from_string(msg
->terminate_srcip
.end
, 0);
509 DBG1(DBG_CFG
, "invalid end address: %s", msg
->terminate_srcip
.end
);
510 start
->destroy(start
);
513 chunk_end
= end
->get_address(end
);
516 enumerator
= charon
->controller
->create_ike_sa_enumerator(
517 charon
->controller
, TRUE
);
518 while (enumerator
->enumerate(enumerator
, &ike_sa
))
522 vips
= ike_sa
->create_virtual_ip_enumerator(ike_sa
, FALSE
);
523 while (vips
->enumerate(vips
, &vip
))
527 if (vip
->ip_equals(vip
, start
))
535 chunk
= vip
->get_address(vip
);
536 if (chunk
.len
== chunk_start
.len
&&
537 chunk
.len
== chunk_end
.len
&&
538 memcmp(chunk
.ptr
, chunk_start
.ptr
, chunk
.len
) >= 0 &&
539 memcmp(chunk
.ptr
, chunk_end
.ptr
, chunk
.len
) <= 0)
550 /* schedule delete asynchronously */
551 lib
->processor
->queue_job(lib
->processor
, (job_t
*)
552 delete_ike_sa_job_create(ike_sa
->get_id(ike_sa
), TRUE
));
555 enumerator
->destroy(enumerator
);
556 start
->destroy(start
);
560 METHOD(stroke_control_t
, purge_ike
, void,
561 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
563 enumerator_t
*enumerator
, *children
;
565 child_sa_t
*child_sa
;
569 list
= linked_list_create();
570 enumerator
= charon
->controller
->create_ike_sa_enumerator(
571 charon
->controller
, TRUE
);
572 while (enumerator
->enumerate(enumerator
, &ike_sa
))
574 children
= ike_sa
->create_child_sa_enumerator(ike_sa
);
575 if (!children
->enumerate(children
, (void**)&child_sa
))
577 list
->insert_last(list
,
578 (void*)(uintptr_t)ike_sa
->get_unique_id(ike_sa
));
580 children
->destroy(children
);
582 enumerator
->destroy(enumerator
);
584 enumerator
= list
->create_enumerator(list
);
585 while (enumerator
->enumerate(enumerator
, &del
))
587 charon_terminate(this, del
, msg
, out
, FALSE
);
589 enumerator
->destroy(enumerator
);
594 * call charon to install a shunt or trap
596 static void charon_route(peer_cfg_t
*peer_cfg
, child_cfg_t
*child_cfg
,
597 char *name
, FILE *out
)
601 mode
= child_cfg
->get_mode(child_cfg
);
602 if (mode
== MODE_PASS
|| mode
== MODE_DROP
)
604 if (charon
->shunts
->install(charon
->shunts
,
605 peer_cfg
->get_name(peer_cfg
), child_cfg
))
607 fprintf(out
, "'%s' shunt %N policy installed\n",
608 name
, ipsec_mode_names
, mode
);
612 fprintf(out
, "'%s' shunt %N policy installation failed\n",
613 name
, ipsec_mode_names
, mode
);
618 if (charon
->traps
->install(charon
->traps
, peer_cfg
, child_cfg
))
620 fprintf(out
, "'%s' routed\n", name
);
624 fprintf(out
, "routing '%s' failed\n", name
);
629 METHOD(stroke_control_t
, route
, void,
630 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
632 child_cfg_t
*child_cfg
= NULL
;
633 peer_cfg_t
*peer_cfg
;
634 enumerator_t
*enumerator
;
637 peer_cfg
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
,
641 child_cfg
= get_child_from_peer(peer_cfg
, msg
->route
.name
);
642 if (child_cfg
== NULL
)
644 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
645 while (enumerator
->enumerate(enumerator
, &child_cfg
))
648 charon_route(peer_cfg
, child_cfg
, child_cfg
->get_name(child_cfg
),
651 enumerator
->destroy(enumerator
);
655 DBG1(DBG_CFG
, "no child config named '%s'", msg
->route
.name
);
656 fprintf(out
, "no child config named '%s'\n", msg
->route
.name
);
658 peer_cfg
->destroy(peer_cfg
);
664 enumerator
= charon
->backends
->create_peer_cfg_enumerator(
665 charon
->backends
, NULL
, NULL
, NULL
, NULL
, IKE_ANY
);
666 while (enumerator
->enumerate(enumerator
, &peer_cfg
))
668 child_cfg
= get_child_from_peer(peer_cfg
, msg
->route
.name
);
671 peer_cfg
->get_ref(peer_cfg
);
675 enumerator
->destroy(enumerator
);
677 if (child_cfg
== NULL
)
679 DBG1(DBG_CFG
, "no config named '%s'", msg
->route
.name
);
680 fprintf(out
, "no config named '%s'\n", msg
->route
.name
);
684 charon_route(peer_cfg
, child_cfg
, msg
->route
.name
, out
);
685 peer_cfg
->destroy(peer_cfg
);
686 child_cfg
->destroy(child_cfg
);
689 METHOD(stroke_control_t
, unroute
, void,
690 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
692 if (charon
->shunts
->uninstall(charon
->shunts
, NULL
, msg
->unroute
.name
))
694 fprintf(out
, "shunt policy '%s' uninstalled\n", msg
->unroute
.name
);
696 else if (charon
->traps
->uninstall(charon
->traps
, NULL
, msg
->unroute
.name
))
698 fprintf(out
, "trap policy '%s' unrouted\n", msg
->unroute
.name
);
702 fprintf(out
, "configuration '%s' not found\n", msg
->unroute
.name
);
706 METHOD(stroke_control_t
, destroy
, void,
707 private_stroke_control_t
*this)
715 stroke_control_t
*stroke_control_create()
717 private_stroke_control_t
*this;
721 .initiate
= _initiate
,
722 .terminate
= _terminate
,
723 .terminate_srcip
= _terminate_srcip
,
725 .purge_ike
= _purge_ike
,
730 .timeout
= lib
->settings
->get_int(lib
->settings
,
731 "%s.plugins.stroke.timeout", 0, lib
->ns
),
734 return &this->public;