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