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 */
55 * Log using vici event messages
57 static bool log_vici(log_info_t
*info
, debug_t group
, level_t level
,
58 ike_sa_t
*ike_sa
, char *text
)
60 if (level
<= info
->level
)
62 vici_message_t
*message
;
63 vici_builder_t
*builder
;
65 builder
= vici_builder_create();
66 builder
->add_kv(builder
, "group", "%N", debug_names
, group
);
67 builder
->add_kv(builder
, "level", "%d", level
);
70 builder
->add_kv(builder
, "ikesa-name", "%s",
71 ike_sa
->get_name(ike_sa
));
72 builder
->add_kv(builder
, "ikesa-uniqueid", "%u",
73 ike_sa
->get_unique_id(ike_sa
));
75 builder
->add_kv(builder
, "msg", "%s", text
);
77 message
= builder
->finalize(builder
);
80 info
->dispatcher
->raise_event(info
->dispatcher
, "control-log",
88 * Send a (error) reply message
90 static vici_message_t
* send_reply(private_vici_control_t
*this, char *fmt
, ...)
92 vici_builder_t
*builder
;
95 builder
= vici_builder_create();
96 builder
->add_kv(builder
, "success", fmt ?
"no" : "yes");
100 builder
->vadd_kv(builder
, "errmsg", fmt
, args
);
103 return builder
->finalize(builder
);
107 * Get the child_cfg having name from peer_cfg
109 static child_cfg_t
* get_child_from_peer(peer_cfg_t
*peer_cfg
, char *name
)
111 child_cfg_t
*current
, *found
= NULL
;
112 enumerator_t
*enumerator
;
114 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
115 while (enumerator
->enumerate(enumerator
, ¤t
))
117 if (streq(current
->get_name(current
), name
))
120 found
->get_ref(found
);
124 enumerator
->destroy(enumerator
);
128 CALLBACK(initiate
, vici_message_t
*,
129 private_vici_control_t
*this, char *name
, u_int id
, vici_message_t
*request
)
131 child_cfg_t
*child_cfg
= NULL
;
132 peer_cfg_t
*peer_cfg
;
133 enumerator_t
*enumerator
;
137 .dispatcher
= this->dispatcher
,
141 child
= request
->get_str(request
, NULL
, "child");
142 timeout
= request
->get_int(request
, 0, "timeout");
143 log
.level
= request
->get_int(request
, 1, "loglevel");
147 return send_reply(this, "missing configuration name");
149 enumerator
= charon
->backends
->create_peer_cfg_enumerator(charon
->backends
,
150 NULL
, NULL
, NULL
, NULL
, IKE_ANY
);
151 while (enumerator
->enumerate(enumerator
, &peer_cfg
))
153 child_cfg
= get_child_from_peer(peer_cfg
, child
);
156 peer_cfg
->get_ref(peer_cfg
);
160 enumerator
->destroy(enumerator
);
164 return send_reply(this, "CHILD_SA config '%s' not found", child
);
166 switch (charon
->controller
->initiate(charon
->controller
,
167 peer_cfg
, child_cfg
, (controller_cb_t
)log_vici
, &log
, timeout
))
170 return send_reply(this, NULL
);
172 return send_reply(this, "CHILD_SA '%s' not established after %dms",
176 return send_reply(this, "establishing CHILD_SA '%s' failed", child
);
180 CALLBACK(terminate
, vici_message_t
*,
181 private_vici_control_t
*this, char *name
, u_int id
, vici_message_t
*request
)
183 enumerator_t
*enumerator
, *isas
, *csas
;
185 u_int timeout
, child_id
, ike_id
, current
, *del
, done
= 0;
187 child_sa_t
*child_sa
;
189 vici_message_t
*reply
;
191 .dispatcher
= this->dispatcher
,
195 child
= request
->get_str(request
, NULL
, "child");
196 ike
= request
->get_str(request
, NULL
, "ike");
197 child_id
= request
->get_int(request
, 0, "child-id");
198 ike_id
= request
->get_int(request
, 0, "ike-id");
199 timeout
= request
->get_int(request
, 0, "timeout");
200 log
.level
= request
->get_int(request
, 1, "loglevel");
202 if (!child
&& !ike
&& !ike_id
&& !child_id
)
204 return send_reply(this, "missing terminate selector");
207 ids
= array_create(sizeof(u_int
), 0);
209 isas
= charon
->controller
->create_ike_sa_enumerator(charon
->controller
, TRUE
);
210 while (isas
->enumerate(isas
, &ike_sa
))
212 if (child
|| child_id
)
214 if (ike
&& !streq(ike
, ike_sa
->get_name(ike_sa
)))
218 if (ike_id
&& ike_id
!= ike_sa
->get_unique_id(ike_sa
))
222 csas
= ike_sa
->create_child_sa_enumerator(ike_sa
);
223 while (csas
->enumerate(csas
, &child_sa
))
225 if (child
&& !streq(child
, child_sa
->get_name(child_sa
)))
229 if (child_id
&& child_sa
->get_reqid(child_sa
) != child_id
)
233 current
= child_sa
->get_reqid(child_sa
);
234 array_insert(ids
, ARRAY_TAIL
, ¤t
);
238 else if (ike
&& streq(ike
, ike_sa
->get_name(ike_sa
)))
240 current
= ike_sa
->get_unique_id(ike_sa
);
241 array_insert(ids
, ARRAY_TAIL
, ¤t
);
243 else if (ike_id
&& ike_id
== ike_sa
->get_unique_id(ike_sa
))
245 array_insert(ids
, ARRAY_TAIL
, &ike_id
);
250 enumerator
= array_create_enumerator(ids
);
251 while (enumerator
->enumerate(enumerator
, &del
))
253 if (child
|| child_id
)
255 if (charon
->controller
->terminate_child(charon
->controller
, *del
,
256 (controller_cb_t
)log_vici
, &log
, timeout
) == SUCCESS
)
263 if (charon
->controller
->terminate_ike(charon
->controller
, *del
,
264 (controller_cb_t
)log_vici
, &log
, timeout
) == SUCCESS
)
270 enumerator
->destroy(enumerator
);
272 if (array_count(ids
) == 0)
274 reply
= send_reply(this, "no matching SAs to terminate found");
276 else if (done
< array_count(ids
))
278 if (array_count(ids
) == 1)
280 reply
= send_reply(this, "terminating SA failed");
284 reply
= send_reply(this, "terminated %u of %u SAs",
285 done
, array_count(ids
));
290 reply
= send_reply(this, NULL
);
296 static void manage_command(private_vici_control_t
*this,
297 char *name
, vici_command_cb_t cb
, bool reg
)
299 this->dispatcher
->manage_command(this->dispatcher
, name
,
300 reg ? cb
: NULL
, this);
304 * (Un-)register dispatcher functions
306 static void manage_commands(private_vici_control_t
*this, bool reg
)
308 manage_command(this, "initiate", initiate
, reg
);
309 manage_command(this, "terminate", terminate
, reg
);
310 this->dispatcher
->manage_event(this->dispatcher
, "control-log", reg
);
313 METHOD(vici_control_t
, destroy
, void,
314 private_vici_control_t
*this)
316 manage_commands(this, FALSE
);
323 vici_control_t
*vici_control_create(vici_dispatcher_t
*dispatcher
)
325 private_vici_control_t
*this;
331 .dispatcher
= dispatcher
,
334 manage_commands(this, TRUE
);
336 return &this->public;