2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
16 #include "stroke_control.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>
23 typedef struct private_stroke_control_t private_stroke_control_t
;
26 * private data of stroke_control
28 struct private_stroke_control_t
{
33 stroke_control_t
public;
37 typedef struct stroke_log_info_t stroke_log_info_t
;
40 * helper struct to say what and where to log when using controller callback
42 struct stroke_log_info_t
{
56 * logging to the stroke interface
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
)
61 if (level
<= info
->level
)
63 if (vfprintf(info
->out
, format
, args
) < 0 ||
64 fprintf(info
->out
, "\n") < 0 ||
65 fflush(info
->out
) != 0)
74 * get the child_cfg with the same name as the peer cfg
76 static child_cfg_t
* get_child_from_peer(peer_cfg_t
*peer_cfg
, char *name
)
78 child_cfg_t
*current
, *found
= NULL
;
79 enumerator_t
*enumerator
;
81 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
82 while (enumerator
->enumerate(enumerator
, ¤t
))
84 if (streq(current
->get_name(current
), name
))
87 found
->get_ref(found
);
91 enumerator
->destroy(enumerator
);
96 * call the charon controller to initiate the connection
98 static void charon_initiate(peer_cfg_t
*peer_cfg
, child_cfg_t
*child_cfg
,
99 stroke_msg_t
*msg
, FILE *out
)
101 if (msg
->output_verbosity
< 0)
103 charon
->controller
->initiate(charon
->controller
, peer_cfg
, child_cfg
,
108 stroke_log_info_t info
= { msg
->output_verbosity
, out
};
110 charon
->controller
->initiate(charon
->controller
, peer_cfg
, child_cfg
,
111 (controller_cb_t
)stroke_log
, &info
);
115 METHOD(stroke_control_t
, initiate
, void,
116 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
118 child_cfg_t
*child_cfg
= NULL
;
119 peer_cfg_t
*peer_cfg
;
120 enumerator_t
*enumerator
;
123 peer_cfg
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
,
127 if (peer_cfg
->get_ike_version(peer_cfg
) != 2)
129 DBG1(DBG_CFG
, "ignoring initiation request for IKEv%d config",
130 peer_cfg
->get_ike_version(peer_cfg
));
131 peer_cfg
->destroy(peer_cfg
);
135 child_cfg
= get_child_from_peer(peer_cfg
, msg
->initiate
.name
);
136 if (child_cfg
== NULL
)
138 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
139 while (enumerator
->enumerate(enumerator
, &child_cfg
))
142 charon_initiate(peer_cfg
->get_ref(peer_cfg
),
143 child_cfg
->get_ref(child_cfg
), msg
, out
);
145 enumerator
->destroy(enumerator
);
149 DBG1(DBG_CFG
, "no child config named '%s'", msg
->initiate
.name
);
150 fprintf(out
, "no child config named '%s'\n", msg
->initiate
.name
);
152 peer_cfg
->destroy(peer_cfg
);
158 enumerator
= charon
->backends
->create_peer_cfg_enumerator(charon
->backends
,
159 NULL
, NULL
, NULL
, NULL
);
160 while (enumerator
->enumerate(enumerator
, &peer_cfg
))
162 if (peer_cfg
->get_ike_version(peer_cfg
) != 2)
166 child_cfg
= get_child_from_peer(peer_cfg
, msg
->initiate
.name
);
169 peer_cfg
->get_ref(peer_cfg
);
173 enumerator
->destroy(enumerator
);
175 if (child_cfg
== NULL
)
177 DBG1(DBG_CFG
, "no config named '%s'", msg
->initiate
.name
);
178 fprintf(out
, "no config named '%s'\n", msg
->initiate
.name
);
182 charon_initiate(peer_cfg
, child_cfg
, msg
, out
);
186 * Parse a terminate/rekey specifier
188 static bool parse_specifier(char *string
, u_int32_t
*id
,
189 char **name
, bool *child
, bool *all
)
198 len
= strlen(string
);
203 switch (string
[len
-1])
207 pos
= strchr(string
, '{');
211 pos
= strchr(string
, '[');
221 /* is a single name */
223 else if (pos
== string
+ len
- 2)
224 { /* is name[] or name{} */
225 string
[len
-2] = '\0';
234 if (*(pos
+ 1) == '*')
241 { /* is name[123] or name{23} */
252 METHOD(stroke_control_t
, terminate
, void,
253 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
259 enumerator_t
*enumerator
;
260 linked_list_t
*ike_list
, *child_list
;
261 stroke_log_info_t info
;
264 if (!parse_specifier(msg
->terminate
.name
, &id
, &name
, &child
, &all
))
266 DBG1(DBG_CFG
, "error parsing specifier string");
271 info
.level
= msg
->output_verbosity
;
277 charon
->controller
->terminate_child(charon
->controller
, id
,
278 (controller_cb_t
)stroke_log
, &info
);
282 charon
->controller
->terminate_ike(charon
->controller
, id
,
283 (controller_cb_t
)stroke_log
, &info
);
288 ike_list
= linked_list_create();
289 child_list
= linked_list_create();
290 enumerator
= charon
->controller
->create_ike_sa_enumerator(
291 charon
->controller
, TRUE
);
292 while (enumerator
->enumerate(enumerator
, &ike_sa
))
294 child_sa_t
*child_sa
;
295 iterator_t
*children
;
299 children
= ike_sa
->create_child_sa_iterator(ike_sa
);
300 while (children
->iterate(children
, (void**)&child_sa
))
302 if (streq(name
, child_sa
->get_name(child_sa
)))
304 child_list
->insert_last(child_list
,
305 (void*)(uintptr_t)child_sa
->get_reqid(child_sa
));
312 children
->destroy(children
);
313 if (child_list
->get_count(child_list
) && !all
)
318 else if (streq(name
, ike_sa
->get_name(ike_sa
)))
320 ike_list
->insert_last(ike_list
,
321 (void*)(uintptr_t)ike_sa
->get_unique_id(ike_sa
));
328 enumerator
->destroy(enumerator
);
330 enumerator
= child_list
->create_enumerator(child_list
);
331 while (enumerator
->enumerate(enumerator
, &del
))
333 charon
->controller
->terminate_child(charon
->controller
, del
,
334 (controller_cb_t
)stroke_log
, &info
);
336 enumerator
->destroy(enumerator
);
338 enumerator
= ike_list
->create_enumerator(ike_list
);
339 while (enumerator
->enumerate(enumerator
, &del
))
341 charon
->controller
->terminate_ike(charon
->controller
, del
,
342 (controller_cb_t
)stroke_log
, &info
);
344 enumerator
->destroy(enumerator
);
346 if (child_list
->get_count(child_list
) == 0 &&
347 ike_list
->get_count(ike_list
) == 0)
349 DBG1(DBG_CFG
, "no %s_SA named '%s' found",
350 child ?
"CHILD" : "IKE", name
);
352 ike_list
->destroy(ike_list
);
353 child_list
->destroy(child_list
);
356 METHOD(stroke_control_t
, rekey
, void,
357 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
361 bool child
, all
, finished
= FALSE
;
363 enumerator_t
*enumerator
;
365 if (!parse_specifier(msg
->terminate
.name
, &id
, &name
, &child
, &all
))
367 DBG1(DBG_CFG
, "error parsing specifier string");
370 enumerator
= charon
->controller
->create_ike_sa_enumerator(
371 charon
->controller
, TRUE
);
372 while (enumerator
->enumerate(enumerator
, &ike_sa
))
374 child_sa_t
*child_sa
;
375 iterator_t
*children
;
379 children
= ike_sa
->create_child_sa_iterator(ike_sa
);
380 while (children
->iterate(children
, (void**)&child_sa
))
382 if ((name
&& streq(name
, child_sa
->get_name(child_sa
))) ||
383 (id
&& id
== child_sa
->get_reqid(child_sa
)))
385 lib
->processor
->queue_job(lib
->processor
,
386 (job_t
*)rekey_child_sa_job_create(
387 child_sa
->get_reqid(child_sa
),
388 child_sa
->get_protocol(child_sa
),
389 child_sa
->get_spi(child_sa
, TRUE
)));
397 children
->destroy(children
);
399 else if ((name
&& streq(name
, ike_sa
->get_name(ike_sa
))) ||
400 (id
&& id
== ike_sa
->get_unique_id(ike_sa
)))
402 lib
->processor
->queue_job(lib
->processor
,
403 (job_t
*)rekey_ike_sa_job_create(ike_sa
->get_id(ike_sa
), FALSE
));
414 enumerator
->destroy(enumerator
);
417 METHOD(stroke_control_t
, terminate_srcip
, void,
418 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
420 enumerator_t
*enumerator
;
422 host_t
*start
= NULL
, *end
= NULL
, *vip
;
423 chunk_t chunk_start
, chunk_end
= chunk_empty
, chunk_vip
;
425 if (msg
->terminate_srcip
.start
)
427 start
= host_create_from_string(msg
->terminate_srcip
.start
, 0);
431 DBG1(DBG_CFG
, "invalid start address: %s", msg
->terminate_srcip
.start
);
434 chunk_start
= start
->get_address(start
);
435 if (msg
->terminate_srcip
.end
)
437 end
= host_create_from_string(msg
->terminate_srcip
.end
, 0);
440 DBG1(DBG_CFG
, "invalid end address: %s", msg
->terminate_srcip
.end
);
441 start
->destroy(start
);
444 chunk_end
= end
->get_address(end
);
447 enumerator
= charon
->controller
->create_ike_sa_enumerator(
448 charon
->controller
, TRUE
);
449 while (enumerator
->enumerate(enumerator
, &ike_sa
))
451 vip
= ike_sa
->get_virtual_ip(ike_sa
, FALSE
);
458 if (!vip
->ip_equals(vip
, start
))
465 chunk_vip
= vip
->get_address(vip
);
466 if (chunk_vip
.len
!= chunk_start
.len
||
467 chunk_vip
.len
!= chunk_end
.len
||
468 memcmp(chunk_vip
.ptr
, chunk_start
.ptr
, chunk_vip
.len
) < 0 ||
469 memcmp(chunk_vip
.ptr
, chunk_end
.ptr
, chunk_vip
.len
) > 0)
475 /* schedule delete asynchronously */
476 lib
->processor
->queue_job(lib
->processor
, (job_t
*)
477 delete_ike_sa_job_create(ike_sa
->get_id(ike_sa
), TRUE
));
479 enumerator
->destroy(enumerator
);
480 start
->destroy(start
);
484 METHOD(stroke_control_t
, purge_ike
, void,
485 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
487 enumerator_t
*enumerator
;
488 iterator_t
*iterator
;
490 child_sa_t
*child_sa
;
493 stroke_log_info_t info
;
496 info
.level
= msg
->output_verbosity
;
498 list
= linked_list_create();
499 enumerator
= charon
->controller
->create_ike_sa_enumerator(
500 charon
->controller
, TRUE
);
501 while (enumerator
->enumerate(enumerator
, &ike_sa
))
503 iterator
= ike_sa
->create_child_sa_iterator(ike_sa
);
504 if (!iterator
->iterate(iterator
, (void**)&child_sa
))
506 list
->insert_last(list
,
507 (void*)(uintptr_t)ike_sa
->get_unique_id(ike_sa
));
509 iterator
->destroy(iterator
);
511 enumerator
->destroy(enumerator
);
513 enumerator
= list
->create_enumerator(list
);
514 while (enumerator
->enumerate(enumerator
, &del
))
516 charon
->controller
->terminate_ike(charon
->controller
, del
,
517 (controller_cb_t
)stroke_log
, &info
);
519 enumerator
->destroy(enumerator
);
524 * call charon to install a trap
526 static void charon_route(peer_cfg_t
*peer_cfg
, child_cfg_t
*child_cfg
,
527 char *name
, FILE *out
)
529 if (charon
->traps
->install(charon
->traps
, peer_cfg
, child_cfg
))
531 fprintf(out
, "'%s' routed\n", name
);
535 fprintf(out
, "routing '%s' failed\n", name
);
539 METHOD(stroke_control_t
, route
, void,
540 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
542 child_cfg_t
*child_cfg
= NULL
;
543 peer_cfg_t
*peer_cfg
;
544 enumerator_t
*enumerator
;
547 peer_cfg
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
,
551 if (peer_cfg
->get_ike_version(peer_cfg
) != 2)
553 DBG1(DBG_CFG
, "ignoring initiation request for IKEv%d config",
554 peer_cfg
->get_ike_version(peer_cfg
));
555 peer_cfg
->destroy(peer_cfg
);
559 child_cfg
= get_child_from_peer(peer_cfg
, msg
->route
.name
);
560 if (child_cfg
== NULL
)
562 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
563 while (enumerator
->enumerate(enumerator
, &child_cfg
))
566 charon_route(peer_cfg
, child_cfg
, child_cfg
->get_name(child_cfg
),
569 enumerator
->destroy(enumerator
);
573 DBG1(DBG_CFG
, "no child config named '%s'", msg
->route
.name
);
574 fprintf(out
, "no child config named '%s'\n", msg
->route
.name
);
576 peer_cfg
->destroy(peer_cfg
);
582 enumerator
= charon
->backends
->create_peer_cfg_enumerator(charon
->backends
,
583 NULL
, NULL
, NULL
, NULL
);
584 while (enumerator
->enumerate(enumerator
, &peer_cfg
))
586 if (peer_cfg
->get_ike_version(peer_cfg
) != 2)
590 child_cfg
= get_child_from_peer(peer_cfg
, msg
->route
.name
);
593 peer_cfg
->get_ref(peer_cfg
);
597 enumerator
->destroy(enumerator
);
599 if (child_cfg
== NULL
)
601 DBG1(DBG_CFG
, "no config named '%s'", msg
->route
.name
);
602 fprintf(out
, "no config named '%s'\n", msg
->route
.name
);
606 charon_route(peer_cfg
, child_cfg
, msg
->route
.name
, out
);
607 peer_cfg
->destroy(peer_cfg
);
608 child_cfg
->destroy(child_cfg
);
611 METHOD(stroke_control_t
, unroute
, void,
612 private_stroke_control_t
*this, stroke_msg_t
*msg
, FILE *out
)
614 child_sa_t
*child_sa
;
615 enumerator_t
*enumerator
;
618 enumerator
= charon
->traps
->create_enumerator(charon
->traps
);
619 while (enumerator
->enumerate(enumerator
, NULL
, &child_sa
))
621 if (streq(msg
->unroute
.name
, child_sa
->get_name(child_sa
)))
623 id
= child_sa
->get_reqid(child_sa
);
624 enumerator
->destroy(enumerator
);
625 charon
->traps
->uninstall(charon
->traps
, id
);
626 fprintf(out
, "configuration '%s' unrouted\n", msg
->unroute
.name
);
630 enumerator
->destroy(enumerator
);
631 fprintf(out
, "configuration '%s' not found\n", msg
->unroute
.name
);
634 METHOD(stroke_control_t
, destroy
, void,
635 private_stroke_control_t
*this)
643 stroke_control_t
*stroke_control_create()
645 private_stroke_control_t
*this;
649 .initiate
= _initiate
,
650 .terminate
= _terminate
,
651 .terminate_srcip
= _terminate_srcip
,
653 .purge_ike
= _purge_ike
,
660 return &this->public;