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