2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
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 "vici_control.h"
17 #include "vici_builder.h"
22 #include <collections/array.h>
24 typedef struct private_vici_control_t private_vici_control_t
;
27 * Private data of an vici_control_t object.
29 struct private_vici_control_t
{
32 * Public vici_control_t interface.
34 vici_control_t
public;
39 vici_dispatcher_t
*dispatcher
;
43 * Log callback helper data
46 /** dispatcher to send log messages over */
47 vici_dispatcher_t
*dispatcher
;
48 /** connection ID to send messages to */
52 /** prevent recursive log */
57 * Log using vici event messages
59 static bool log_vici(log_info_t
*info
, debug_t group
, level_t level
,
60 ike_sa_t
*ike_sa
, char *text
)
62 if (level
<= info
->level
)
64 if (info
->recursive
++ == 0)
66 vici_message_t
*message
;
67 vici_builder_t
*builder
;
69 builder
= vici_builder_create();
70 builder
->add_kv(builder
, "group", "%N", debug_names
, group
);
71 builder
->add_kv(builder
, "level", "%d", level
);
74 builder
->add_kv(builder
, "ikesa-name", "%s",
75 ike_sa
->get_name(ike_sa
));
76 builder
->add_kv(builder
, "ikesa-uniqueid", "%u",
77 ike_sa
->get_unique_id(ike_sa
));
79 builder
->add_kv(builder
, "msg", "%s", text
);
81 message
= builder
->finalize(builder
);
84 info
->dispatcher
->raise_event(info
->dispatcher
, "control-log",
94 * Send a (error) reply message
96 static vici_message_t
* send_reply(private_vici_control_t
*this, char *fmt
, ...)
98 vici_builder_t
*builder
;
101 builder
= vici_builder_create();
102 builder
->add_kv(builder
, "success", fmt ?
"no" : "yes");
106 builder
->vadd_kv(builder
, "errmsg", fmt
, args
);
109 return builder
->finalize(builder
);
113 * Get the child_cfg having name from peer_cfg
115 static child_cfg_t
* get_child_from_peer(peer_cfg_t
*peer_cfg
, char *name
)
117 child_cfg_t
*current
, *found
= NULL
;
118 enumerator_t
*enumerator
;
120 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
121 while (enumerator
->enumerate(enumerator
, ¤t
))
123 if (streq(current
->get_name(current
), name
))
126 found
->get_ref(found
);
130 enumerator
->destroy(enumerator
);
134 CALLBACK(initiate
, vici_message_t
*,
135 private_vici_control_t
*this, char *name
, u_int id
, vici_message_t
*request
)
137 child_cfg_t
*child_cfg
= NULL
;
138 peer_cfg_t
*peer_cfg
;
139 enumerator_t
*enumerator
;
143 .dispatcher
= this->dispatcher
,
147 child
= request
->get_str(request
, NULL
, "child");
148 timeout
= request
->get_int(request
, 0, "timeout");
149 log
.level
= request
->get_int(request
, 1, "loglevel");
153 return send_reply(this, "missing configuration name");
155 enumerator
= charon
->backends
->create_peer_cfg_enumerator(charon
->backends
,
156 NULL
, NULL
, NULL
, NULL
, IKE_ANY
);
157 while (enumerator
->enumerate(enumerator
, &peer_cfg
))
159 child_cfg
= get_child_from_peer(peer_cfg
, child
);
162 peer_cfg
->get_ref(peer_cfg
);
166 enumerator
->destroy(enumerator
);
170 return send_reply(this, "CHILD_SA config '%s' not found", child
);
172 switch (charon
->controller
->initiate(charon
->controller
,
173 peer_cfg
, child_cfg
, (controller_cb_t
)log_vici
, &log
, timeout
))
176 return send_reply(this, NULL
);
178 return send_reply(this, "CHILD_SA '%s' not established after %dms",
182 return send_reply(this, "establishing CHILD_SA '%s' failed", child
);
186 CALLBACK(terminate
, vici_message_t
*,
187 private_vici_control_t
*this, char *name
, u_int id
, vici_message_t
*request
)
189 enumerator_t
*enumerator
, *isas
, *csas
;
191 u_int timeout
, child_id
, ike_id
, current
, *del
, done
= 0;
193 child_sa_t
*child_sa
;
195 vici_message_t
*reply
;
197 .dispatcher
= this->dispatcher
,
201 child
= request
->get_str(request
, NULL
, "child");
202 ike
= request
->get_str(request
, NULL
, "ike");
203 child_id
= request
->get_int(request
, 0, "child-id");
204 ike_id
= request
->get_int(request
, 0, "ike-id");
205 timeout
= request
->get_int(request
, 0, "timeout");
206 log
.level
= request
->get_int(request
, 1, "loglevel");
208 if (!child
&& !ike
&& !ike_id
&& !child_id
)
210 return send_reply(this, "missing terminate selector");
213 ids
= array_create(sizeof(u_int
), 0);
215 isas
= charon
->controller
->create_ike_sa_enumerator(charon
->controller
, TRUE
);
216 while (isas
->enumerate(isas
, &ike_sa
))
218 if (child
|| child_id
)
220 if (ike
&& !streq(ike
, ike_sa
->get_name(ike_sa
)))
224 if (ike_id
&& ike_id
!= ike_sa
->get_unique_id(ike_sa
))
228 csas
= ike_sa
->create_child_sa_enumerator(ike_sa
);
229 while (csas
->enumerate(csas
, &child_sa
))
231 if (child
&& !streq(child
, child_sa
->get_name(child_sa
)))
235 if (child_id
&& child_sa
->get_reqid(child_sa
) != child_id
)
239 current
= child_sa
->get_reqid(child_sa
);
240 array_insert(ids
, ARRAY_TAIL
, ¤t
);
244 else if (ike
&& streq(ike
, ike_sa
->get_name(ike_sa
)))
246 current
= ike_sa
->get_unique_id(ike_sa
);
247 array_insert(ids
, ARRAY_TAIL
, ¤t
);
249 else if (ike_id
&& ike_id
== ike_sa
->get_unique_id(ike_sa
))
251 array_insert(ids
, ARRAY_TAIL
, &ike_id
);
256 enumerator
= array_create_enumerator(ids
);
257 while (enumerator
->enumerate(enumerator
, &del
))
259 if (child
|| child_id
)
261 if (charon
->controller
->terminate_child(charon
->controller
, *del
,
262 (controller_cb_t
)log_vici
, &log
, timeout
) == SUCCESS
)
269 if (charon
->controller
->terminate_ike(charon
->controller
, *del
,
270 (controller_cb_t
)log_vici
, &log
, timeout
) == SUCCESS
)
276 enumerator
->destroy(enumerator
);
278 if (array_count(ids
) == 0)
280 reply
= send_reply(this, "no matching SAs to terminate found");
282 else if (done
< array_count(ids
))
284 if (array_count(ids
) == 1)
286 reply
= send_reply(this, "terminating SA failed");
290 reply
= send_reply(this, "terminated %u of %u SAs",
291 done
, array_count(ids
));
296 reply
= send_reply(this, NULL
);
302 static void manage_command(private_vici_control_t
*this,
303 char *name
, vici_command_cb_t cb
, bool reg
)
305 this->dispatcher
->manage_command(this->dispatcher
, name
,
306 reg ? cb
: NULL
, this);
310 * (Un-)register dispatcher functions
312 static void manage_commands(private_vici_control_t
*this, bool reg
)
314 manage_command(this, "initiate", initiate
, reg
);
315 manage_command(this, "terminate", terminate
, reg
);
316 this->dispatcher
->manage_event(this->dispatcher
, "control-log", reg
);
319 METHOD(vici_control_t
, destroy
, void,
320 private_vici_control_t
*this)
322 manage_commands(this, FALSE
);
329 vici_control_t
*vici_control_create(vici_dispatcher_t
*dispatcher
)
331 private_vici_control_t
*this;
337 .dispatcher
= dispatcher
,
340 manage_commands(this, TRUE
);
342 return &this->public;