]>
Commit | Line | Data |
---|---|---|
5f95657c | 1 | /* |
808472c9 TB |
2 | * Copyright (C) 2015-2017 Tobias Brunner |
3 | * HSR Hochschule fuer Technik Rapperswil | |
43b46b26 | 4 | * |
5f95657c MW |
5 | * Copyright (C) 2014 Martin Willi |
6 | * Copyright (C) 2014 revosec AG | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2 of the License, or (at your | |
11 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | * for more details. | |
17 | */ | |
18 | ||
19 | #include "vici_control.h" | |
20 | #include "vici_builder.h" | |
21 | ||
22 | #include <inttypes.h> | |
23 | ||
24 | #include <daemon.h> | |
c7d4dad6 | 25 | #include <collections/array.h> |
808472c9 TB |
26 | #include <processing/jobs/rekey_ike_sa_job.h> |
27 | #include <processing/jobs/rekey_child_sa_job.h> | |
43b46b26 | 28 | #include <processing/jobs/redirect_job.h> |
5f95657c MW |
29 | |
30 | typedef struct private_vici_control_t private_vici_control_t; | |
31 | ||
32 | /** | |
33 | * Private data of an vici_control_t object. | |
34 | */ | |
35 | struct private_vici_control_t { | |
36 | ||
37 | /** | |
38 | * Public vici_control_t interface. | |
39 | */ | |
40 | vici_control_t public; | |
41 | ||
42 | /** | |
43 | * Dispatcher | |
44 | */ | |
45 | vici_dispatcher_t *dispatcher; | |
46 | }; | |
47 | ||
48 | /** | |
49 | * Log callback helper data | |
50 | */ | |
51 | typedef struct { | |
52 | /** dispatcher to send log messages over */ | |
53 | vici_dispatcher_t *dispatcher; | |
54 | /** connection ID to send messages to */ | |
55 | u_int id; | |
56 | /** loglevel */ | |
57 | level_t level; | |
3b5808a0 MW |
58 | /** prevent recursive log */ |
59 | u_int recursive; | |
5f95657c MW |
60 | } log_info_t; |
61 | ||
62 | /** | |
63 | * Log using vici event messages | |
64 | */ | |
65 | static bool log_vici(log_info_t *info, debug_t group, level_t level, | |
66 | ike_sa_t *ike_sa, char *text) | |
67 | { | |
68 | if (level <= info->level) | |
69 | { | |
3b5808a0 | 70 | if (info->recursive++ == 0) |
5f95657c | 71 | { |
3b5808a0 MW |
72 | vici_message_t *message; |
73 | vici_builder_t *builder; | |
5f95657c | 74 | |
3b5808a0 MW |
75 | builder = vici_builder_create(); |
76 | builder->add_kv(builder, "group", "%N", debug_names, group); | |
77 | builder->add_kv(builder, "level", "%d", level); | |
78 | if (ike_sa) | |
79 | { | |
80 | builder->add_kv(builder, "ikesa-name", "%s", | |
81 | ike_sa->get_name(ike_sa)); | |
82 | builder->add_kv(builder, "ikesa-uniqueid", "%u", | |
83 | ike_sa->get_unique_id(ike_sa)); | |
84 | } | |
85 | builder->add_kv(builder, "msg", "%s", text); | |
86 | ||
87 | message = builder->finalize(builder); | |
88 | if (message) | |
89 | { | |
90 | info->dispatcher->raise_event(info->dispatcher, "control-log", | |
91 | info->id, message); | |
92 | } | |
5f95657c | 93 | } |
3b5808a0 | 94 | info->recursive--; |
5f95657c MW |
95 | } |
96 | return TRUE; | |
97 | } | |
98 | ||
99 | /** | |
100 | * Send a (error) reply message | |
101 | */ | |
102 | static vici_message_t* send_reply(private_vici_control_t *this, char *fmt, ...) | |
103 | { | |
104 | vici_builder_t *builder; | |
105 | va_list args; | |
106 | ||
107 | builder = vici_builder_create(); | |
108 | builder->add_kv(builder, "success", fmt ? "no" : "yes"); | |
109 | if (fmt) | |
110 | { | |
111 | va_start(args, fmt); | |
112 | builder->vadd_kv(builder, "errmsg", fmt, args); | |
113 | va_end(args); | |
114 | } | |
115 | return builder->finalize(builder); | |
116 | } | |
117 | ||
118 | /** | |
119 | * Get the child_cfg having name from peer_cfg | |
120 | */ | |
121 | static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name) | |
122 | { | |
123 | child_cfg_t *current, *found = NULL; | |
124 | enumerator_t *enumerator; | |
125 | ||
126 | enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); | |
127 | while (enumerator->enumerate(enumerator, ¤t)) | |
128 | { | |
129 | if (streq(current->get_name(current), name)) | |
130 | { | |
131 | found = current; | |
132 | found->get_ref(found); | |
133 | break; | |
134 | } | |
135 | } | |
136 | enumerator->destroy(enumerator); | |
137 | return found; | |
138 | } | |
139 | ||
550f3f56 MW |
140 | /** |
141 | * Find a peer/child config from a child config name | |
142 | */ | |
eaca77d0 | 143 | static child_cfg_t* find_child_cfg(char *name, char *pname, peer_cfg_t **out) |
550f3f56 MW |
144 | { |
145 | enumerator_t *enumerator; | |
146 | peer_cfg_t *peer_cfg; | |
69679482 | 147 | child_cfg_t *child_cfg = NULL; |
550f3f56 MW |
148 | |
149 | enumerator = charon->backends->create_peer_cfg_enumerator( | |
150 | charon->backends, NULL, NULL, NULL, NULL, IKE_ANY); | |
151 | while (enumerator->enumerate(enumerator, &peer_cfg)) | |
152 | { | |
eaca77d0 MW |
153 | if (pname && !streq(pname, peer_cfg->get_name(peer_cfg))) |
154 | { | |
155 | continue; | |
156 | } | |
550f3f56 MW |
157 | child_cfg = get_child_from_peer(peer_cfg, name); |
158 | if (child_cfg) | |
159 | { | |
160 | *out = peer_cfg->get_ref(peer_cfg); | |
161 | break; | |
162 | } | |
163 | } | |
164 | enumerator->destroy(enumerator); | |
165 | ||
166 | return child_cfg; | |
167 | } | |
168 | ||
5f95657c MW |
169 | CALLBACK(initiate, vici_message_t*, |
170 | private_vici_control_t *this, char *name, u_int id, vici_message_t *request) | |
171 | { | |
172 | child_cfg_t *child_cfg = NULL; | |
173 | peer_cfg_t *peer_cfg; | |
eaca77d0 | 174 | char *child, *ike; |
5e79ae2d | 175 | int timeout; |
256e666d | 176 | bool limits; |
5e79ae2d | 177 | controller_cb_t log_cb = NULL; |
5f95657c MW |
178 | log_info_t log = { |
179 | .dispatcher = this->dispatcher, | |
180 | .id = id, | |
181 | }; | |
182 | ||
183 | child = request->get_str(request, NULL, "child"); | |
eaca77d0 | 184 | ike = request->get_str(request, NULL, "ike"); |
5f95657c | 185 | timeout = request->get_int(request, 0, "timeout"); |
256e666d | 186 | limits = request->get_bool(request, FALSE, "init-limits"); |
5f95657c MW |
187 | log.level = request->get_int(request, 1, "loglevel"); |
188 | ||
189 | if (!child) | |
190 | { | |
191 | return send_reply(this, "missing configuration name"); | |
192 | } | |
5e79ae2d MW |
193 | if (timeout >= 0) |
194 | { | |
195 | log_cb = (controller_cb_t)log_vici; | |
196 | } | |
2676ffdb MW |
197 | |
198 | DBG1(DBG_CFG, "vici initiate '%s'", child); | |
199 | ||
eaca77d0 | 200 | child_cfg = find_child_cfg(child, ike, &peer_cfg); |
5f95657c MW |
201 | if (!child_cfg) |
202 | { | |
203 | return send_reply(this, "CHILD_SA config '%s' not found", child); | |
204 | } | |
ff0abde9 | 205 | switch (charon->controller->initiate(charon->controller, peer_cfg, |
5e79ae2d | 206 | child_cfg, log_cb, &log, timeout, limits)) |
5f95657c MW |
207 | { |
208 | case SUCCESS: | |
209 | return send_reply(this, NULL); | |
210 | case OUT_OF_RES: | |
211 | return send_reply(this, "CHILD_SA '%s' not established after %dms", | |
212 | child, timeout); | |
256e666d TB |
213 | case INVALID_STATE: |
214 | return send_reply(this, "establishing CHILD_SA '%s' not possible " | |
215 | "at the moment due to limits", child); | |
5f95657c MW |
216 | case FAILED: |
217 | default: | |
218 | return send_reply(this, "establishing CHILD_SA '%s' failed", child); | |
219 | } | |
220 | } | |
221 | ||
c7d4dad6 MW |
222 | CALLBACK(terminate, vici_message_t*, |
223 | private_vici_control_t *this, char *name, u_int id, vici_message_t *request) | |
224 | { | |
225 | enumerator_t *enumerator, *isas, *csas; | |
bc006ac1 | 226 | char *child, *ike, *errmsg = NULL; |
5e79ae2d | 227 | u_int child_id, ike_id, current, *del, done = 0; |
0bcfed1a | 228 | bool force; |
5e79ae2d | 229 | int timeout; |
c7d4dad6 MW |
230 | ike_sa_t *ike_sa; |
231 | child_sa_t *child_sa; | |
232 | array_t *ids; | |
bc006ac1 | 233 | vici_builder_t *builder; |
5e79ae2d | 234 | controller_cb_t log_cb = NULL; |
c7d4dad6 MW |
235 | log_info_t log = { |
236 | .dispatcher = this->dispatcher, | |
237 | .id = id, | |
238 | }; | |
239 | ||
240 | child = request->get_str(request, NULL, "child"); | |
241 | ike = request->get_str(request, NULL, "ike"); | |
242 | child_id = request->get_int(request, 0, "child-id"); | |
243 | ike_id = request->get_int(request, 0, "ike-id"); | |
0bcfed1a | 244 | force = request->get_bool(request, FALSE, "force"); |
c7d4dad6 MW |
245 | timeout = request->get_int(request, 0, "timeout"); |
246 | log.level = request->get_int(request, 1, "loglevel"); | |
247 | ||
248 | if (!child && !ike && !ike_id && !child_id) | |
249 | { | |
250 | return send_reply(this, "missing terminate selector"); | |
251 | } | |
252 | ||
2676ffdb MW |
253 | if (ike_id) |
254 | { | |
255 | DBG1(DBG_CFG, "vici terminate IKE_SA #%d", ike_id); | |
256 | } | |
257 | if (child_id) | |
258 | { | |
259 | DBG1(DBG_CFG, "vici terminate CHILD_SA #%d", child_id); | |
260 | } | |
261 | if (ike) | |
262 | { | |
263 | DBG1(DBG_CFG, "vici terminate IKE_SA '%s'", ike); | |
264 | } | |
265 | if (child) | |
266 | { | |
267 | DBG1(DBG_CFG, "vici terminate CHILD_SA '%s'", child); | |
268 | } | |
269 | ||
5e79ae2d MW |
270 | if (timeout >= 0) |
271 | { | |
272 | log_cb = (controller_cb_t)log_vici; | |
273 | } | |
274 | ||
c7d4dad6 MW |
275 | ids = array_create(sizeof(u_int), 0); |
276 | ||
277 | isas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE); | |
278 | while (isas->enumerate(isas, &ike_sa)) | |
279 | { | |
280 | if (child || child_id) | |
281 | { | |
282 | if (ike && !streq(ike, ike_sa->get_name(ike_sa))) | |
283 | { | |
284 | continue; | |
285 | } | |
286 | if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa)) | |
287 | { | |
288 | continue; | |
289 | } | |
290 | csas = ike_sa->create_child_sa_enumerator(ike_sa); | |
291 | while (csas->enumerate(csas, &child_sa)) | |
292 | { | |
293 | if (child && !streq(child, child_sa->get_name(child_sa))) | |
294 | { | |
295 | continue; | |
296 | } | |
971a9168 | 297 | if (child_id && child_sa->get_unique_id(child_sa) != child_id) |
c7d4dad6 MW |
298 | { |
299 | continue; | |
300 | } | |
971a9168 | 301 | current = child_sa->get_unique_id(child_sa); |
c7d4dad6 MW |
302 | array_insert(ids, ARRAY_TAIL, ¤t); |
303 | } | |
304 | csas->destroy(csas); | |
305 | } | |
306 | else if (ike && streq(ike, ike_sa->get_name(ike_sa))) | |
307 | { | |
308 | current = ike_sa->get_unique_id(ike_sa); | |
309 | array_insert(ids, ARRAY_TAIL, ¤t); | |
310 | } | |
311 | else if (ike_id && ike_id == ike_sa->get_unique_id(ike_sa)) | |
312 | { | |
313 | array_insert(ids, ARRAY_TAIL, &ike_id); | |
314 | } | |
315 | } | |
316 | isas->destroy(isas); | |
317 | ||
318 | enumerator = array_create_enumerator(ids); | |
319 | while (enumerator->enumerate(enumerator, &del)) | |
320 | { | |
321 | if (child || child_id) | |
322 | { | |
323 | if (charon->controller->terminate_child(charon->controller, *del, | |
5e79ae2d | 324 | log_cb, &log, timeout) == SUCCESS) |
c7d4dad6 MW |
325 | { |
326 | done++; | |
327 | } | |
328 | } | |
329 | else | |
330 | { | |
0bcfed1a | 331 | if (charon->controller->terminate_ike(charon->controller, *del, force, |
5e79ae2d | 332 | log_cb, &log, timeout) == SUCCESS) |
c7d4dad6 MW |
333 | { |
334 | done++; | |
335 | } | |
336 | } | |
337 | } | |
338 | enumerator->destroy(enumerator); | |
339 | ||
bc006ac1 | 340 | builder = vici_builder_create(); |
c7d4dad6 MW |
341 | if (array_count(ids) == 0) |
342 | { | |
bc006ac1 | 343 | errmsg = "no matching SAs to terminate found"; |
c7d4dad6 MW |
344 | } |
345 | else if (done < array_count(ids)) | |
346 | { | |
347 | if (array_count(ids) == 1) | |
348 | { | |
bc006ac1 | 349 | errmsg = "terminating SA failed"; |
c7d4dad6 MW |
350 | } |
351 | else | |
352 | { | |
bc006ac1 | 353 | errmsg = "not all matching SAs could be terminated"; |
c7d4dad6 MW |
354 | } |
355 | } | |
bc006ac1 MW |
356 | builder->add_kv(builder, "success", errmsg ? "no" : "yes"); |
357 | builder->add_kv(builder, "matches", "%u", array_count(ids)); | |
358 | builder->add_kv(builder, "terminated", "%u", done); | |
359 | if (errmsg) | |
c7d4dad6 | 360 | { |
bc006ac1 | 361 | builder->add_kv(builder, "errmsg", "%s", errmsg); |
c7d4dad6 MW |
362 | } |
363 | array_destroy(ids); | |
bc006ac1 | 364 | return builder->finalize(builder); |
c7d4dad6 MW |
365 | } |
366 | ||
808472c9 TB |
367 | CALLBACK(rekey, vici_message_t*, |
368 | private_vici_control_t *this, char *name, u_int id, vici_message_t *request) | |
369 | { | |
370 | enumerator_t *isas, *csas; | |
371 | char *child, *ike, *errmsg = NULL; | |
372 | u_int child_id, ike_id, found = 0; | |
373 | ike_sa_t *ike_sa; | |
374 | child_sa_t *child_sa; | |
375 | vici_builder_t *builder; | |
376 | ||
377 | child = request->get_str(request, NULL, "child"); | |
378 | ike = request->get_str(request, NULL, "ike"); | |
379 | child_id = request->get_int(request, 0, "child-id"); | |
380 | ike_id = request->get_int(request, 0, "ike-id"); | |
381 | ||
382 | if (!child && !ike && !ike_id && !child_id) | |
383 | { | |
384 | return send_reply(this, "missing rekey selector"); | |
385 | } | |
386 | ||
387 | if (ike_id) | |
388 | { | |
389 | DBG1(DBG_CFG, "vici rekey IKE_SA #%d", ike_id); | |
390 | } | |
391 | if (child_id) | |
392 | { | |
393 | DBG1(DBG_CFG, "vici rekey CHILD_SA #%d", child_id); | |
394 | } | |
395 | if (ike) | |
396 | { | |
397 | DBG1(DBG_CFG, "vici rekey IKE_SA '%s'", ike); | |
398 | } | |
399 | if (child) | |
400 | { | |
401 | DBG1(DBG_CFG, "vici rekey CHILD_SA '%s'", child); | |
402 | } | |
403 | ||
404 | isas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE); | |
405 | while (isas->enumerate(isas, &ike_sa)) | |
406 | { | |
407 | if (child || child_id) | |
408 | { | |
409 | if (ike && !streq(ike, ike_sa->get_name(ike_sa))) | |
410 | { | |
411 | continue; | |
412 | } | |
413 | if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa)) | |
414 | { | |
415 | continue; | |
416 | } | |
417 | csas = ike_sa->create_child_sa_enumerator(ike_sa); | |
418 | while (csas->enumerate(csas, &child_sa)) | |
419 | { | |
420 | if (child && !streq(child, child_sa->get_name(child_sa))) | |
421 | { | |
422 | continue; | |
423 | } | |
424 | if (child_id && child_sa->get_unique_id(child_sa) != child_id) | |
425 | { | |
426 | continue; | |
427 | } | |
428 | lib->processor->queue_job(lib->processor, | |
429 | (job_t*)rekey_child_sa_job_create( | |
430 | child_sa->get_protocol(child_sa), | |
431 | child_sa->get_spi(child_sa, TRUE), | |
432 | ike_sa->get_my_host(ike_sa))); | |
433 | found++; | |
434 | } | |
435 | csas->destroy(csas); | |
436 | } | |
437 | else if ((ike && streq(ike, ike_sa->get_name(ike_sa))) || | |
438 | (ike_id && ike_id == ike_sa->get_unique_id(ike_sa))) | |
439 | { | |
440 | lib->processor->queue_job(lib->processor, | |
441 | (job_t*)rekey_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE)); | |
442 | found++; | |
443 | } | |
444 | } | |
445 | isas->destroy(isas); | |
446 | ||
447 | builder = vici_builder_create(); | |
448 | if (!found) | |
449 | { | |
450 | errmsg = "no matching SAs to rekey found"; | |
451 | } | |
452 | builder->add_kv(builder, "success", errmsg ? "no" : "yes"); | |
453 | builder->add_kv(builder, "matches", "%u", found); | |
454 | if (errmsg) | |
455 | { | |
456 | builder->add_kv(builder, "errmsg", "%s", errmsg); | |
457 | } | |
458 | return builder->finalize(builder); | |
459 | } | |
460 | ||
27074f31 TB |
461 | /** |
462 | * Parse a peer-ip specified, which can be a subnet in CIDR notation, a range | |
463 | * or a single IP address. | |
464 | */ | |
465 | static traffic_selector_t *parse_peer_ip(char *ip) | |
466 | { | |
467 | traffic_selector_t *ts; | |
468 | host_t *from, *to; | |
469 | ts_type_t type; | |
470 | ||
471 | if (host_create_from_range(ip, &from, &to)) | |
472 | { | |
473 | if (to->get_family(to) == AF_INET) | |
474 | { | |
475 | type = TS_IPV4_ADDR_RANGE; | |
476 | } | |
477 | else | |
478 | { | |
479 | type = TS_IPV6_ADDR_RANGE; | |
480 | } | |
481 | ts = traffic_selector_create_from_bytes(0, type, | |
482 | from->get_address(from), 0, | |
483 | to->get_address(to), 0xFFFF); | |
484 | from->destroy(from); | |
485 | to->destroy(to); | |
486 | return ts; | |
487 | } | |
488 | return traffic_selector_create_from_cidr(ip, 0, 0, 0xFFFF); | |
489 | } | |
490 | ||
43b46b26 TB |
491 | CALLBACK(redirect, vici_message_t*, |
492 | private_vici_control_t *this, char *name, u_int id, vici_message_t *request) | |
493 | { | |
494 | enumerator_t *sas; | |
495 | char *ike, *peer_ip, *peer_id, *gw, *errmsg = NULL; | |
496 | u_int ike_id, current, found = 0; | |
bef4518d | 497 | identification_t *gateway, *identity = NULL, *other_id; |
27074f31 | 498 | traffic_selector_t *ts = NULL; |
43b46b26 TB |
499 | ike_sa_t *ike_sa; |
500 | vici_builder_t *builder; | |
501 | ||
502 | ike = request->get_str(request, NULL, "ike"); | |
503 | ike_id = request->get_int(request, 0, "ike-id"); | |
504 | peer_ip = request->get_str(request, NULL, "peer-ip"); | |
505 | peer_id = request->get_str(request, NULL, "peer-id"); | |
506 | gw = request->get_str(request, NULL, "gateway"); | |
507 | ||
508 | if (!gw || !(gateway = identification_create_from_string(gw))) | |
509 | { | |
510 | return send_reply(this, "missing target gateway"); | |
511 | } | |
512 | switch (gateway->get_type(gateway)) | |
513 | { | |
514 | case ID_IPV4_ADDR: | |
515 | case ID_IPV6_ADDR: | |
516 | case ID_FQDN: | |
517 | break; | |
518 | default: | |
519 | return send_reply(this, "unsupported gateway identity"); | |
520 | } | |
521 | if (peer_ip) | |
522 | { | |
27074f31 TB |
523 | ts = parse_peer_ip(peer_ip); |
524 | if (!ts) | |
43b46b26 TB |
525 | { |
526 | return send_reply(this, "invalid peer IP selector"); | |
527 | } | |
27074f31 | 528 | DBG1(DBG_CFG, "vici redirect IKE_SAs with src %R to %Y", ts, |
43b46b26 TB |
529 | gateway); |
530 | } | |
531 | if (peer_id) | |
532 | { | |
533 | identity = identification_create_from_string(peer_id); | |
534 | if (!identity) | |
535 | { | |
27074f31 | 536 | DESTROY_IF(ts); |
43b46b26 TB |
537 | return send_reply(this, "invalid peer identity selector"); |
538 | } | |
539 | DBG1(DBG_CFG, "vici redirect IKE_SAs with ID '%Y' to %Y", identity, | |
540 | gateway); | |
541 | } | |
542 | if (ike_id) | |
543 | { | |
27074f31 | 544 | DBG1(DBG_CFG, "vici redirect IKE_SA #%d to '%Y'", ike_id, gateway); |
43b46b26 TB |
545 | } |
546 | if (ike) | |
547 | { | |
27074f31 | 548 | DBG1(DBG_CFG, "vici redirect IKE_SA '%s' to '%Y'", ike, gateway); |
43b46b26 TB |
549 | } |
550 | if (!peer_ip && !peer_id && !ike && !ike_id) | |
551 | { | |
c13eb737 | 552 | return send_reply(this, "missing redirect selector"); |
43b46b26 TB |
553 | } |
554 | ||
555 | sas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE); | |
556 | while (sas->enumerate(sas, &ike_sa)) | |
557 | { | |
558 | if (ike_sa->get_version(ike_sa) != IKEV2) | |
559 | { | |
560 | continue; | |
561 | } | |
562 | current = ike_sa->get_unique_id(ike_sa); | |
563 | if (ike_id && ike_id != current) | |
564 | { | |
565 | continue; | |
566 | } | |
567 | if (ike && !streq(ike, ike_sa->get_name(ike_sa))) | |
568 | { | |
569 | continue; | |
570 | } | |
27074f31 | 571 | if (ts && !ts->includes(ts, ike_sa->get_other_host(ike_sa))) |
43b46b26 TB |
572 | { |
573 | continue; | |
574 | } | |
bef4518d | 575 | if (identity) |
43b46b26 | 576 | { |
bef4518d TB |
577 | other_id = ike_sa->get_other_eap_id(ike_sa); |
578 | if (!other_id->matches(other_id, identity)) | |
579 | { | |
580 | continue; | |
581 | } | |
43b46b26 TB |
582 | } |
583 | lib->processor->queue_job(lib->processor, | |
584 | (job_t*)redirect_job_create(ike_sa->get_id(ike_sa), gateway)); | |
585 | found++; | |
586 | } | |
587 | sas->destroy(sas); | |
588 | ||
589 | builder = vici_builder_create(); | |
590 | if (!found) | |
591 | { | |
592 | errmsg = "no matching SAs to redirect found"; | |
593 | } | |
594 | builder->add_kv(builder, "success", errmsg ? "no" : "yes"); | |
808472c9 | 595 | builder->add_kv(builder, "matches", "%u", found); |
43b46b26 TB |
596 | if (errmsg) |
597 | { | |
598 | builder->add_kv(builder, "errmsg", "%s", errmsg); | |
599 | } | |
600 | gateway->destroy(gateway); | |
601 | DESTROY_IF(identity); | |
27074f31 | 602 | DESTROY_IF(ts); |
43b46b26 TB |
603 | return builder->finalize(builder); |
604 | } | |
605 | ||
5c6e81dc MW |
606 | CALLBACK(install, vici_message_t*, |
607 | private_vici_control_t *this, char *name, u_int id, vici_message_t *request) | |
608 | { | |
609 | child_cfg_t *child_cfg = NULL; | |
610 | peer_cfg_t *peer_cfg; | |
eaca77d0 | 611 | char *child, *ike; |
5c6e81dc MW |
612 | bool ok; |
613 | ||
614 | child = request->get_str(request, NULL, "child"); | |
eaca77d0 | 615 | ike = request->get_str(request, NULL, "ike"); |
5c6e81dc MW |
616 | if (!child) |
617 | { | |
618 | return send_reply(this, "missing configuration name"); | |
619 | } | |
2676ffdb MW |
620 | |
621 | DBG1(DBG_CFG, "vici install '%s'", child); | |
622 | ||
eaca77d0 | 623 | child_cfg = find_child_cfg(child, ike, &peer_cfg); |
5c6e81dc MW |
624 | if (!child_cfg) |
625 | { | |
626 | return send_reply(this, "configuration name not found"); | |
627 | } | |
628 | switch (child_cfg->get_mode(child_cfg)) | |
629 | { | |
630 | case MODE_PASS: | |
631 | case MODE_DROP: | |
7627f5f9 TB |
632 | ok = charon->shunts->install(charon->shunts, |
633 | peer_cfg->get_name(peer_cfg), child_cfg); | |
5c6e81dc MW |
634 | break; |
635 | default: | |
24fa1bb0 | 636 | ok = charon->traps->install(charon->traps, peer_cfg, child_cfg); |
5c6e81dc MW |
637 | break; |
638 | } | |
639 | peer_cfg->destroy(peer_cfg); | |
640 | child_cfg->destroy(child_cfg); | |
641 | ||
642 | return send_reply(this, ok ? NULL : "installing policy '%s' failed", child); | |
643 | } | |
644 | ||
645 | CALLBACK(uninstall, vici_message_t*, | |
646 | private_vici_control_t *this, char *name, u_int id, vici_message_t *request) | |
647 | { | |
6f569263 | 648 | char *child, *ike; |
5c6e81dc MW |
649 | |
650 | child = request->get_str(request, NULL, "child"); | |
7627f5f9 | 651 | ike = request->get_str(request, NULL, "ike"); |
5c6e81dc MW |
652 | if (!child) |
653 | { | |
654 | return send_reply(this, "missing configuration name"); | |
655 | } | |
2676ffdb MW |
656 | |
657 | DBG1(DBG_CFG, "vici uninstall '%s'", child); | |
658 | ||
6f569263 | 659 | if (charon->shunts->uninstall(charon->shunts, ike, child)) |
5c6e81dc MW |
660 | { |
661 | return send_reply(this, NULL); | |
662 | } | |
ca213e19 | 663 | else if (charon->traps->uninstall(charon->traps, ike, child)) |
5c6e81dc | 664 | { |
ca213e19 | 665 | return send_reply(this, NULL); |
5c6e81dc MW |
666 | } |
667 | return send_reply(this, "policy '%s' not found", child); | |
668 | } | |
669 | ||
455e213c MW |
670 | CALLBACK(reload_settings, vici_message_t*, |
671 | private_vici_control_t *this, char *name, u_int id, vici_message_t *request) | |
672 | { | |
673 | if (lib->settings->load_files(lib->settings, lib->conf, FALSE)) | |
674 | { | |
83bf6db3 | 675 | charon->load_loggers(charon); |
455e213c MW |
676 | lib->plugins->reload(lib->plugins, NULL); |
677 | return send_reply(this, NULL); | |
678 | } | |
679 | return send_reply(this, "reloading '%s' failed", lib->conf); | |
680 | } | |
681 | ||
5f95657c MW |
682 | static void manage_command(private_vici_control_t *this, |
683 | char *name, vici_command_cb_t cb, bool reg) | |
684 | { | |
685 | this->dispatcher->manage_command(this->dispatcher, name, | |
686 | reg ? cb : NULL, this); | |
687 | } | |
688 | ||
689 | /** | |
690 | * (Un-)register dispatcher functions | |
691 | */ | |
692 | static void manage_commands(private_vici_control_t *this, bool reg) | |
693 | { | |
694 | manage_command(this, "initiate", initiate, reg); | |
c7d4dad6 | 695 | manage_command(this, "terminate", terminate, reg); |
808472c9 | 696 | manage_command(this, "rekey", rekey, reg); |
43b46b26 | 697 | manage_command(this, "redirect", redirect, reg); |
5c6e81dc MW |
698 | manage_command(this, "install", install, reg); |
699 | manage_command(this, "uninstall", uninstall, reg); | |
455e213c | 700 | manage_command(this, "reload-settings", reload_settings, reg); |
5f95657c MW |
701 | this->dispatcher->manage_event(this->dispatcher, "control-log", reg); |
702 | } | |
703 | ||
704 | METHOD(vici_control_t, destroy, void, | |
705 | private_vici_control_t *this) | |
706 | { | |
707 | manage_commands(this, FALSE); | |
708 | free(this); | |
709 | } | |
710 | ||
711 | /** | |
712 | * See header | |
713 | */ | |
714 | vici_control_t *vici_control_create(vici_dispatcher_t *dispatcher) | |
715 | { | |
716 | private_vici_control_t *this; | |
717 | ||
718 | INIT(this, | |
719 | .public = { | |
720 | .destroy = _destroy, | |
721 | }, | |
722 | .dispatcher = dispatcher, | |
723 | ); | |
724 | ||
725 | manage_commands(this, TRUE); | |
726 | ||
727 | return &this->public; | |
728 | } |