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