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