4f040f9fe93fce67a67c2da42786f6ede938b913
[strongswan.git] / src / libcharon / plugins / vici / vici_query.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 /*
17 * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
18 *
19 * Permission is hereby granted, free of charge, to any person obtaining a copy
20 * of this software and associated documentation files (the "Software"), to deal
21 * in the Software without restriction, including without limitation the rights
22 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 * copies of the Software, and to permit persons to whom the Software is
24 * furnished to do so, subject to the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 * THE SOFTWARE.
36 */
37
38 #include "vici_query.h"
39 #include "vici_builder.h"
40
41 #include <inttypes.h>
42 #include <time.h>
43 #ifndef WIN32
44 #include <sys/utsname.h>
45 #endif
46 #ifdef HAVE_MALLINFO
47 #include <malloc.h>
48 #endif
49
50 #include <daemon.h>
51
52 typedef struct private_vici_query_t private_vici_query_t;
53
54 /**
55 * Private data of an vici_query_t object.
56 */
57 struct private_vici_query_t {
58
59 /**
60 * Public vici_query_t interface.
61 */
62 vici_query_t public;
63
64 /**
65 * Dispatcher
66 */
67 vici_dispatcher_t *dispatcher;
68
69 /**
70 * Daemon startup timestamp
71 */
72 time_t uptime;
73 };
74
75 /**
76 * List details of a CHILD_SA
77 */
78 static void list_child(private_vici_query_t *this, vici_builder_t *b,
79 child_sa_t *child, time_t now)
80 {
81 time_t t;
82 u_int64_t bytes, packets;
83 u_int16_t alg, ks;
84 proposal_t *proposal;
85 enumerator_t *enumerator;
86 traffic_selector_t *ts;
87
88 b->add_kv(b, "uniqueid", "%u", child->get_unique_id(child));
89 b->add_kv(b, "reqid", "%u", child->get_reqid(child));
90 b->add_kv(b, "state", "%N", child_sa_state_names, child->get_state(child));
91 b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
92 if (child->get_state(child) == CHILD_INSTALLED ||
93 child->get_state(child) == CHILD_REKEYING ||
94 child->get_state(child) == CHILD_REKEYED)
95 {
96 b->add_kv(b, "protocol", "%N", protocol_id_names,
97 child->get_protocol(child));
98 if (child->has_encap(child))
99 {
100 b->add_kv(b, "encap", "yes");
101 }
102 b->add_kv(b, "spi-in", "%.8x", ntohl(child->get_spi(child, TRUE)));
103 b->add_kv(b, "spi-out", "%.8x", ntohl(child->get_spi(child, FALSE)));
104
105 if (child->get_ipcomp(child) != IPCOMP_NONE)
106 {
107 b->add_kv(b, "cpi-in", "%.4x", ntohs(child->get_cpi(child, TRUE)));
108 b->add_kv(b, "cpi-out", "%.4x", ntohs(child->get_cpi(child, FALSE)));
109 }
110 proposal = child->get_proposal(child);
111 if (proposal)
112 {
113 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
114 &alg, &ks) && alg != ENCR_UNDEFINED)
115 {
116 b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg);
117 if (ks)
118 {
119 b->add_kv(b, "encr-keysize", "%u", ks);
120 }
121 }
122 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
123 &alg, &ks) && alg != ENCR_UNDEFINED)
124 {
125 b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg);
126 if (ks)
127 {
128 b->add_kv(b, "integ-keysize", "%u", ks);
129 }
130 }
131 if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION,
132 &alg, NULL))
133 {
134 b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg);
135 }
136 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP,
137 &alg, NULL))
138 {
139 b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg);
140 }
141 if (proposal->get_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS,
142 &alg, NULL) && alg == EXT_SEQ_NUMBERS)
143 {
144 b->add_kv(b, "esn", "1");
145 }
146 }
147
148 child->get_usestats(child, TRUE, &t, &bytes, &packets);
149 b->add_kv(b, "bytes-in", "%" PRIu64, bytes);
150 b->add_kv(b, "packets-in", "%" PRIu64, packets);
151 if (t)
152 {
153 b->add_kv(b, "use-in", "%"PRIu64, (u_int64_t)(now - t));
154 }
155
156 child->get_usestats(child, FALSE, &t, &bytes, &packets);
157 b->add_kv(b, "bytes-out", "%"PRIu64, bytes);
158 b->add_kv(b, "packets-out", "%"PRIu64, packets);
159 if (t)
160 {
161 b->add_kv(b, "use-out", "%"PRIu64, (u_int64_t)(now - t));
162 }
163
164 t = child->get_lifetime(child, FALSE);
165 if (t)
166 {
167 b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now));
168 }
169 t = child->get_lifetime(child, TRUE);
170 if (t)
171 {
172 b->add_kv(b, "life-time", "%"PRId64, (int64_t)(t - now));
173 }
174 t = child->get_installtime(child);
175 b->add_kv(b, "install-time", "%"PRId64, (int64_t)(now - t));
176 }
177
178 b->begin_list(b, "local-ts");
179 enumerator = child->create_ts_enumerator(child, TRUE);
180 while (enumerator->enumerate(enumerator, &ts))
181 {
182 b->add_li(b, "%R", ts);
183 }
184 enumerator->destroy(enumerator);
185 b->end_list(b /* local-ts */);
186
187 b->begin_list(b, "remote-ts");
188 enumerator = child->create_ts_enumerator(child, FALSE);
189 while (enumerator->enumerate(enumerator, &ts))
190 {
191 b->add_li(b, "%R", ts);
192 }
193 enumerator->destroy(enumerator);
194 b->end_list(b /* remote-ts */);
195 }
196
197 /**
198 * List tasks in a specific queue
199 */
200 static void list_task_queue(private_vici_query_t *this, vici_builder_t *b,
201 ike_sa_t *ike_sa, task_queue_t q, char *name)
202 {
203 enumerator_t *enumerator;
204 bool has = FALSE;
205 task_t *task;
206
207 enumerator = ike_sa->create_task_enumerator(ike_sa, q);
208 while (enumerator->enumerate(enumerator, &task))
209 {
210 if (!has)
211 {
212 b->begin_list(b, name);
213 has = TRUE;
214 }
215 b->add_li(b, "%N", task_type_names, task->get_type(task));
216 }
217 enumerator->destroy(enumerator);
218 if (has)
219 {
220 b->end_list(b);
221 }
222 }
223
224 /**
225 * List details of an IKE_SA
226 */
227 static void list_ike(private_vici_query_t *this, vici_builder_t *b,
228 ike_sa_t *ike_sa, time_t now)
229 {
230 time_t t;
231 ike_sa_id_t *id;
232 identification_t *eap;
233 proposal_t *proposal;
234 u_int16_t alg, ks;
235
236 b->add_kv(b, "uniqueid", "%u", ike_sa->get_unique_id(ike_sa));
237 b->add_kv(b, "version", "%u", ike_sa->get_version(ike_sa));
238 b->add_kv(b, "state", "%N", ike_sa_state_names, ike_sa->get_state(ike_sa));
239
240 b->add_kv(b, "local-host", "%H", ike_sa->get_my_host(ike_sa));
241 b->add_kv(b, "local-id", "%Y", ike_sa->get_my_id(ike_sa));
242
243 b->add_kv(b, "remote-host", "%H", ike_sa->get_other_host(ike_sa));
244 b->add_kv(b, "remote-id", "%Y", ike_sa->get_other_id(ike_sa));
245
246 eap = ike_sa->get_other_eap_id(ike_sa);
247
248 if (!eap->equals(eap, ike_sa->get_other_id(ike_sa)))
249 {
250 if (ike_sa->get_version(ike_sa) == IKEV1)
251 {
252 b->add_kv(b, "remote-xauth-id", "%Y", eap);
253 }
254 else
255 {
256 b->add_kv(b, "remote-eap-id", "%Y", eap);
257 }
258 }
259
260 id = ike_sa->get_id(ike_sa);
261 if (id->is_initiator(id))
262 {
263 b->add_kv(b, "initiator", "yes");
264 }
265 b->add_kv(b, "initiator-spi", "%.16"PRIx64, id->get_initiator_spi(id));
266 b->add_kv(b, "responder-spi", "%.16"PRIx64, id->get_responder_spi(id));
267
268 proposal = ike_sa->get_proposal(ike_sa);
269 if (proposal)
270 {
271 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &ks))
272 {
273 b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg);
274 if (ks)
275 {
276 b->add_kv(b, "encr-keysize", "%u", ks);
277 }
278 }
279 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, &ks))
280 {
281 b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg);
282 if (ks)
283 {
284 b->add_kv(b, "integ-keysize", "%u", ks);
285 }
286 }
287 if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
288 {
289 b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg);
290 }
291 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &alg, NULL))
292 {
293 b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg);
294 }
295 }
296
297 if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
298 {
299 t = ike_sa->get_statistic(ike_sa, STAT_ESTABLISHED);
300 b->add_kv(b, "established", "%"PRId64, (int64_t)(now - t));
301 t = ike_sa->get_statistic(ike_sa, STAT_REKEY);
302 if (t)
303 {
304 b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now));
305 }
306 t = ike_sa->get_statistic(ike_sa, STAT_REAUTH);
307 if (t)
308 {
309 b->add_kv(b, "reauth-time", "%"PRId64, (int64_t)(t - now));
310 }
311 }
312
313 list_task_queue(this, b, ike_sa, TASK_QUEUE_QUEUED, "tasks-queued");
314 list_task_queue(this, b, ike_sa, TASK_QUEUE_ACTIVE, "tasks-active");
315 list_task_queue(this, b, ike_sa, TASK_QUEUE_PASSIVE, "tasks-passive");
316 }
317
318 CALLBACK(list_sas, vici_message_t*,
319 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
320 {
321 vici_builder_t *b;
322 enumerator_t *isas, *csas;
323 ike_sa_t *ike_sa;
324 child_sa_t *child_sa;
325 time_t now;
326 char *ike;
327 u_int ike_id;
328 bool bl;
329
330 bl = request->get_str(request, NULL, "noblock") == NULL;
331 ike = request->get_str(request, NULL, "ike");
332 ike_id = request->get_int(request, 0, "ike-id");
333
334 isas = charon->controller->create_ike_sa_enumerator(charon->controller, bl);
335 while (isas->enumerate(isas, &ike_sa))
336 {
337 if (ike && !streq(ike, ike_sa->get_name(ike_sa)))
338 {
339 continue;
340 }
341 if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa))
342 {
343 continue;
344 }
345
346 now = time_monotonic(NULL);
347
348 b = vici_builder_create();
349 b->begin_section(b, ike_sa->get_name(ike_sa));
350
351 list_ike(this, b, ike_sa, now);
352
353 b->begin_section(b, "child-sas");
354 csas = ike_sa->create_child_sa_enumerator(ike_sa);
355 while (csas->enumerate(csas, &child_sa))
356 {
357 b->begin_section(b, child_sa->get_name(child_sa));
358 list_child(this, b, child_sa, now);
359 b->end_section(b);
360 }
361 csas->destroy(csas);
362 b->end_section(b /* child-sas */ );
363
364 b->end_section(b);
365
366 this->dispatcher->raise_event(this->dispatcher, "list-sa", id,
367 b->finalize(b));
368 }
369 isas->destroy(isas);
370
371 b = vici_builder_create();
372 return b->finalize(b);
373 }
374
375 /**
376 * Raise a list-policy event for given CHILD_SA
377 */
378 static void raise_policy(private_vici_query_t *this, u_int id, child_sa_t *child)
379 {
380 enumerator_t *enumerator;
381 traffic_selector_t *ts;
382 vici_builder_t *b;
383
384 b = vici_builder_create();
385 b->begin_section(b, child->get_name(child));
386
387 b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
388
389 b->begin_list(b, "local-ts");
390 enumerator = child->create_ts_enumerator(child, TRUE);
391 while (enumerator->enumerate(enumerator, &ts))
392 {
393 b->add_li(b, "%R", ts);
394 }
395 enumerator->destroy(enumerator);
396 b->end_list(b /* local-ts */);
397
398 b->begin_list(b, "remote-ts");
399 enumerator = child->create_ts_enumerator(child, FALSE);
400 while (enumerator->enumerate(enumerator, &ts))
401 {
402 b->add_li(b, "%R", ts);
403 }
404 enumerator->destroy(enumerator);
405 b->end_list(b /* remote-ts */);
406
407 b->end_section(b);
408
409 this->dispatcher->raise_event(this->dispatcher, "list-policy", id,
410 b->finalize(b));
411 }
412
413 /**
414 * Raise a list-policy event for given CHILD_SA config
415 */
416 static void raise_policy_cfg(private_vici_query_t *this, u_int id,
417 child_cfg_t *cfg)
418 {
419 enumerator_t *enumerator;
420 linked_list_t *list;
421 traffic_selector_t *ts;
422 vici_builder_t *b;
423
424 b = vici_builder_create();
425 b->begin_section(b, cfg->get_name(cfg));
426
427 b->add_kv(b, "mode", "%N", ipsec_mode_names, cfg->get_mode(cfg));
428
429 b->begin_list(b, "local-ts");
430 list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL);
431 enumerator = list->create_enumerator(list);
432 while (enumerator->enumerate(enumerator, &ts))
433 {
434 b->add_li(b, "%R", ts);
435 }
436 enumerator->destroy(enumerator);
437 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
438 b->end_list(b /* local-ts */);
439
440 b->begin_list(b, "remote-ts");
441 list = cfg->get_traffic_selectors(cfg, FALSE, NULL, NULL);
442 enumerator = list->create_enumerator(list);
443 while (enumerator->enumerate(enumerator, &ts))
444 {
445 b->add_li(b, "%R", ts);
446 }
447 enumerator->destroy(enumerator);
448 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
449 b->end_list(b /* remote-ts */);
450
451 b->end_section(b);
452
453 this->dispatcher->raise_event(this->dispatcher, "list-policy", id,
454 b->finalize(b));
455 }
456
457 CALLBACK(list_policies, vici_message_t*,
458 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
459 {
460 enumerator_t *enumerator;
461 vici_builder_t *b;
462 child_sa_t *child_sa;
463 child_cfg_t *child_cfg;
464 bool drop, pass, trap;
465 char *child;
466
467 drop = request->get_str(request, NULL, "drop") != NULL;
468 pass = request->get_str(request, NULL, "pass") != NULL;
469 trap = request->get_str(request, NULL, "trap") != NULL;
470 child = request->get_str(request, NULL, "child");
471
472 if (trap)
473 {
474 enumerator = charon->traps->create_enumerator(charon->traps);
475 while (enumerator->enumerate(enumerator, NULL, &child_sa))
476 {
477 if (child && !streq(child, child_sa->get_name(child_sa)))
478 {
479 continue;
480 }
481 raise_policy(this, id, child_sa);
482 }
483 enumerator->destroy(enumerator);
484 }
485
486 if (drop || pass)
487 {
488 enumerator = charon->shunts->create_enumerator(charon->shunts);
489 while (enumerator->enumerate(enumerator, &child_cfg))
490 {
491 if (child && !streq(child, child_cfg->get_name(child_cfg)))
492 {
493 continue;
494 }
495 switch (child_cfg->get_mode(child_cfg))
496 {
497 case MODE_DROP:
498 if (drop)
499 {
500 raise_policy_cfg(this, id, child_cfg);
501 }
502 break;
503 case MODE_PASS:
504 if (pass)
505 {
506 raise_policy_cfg(this, id, child_cfg);
507 }
508 break;
509 default:
510 break;
511 }
512 }
513 enumerator->destroy(enumerator);
514 }
515
516 b = vici_builder_create();
517 return b->finalize(b);
518 }
519
520 /**
521 * Build sections for auth configs, local or remote
522 */
523 static void build_auth_cfgs(peer_cfg_t *peer_cfg, bool local, vici_builder_t *b)
524 {
525 enumerator_t *enumerator, *rules;
526 auth_rule_t rule;
527 auth_cfg_t *auth;
528 union {
529 uintptr_t u;
530 identification_t *id;
531 certificate_t *cert;
532 char *str;
533 } v;
534 char buf[32];
535 int i = 0;
536
537 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
538 while (enumerator->enumerate(enumerator, &auth))
539 {
540 snprintf(buf, sizeof(buf), "%s-%d", local ? "local" : "remote", ++i);
541 b->begin_section(b, buf);
542
543 rules = auth->create_enumerator(auth);
544 while (rules->enumerate(rules, &rule, &v))
545 {
546 switch (rule)
547 {
548 case AUTH_RULE_AUTH_CLASS:
549 b->add_kv(b, "class", "%N", auth_class_names, v.u);
550 break;
551 case AUTH_RULE_EAP_TYPE:
552 b->add_kv(b, "eap-type", "%N", eap_type_names, v.u);
553 break;
554 case AUTH_RULE_EAP_VENDOR:
555 b->add_kv(b, "eap-vendor", "%u", v.u);
556 break;
557 case AUTH_RULE_XAUTH_BACKEND:
558 b->add_kv(b, "xauth", "%s", v.str);
559 break;
560 case AUTH_RULE_CRL_VALIDATION:
561 b->add_kv(b, "revocation", "%N", cert_validation_names, v.u);
562 break;
563 case AUTH_RULE_IDENTITY:
564 b->add_kv(b, "id", "%Y", v.id);
565 break;
566 case AUTH_RULE_AAA_IDENTITY:
567 b->add_kv(b, "aaa_id", "%Y", v.id);
568 break;
569 case AUTH_RULE_EAP_IDENTITY:
570 b->add_kv(b, "eap_id", "%Y", v.id);
571 break;
572 case AUTH_RULE_XAUTH_IDENTITY:
573 b->add_kv(b, "xauth_id", "%Y", v.id);
574 break;
575 default:
576 break;
577 }
578 }
579 rules->destroy(rules);
580
581 b->begin_list(b, "groups");
582 rules = auth->create_enumerator(auth);
583 while (rules->enumerate(rules, &rule, &v))
584 {
585 if (rule == AUTH_RULE_GROUP)
586 {
587 b->add_li(b, "%Y", v.id);
588 }
589 }
590 rules->destroy(rules);
591 b->end_list(b);
592
593 b->begin_list(b, "certs");
594 rules = auth->create_enumerator(auth);
595 while (rules->enumerate(rules, &rule, &v))
596 {
597 if (rule == AUTH_RULE_SUBJECT_CERT)
598 {
599 b->add_li(b, "%Y", v.cert->get_subject(v.cert));
600 }
601 }
602 rules->destroy(rules);
603 b->end_list(b);
604
605 b->begin_list(b, "cacerts");
606 rules = auth->create_enumerator(auth);
607 while (rules->enumerate(rules, &rule, &v))
608 {
609 if (rule == AUTH_RULE_CA_CERT)
610 {
611 b->add_li(b, "%Y", v.cert->get_subject(v.cert));
612 }
613 }
614 rules->destroy(rules);
615 b->end_list(b);
616
617 b->end_section(b);
618 }
619 enumerator->destroy(enumerator);
620 }
621
622 CALLBACK(list_conns, vici_message_t*,
623 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
624 {
625 enumerator_t *enumerator, *tokens, *selectors, *children;
626 peer_cfg_t *peer_cfg;
627 ike_cfg_t *ike_cfg;
628 child_cfg_t *child_cfg;
629 char *ike, *str;
630 linked_list_t *list;
631 traffic_selector_t *ts;
632 vici_builder_t *b;
633
634 ike = request->get_str(request, NULL, "ike");
635
636 enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
637 NULL, NULL, NULL, NULL, IKE_ANY);
638 while (enumerator->enumerate(enumerator, &peer_cfg))
639 {
640 if (ike && !streq(ike, peer_cfg->get_name(peer_cfg)))
641 {
642 continue;
643 }
644
645 b = vici_builder_create();
646 b->begin_section(b, peer_cfg->get_name(peer_cfg));
647
648 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
649
650 b->begin_list(b, "local_addrs");
651 str = ike_cfg->get_my_addr(ike_cfg);
652 tokens = enumerator_create_token(str, ",", " ");
653 while (tokens->enumerate(tokens, &str))
654 {
655 b->add_li(b, "%s", str);
656 }
657 tokens->destroy(tokens);
658 b->end_list(b);
659
660 b->begin_list(b, "remote_addrs");
661 str = ike_cfg->get_other_addr(ike_cfg);
662 tokens = enumerator_create_token(str, ",", " ");
663 while (tokens->enumerate(tokens, &str))
664 {
665 b->add_li(b, "%s", str);
666 }
667 tokens->destroy(tokens);
668 b->end_list(b);
669
670 b->add_kv(b, "version", "%N", ike_version_names,
671 peer_cfg->get_ike_version(peer_cfg));
672
673 build_auth_cfgs(peer_cfg, TRUE, b);
674 build_auth_cfgs(peer_cfg, FALSE, b);
675
676 b->begin_section(b, "children");
677
678 children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
679 while (children->enumerate(children, &child_cfg))
680 {
681 b->begin_section(b, child_cfg->get_name(child_cfg));
682
683 b->add_kv(b, "mode", "%N", ipsec_mode_names,
684 child_cfg->get_mode(child_cfg));
685
686 b->begin_list(b, "local-ts");
687 list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
688 selectors = list->create_enumerator(list);
689 while (selectors->enumerate(selectors, &ts))
690 {
691 b->add_li(b, "%R", ts);
692 }
693 selectors->destroy(selectors);
694 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
695 b->end_list(b /* local-ts */);
696
697 b->begin_list(b, "remote-ts");
698 list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
699 selectors = list->create_enumerator(list);
700 while (selectors->enumerate(selectors, &ts))
701 {
702 b->add_li(b, "%R", ts);
703 }
704 selectors->destroy(selectors);
705 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
706 b->end_list(b /* remote-ts */);
707
708 b->end_section(b);
709 }
710 children->destroy(children);
711
712 b->end_section(b); /* children */
713
714 b->end_section(b); /* name */
715
716 this->dispatcher->raise_event(this->dispatcher, "list-conn", id,
717 b->finalize(b));
718 }
719 enumerator->destroy(enumerator);
720
721 b = vici_builder_create();
722 return b->finalize(b);
723 }
724
725 /**
726 * Do we have a private key for given certificate
727 */
728 static bool has_privkey(private_vici_query_t *this, certificate_t *cert)
729 {
730 private_key_t *private;
731 public_key_t *public;
732 identification_t *keyid;
733 chunk_t chunk;
734 bool found = FALSE;
735
736 public = cert->get_public_key(cert);
737 if (public)
738 {
739 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
740 {
741 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
742 private = lib->credmgr->get_private(lib->credmgr,
743 public->get_type(public), keyid, NULL);
744 if (private)
745 {
746 found = TRUE;
747 private->destroy(private);
748 }
749 keyid->destroy(keyid);
750 }
751 public->destroy(public);
752 }
753 return found;
754 }
755
756 CALLBACK(list_certs, vici_message_t*,
757 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
758 {
759 enumerator_t *enumerator, *added;
760 linked_list_t *list;
761 certificate_t *cert, *current;
762 chunk_t encoding;
763 identification_t *subject = NULL;
764 int type;
765 vici_builder_t *b;
766 bool found;
767 char *str;
768
769 str = request->get_str(request, "ANY", "type");
770 if (!enum_from_name(certificate_type_names, str, &type))
771 {
772 b = vici_builder_create();
773 return b->finalize(b);
774 }
775 str = request->get_str(request, NULL, "subject");
776 if (str)
777 {
778 subject = identification_create_from_string(str);
779 }
780
781 list = linked_list_create();
782 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
783 type, KEY_ANY, subject, FALSE);
784 while (enumerator->enumerate(enumerator, &cert))
785 {
786 found = FALSE;
787 added = list->create_enumerator(list);
788 while (added->enumerate(added, &current))
789 {
790 if (current->equals(current, cert))
791 {
792 found = TRUE;
793 break;
794 }
795 }
796 added->destroy(added);
797
798 if (!found && cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
799 {
800 b = vici_builder_create();
801 b->add_kv(b, "type", "%N",
802 certificate_type_names, cert->get_type(cert));
803 if (has_privkey(this, cert))
804 {
805 b->add_kv(b, "has_privkey", "yes");
806 }
807 b->add(b, VICI_KEY_VALUE, "data", encoding);
808 free(encoding.ptr);
809
810 this->dispatcher->raise_event(this->dispatcher, "list-cert", id,
811 b->finalize(b));
812 list->insert_last(list, cert->get_ref(cert));
813 }
814 }
815 enumerator->destroy(enumerator);
816
817 list->destroy_offset(list, offsetof(certificate_t, destroy));
818 DESTROY_IF(subject);
819
820 b = vici_builder_create();
821 return b->finalize(b);
822 }
823
824 CALLBACK(version, vici_message_t*,
825 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
826 {
827 vici_builder_t *b;
828
829 b = vici_builder_create();
830
831 b->add_kv(b, "daemon", "%s", lib->ns);
832 b->add_kv(b, "version", "%s", VERSION);
833
834 #ifdef WIN32
835 {
836 OSVERSIONINFOEX osvie;
837
838 memset(&osvie, 0, sizeof(osvie));
839 osvie.dwOSVersionInfoSize = sizeof(osvie);
840
841 if (GetVersionEx((LPOSVERSIONINFO)&osvie))
842 {
843 b->add_kv(b, "sysname", "Windows %s",
844 osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server");
845 b->add_kv(b, "release", "%d.%d.%d (SP %d.%d)",
846 osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber,
847 osvie.wServicePackMajor, osvie.wServicePackMinor);
848 b->add_kv(b, "machine", "%s",
849 #ifdef WIN64
850 "x86_64");
851 #else
852 "x86");
853 #endif /* !WIN64 */
854 }
855 }
856 #else /* !WIN32 */
857 {
858 struct utsname utsname;
859
860 if (uname(&utsname) == 0)
861 {
862 b->add_kv(b, "sysname", "%s", utsname.sysname);
863 b->add_kv(b, "release", "%s", utsname.release);
864 b->add_kv(b, "machine", "%s", utsname.machine);
865 }
866 }
867 #endif /* !WIN32 */
868 return b->finalize(b);
869 }
870
871 /**
872 * Callback function for memusage summary
873 */
874 CALLBACK(sum_usage, void,
875 vici_builder_t *b, int count, size_t bytes, int whitelisted)
876 {
877 b->begin_section(b, "mem");
878 b->add_kv(b, "total", "%zu", bytes);
879 b->add_kv(b, "allocs", "%d", count);
880 b->end_section(b);
881 }
882
883 CALLBACK(stats, vici_message_t*,
884 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
885 {
886 vici_builder_t *b;
887 enumerator_t *enumerator;
888 plugin_t *plugin;
889 time_t since, now;
890 int i;
891
892 b = vici_builder_create();
893
894 now = time_monotonic(NULL);
895 since = time(NULL) - (now - this->uptime);
896
897 b->begin_section(b, "uptime");
898 b->add_kv(b, "running", "%V", &now, &this->uptime);
899 b->add_kv(b, "since", "%T", &since, FALSE);
900 b->end_section(b);
901
902 b->begin_section(b, "workers");
903 b->add_kv(b, "total", "%d",
904 lib->processor->get_total_threads(lib->processor));
905 b->add_kv(b, "idle", "%d",
906 lib->processor->get_idle_threads(lib->processor));
907 b->begin_section(b, "active");
908 for (i = 0; i < JOB_PRIO_MAX; i++)
909 {
910 b->add_kv(b, enum_to_name(job_priority_names, i), "%d",
911 lib->processor->get_working_threads(lib->processor, i));
912 }
913 b->end_section(b);
914 b->end_section(b);
915
916 b->begin_section(b, "queues");
917 for (i = 0; i < JOB_PRIO_MAX; i++)
918 {
919 b->add_kv(b, enum_to_name(job_priority_names, i), "%d",
920 lib->processor->get_job_load(lib->processor, i));
921 }
922 b->end_section(b);
923
924 b->add_kv(b, "scheduled", "%d",
925 lib->scheduler->get_job_load(lib->scheduler));
926
927 b->begin_section(b, "ikesas");
928 b->add_kv(b, "total", "%u",
929 charon->ike_sa_manager->get_count(charon->ike_sa_manager));
930 b->add_kv(b, "half-open", "%u",
931 charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
932 NULL));
933 b->end_section(b);
934
935 b->begin_list(b, "plugins");
936 enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
937 while (enumerator->enumerate(enumerator, &plugin, NULL))
938 {
939 b->add_li(b, "%s", plugin->get_name(plugin));
940 }
941 enumerator->destroy(enumerator);
942 b->end_list(b);
943
944 if (lib->leak_detective)
945 {
946 lib->leak_detective->usage(lib->leak_detective, NULL, sum_usage, b);
947 }
948 #ifdef WIN32
949 else
950 {
951 DWORD lasterr = ERROR_INVALID_HANDLE;
952 HANDLE heaps[32];
953 int i, count;
954 char buf[16];
955 size_t total = 0;
956 int allocs = 0;
957
958 b->begin_section(b, "mem");
959 count = GetProcessHeaps(countof(heaps), heaps);
960 for (i = 0; i < count; i++)
961 {
962 PROCESS_HEAP_ENTRY entry = {};
963 size_t heap_total = 0;
964 int heap_allocs = 0;
965
966 if (HeapLock(heaps[i]))
967 {
968 while (HeapWalk(heaps[i], &entry))
969 {
970 if (entry.wFlags & PROCESS_HEAP_ENTRY_BUSY)
971 {
972 heap_total += entry.cbData;
973 heap_allocs++;
974 }
975 }
976 lasterr = GetLastError();
977 HeapUnlock(heaps[i]);
978 }
979 if (lasterr != ERROR_NO_MORE_ITEMS)
980 {
981 break;
982 }
983 snprintf(buf, sizeof(buf), "heap-%d", i);
984 b->begin_section(b, buf);
985 b->add_kv(b, "total", "%zu", heap_total);
986 b->add_kv(b, "allocs", "%d", heap_allocs);
987 b->end_section(b);
988
989 total += heap_total;
990 allocs += heap_allocs;
991 }
992 if (lasterr == ERROR_NO_MORE_ITEMS)
993 {
994 b->add_kv(b, "total", "%zu", total);
995 b->add_kv(b, "allocs", "%d", allocs);
996 }
997 b->end_section(b);
998 }
999 #endif
1000
1001 #ifdef HAVE_MALLINFO
1002 {
1003 struct mallinfo mi = mallinfo();
1004
1005 b->begin_section(b, "mallinfo");
1006 b->add_kv(b, "sbrk", "%u", mi.arena);
1007 b->add_kv(b, "mmap", "%u", mi.hblkhd);
1008 b->add_kv(b, "used", "%u", mi.uordblks);
1009 b->add_kv(b, "free", "%u", mi.fordblks);
1010 b->end_section(b);
1011 }
1012 #endif /* HAVE_MALLINFO */
1013
1014 return b->finalize(b);
1015 }
1016
1017 static void manage_command(private_vici_query_t *this,
1018 char *name, vici_command_cb_t cb, bool reg)
1019 {
1020 this->dispatcher->manage_command(this->dispatcher, name,
1021 reg ? cb : NULL, this);
1022 }
1023
1024 /**
1025 * (Un-)register dispatcher functions
1026 */
1027 static void manage_commands(private_vici_query_t *this, bool reg)
1028 {
1029 this->dispatcher->manage_event(this->dispatcher, "list-sa", reg);
1030 this->dispatcher->manage_event(this->dispatcher, "list-policy", reg);
1031 this->dispatcher->manage_event(this->dispatcher, "list-conn", reg);
1032 this->dispatcher->manage_event(this->dispatcher, "list-cert", reg);
1033 this->dispatcher->manage_event(this->dispatcher, "ike-updown", reg);
1034 this->dispatcher->manage_event(this->dispatcher, "child-updown", reg);
1035 manage_command(this, "list-sas", list_sas, reg);
1036 manage_command(this, "list-policies", list_policies, reg);
1037 manage_command(this, "list-conns", list_conns, reg);
1038 manage_command(this, "list-certs", list_certs, reg);
1039 manage_command(this, "version", version, reg);
1040 manage_command(this, "stats", stats, reg);
1041 }
1042
1043 METHOD(listener_t, ike_updown, bool,
1044 private_vici_query_t *this, ike_sa_t *ike_sa, bool up)
1045 {
1046 vici_builder_t *b;
1047 time_t now;
1048
1049 if (!this->dispatcher->has_event_listeners(this->dispatcher, "ike-updown"))
1050 {
1051 return TRUE;
1052 }
1053
1054 now = time_monotonic(NULL);
1055
1056 b = vici_builder_create();
1057
1058 if (up)
1059 {
1060 b->add_kv(b, "up", "yes");
1061 }
1062
1063 b->begin_section(b, ike_sa->get_name(ike_sa));
1064 list_ike(this, b, ike_sa, now);
1065 b->begin_section(b, "child-sas");
1066 b->end_section(b);
1067 b->end_section(b);
1068
1069 this->dispatcher->raise_event(this->dispatcher,
1070 "ike-updown", 0, b->finalize(b));
1071
1072 return TRUE;
1073 }
1074
1075 METHOD(listener_t, child_updown, bool,
1076 private_vici_query_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up)
1077 {
1078 vici_builder_t *b;
1079 time_t now;
1080
1081 if (!this->dispatcher->has_event_listeners(this->dispatcher, "child-updown"))
1082 {
1083 return TRUE;
1084 }
1085
1086 now = time_monotonic(NULL);
1087 b = vici_builder_create();
1088
1089 if (up)
1090 {
1091 b->add_kv(b, "up", "yes");
1092 }
1093
1094 b->begin_section(b, ike_sa->get_name(ike_sa));
1095 list_ike(this, b, ike_sa, now);
1096 b->begin_section(b, "child-sas");
1097
1098 b->begin_section(b, child_sa->get_name(child_sa));
1099 list_child(this, b, child_sa, now);
1100 b->end_section(b);
1101
1102 b->end_section(b);
1103 b->end_section(b);
1104
1105 this->dispatcher->raise_event(this->dispatcher,
1106 "child-updown", 0, b->finalize(b));
1107
1108 return TRUE;
1109 }
1110
1111 METHOD(vici_query_t, destroy, void,
1112 private_vici_query_t *this)
1113 {
1114 manage_commands(this, FALSE);
1115 free(this);
1116 }
1117
1118 /**
1119 * See header
1120 */
1121 vici_query_t *vici_query_create(vici_dispatcher_t *dispatcher)
1122 {
1123 private_vici_query_t *this;
1124
1125 INIT(this,
1126 .public = {
1127 .listener = {
1128 .ike_updown = _ike_updown,
1129 .child_updown = _child_updown,
1130 },
1131 .destroy = _destroy,
1132 },
1133 .dispatcher = dispatcher,
1134 .uptime = time_monotonic(NULL),
1135 );
1136
1137 manage_commands(this, TRUE);
1138
1139 return &this->public;
1140 }