2ea92285130108af77a2d1714ab8bb754b160593
[strongswan.git] / src / libcharon / plugins / vici / vici_query.c
1 /*
2 * Copyright (C) 2015 Tobias Brunner, Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
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 /*
20 * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
21 *
22 * Permission is hereby granted, free of charge, to any person obtaining a copy
23 * of this software and associated documentation files (the "Software"), to deal
24 * in the Software without restriction, including without limitation the rights
25 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26 * copies of the Software, and to permit persons to whom the Software is
27 * furnished to do so, subject to the following conditions:
28 *
29 * The above copyright notice and this permission notice shall be included in
30 * all copies or substantial portions of the Software.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38 * THE SOFTWARE.
39 */
40
41 #include "vici_query.h"
42 #include "vici_builder.h"
43 #include "vici_version.h"
44 #include "vici_cert_info.h"
45
46 #include <inttypes.h>
47 #include <time.h>
48 #ifndef WIN32
49 #include <sys/utsname.h>
50 #endif
51 #ifdef HAVE_MALLINFO
52 #include <malloc.h>
53 #endif
54
55 #include <daemon.h>
56
57 typedef struct private_vici_query_t private_vici_query_t;
58
59 /**
60 * Private data of an vici_query_t object.
61 */
62 struct private_vici_query_t {
63
64 /**
65 * Public vici_query_t interface.
66 */
67 vici_query_t public;
68
69 /**
70 * Dispatcher
71 */
72 vici_dispatcher_t *dispatcher;
73
74 /**
75 * Daemon startup timestamp
76 */
77 time_t uptime;
78 };
79
80 /**
81 * List details of a CHILD_SA
82 */
83 static void list_child(private_vici_query_t *this, vici_builder_t *b,
84 child_sa_t *child, time_t now)
85 {
86 time_t t;
87 u_int64_t bytes, packets;
88 u_int16_t alg, ks;
89 proposal_t *proposal;
90 enumerator_t *enumerator;
91 traffic_selector_t *ts;
92
93 b->add_kv(b, "uniqueid", "%u", child->get_unique_id(child));
94 b->add_kv(b, "reqid", "%u", child->get_reqid(child));
95 b->add_kv(b, "state", "%N", child_sa_state_names, child->get_state(child));
96 b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
97 if (child->get_state(child) == CHILD_INSTALLED ||
98 child->get_state(child) == CHILD_REKEYING ||
99 child->get_state(child) == CHILD_REKEYED)
100 {
101 b->add_kv(b, "protocol", "%N", protocol_id_names,
102 child->get_protocol(child));
103 if (child->has_encap(child))
104 {
105 b->add_kv(b, "encap", "yes");
106 }
107 b->add_kv(b, "spi-in", "%.8x", ntohl(child->get_spi(child, TRUE)));
108 b->add_kv(b, "spi-out", "%.8x", ntohl(child->get_spi(child, FALSE)));
109
110 if (child->get_ipcomp(child) != IPCOMP_NONE)
111 {
112 b->add_kv(b, "cpi-in", "%.4x", ntohs(child->get_cpi(child, TRUE)));
113 b->add_kv(b, "cpi-out", "%.4x", ntohs(child->get_cpi(child, FALSE)));
114 }
115 proposal = child->get_proposal(child);
116 if (proposal)
117 {
118 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
119 &alg, &ks) && alg != ENCR_UNDEFINED)
120 {
121 b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg);
122 if (ks)
123 {
124 b->add_kv(b, "encr-keysize", "%u", ks);
125 }
126 }
127 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
128 &alg, &ks) && alg != ENCR_UNDEFINED)
129 {
130 b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg);
131 if (ks)
132 {
133 b->add_kv(b, "integ-keysize", "%u", ks);
134 }
135 }
136 if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION,
137 &alg, NULL))
138 {
139 b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg);
140 }
141 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP,
142 &alg, NULL))
143 {
144 b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg);
145 }
146 if (proposal->get_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS,
147 &alg, NULL) && alg == EXT_SEQ_NUMBERS)
148 {
149 b->add_kv(b, "esn", "1");
150 }
151 }
152
153 child->get_usestats(child, TRUE, &t, &bytes, &packets);
154 b->add_kv(b, "bytes-in", "%" PRIu64, bytes);
155 b->add_kv(b, "packets-in", "%" PRIu64, packets);
156 if (t)
157 {
158 b->add_kv(b, "use-in", "%"PRIu64, (u_int64_t)(now - t));
159 }
160
161 child->get_usestats(child, FALSE, &t, &bytes, &packets);
162 b->add_kv(b, "bytes-out", "%"PRIu64, bytes);
163 b->add_kv(b, "packets-out", "%"PRIu64, packets);
164 if (t)
165 {
166 b->add_kv(b, "use-out", "%"PRIu64, (u_int64_t)(now - t));
167 }
168
169 t = child->get_lifetime(child, FALSE);
170 if (t)
171 {
172 b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now));
173 }
174 t = child->get_lifetime(child, TRUE);
175 if (t)
176 {
177 b->add_kv(b, "life-time", "%"PRId64, (int64_t)(t - now));
178 }
179 t = child->get_installtime(child);
180 b->add_kv(b, "install-time", "%"PRId64, (int64_t)(now - t));
181 }
182
183 b->begin_list(b, "local-ts");
184 enumerator = child->create_ts_enumerator(child, TRUE);
185 while (enumerator->enumerate(enumerator, &ts))
186 {
187 b->add_li(b, "%R", ts);
188 }
189 enumerator->destroy(enumerator);
190 b->end_list(b /* local-ts */);
191
192 b->begin_list(b, "remote-ts");
193 enumerator = child->create_ts_enumerator(child, FALSE);
194 while (enumerator->enumerate(enumerator, &ts))
195 {
196 b->add_li(b, "%R", ts);
197 }
198 enumerator->destroy(enumerator);
199 b->end_list(b /* remote-ts */);
200 }
201
202 /**
203 * List tasks in a specific queue
204 */
205 static void list_task_queue(private_vici_query_t *this, vici_builder_t *b,
206 ike_sa_t *ike_sa, task_queue_t q, char *name)
207 {
208 enumerator_t *enumerator;
209 bool has = FALSE;
210 task_t *task;
211
212 enumerator = ike_sa->create_task_enumerator(ike_sa, q);
213 while (enumerator->enumerate(enumerator, &task))
214 {
215 if (!has)
216 {
217 b->begin_list(b, name);
218 has = TRUE;
219 }
220 b->add_li(b, "%N", task_type_names, task->get_type(task));
221 }
222 enumerator->destroy(enumerator);
223 if (has)
224 {
225 b->end_list(b);
226 }
227 }
228
229 /**
230 * Add an IKE_SA condition to the given builder
231 */
232 static void add_condition(vici_builder_t *b, ike_sa_t *ike_sa,
233 char *key, ike_condition_t cond)
234 {
235 if (ike_sa->has_condition(ike_sa, cond))
236 {
237 b->add_kv(b, key, "yes");
238 }
239 }
240
241 /**
242 * List virtual IPs
243 */
244 static void list_vips(private_vici_query_t *this, vici_builder_t *b,
245 ike_sa_t *ike_sa, bool local, char *name)
246 {
247 enumerator_t *enumerator;
248 bool has = FALSE;
249 host_t *vip;
250
251 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
252 while (enumerator->enumerate(enumerator, &vip))
253 {
254 if (!has)
255 {
256 b->begin_list(b, name);
257 has = TRUE;
258 }
259 b->add_li(b, "%H", vip);
260 }
261 enumerator->destroy(enumerator);
262 if (has)
263 {
264 b->end_list(b);
265 }
266 }
267
268 /**
269 * List details of an IKE_SA
270 */
271 static void list_ike(private_vici_query_t *this, vici_builder_t *b,
272 ike_sa_t *ike_sa, time_t now)
273 {
274 time_t t;
275 ike_sa_id_t *id;
276 identification_t *eap;
277 proposal_t *proposal;
278 u_int16_t alg, ks;
279
280 b->add_kv(b, "uniqueid", "%u", ike_sa->get_unique_id(ike_sa));
281 b->add_kv(b, "version", "%u", ike_sa->get_version(ike_sa));
282 b->add_kv(b, "state", "%N", ike_sa_state_names, ike_sa->get_state(ike_sa));
283
284 b->add_kv(b, "local-host", "%H", ike_sa->get_my_host(ike_sa));
285 b->add_kv(b, "local-id", "%Y", ike_sa->get_my_id(ike_sa));
286
287 b->add_kv(b, "remote-host", "%H", ike_sa->get_other_host(ike_sa));
288 b->add_kv(b, "remote-id", "%Y", ike_sa->get_other_id(ike_sa));
289
290 eap = ike_sa->get_other_eap_id(ike_sa);
291
292 if (!eap->equals(eap, ike_sa->get_other_id(ike_sa)))
293 {
294 if (ike_sa->get_version(ike_sa) == IKEV1)
295 {
296 b->add_kv(b, "remote-xauth-id", "%Y", eap);
297 }
298 else
299 {
300 b->add_kv(b, "remote-eap-id", "%Y", eap);
301 }
302 }
303
304 id = ike_sa->get_id(ike_sa);
305 if (id->is_initiator(id))
306 {
307 b->add_kv(b, "initiator", "yes");
308 }
309 b->add_kv(b, "initiator-spi", "%.16"PRIx64, id->get_initiator_spi(id));
310 b->add_kv(b, "responder-spi", "%.16"PRIx64, id->get_responder_spi(id));
311
312 add_condition(b, ike_sa, "nat-local", COND_NAT_HERE);
313 add_condition(b, ike_sa, "nat-remote", COND_NAT_THERE);
314 add_condition(b, ike_sa, "nat-fake", COND_NAT_FAKE);
315 add_condition(b, ike_sa, "nat-any", COND_NAT_ANY);
316
317 proposal = ike_sa->get_proposal(ike_sa);
318 if (proposal)
319 {
320 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &ks))
321 {
322 b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg);
323 if (ks)
324 {
325 b->add_kv(b, "encr-keysize", "%u", ks);
326 }
327 }
328 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, &ks))
329 {
330 b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg);
331 if (ks)
332 {
333 b->add_kv(b, "integ-keysize", "%u", ks);
334 }
335 }
336 if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
337 {
338 b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg);
339 }
340 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &alg, NULL))
341 {
342 b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg);
343 }
344 }
345
346 if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
347 {
348 t = ike_sa->get_statistic(ike_sa, STAT_ESTABLISHED);
349 b->add_kv(b, "established", "%"PRId64, (int64_t)(now - t));
350 t = ike_sa->get_statistic(ike_sa, STAT_REKEY);
351 if (t)
352 {
353 b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now));
354 }
355 t = ike_sa->get_statistic(ike_sa, STAT_REAUTH);
356 if (t)
357 {
358 b->add_kv(b, "reauth-time", "%"PRId64, (int64_t)(t - now));
359 }
360 }
361
362 list_vips(this, b, ike_sa, TRUE, "local-vips");
363 list_vips(this, b, ike_sa, FALSE, "remote-vips");
364
365 list_task_queue(this, b, ike_sa, TASK_QUEUE_QUEUED, "tasks-queued");
366 list_task_queue(this, b, ike_sa, TASK_QUEUE_ACTIVE, "tasks-active");
367 list_task_queue(this, b, ike_sa, TASK_QUEUE_PASSIVE, "tasks-passive");
368 }
369
370 CALLBACK(list_sas, vici_message_t*,
371 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
372 {
373 vici_builder_t *b;
374 enumerator_t *isas, *csas;
375 ike_sa_t *ike_sa;
376 child_sa_t *child_sa;
377 time_t now;
378 char *ike;
379 u_int ike_id;
380 bool bl;
381
382 bl = request->get_str(request, NULL, "noblock") == NULL;
383 ike = request->get_str(request, NULL, "ike");
384 ike_id = request->get_int(request, 0, "ike-id");
385
386 isas = charon->controller->create_ike_sa_enumerator(charon->controller, bl);
387 while (isas->enumerate(isas, &ike_sa))
388 {
389 if (ike && !streq(ike, ike_sa->get_name(ike_sa)))
390 {
391 continue;
392 }
393 if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa))
394 {
395 continue;
396 }
397
398 now = time_monotonic(NULL);
399
400 b = vici_builder_create();
401 b->begin_section(b, ike_sa->get_name(ike_sa));
402
403 list_ike(this, b, ike_sa, now);
404
405 b->begin_section(b, "child-sas");
406 csas = ike_sa->create_child_sa_enumerator(ike_sa);
407 while (csas->enumerate(csas, &child_sa))
408 {
409 b->begin_section(b, child_sa->get_name(child_sa));
410 list_child(this, b, child_sa, now);
411 b->end_section(b);
412 }
413 csas->destroy(csas);
414 b->end_section(b /* child-sas */ );
415
416 b->end_section(b);
417
418 this->dispatcher->raise_event(this->dispatcher, "list-sa", id,
419 b->finalize(b));
420 }
421 isas->destroy(isas);
422
423 b = vici_builder_create();
424 return b->finalize(b);
425 }
426
427 /**
428 * Raise a list-policy event for given CHILD_SA
429 */
430 static void raise_policy(private_vici_query_t *this, u_int id, child_sa_t *child)
431 {
432 enumerator_t *enumerator;
433 traffic_selector_t *ts;
434 vici_builder_t *b;
435
436 b = vici_builder_create();
437 b->begin_section(b, child->get_name(child));
438
439 b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
440
441 b->begin_list(b, "local-ts");
442 enumerator = child->create_ts_enumerator(child, TRUE);
443 while (enumerator->enumerate(enumerator, &ts))
444 {
445 b->add_li(b, "%R", ts);
446 }
447 enumerator->destroy(enumerator);
448 b->end_list(b /* local-ts */);
449
450 b->begin_list(b, "remote-ts");
451 enumerator = child->create_ts_enumerator(child, FALSE);
452 while (enumerator->enumerate(enumerator, &ts))
453 {
454 b->add_li(b, "%R", ts);
455 }
456 enumerator->destroy(enumerator);
457 b->end_list(b /* remote-ts */);
458
459 b->end_section(b);
460
461 this->dispatcher->raise_event(this->dispatcher, "list-policy", id,
462 b->finalize(b));
463 }
464
465 /**
466 * Raise a list-policy event for given CHILD_SA config
467 */
468 static void raise_policy_cfg(private_vici_query_t *this, u_int id,
469 child_cfg_t *cfg)
470 {
471 enumerator_t *enumerator;
472 linked_list_t *list;
473 traffic_selector_t *ts;
474 vici_builder_t *b;
475
476 b = vici_builder_create();
477 b->begin_section(b, cfg->get_name(cfg));
478
479 b->add_kv(b, "mode", "%N", ipsec_mode_names, cfg->get_mode(cfg));
480
481 b->begin_list(b, "local-ts");
482 list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL);
483 enumerator = list->create_enumerator(list);
484 while (enumerator->enumerate(enumerator, &ts))
485 {
486 b->add_li(b, "%R", ts);
487 }
488 enumerator->destroy(enumerator);
489 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
490 b->end_list(b /* local-ts */);
491
492 b->begin_list(b, "remote-ts");
493 list = cfg->get_traffic_selectors(cfg, FALSE, NULL, NULL);
494 enumerator = list->create_enumerator(list);
495 while (enumerator->enumerate(enumerator, &ts))
496 {
497 b->add_li(b, "%R", ts);
498 }
499 enumerator->destroy(enumerator);
500 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
501 b->end_list(b /* remote-ts */);
502
503 b->end_section(b);
504
505 this->dispatcher->raise_event(this->dispatcher, "list-policy", id,
506 b->finalize(b));
507 }
508
509 CALLBACK(list_policies, vici_message_t*,
510 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
511 {
512 enumerator_t *enumerator;
513 vici_builder_t *b;
514 child_sa_t *child_sa;
515 child_cfg_t *child_cfg;
516 bool drop, pass, trap;
517 char *child;
518
519 drop = request->get_str(request, NULL, "drop") != NULL;
520 pass = request->get_str(request, NULL, "pass") != NULL;
521 trap = request->get_str(request, NULL, "trap") != NULL;
522 child = request->get_str(request, NULL, "child");
523
524 if (trap)
525 {
526 enumerator = charon->traps->create_enumerator(charon->traps);
527 while (enumerator->enumerate(enumerator, NULL, &child_sa))
528 {
529 if (child && !streq(child, child_sa->get_name(child_sa)))
530 {
531 continue;
532 }
533 raise_policy(this, id, child_sa);
534 }
535 enumerator->destroy(enumerator);
536 }
537
538 if (drop || pass)
539 {
540 enumerator = charon->shunts->create_enumerator(charon->shunts);
541 while (enumerator->enumerate(enumerator, &child_cfg))
542 {
543 if (child && !streq(child, child_cfg->get_name(child_cfg)))
544 {
545 continue;
546 }
547 switch (child_cfg->get_mode(child_cfg))
548 {
549 case MODE_DROP:
550 if (drop)
551 {
552 raise_policy_cfg(this, id, child_cfg);
553 }
554 break;
555 case MODE_PASS:
556 if (pass)
557 {
558 raise_policy_cfg(this, id, child_cfg);
559 }
560 break;
561 default:
562 break;
563 }
564 }
565 enumerator->destroy(enumerator);
566 }
567
568 b = vici_builder_create();
569 return b->finalize(b);
570 }
571
572 /**
573 * Build sections for auth configs, local or remote
574 */
575 static void build_auth_cfgs(peer_cfg_t *peer_cfg, bool local, vici_builder_t *b)
576 {
577 enumerator_t *enumerator, *rules;
578 auth_rule_t rule;
579 auth_cfg_t *auth;
580 union {
581 uintptr_t u;
582 identification_t *id;
583 certificate_t *cert;
584 char *str;
585 } v;
586 char buf[32];
587 int i = 0;
588
589 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
590 while (enumerator->enumerate(enumerator, &auth))
591 {
592 snprintf(buf, sizeof(buf), "%s-%d", local ? "local" : "remote", ++i);
593 b->begin_section(b, buf);
594
595 rules = auth->create_enumerator(auth);
596 while (rules->enumerate(rules, &rule, &v))
597 {
598 switch (rule)
599 {
600 case AUTH_RULE_AUTH_CLASS:
601 b->add_kv(b, "class", "%N", auth_class_names, v.u);
602 break;
603 case AUTH_RULE_EAP_TYPE:
604 b->add_kv(b, "eap-type", "%N", eap_type_names, v.u);
605 break;
606 case AUTH_RULE_EAP_VENDOR:
607 b->add_kv(b, "eap-vendor", "%u", v.u);
608 break;
609 case AUTH_RULE_XAUTH_BACKEND:
610 b->add_kv(b, "xauth", "%s", v.str);
611 break;
612 case AUTH_RULE_CRL_VALIDATION:
613 b->add_kv(b, "revocation", "%N", cert_validation_names, v.u);
614 break;
615 case AUTH_RULE_IDENTITY:
616 b->add_kv(b, "id", "%Y", v.id);
617 break;
618 case AUTH_RULE_AAA_IDENTITY:
619 b->add_kv(b, "aaa_id", "%Y", v.id);
620 break;
621 case AUTH_RULE_EAP_IDENTITY:
622 b->add_kv(b, "eap_id", "%Y", v.id);
623 break;
624 case AUTH_RULE_XAUTH_IDENTITY:
625 b->add_kv(b, "xauth_id", "%Y", v.id);
626 break;
627 default:
628 break;
629 }
630 }
631 rules->destroy(rules);
632
633 b->begin_list(b, "groups");
634 rules = auth->create_enumerator(auth);
635 while (rules->enumerate(rules, &rule, &v))
636 {
637 if (rule == AUTH_RULE_GROUP)
638 {
639 b->add_li(b, "%Y", v.id);
640 }
641 }
642 rules->destroy(rules);
643 b->end_list(b);
644
645 b->begin_list(b, "certs");
646 rules = auth->create_enumerator(auth);
647 while (rules->enumerate(rules, &rule, &v))
648 {
649 if (rule == AUTH_RULE_SUBJECT_CERT)
650 {
651 b->add_li(b, "%Y", v.cert->get_subject(v.cert));
652 }
653 }
654 rules->destroy(rules);
655 b->end_list(b);
656
657 b->begin_list(b, "cacerts");
658 rules = auth->create_enumerator(auth);
659 while (rules->enumerate(rules, &rule, &v))
660 {
661 if (rule == AUTH_RULE_CA_CERT)
662 {
663 b->add_li(b, "%Y", v.cert->get_subject(v.cert));
664 }
665 }
666 rules->destroy(rules);
667 b->end_list(b);
668
669 b->end_section(b);
670 }
671 enumerator->destroy(enumerator);
672 }
673
674 CALLBACK(list_conns, vici_message_t*,
675 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
676 {
677 enumerator_t *enumerator, *tokens, *selectors, *children;
678 peer_cfg_t *peer_cfg;
679 ike_cfg_t *ike_cfg;
680 child_cfg_t *child_cfg;
681 char *ike, *str;
682 linked_list_t *list;
683 traffic_selector_t *ts;
684 vici_builder_t *b;
685
686 ike = request->get_str(request, NULL, "ike");
687
688 enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
689 NULL, NULL, NULL, NULL, IKE_ANY);
690 while (enumerator->enumerate(enumerator, &peer_cfg))
691 {
692 if (ike && !streq(ike, peer_cfg->get_name(peer_cfg)))
693 {
694 continue;
695 }
696
697 b = vici_builder_create();
698 b->begin_section(b, peer_cfg->get_name(peer_cfg));
699
700 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
701
702 b->begin_list(b, "local_addrs");
703 str = ike_cfg->get_my_addr(ike_cfg);
704 tokens = enumerator_create_token(str, ",", " ");
705 while (tokens->enumerate(tokens, &str))
706 {
707 b->add_li(b, "%s", str);
708 }
709 tokens->destroy(tokens);
710 b->end_list(b);
711
712 b->begin_list(b, "remote_addrs");
713 str = ike_cfg->get_other_addr(ike_cfg);
714 tokens = enumerator_create_token(str, ",", " ");
715 while (tokens->enumerate(tokens, &str))
716 {
717 b->add_li(b, "%s", str);
718 }
719 tokens->destroy(tokens);
720 b->end_list(b);
721
722 b->add_kv(b, "version", "%N", ike_version_names,
723 peer_cfg->get_ike_version(peer_cfg));
724
725 build_auth_cfgs(peer_cfg, TRUE, b);
726 build_auth_cfgs(peer_cfg, FALSE, b);
727
728 b->begin_section(b, "children");
729
730 children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
731 while (children->enumerate(children, &child_cfg))
732 {
733 b->begin_section(b, child_cfg->get_name(child_cfg));
734
735 b->add_kv(b, "mode", "%N", ipsec_mode_names,
736 child_cfg->get_mode(child_cfg));
737
738 b->begin_list(b, "local-ts");
739 list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
740 selectors = list->create_enumerator(list);
741 while (selectors->enumerate(selectors, &ts))
742 {
743 b->add_li(b, "%R", ts);
744 }
745 selectors->destroy(selectors);
746 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
747 b->end_list(b /* local-ts */);
748
749 b->begin_list(b, "remote-ts");
750 list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
751 selectors = list->create_enumerator(list);
752 while (selectors->enumerate(selectors, &ts))
753 {
754 b->add_li(b, "%R", ts);
755 }
756 selectors->destroy(selectors);
757 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
758 b->end_list(b /* remote-ts */);
759
760 b->end_section(b);
761 }
762 children->destroy(children);
763
764 b->end_section(b); /* children */
765
766 b->end_section(b); /* name */
767
768 this->dispatcher->raise_event(this->dispatcher, "list-conn", id,
769 b->finalize(b));
770 }
771 enumerator->destroy(enumerator);
772
773 b = vici_builder_create();
774 return b->finalize(b);
775 }
776
777 /**
778 * Do we have a private key for given certificate
779 */
780 static bool has_privkey(certificate_t *cert)
781 {
782 private_key_t *private;
783 public_key_t *public;
784 identification_t *keyid;
785 chunk_t chunk;
786 bool found = FALSE;
787
788 public = cert->get_public_key(cert);
789 if (public)
790 {
791 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
792 {
793 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
794 private = lib->credmgr->get_private(lib->credmgr,
795 public->get_type(public), keyid, NULL);
796 if (private)
797 {
798 found = TRUE;
799 private->destroy(private);
800 }
801 keyid->destroy(keyid);
802 }
803 public->destroy(public);
804 }
805 return found;
806 }
807
808 /**
809 * Store cert filter data
810 */
811 typedef struct {
812 vici_version_t version;
813 certificate_type_t type;
814 x509_flag_t flag;
815 identification_t *subject;
816 } cert_filter_t;
817
818 /**
819 * Enumerate all X.509 certificates with a given flag
820 */
821 static void enum_x509(private_vici_query_t *this, u_int id,
822 linked_list_t *certs, cert_filter_t *filter,
823 x509_flag_t flag, char *cert_type)
824 {
825 enumerator_t *enumerator;
826 certificate_t *cert;
827 vici_builder_t *b;
828 chunk_t encoding;
829 x509_flag_t mask;
830 x509_t *x509;
831
832 if (filter->type != CERT_ANY && filter->version != VICI_1_0 &&
833 filter->flag != flag)
834 {
835 return;
836 }
837 mask = X509_CA | X509_AA | X509_OCSP_SIGNER;
838
839 enumerator = certs->create_enumerator(certs);
840 while (enumerator->enumerate(enumerator, &cert))
841 {
842 x509 = (x509_t*)cert;
843 if ((x509->get_flags(x509) & mask) != flag)
844 {
845 continue;
846 }
847
848 if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
849 {
850 b = vici_builder_create();
851 if (filter->version == VICI_1_0)
852 {
853 b->add_kv(b, "type", "%N", certificate_type_names,
854 cert->get_type(cert));
855 }
856 else
857 {
858 b->add_kv(b, "vici", "%N", vici_version_names, VICI_VERSION);
859 b->add_kv(b, "type", "%s", cert_type);
860 }
861 if (has_privkey(cert))
862 {
863 b->add_kv(b, "has_privkey", "yes");
864 }
865 b->add(b, VICI_KEY_VALUE, "data", encoding);
866 free(encoding.ptr);
867
868 this->dispatcher->raise_event(this->dispatcher, "list-cert", id,
869 b->finalize(b));
870 }
871 }
872 enumerator->destroy(enumerator);
873 }
874
875 /**
876 * Enumerate all non-X.509 certificate types
877 */
878 static void enum_others(private_vici_query_t *this, u_int id,
879 linked_list_t *certs, cert_filter_t *filter,
880 char *cert_type)
881 {
882 enumerator_t *enumerator;
883 certificate_t *cert;
884 vici_builder_t *b;
885 chunk_t encoding;
886
887 enumerator = certs->create_enumerator(certs);
888 while (enumerator->enumerate(enumerator, &cert))
889 {
890 if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
891 {
892 b = vici_builder_create();
893 if (filter->version == VICI_1_0)
894 {
895 b->add_kv(b, "type", "%N", certificate_type_names,
896 cert->get_type(cert));
897 }
898 else
899 {
900 b->add_kv(b, "vici", "%N", vici_version_names, VICI_VERSION);
901 b->add_kv(b, "type", "%s", cert_type);
902 }
903 if (has_privkey(cert))
904 {
905 b->add_kv(b, "has_privkey", "yes");
906 }
907 b->add(b, VICI_KEY_VALUE, "data", encoding);
908 free(encoding.ptr);
909
910 this->dispatcher->raise_event(this->dispatcher, "list-cert", id,
911 b->finalize(b));
912 }
913 }
914 enumerator->destroy(enumerator);
915 }
916
917 /**
918 * Enumerate all certificates of a given type
919 */
920 static void enum_certs(private_vici_query_t *this, u_int id,
921 cert_filter_t *filter, certificate_type_t type,
922 char *cert_type)
923 {
924 enumerator_t *e1, *e2;
925 certificate_t *cert, *current;
926 linked_list_t *certs;
927 bool found;
928
929 if (filter->type != CERT_ANY && filter->type != type)
930 {
931 return;
932 }
933 certs = linked_list_create();
934
935 e1 = lib->credmgr->create_cert_enumerator(lib->credmgr, type, KEY_ANY,
936 filter->subject, FALSE);
937 while (e1->enumerate(e1, &cert))
938 {
939 found = FALSE;
940
941 e2 = certs->create_enumerator(certs);
942 while (e2->enumerate(e2, &current))
943 {
944 if (current->equals(current, cert))
945 {
946 found = TRUE;
947 break;
948 }
949 }
950 e2->destroy(e2);
951
952 if (!found)
953 {
954 certs->insert_last(certs, cert->get_ref(cert));
955 }
956 }
957 e1->destroy(e1);
958
959 if (type == CERT_X509)
960 {
961 enum_x509(this, id, certs, filter, X509_NONE, "x509");
962 enum_x509(this, id, certs, filter, X509_CA, "x509ca");
963 enum_x509(this, id, certs, filter, X509_AA, "x509ac");
964 enum_x509(this, id, certs, filter, X509_OCSP_SIGNER, "x509ocsp");
965 }
966 else
967 {
968 enum_others(this, id, certs, filter, cert_type);
969 }
970 certs->destroy_offset(certs, offsetof(certificate_t, destroy));
971 }
972
973 CALLBACK(list_certs, vici_message_t*,
974 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
975 {
976 cert_filter_t filter = {
977 .version = VICI_1_0,
978 .type = CERT_ANY,
979 .flag = X509_NONE,
980 .subject = NULL
981 };
982 vici_builder_t *b;
983 char *str;
984
985 str = request->get_str(request, "1.0", "vici");
986 if (!enum_from_name(vici_version_names, str, &filter.version))
987 {
988 DBG1(DBG_CFG, "unsupported vici version '%s'", str);
989 goto finalize;
990 }
991 str = request->get_str(request, "ANY", "type");
992
993 if (filter.version == VICI_1_0)
994 {
995 if (!enum_from_name(certificate_type_names, str, &filter.type))
996 {
997 DBG1(DBG_CFG, "invalid certificate type '%s'", str);
998 goto finalize;
999 }
1000 }
1001 else /* VICI 2.0 */
1002 {
1003 vici_cert_info_t *cert_info;
1004
1005 cert_info = vici_cert_info_retrieve(str);
1006 if (cert_info)
1007 {
1008 filter.type = cert_info->type;
1009 filter.flag = cert_info->flag;
1010 }
1011 else
1012 {
1013 DBG1(DBG_CFG, "invalid certificate type '%s'", str);
1014 goto finalize;
1015 }
1016 }
1017
1018 str = request->get_str(request, NULL, "subject");
1019 if (str)
1020 {
1021 filter.subject = identification_create_from_string(str);
1022 }
1023 enum_certs(this, id, &filter, CERT_TRUSTED_PUBKEY, "pubkey");
1024 enum_certs(this, id, &filter, CERT_X509, "x509");
1025 enum_certs(this, id, &filter, CERT_X509_AC, "x509ac");
1026 enum_certs(this, id, &filter, CERT_X509_CRL, "x509crl");
1027 enum_certs(this, id, &filter, CERT_X509_OCSP_RESPONSE, "ocsp");
1028 DESTROY_IF(filter.subject);
1029
1030 finalize:
1031 b = vici_builder_create();
1032 return b->finalize(b);
1033 }
1034
1035 /**
1036 * Add a key/value pair of ALG => plugin
1037 */
1038 static void add_algorithm(vici_builder_t *b, enum_name_t *alg_names,
1039 int alg_type, const char *plugin_name)
1040 {
1041 char alg_name[BUF_LEN];
1042
1043 sprintf(alg_name, "%N", alg_names, alg_type);
1044 b->add_kv(b, alg_name, (char*)plugin_name);
1045 }
1046
1047 CALLBACK(get_algorithms, vici_message_t*,
1048 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
1049 {
1050 vici_builder_t *b;
1051 enumerator_t *enumerator;
1052 encryption_algorithm_t encryption;
1053 integrity_algorithm_t integrity;
1054 hash_algorithm_t hash;
1055 pseudo_random_function_t prf;
1056 diffie_hellman_group_t group;
1057 rng_quality_t quality;
1058 const char *plugin_name;
1059
1060 b = vici_builder_create();
1061
1062 b->begin_section(b, "encryption");
1063 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
1064 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1065 {
1066 add_algorithm(b, encryption_algorithm_names, encryption, plugin_name);
1067 }
1068 enumerator->destroy(enumerator);
1069 b->end_section(b);
1070
1071 b->begin_section(b, "integrity");
1072 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1073 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
1074 {
1075 add_algorithm(b, integrity_algorithm_names, integrity, plugin_name);
1076 }
1077 enumerator->destroy(enumerator);
1078 b->end_section(b);
1079
1080 b->begin_section(b, "aead");
1081 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
1082 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1083 {
1084 add_algorithm(b, encryption_algorithm_names, encryption, plugin_name);
1085 }
1086 enumerator->destroy(enumerator);
1087 b->end_section(b);
1088
1089 b->begin_section(b, "hasher");
1090 enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
1091 while (enumerator->enumerate(enumerator, &hash, &plugin_name))
1092 {
1093 add_algorithm(b, hash_algorithm_names, hash, plugin_name);
1094 }
1095 enumerator->destroy(enumerator);
1096 b->end_section(b);
1097
1098 b->begin_section(b, "prf");
1099 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
1100 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
1101 {
1102 add_algorithm(b, pseudo_random_function_names, prf, plugin_name);
1103 }
1104 enumerator->destroy(enumerator);
1105 b->end_section(b);
1106
1107 b->begin_section(b, "dh");
1108 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1109 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1110 {
1111 add_algorithm(b, diffie_hellman_group_names, group, plugin_name);
1112 }
1113 enumerator->destroy(enumerator);
1114 b->end_section(b);
1115
1116 b->begin_section(b, "rng");
1117 enumerator = lib->crypto->create_rng_enumerator(lib->crypto);
1118 while (enumerator->enumerate(enumerator, &quality, &plugin_name))
1119 {
1120 add_algorithm(b, rng_quality_names, quality, plugin_name);
1121 }
1122 enumerator->destroy(enumerator);
1123 b->end_section(b);
1124
1125 b->begin_section(b, "nonce-gen");
1126 enumerator = lib->crypto->create_nonce_gen_enumerator(lib->crypto);
1127 while (enumerator->enumerate(enumerator, &plugin_name))
1128 {
1129 b->add_kv(b, "NONCE_GEN", (char*)plugin_name);
1130 }
1131 enumerator->destroy(enumerator);
1132 b->end_section(b);
1133
1134 return b->finalize(b);
1135 }
1136
1137 CALLBACK(version, vici_message_t*,
1138 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
1139 {
1140 vici_builder_t *b;
1141
1142 b = vici_builder_create();
1143
1144 b->add_kv(b, "vici", "%N", vici_version_names, VICI_VERSION);
1145 b->add_kv(b, "daemon", "%s", lib->ns);
1146 b->add_kv(b, "version", "%s", VERSION);
1147
1148 #ifdef WIN32
1149 {
1150 OSVERSIONINFOEX osvie;
1151
1152 memset(&osvie, 0, sizeof(osvie));
1153 osvie.dwOSVersionInfoSize = sizeof(osvie);
1154
1155 if (GetVersionEx((LPOSVERSIONINFO)&osvie))
1156 {
1157 b->add_kv(b, "sysname", "Windows %s",
1158 osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server");
1159 b->add_kv(b, "release", "%d.%d.%d (SP %d.%d)",
1160 osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber,
1161 osvie.wServicePackMajor, osvie.wServicePackMinor);
1162 b->add_kv(b, "machine", "%s",
1163 #ifdef WIN64
1164 "x86_64");
1165 #else
1166 "x86");
1167 #endif /* !WIN64 */
1168 }
1169 }
1170 #else /* !WIN32 */
1171 {
1172 struct utsname utsname;
1173
1174 if (uname(&utsname) == 0)
1175 {
1176 b->add_kv(b, "sysname", "%s", utsname.sysname);
1177 b->add_kv(b, "release", "%s", utsname.release);
1178 b->add_kv(b, "machine", "%s", utsname.machine);
1179 }
1180 }
1181 #endif /* !WIN32 */
1182 return b->finalize(b);
1183 }
1184
1185 CALLBACK(stats, vici_message_t*,
1186 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
1187 {
1188 vici_builder_t *b;
1189 enumerator_t *enumerator;
1190 plugin_t *plugin;
1191 time_t since, now;
1192 int i;
1193
1194 b = vici_builder_create();
1195
1196 now = time_monotonic(NULL);
1197 since = time(NULL) - (now - this->uptime);
1198
1199 b->begin_section(b, "uptime");
1200 b->add_kv(b, "running", "%V", &now, &this->uptime);
1201 b->add_kv(b, "since", "%T", &since, FALSE);
1202 b->end_section(b);
1203
1204 b->begin_section(b, "workers");
1205 b->add_kv(b, "total", "%d",
1206 lib->processor->get_total_threads(lib->processor));
1207 b->add_kv(b, "idle", "%d",
1208 lib->processor->get_idle_threads(lib->processor));
1209 b->begin_section(b, "active");
1210 for (i = 0; i < JOB_PRIO_MAX; i++)
1211 {
1212 b->add_kv(b, enum_to_name(job_priority_names, i), "%d",
1213 lib->processor->get_working_threads(lib->processor, i));
1214 }
1215 b->end_section(b);
1216 b->end_section(b);
1217
1218 b->begin_section(b, "queues");
1219 for (i = 0; i < JOB_PRIO_MAX; i++)
1220 {
1221 b->add_kv(b, enum_to_name(job_priority_names, i), "%d",
1222 lib->processor->get_job_load(lib->processor, i));
1223 }
1224 b->end_section(b);
1225
1226 b->add_kv(b, "scheduled", "%d",
1227 lib->scheduler->get_job_load(lib->scheduler));
1228
1229 b->begin_section(b, "ikesas");
1230 b->add_kv(b, "total", "%u",
1231 charon->ike_sa_manager->get_count(charon->ike_sa_manager));
1232 b->add_kv(b, "half-open", "%u",
1233 charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
1234 NULL, FALSE));
1235 b->end_section(b);
1236
1237 b->begin_list(b, "plugins");
1238 enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
1239 while (enumerator->enumerate(enumerator, &plugin, NULL))
1240 {
1241 b->add_li(b, "%s", plugin->get_name(plugin));
1242 }
1243 enumerator->destroy(enumerator);
1244 b->end_list(b);
1245
1246 #ifdef WIN32
1247 {
1248 DWORD lasterr = ERROR_INVALID_HANDLE;
1249 HANDLE heaps[32];
1250 int i, count;
1251 char buf[16];
1252 size_t total = 0;
1253 int allocs = 0;
1254
1255 b->begin_section(b, "mem");
1256 count = GetProcessHeaps(countof(heaps), heaps);
1257 for (i = 0; i < count; i++)
1258 {
1259 PROCESS_HEAP_ENTRY entry = {};
1260 size_t heap_total = 0;
1261 int heap_allocs = 0;
1262
1263 if (HeapLock(heaps[i]))
1264 {
1265 while (HeapWalk(heaps[i], &entry))
1266 {
1267 if (entry.wFlags & PROCESS_HEAP_ENTRY_BUSY)
1268 {
1269 heap_total += entry.cbData;
1270 heap_allocs++;
1271 }
1272 }
1273 lasterr = GetLastError();
1274 HeapUnlock(heaps[i]);
1275 }
1276 if (lasterr != ERROR_NO_MORE_ITEMS)
1277 {
1278 break;
1279 }
1280 snprintf(buf, sizeof(buf), "heap-%d", i);
1281 b->begin_section(b, buf);
1282 b->add_kv(b, "total", "%zu", heap_total);
1283 b->add_kv(b, "allocs", "%d", heap_allocs);
1284 b->end_section(b);
1285
1286 total += heap_total;
1287 allocs += heap_allocs;
1288 }
1289 if (lasterr == ERROR_NO_MORE_ITEMS)
1290 {
1291 b->add_kv(b, "total", "%zu", total);
1292 b->add_kv(b, "allocs", "%d", allocs);
1293 }
1294 b->end_section(b);
1295 }
1296 #endif
1297
1298 #ifdef HAVE_MALLINFO
1299 {
1300 struct mallinfo mi = mallinfo();
1301
1302 b->begin_section(b, "mallinfo");
1303 b->add_kv(b, "sbrk", "%u", mi.arena);
1304 b->add_kv(b, "mmap", "%u", mi.hblkhd);
1305 b->add_kv(b, "used", "%u", mi.uordblks);
1306 b->add_kv(b, "free", "%u", mi.fordblks);
1307 b->end_section(b);
1308 }
1309 #endif /* HAVE_MALLINFO */
1310
1311 return b->finalize(b);
1312 }
1313
1314 static void manage_command(private_vici_query_t *this,
1315 char *name, vici_command_cb_t cb, bool reg)
1316 {
1317 this->dispatcher->manage_command(this->dispatcher, name,
1318 reg ? cb : NULL, this);
1319 }
1320
1321 /**
1322 * (Un-)register dispatcher functions
1323 */
1324 static void manage_commands(private_vici_query_t *this, bool reg)
1325 {
1326 this->dispatcher->manage_event(this->dispatcher, "list-sa", reg);
1327 this->dispatcher->manage_event(this->dispatcher, "list-policy", reg);
1328 this->dispatcher->manage_event(this->dispatcher, "list-conn", reg);
1329 this->dispatcher->manage_event(this->dispatcher, "list-cert", reg);
1330 this->dispatcher->manage_event(this->dispatcher, "ike-updown", reg);
1331 this->dispatcher->manage_event(this->dispatcher, "ike-rekey", reg);
1332 this->dispatcher->manage_event(this->dispatcher, "child-updown", reg);
1333 this->dispatcher->manage_event(this->dispatcher, "child-rekey", reg);
1334 manage_command(this, "list-sas", list_sas, reg);
1335 manage_command(this, "list-policies", list_policies, reg);
1336 manage_command(this, "list-conns", list_conns, reg);
1337 manage_command(this, "list-certs", list_certs, reg);
1338 manage_command(this, "get-algorithms", get_algorithms, reg);
1339 manage_command(this, "version", version, reg);
1340 manage_command(this, "stats", stats, reg);
1341 }
1342
1343 METHOD(listener_t, ike_updown, bool,
1344 private_vici_query_t *this, ike_sa_t *ike_sa, bool up)
1345 {
1346 vici_builder_t *b;
1347 time_t now;
1348
1349 if (!this->dispatcher->has_event_listeners(this->dispatcher, "ike-updown"))
1350 {
1351 return TRUE;
1352 }
1353
1354 now = time_monotonic(NULL);
1355
1356 b = vici_builder_create();
1357
1358 if (up)
1359 {
1360 b->add_kv(b, "up", "yes");
1361 }
1362
1363 b->begin_section(b, ike_sa->get_name(ike_sa));
1364 list_ike(this, b, ike_sa, now);
1365 b->end_section(b);
1366
1367 this->dispatcher->raise_event(this->dispatcher,
1368 "ike-updown", 0, b->finalize(b));
1369
1370 return TRUE;
1371 }
1372
1373 METHOD(listener_t, ike_rekey, bool,
1374 private_vici_query_t *this, ike_sa_t *old, ike_sa_t *new)
1375 {
1376 vici_builder_t *b;
1377 time_t now;
1378
1379 if (!this->dispatcher->has_event_listeners(this->dispatcher, "ike-rekey"))
1380 {
1381 return TRUE;
1382 }
1383
1384 now = time_monotonic(NULL);
1385
1386 b = vici_builder_create();
1387 b->begin_section(b, old->get_name(old));
1388 b->begin_section(b, "old");
1389 list_ike(this, b, old, now);
1390 b->end_section(b);
1391 b->begin_section(b, "new");
1392 list_ike(this, b, new, now);
1393 b->end_section(b);
1394 b->end_section(b);
1395
1396 this->dispatcher->raise_event(this->dispatcher,
1397 "ike-rekey", 0, b->finalize(b));
1398
1399 return TRUE;
1400 }
1401
1402 METHOD(listener_t, child_updown, bool,
1403 private_vici_query_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up)
1404 {
1405 vici_builder_t *b;
1406 time_t now;
1407
1408 if (!this->dispatcher->has_event_listeners(this->dispatcher, "child-updown"))
1409 {
1410 return TRUE;
1411 }
1412
1413 now = time_monotonic(NULL);
1414 b = vici_builder_create();
1415
1416 if (up)
1417 {
1418 b->add_kv(b, "up", "yes");
1419 }
1420
1421 b->begin_section(b, ike_sa->get_name(ike_sa));
1422 list_ike(this, b, ike_sa, now);
1423 b->begin_section(b, "child-sas");
1424
1425 b->begin_section(b, child_sa->get_name(child_sa));
1426 list_child(this, b, child_sa, now);
1427 b->end_section(b);
1428
1429 b->end_section(b);
1430 b->end_section(b);
1431
1432 this->dispatcher->raise_event(this->dispatcher,
1433 "child-updown", 0, b->finalize(b));
1434
1435 return TRUE;
1436 }
1437
1438 METHOD(listener_t, child_rekey, bool,
1439 private_vici_query_t *this, ike_sa_t *ike_sa, child_sa_t *old,
1440 child_sa_t *new)
1441 {
1442 vici_builder_t *b;
1443 time_t now;
1444
1445 if (!this->dispatcher->has_event_listeners(this->dispatcher, "child-rekey"))
1446 {
1447 return TRUE;
1448 }
1449
1450 now = time_monotonic(NULL);
1451 b = vici_builder_create();
1452
1453 b->begin_section(b, ike_sa->get_name(ike_sa));
1454 list_ike(this, b, ike_sa, now);
1455 b->begin_section(b, "child-sas");
1456
1457 b->begin_section(b, old->get_name(old));
1458
1459 b->begin_section(b, "old");
1460 list_child(this, b, old, now);
1461 b->end_section(b);
1462 b->begin_section(b, "new");
1463 list_child(this, b, new, now);
1464 b->end_section(b);
1465
1466 b->end_section(b);
1467
1468 b->end_section(b);
1469 b->end_section(b);
1470
1471 this->dispatcher->raise_event(this->dispatcher,
1472 "child-rekey", 0, b->finalize(b));
1473
1474 return TRUE;
1475 }
1476
1477 METHOD(vici_query_t, destroy, void,
1478 private_vici_query_t *this)
1479 {
1480 manage_commands(this, FALSE);
1481 free(this);
1482 }
1483
1484 /**
1485 * See header
1486 */
1487 vici_query_t *vici_query_create(vici_dispatcher_t *dispatcher)
1488 {
1489 private_vici_query_t *this;
1490
1491 INIT(this,
1492 .public = {
1493 .listener = {
1494 .ike_updown = _ike_updown,
1495 .ike_rekey = _ike_rekey,
1496 .child_updown = _child_updown,
1497 .child_rekey = _child_rekey,
1498 },
1499 .destroy = _destroy,
1500 },
1501 .dispatcher = dispatcher,
1502 .uptime = time_monotonic(NULL),
1503 );
1504
1505 manage_commands(this, TRUE);
1506
1507 return &this->public;
1508 }