Version bump to 5.8.2rc1
[strongswan.git] / src / libcharon / plugins / vici / vici_query.c
1 /*
2 * Copyright (C) 2015-2017 Tobias Brunner
3 * Copyright (C) 2015-2018 Andreas Steffen
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * Copyright (C) 2014 Martin Willi
7 * Copyright (C) 2014 revosec AG
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
18 */
19
20 /*
21 * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39 * THE SOFTWARE.
40 */
41
42 #include "vici_query.h"
43 #include "vici_builder.h"
44 #include "vici_cert_info.h"
45
46 #include <inttypes.h>
47 #include <time.h>
48 #ifndef WIN32
49 #include <sys/utsname.h>
50 #endif
51 #ifdef HAVE_MALLINFO
52 #include <malloc.h>
53 #endif
54
55 #include <daemon.h>
56 #include <asn1/asn1.h>
57 #include <credentials/certificates/certificate.h>
58 #include <credentials/certificates/x509.h>
59 #include <counters_query.h>
60
61 ENUM(vici_counter_type_names,
62 COUNTER_INIT_IKE_SA_REKEY, COUNTER_OUT_INFORMATIONAL_RSP,
63 "ike-rekey-init",
64 "ike-rekey-resp",
65 "child-rekey",
66 "invalid",
67 "invalid-spi",
68 "ike-init-in-req",
69 "ike-init-in-resp",
70 "ike-init-out-req",
71 "ike-init-out-resp",
72 "ike-auth-in-req",
73 "ike-auth-in-resp",
74 "ike-auth-out-req",
75 "ike-auth-out-resp",
76 "create-child-in-req",
77 "create-child-in-resp",
78 "create-child-out-req",
79 "create-child-out-resp",
80 "info-in-req",
81 "info-in-resp",
82 "info-out-req",
83 "info-out-resp",
84 );
85
86 typedef struct private_vici_query_t private_vici_query_t;
87
88 /**
89 * Private data of an vici_query_t object.
90 */
91 struct private_vici_query_t {
92
93 /**
94 * Public vici_query_t interface.
95 */
96 vici_query_t public;
97
98 /**
99 * Dispatcher
100 */
101 vici_dispatcher_t *dispatcher;
102
103 /**
104 * Query interface for counters
105 */
106 counters_query_t *counters;
107
108 /**
109 * Daemon startup timestamp
110 */
111 time_t uptime;
112 };
113
114 /**
115 * Add the given mark/mask to the message using the provided labels
116 */
117 static void add_mark(vici_builder_t *b, mark_t mark,
118 char *label, char *mask_label)
119 {
120 if (mark.value | mark.mask)
121 {
122 b->add_kv(b, label, "%.8x", mark.value);
123 if (~mark.mask)
124 {
125 b->add_kv(b, mask_label, "%.8x", mark.mask);
126 }
127 }
128 }
129
130 /**
131 * List the mode of a CHILD_SA or config
132 */
133 static void list_mode(vici_builder_t *b, child_sa_t *child, child_cfg_t *cfg)
134 {
135 ipsec_mode_t mode;
136 char *sub_mode = "";
137
138 if (child || cfg)
139 {
140 if (!cfg)
141 {
142 cfg = child->get_config(child);
143 }
144 mode = child ? child->get_mode(child) : cfg->get_mode(cfg);
145 if (mode == MODE_TRANSPORT && cfg->has_option(cfg, OPT_PROXY_MODE))
146 { /* only report this if the negotiated mode is actually TRANSPORT */
147 sub_mode = "_PROXY";
148 }
149 b->add_kv(b, "mode", "%N%s", ipsec_mode_names, mode, sub_mode);
150 }
151 }
152
153 /**
154 * List IPsec-related details about a CHILD_SA
155 */
156 static void list_child_ipsec(vici_builder_t *b, child_sa_t *child)
157 {
158 proposal_t *proposal;
159 uint16_t alg, ks;
160 uint32_t if_id;
161
162 b->add_kv(b, "protocol", "%N", protocol_id_names,
163 child->get_protocol(child));
164 if (child->has_encap(child))
165 {
166 b->add_kv(b, "encap", "yes");
167 }
168 b->add_kv(b, "spi-in", "%.8x", ntohl(child->get_spi(child, TRUE)));
169 b->add_kv(b, "spi-out", "%.8x", ntohl(child->get_spi(child, FALSE)));
170
171 if (child->get_ipcomp(child) != IPCOMP_NONE)
172 {
173 b->add_kv(b, "cpi-in", "%.4x", ntohs(child->get_cpi(child, TRUE)));
174 b->add_kv(b, "cpi-out", "%.4x", ntohs(child->get_cpi(child, FALSE)));
175 }
176 add_mark(b, child->get_mark(child, TRUE), "mark-in", "mark-mask-in");
177 add_mark(b, child->get_mark(child, FALSE), "mark-out", "mark-mask-out");
178
179 if_id = child->get_if_id(child, TRUE);
180 if (if_id)
181 {
182 b->add_kv(b, "if-id-in", "%.8x", if_id);
183 }
184 if_id = child->get_if_id(child, FALSE);
185 if (if_id)
186 {
187 b->add_kv(b, "if-id-out", "%.8x", if_id);
188 }
189
190 proposal = child->get_proposal(child);
191 if (proposal)
192 {
193 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
194 &alg, &ks) && alg != ENCR_UNDEFINED)
195 {
196 b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg);
197 if (ks)
198 {
199 b->add_kv(b, "encr-keysize", "%u", ks);
200 }
201 }
202 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
203 &alg, &ks) && alg != AUTH_UNDEFINED)
204 {
205 b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg);
206 if (ks)
207 {
208 b->add_kv(b, "integ-keysize", "%u", ks);
209 }
210 }
211 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP,
212 &alg, NULL))
213 {
214 b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg);
215 }
216 if (proposal->get_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS,
217 &alg, NULL) && alg == EXT_SEQ_NUMBERS)
218 {
219 b->add_kv(b, "esn", "1");
220 }
221 }
222 }
223
224 /**
225 * List usage and lifetime stats of a CHILD_SA
226 */
227 static void list_child_stats(vici_builder_t *b, child_sa_t *child, time_t now)
228 {
229 uint64_t bytes, packets;
230 time_t t;
231
232 child->get_usestats(child, TRUE, &t, &bytes, &packets);
233 b->add_kv(b, "bytes-in", "%" PRIu64, bytes);
234 b->add_kv(b, "packets-in", "%" PRIu64, packets);
235 if (t)
236 {
237 b->add_kv(b, "use-in", "%"PRIu64, (uint64_t)(now - t));
238 }
239
240 child->get_usestats(child, FALSE, &t, &bytes, &packets);
241 b->add_kv(b, "bytes-out", "%"PRIu64, bytes);
242 b->add_kv(b, "packets-out", "%"PRIu64, packets);
243 if (t)
244 {
245 b->add_kv(b, "use-out", "%"PRIu64, (uint64_t)(now - t));
246 }
247
248 t = child->get_lifetime(child, FALSE);
249 if (t)
250 {
251 b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now));
252 }
253 t = child->get_lifetime(child, TRUE);
254 if (t)
255 {
256 b->add_kv(b, "life-time", "%"PRId64, (int64_t)(t - now));
257 }
258 t = child->get_installtime(child);
259 b->add_kv(b, "install-time", "%"PRId64, (int64_t)(now - t));
260 }
261
262 /**
263 * List details of a CHILD_SA
264 */
265 static void list_child(private_vici_query_t *this, vici_builder_t *b,
266 child_sa_t *child, time_t now)
267 {
268 enumerator_t *enumerator;
269 traffic_selector_t *ts;
270 child_sa_state_t state;
271
272 b->add_kv(b, "name", "%s", child->get_name(child));
273 b->add_kv(b, "uniqueid", "%u", child->get_unique_id(child));
274 b->add_kv(b, "reqid", "%u", child->get_reqid(child));
275 state = child->get_state(child);
276 b->add_kv(b, "state", "%N", child_sa_state_names, state);
277 list_mode(b, child, NULL);
278
279 switch (state)
280 {
281 case CHILD_INSTALLED:
282 case CHILD_REKEYING:
283 case CHILD_REKEYED:
284 case CHILD_DELETING:
285 case CHILD_DELETED:
286 list_child_ipsec(b, child);
287 list_child_stats(b, child, now);
288 break;
289 default:
290 break;
291 }
292
293 b->begin_list(b, "local-ts");
294 enumerator = child->create_ts_enumerator(child, TRUE);
295 while (enumerator->enumerate(enumerator, &ts))
296 {
297 b->add_li(b, "%R", ts);
298 }
299 enumerator->destroy(enumerator);
300 b->end_list(b /* local-ts */);
301
302 b->begin_list(b, "remote-ts");
303 enumerator = child->create_ts_enumerator(child, FALSE);
304 while (enumerator->enumerate(enumerator, &ts))
305 {
306 b->add_li(b, "%R", ts);
307 }
308 enumerator->destroy(enumerator);
309 b->end_list(b /* remote-ts */);
310 }
311
312 /**
313 * List tasks in a specific queue
314 */
315 static void list_task_queue(private_vici_query_t *this, vici_builder_t *b,
316 ike_sa_t *ike_sa, task_queue_t q, char *name)
317 {
318 enumerator_t *enumerator;
319 bool has = FALSE;
320 task_t *task;
321
322 enumerator = ike_sa->create_task_enumerator(ike_sa, q);
323 while (enumerator->enumerate(enumerator, &task))
324 {
325 if (!has)
326 {
327 b->begin_list(b, name);
328 has = TRUE;
329 }
330 b->add_li(b, "%N", task_type_names, task->get_type(task));
331 }
332 enumerator->destroy(enumerator);
333 if (has)
334 {
335 b->end_list(b);
336 }
337 }
338
339 /**
340 * Add an IKE_SA condition to the given builder
341 */
342 static void add_condition(vici_builder_t *b, ike_sa_t *ike_sa,
343 char *key, ike_condition_t cond)
344 {
345 if (ike_sa->has_condition(ike_sa, cond))
346 {
347 b->add_kv(b, key, "yes");
348 }
349 }
350
351 /**
352 * List virtual IPs
353 */
354 static void list_vips(private_vici_query_t *this, vici_builder_t *b,
355 ike_sa_t *ike_sa, bool local, char *name)
356 {
357 enumerator_t *enumerator;
358 bool has = FALSE;
359 host_t *vip;
360
361 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
362 while (enumerator->enumerate(enumerator, &vip))
363 {
364 if (!has)
365 {
366 b->begin_list(b, name);
367 has = TRUE;
368 }
369 b->add_li(b, "%H", vip);
370 }
371 enumerator->destroy(enumerator);
372 if (has)
373 {
374 b->end_list(b);
375 }
376 }
377
378 /**
379 * List details of an IKE_SA
380 */
381 static void list_ike(private_vici_query_t *this, vici_builder_t *b,
382 ike_sa_t *ike_sa, time_t now)
383 {
384 time_t t;
385 ike_sa_id_t *id;
386 identification_t *eap;
387 proposal_t *proposal;
388 uint32_t if_id;
389 uint16_t alg, ks;
390 host_t *host;
391
392 b->add_kv(b, "uniqueid", "%u", ike_sa->get_unique_id(ike_sa));
393 b->add_kv(b, "version", "%u", ike_sa->get_version(ike_sa));
394 b->add_kv(b, "state", "%N", ike_sa_state_names, ike_sa->get_state(ike_sa));
395
396 host = ike_sa->get_my_host(ike_sa);
397 b->add_kv(b, "local-host", "%H", host);
398 b->add_kv(b, "local-port", "%d", host->get_port(host));
399 b->add_kv(b, "local-id", "%Y", ike_sa->get_my_id(ike_sa));
400
401 host = ike_sa->get_other_host(ike_sa);
402 b->add_kv(b, "remote-host", "%H", host);
403 b->add_kv(b, "remote-port", "%d", host->get_port(host));
404 b->add_kv(b, "remote-id", "%Y", ike_sa->get_other_id(ike_sa));
405
406 eap = ike_sa->get_other_eap_id(ike_sa);
407
408 if (!eap->equals(eap, ike_sa->get_other_id(ike_sa)))
409 {
410 if (ike_sa->get_version(ike_sa) == IKEV1)
411 {
412 b->add_kv(b, "remote-xauth-id", "%Y", eap);
413 }
414 else
415 {
416 b->add_kv(b, "remote-eap-id", "%Y", eap);
417 }
418 }
419
420 id = ike_sa->get_id(ike_sa);
421 if (id->is_initiator(id))
422 {
423 b->add_kv(b, "initiator", "yes");
424 }
425 b->add_kv(b, "initiator-spi", "%.16"PRIx64,
426 be64toh(id->get_initiator_spi(id)));
427 b->add_kv(b, "responder-spi", "%.16"PRIx64,
428 be64toh(id->get_responder_spi(id)));
429
430 add_condition(b, ike_sa, "nat-local", COND_NAT_HERE);
431 add_condition(b, ike_sa, "nat-remote", COND_NAT_THERE);
432 add_condition(b, ike_sa, "nat-fake", COND_NAT_FAKE);
433 add_condition(b, ike_sa, "nat-any", COND_NAT_ANY);
434
435 if_id = ike_sa->get_if_id(ike_sa, TRUE);
436 if (if_id)
437 {
438 b->add_kv(b, "if-id-in", "%.8x", if_id);
439 }
440 if_id = ike_sa->get_if_id(ike_sa, FALSE);
441 if (if_id)
442 {
443 b->add_kv(b, "if-id-out", "%.8x", if_id);
444 }
445
446 proposal = ike_sa->get_proposal(ike_sa);
447 if (proposal)
448 {
449 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &ks))
450 {
451 b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg);
452 if (ks)
453 {
454 b->add_kv(b, "encr-keysize", "%u", ks);
455 }
456 }
457 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, &ks))
458 {
459 b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg);
460 if (ks)
461 {
462 b->add_kv(b, "integ-keysize", "%u", ks);
463 }
464 }
465 if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
466 {
467 b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg);
468 }
469 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &alg, NULL))
470 {
471 b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg);
472 }
473 }
474 add_condition(b, ike_sa, "ppk", COND_PPK);
475
476 if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
477 {
478 t = ike_sa->get_statistic(ike_sa, STAT_ESTABLISHED);
479 b->add_kv(b, "established", "%"PRId64, (int64_t)(now - t));
480 t = ike_sa->get_statistic(ike_sa, STAT_REKEY);
481 if (t)
482 {
483 b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now));
484 }
485 t = ike_sa->get_statistic(ike_sa, STAT_REAUTH);
486 if (t)
487 {
488 b->add_kv(b, "reauth-time", "%"PRId64, (int64_t)(t - now));
489 }
490 }
491
492 list_vips(this, b, ike_sa, TRUE, "local-vips");
493 list_vips(this, b, ike_sa, FALSE, "remote-vips");
494
495 list_task_queue(this, b, ike_sa, TASK_QUEUE_QUEUED, "tasks-queued");
496 list_task_queue(this, b, ike_sa, TASK_QUEUE_ACTIVE, "tasks-active");
497 list_task_queue(this, b, ike_sa, TASK_QUEUE_PASSIVE, "tasks-passive");
498 }
499
500 CALLBACK(list_sas, vici_message_t*,
501 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
502 {
503 vici_builder_t *b;
504 enumerator_t *isas, *csas;
505 ike_sa_t *ike_sa;
506 child_sa_t *child_sa;
507 time_t now;
508 char *ike;
509 u_int ike_id;
510 bool bl;
511 char buf[BUF_LEN];
512
513 bl = request->get_str(request, NULL, "noblock") == NULL;
514 ike = request->get_str(request, NULL, "ike");
515 ike_id = request->get_int(request, 0, "ike-id");
516
517 isas = charon->controller->create_ike_sa_enumerator(charon->controller, bl);
518 while (isas->enumerate(isas, &ike_sa))
519 {
520 if (ike && !streq(ike, ike_sa->get_name(ike_sa)))
521 {
522 continue;
523 }
524 if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa))
525 {
526 continue;
527 }
528
529 now = time_monotonic(NULL);
530
531 b = vici_builder_create();
532 b->begin_section(b, ike_sa->get_name(ike_sa));
533
534 list_ike(this, b, ike_sa, now);
535
536 b->begin_section(b, "child-sas");
537 csas = ike_sa->create_child_sa_enumerator(ike_sa);
538 while (csas->enumerate(csas, &child_sa))
539 {
540 snprintf(buf, sizeof(buf), "%s-%u", child_sa->get_name(child_sa),
541 child_sa->get_unique_id(child_sa));
542 b->begin_section(b, buf);
543 list_child(this, b, child_sa, now);
544 b->end_section(b);
545 }
546 csas->destroy(csas);
547 b->end_section(b /* child-sas */ );
548
549 b->end_section(b);
550
551 this->dispatcher->raise_event(this->dispatcher, "list-sa", id,
552 b->finalize(b));
553 }
554 isas->destroy(isas);
555
556 b = vici_builder_create();
557 return b->finalize(b);
558 }
559
560 /**
561 * Raise a list-policy event for given CHILD_SA
562 */
563 static void raise_policy(private_vici_query_t *this, u_int id, char *ike,
564 child_sa_t *child)
565 {
566 enumerator_t *enumerator;
567 traffic_selector_t *ts;
568 vici_builder_t *b;
569 char buf[BUF_LEN];
570
571 b = vici_builder_create();
572 snprintf(buf, sizeof(buf), "%s/%s", ike, child->get_name(child));
573 b->begin_section(b, buf);
574 b->add_kv(b, "child", "%s", child->get_name(child));
575 b->add_kv(b, "ike", "%s", ike);
576
577 list_mode(b, child, NULL);
578
579 b->begin_list(b, "local-ts");
580 enumerator = child->create_ts_enumerator(child, TRUE);
581 while (enumerator->enumerate(enumerator, &ts))
582 {
583 b->add_li(b, "%R", ts);
584 }
585 enumerator->destroy(enumerator);
586 b->end_list(b /* local-ts */);
587
588 b->begin_list(b, "remote-ts");
589 enumerator = child->create_ts_enumerator(child, FALSE);
590 while (enumerator->enumerate(enumerator, &ts))
591 {
592 b->add_li(b, "%R", ts);
593 }
594 enumerator->destroy(enumerator);
595 b->end_list(b /* remote-ts */);
596
597 b->end_section(b);
598
599 this->dispatcher->raise_event(this->dispatcher, "list-policy", id,
600 b->finalize(b));
601 }
602
603 /**
604 * Raise a list-policy event for given CHILD_SA config
605 */
606 static void raise_policy_cfg(private_vici_query_t *this, u_int id, char *ike,
607 child_cfg_t *cfg)
608 {
609 enumerator_t *enumerator;
610 linked_list_t *list;
611 traffic_selector_t *ts;
612 vici_builder_t *b;
613 char buf[BUF_LEN];
614
615 b = vici_builder_create();
616 snprintf(buf, sizeof(buf), "%s%s%s", ike ? ike : "", ike ? "/" : "",
617 cfg->get_name(cfg));
618 b->begin_section(b, buf);
619 b->add_kv(b, "child", "%s", cfg->get_name(cfg));
620 if (ike)
621 {
622 b->add_kv(b, "ike", "%s", ike);
623 }
624
625 list_mode(b, NULL, cfg);
626
627 b->begin_list(b, "local-ts");
628 list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL, FALSE);
629 enumerator = list->create_enumerator(list);
630 while (enumerator->enumerate(enumerator, &ts))
631 {
632 b->add_li(b, "%R", ts);
633 }
634 enumerator->destroy(enumerator);
635 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
636 b->end_list(b /* local-ts */);
637
638 b->begin_list(b, "remote-ts");
639 list = cfg->get_traffic_selectors(cfg, FALSE, NULL, NULL, FALSE);
640 enumerator = list->create_enumerator(list);
641 while (enumerator->enumerate(enumerator, &ts))
642 {
643 b->add_li(b, "%R", ts);
644 }
645 enumerator->destroy(enumerator);
646 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
647 b->end_list(b /* remote-ts */);
648
649 b->end_section(b);
650
651 this->dispatcher->raise_event(this->dispatcher, "list-policy", id,
652 b->finalize(b));
653 }
654
655 CALLBACK(list_policies, vici_message_t*,
656 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
657 {
658 enumerator_t *enumerator;
659 vici_builder_t *b;
660 child_sa_t *child_sa;
661 peer_cfg_t *peer_cfg;
662 child_cfg_t *child_cfg;
663 bool drop, pass, trap;
664 char *child, *ike, *ns;
665
666 drop = request->get_str(request, NULL, "drop") != NULL;
667 pass = request->get_str(request, NULL, "pass") != NULL;
668 trap = request->get_str(request, NULL, "trap") != NULL;
669 child = request->get_str(request, NULL, "child");
670 ike = request->get_str(request, NULL, "ike");
671
672 if (trap)
673 {
674 enumerator = charon->traps->create_enumerator(charon->traps);
675 while (enumerator->enumerate(enumerator, &peer_cfg, &child_sa))
676 {
677 if ((ike && !streq(ike, peer_cfg->get_name(peer_cfg))) ||
678 (child && !streq(child, child_sa->get_name(child_sa))))
679 {
680 continue;
681 }
682 raise_policy(this, id, peer_cfg->get_name(peer_cfg), child_sa);
683 }
684 enumerator->destroy(enumerator);
685 }
686
687 if (drop || pass)
688 {
689 enumerator = charon->shunts->create_enumerator(charon->shunts);
690 while (enumerator->enumerate(enumerator, &ns, &child_cfg))
691 {
692 if ((ike && !streq(ike, ns)) ||
693 (child && !streq(child, child_cfg->get_name(child_cfg))))
694 {
695 continue;
696 }
697 switch (child_cfg->get_mode(child_cfg))
698 {
699 case MODE_DROP:
700 if (drop)
701 {
702 raise_policy_cfg(this, id, ns, child_cfg);
703 }
704 break;
705 case MODE_PASS:
706 if (pass)
707 {
708 raise_policy_cfg(this, id, ns, child_cfg);
709 }
710 break;
711 default:
712 break;
713 }
714 }
715 enumerator->destroy(enumerator);
716 }
717
718 b = vici_builder_create();
719 return b->finalize(b);
720 }
721
722 /**
723 * Build sections for auth configs, local or remote
724 */
725 static void build_auth_cfgs(peer_cfg_t *peer_cfg, bool local, vici_builder_t *b)
726 {
727 enumerator_t *enumerator, *rules;
728 auth_rule_t rule;
729 auth_cfg_t *auth;
730 union {
731 uintptr_t u;
732 identification_t *id;
733 certificate_t *cert;
734 char *str;
735 } v;
736 char buf[32];
737 int i = 0;
738
739 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
740 while (enumerator->enumerate(enumerator, &auth))
741 {
742 snprintf(buf, sizeof(buf), "%s-%d", local ? "local" : "remote", ++i);
743 b->begin_section(b, buf);
744
745 rules = auth->create_enumerator(auth);
746 while (rules->enumerate(rules, &rule, &v))
747 {
748 switch (rule)
749 {
750 case AUTH_RULE_AUTH_CLASS:
751 b->add_kv(b, "class", "%N", auth_class_names, v.u);
752 break;
753 case AUTH_RULE_EAP_TYPE:
754 b->add_kv(b, "eap-type", "%N", eap_type_names, v.u);
755 break;
756 case AUTH_RULE_EAP_VENDOR:
757 b->add_kv(b, "eap-vendor", "%u", v.u);
758 break;
759 case AUTH_RULE_XAUTH_BACKEND:
760 b->add_kv(b, "xauth", "%s", v.str);
761 break;
762 case AUTH_RULE_CRL_VALIDATION:
763 b->add_kv(b, "revocation", "%N", cert_validation_names, v.u);
764 break;
765 case AUTH_RULE_IDENTITY:
766 b->add_kv(b, "id", "%Y", v.id);
767 break;
768 case AUTH_RULE_CA_IDENTITY:
769 b->add_kv(b, "ca_id", "%Y", v.id);
770 break;
771 case AUTH_RULE_AAA_IDENTITY:
772 b->add_kv(b, "aaa_id", "%Y", v.id);
773 break;
774 case AUTH_RULE_EAP_IDENTITY:
775 b->add_kv(b, "eap_id", "%Y", v.id);
776 break;
777 case AUTH_RULE_XAUTH_IDENTITY:
778 b->add_kv(b, "xauth_id", "%Y", v.id);
779 break;
780 default:
781 break;
782 }
783 }
784 rules->destroy(rules);
785
786 b->begin_list(b, "groups");
787 rules = auth->create_enumerator(auth);
788 while (rules->enumerate(rules, &rule, &v))
789 {
790 if (rule == AUTH_RULE_GROUP)
791 {
792 b->add_li(b, "%Y", v.id);
793 }
794 }
795 rules->destroy(rules);
796 b->end_list(b);
797
798 b->begin_list(b, "cert_policy");
799 rules = auth->create_enumerator(auth);
800 while (rules->enumerate(rules, &rule, &v))
801 {
802 if (rule == AUTH_RULE_CERT_POLICY)
803 {
804 b->add_li(b, "%s", v.str);
805 }
806 }
807 rules->destroy(rules);
808 b->end_list(b);
809
810 b->begin_list(b, "certs");
811 rules = auth->create_enumerator(auth);
812 while (rules->enumerate(rules, &rule, &v))
813 {
814 if (rule == AUTH_RULE_SUBJECT_CERT)
815 {
816 b->add_li(b, "%Y", v.cert->get_subject(v.cert));
817 }
818 }
819 rules->destroy(rules);
820 b->end_list(b);
821
822 b->begin_list(b, "cacerts");
823 rules = auth->create_enumerator(auth);
824 while (rules->enumerate(rules, &rule, &v))
825 {
826 if (rule == AUTH_RULE_CA_CERT)
827 {
828 b->add_li(b, "%Y", v.cert->get_subject(v.cert));
829 }
830 }
831 rules->destroy(rules);
832 b->end_list(b);
833
834 b->end_section(b);
835 }
836 enumerator->destroy(enumerator);
837 }
838
839 CALLBACK(list_conns, vici_message_t*,
840 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
841 {
842 enumerator_t *enumerator, *tokens, *selectors, *children;
843 peer_cfg_t *peer_cfg;
844 ike_cfg_t *ike_cfg;
845 child_cfg_t *child_cfg;
846 char *ike, *str, *interface;
847 uint32_t manual_prio, dpd_delay, dpd_timeout;
848 identification_t *ppk_id;
849 linked_list_t *list;
850 traffic_selector_t *ts;
851 lifetime_cfg_t *lft;
852 vici_builder_t *b;
853
854 ike = request->get_str(request, NULL, "ike");
855
856 enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
857 NULL, NULL, NULL, NULL, IKE_ANY);
858 while (enumerator->enumerate(enumerator, &peer_cfg))
859 {
860 if (ike && !streq(ike, peer_cfg->get_name(peer_cfg)))
861 {
862 continue;
863 }
864
865 b = vici_builder_create();
866 b->begin_section(b, peer_cfg->get_name(peer_cfg));
867
868 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
869
870 b->begin_list(b, "local_addrs");
871 str = ike_cfg->get_my_addr(ike_cfg);
872 tokens = enumerator_create_token(str, ",", " ");
873 while (tokens->enumerate(tokens, &str))
874 {
875 b->add_li(b, "%s", str);
876 }
877 tokens->destroy(tokens);
878 b->end_list(b);
879
880 b->begin_list(b, "remote_addrs");
881 str = ike_cfg->get_other_addr(ike_cfg);
882 tokens = enumerator_create_token(str, ",", " ");
883 while (tokens->enumerate(tokens, &str))
884 {
885 b->add_li(b, "%s", str);
886 }
887 tokens->destroy(tokens);
888 b->end_list(b);
889
890 b->add_kv(b, "version", "%N", ike_version_names,
891 peer_cfg->get_ike_version(peer_cfg));
892 b->add_kv(b, "reauth_time", "%u",
893 peer_cfg->get_reauth_time(peer_cfg, FALSE));
894 b->add_kv(b, "rekey_time", "%u",
895 peer_cfg->get_rekey_time(peer_cfg, FALSE));
896 b->add_kv(b, "unique", "%N", unique_policy_names,
897 peer_cfg->get_unique_policy(peer_cfg));
898
899 dpd_delay = peer_cfg->get_dpd(peer_cfg);
900 if (dpd_delay)
901 {
902 b->add_kv(b, "dpd_delay", "%u", dpd_delay);
903 }
904
905 dpd_timeout = peer_cfg->get_dpd_timeout(peer_cfg);
906 if (dpd_timeout)
907 {
908 b->add_kv(b, "dpd_timeout", "%u", dpd_timeout);
909 }
910
911 ppk_id = peer_cfg->get_ppk_id(peer_cfg);
912 if (ppk_id)
913 {
914 b->add_kv(b, "ppk_id", "%Y", ppk_id);
915 }
916 if (peer_cfg->ppk_required(peer_cfg))
917 {
918 b->add_kv(b, "ppk_required", "yes");
919 }
920
921 build_auth_cfgs(peer_cfg, TRUE, b);
922 build_auth_cfgs(peer_cfg, FALSE, b);
923
924 b->begin_section(b, "children");
925
926 children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
927 while (children->enumerate(children, &child_cfg))
928 {
929 b->begin_section(b, child_cfg->get_name(child_cfg));
930
931 list_mode(b, NULL, child_cfg);
932
933 lft = child_cfg->get_lifetime(child_cfg, FALSE);
934 b->add_kv(b, "rekey_time", "%"PRIu64, lft->time.rekey);
935 b->add_kv(b, "rekey_bytes", "%"PRIu64, lft->bytes.rekey);
936 b->add_kv(b, "rekey_packets", "%"PRIu64, lft->packets.rekey);
937 free(lft);
938
939 b->add_kv(b, "dpd_action", "%N", action_names,
940 child_cfg->get_dpd_action(child_cfg));
941 b->add_kv(b, "close_action", "%N", action_names,
942 child_cfg->get_close_action(child_cfg));
943
944 b->begin_list(b, "local-ts");
945 list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL,
946 NULL, FALSE);
947 selectors = list->create_enumerator(list);
948 while (selectors->enumerate(selectors, &ts))
949 {
950 b->add_li(b, "%R", ts);
951 }
952 selectors->destroy(selectors);
953 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
954 b->end_list(b /* local-ts */);
955
956 b->begin_list(b, "remote-ts");
957 list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL,
958 NULL, FALSE);
959 selectors = list->create_enumerator(list);
960 while (selectors->enumerate(selectors, &ts))
961 {
962 b->add_li(b, "%R", ts);
963 }
964 selectors->destroy(selectors);
965 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
966 b->end_list(b /* remote-ts */);
967
968 interface = child_cfg->get_interface(child_cfg);
969 if (interface)
970 {
971 b->add_kv(b, "interface", "%s", interface);
972 }
973
974 manual_prio = child_cfg->get_manual_prio(child_cfg);
975 if (manual_prio)
976 {
977 b->add_kv(b, "priority", "%u", manual_prio);
978 }
979
980 b->end_section(b);
981 }
982 children->destroy(children);
983
984 b->end_section(b); /* children */
985
986 b->end_section(b); /* name */
987
988 this->dispatcher->raise_event(this->dispatcher, "list-conn", id,
989 b->finalize(b));
990 }
991 enumerator->destroy(enumerator);
992
993 b = vici_builder_create();
994 return b->finalize(b);
995 }
996
997 /**
998 * Do we have a private key for given certificate
999 */
1000 static bool has_privkey(certificate_t *cert)
1001 {
1002 private_key_t *private;
1003 public_key_t *public;
1004 identification_t *keyid;
1005 chunk_t chunk;
1006 bool found = FALSE;
1007
1008 public = cert->get_public_key(cert);
1009 if (public)
1010 {
1011 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
1012 {
1013 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
1014 private = lib->credmgr->get_private(lib->credmgr,
1015 public->get_type(public), keyid, NULL);
1016 if (private)
1017 {
1018 found = TRUE;
1019 private->destroy(private);
1020 }
1021 keyid->destroy(keyid);
1022 }
1023 public->destroy(public);
1024 }
1025 return found;
1026 }
1027
1028 /**
1029 * Store cert filter data
1030 */
1031 typedef struct {
1032 certificate_type_t type;
1033 x509_flag_t flag;
1034 identification_t *subject;
1035 } cert_filter_t;
1036
1037 /**
1038 * Enumerate all X.509 certificates with a given flag
1039 */
1040 static void enum_x509(private_vici_query_t *this, u_int id,
1041 linked_list_t *certs, cert_filter_t *filter,
1042 x509_flag_t flag)
1043 {
1044 enumerator_t *enumerator;
1045 certificate_t *cert;
1046 vici_builder_t *b;
1047 chunk_t encoding;
1048 x509_t *x509;
1049
1050 if (filter->type != CERT_ANY && filter->flag != X509_ANY &&
1051 filter->flag != flag)
1052 {
1053 return;
1054 }
1055
1056 enumerator = certs->create_enumerator(certs);
1057 while (enumerator->enumerate(enumerator, &cert))
1058 {
1059 x509 = (x509_t*)cert;
1060 if ((x509->get_flags(x509) & X509_ANY) != flag)
1061 {
1062 continue;
1063 }
1064
1065 if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
1066 {
1067 b = vici_builder_create();
1068 b->add_kv(b, "type", "%N", certificate_type_names, CERT_X509);
1069 b->add_kv(b, "flag", "%N", x509_flag_names, flag);
1070 if (has_privkey(cert))
1071 {
1072 b->add_kv(b, "has_privkey", "yes");
1073 }
1074 b->add(b, VICI_KEY_VALUE, "data", encoding);
1075 free(encoding.ptr);
1076
1077 this->dispatcher->raise_event(this->dispatcher, "list-cert", id,
1078 b->finalize(b));
1079 }
1080 }
1081 enumerator->destroy(enumerator);
1082 }
1083
1084 /**
1085 * Enumerate all non-X.509 certificate types
1086 */
1087 static void enum_others(private_vici_query_t *this, u_int id,
1088 linked_list_t *certs, certificate_type_t type)
1089 {
1090 enumerator_t *enumerator;
1091 certificate_t *cert;
1092 vici_builder_t *b;
1093 chunk_t encoding, t_ch;
1094 cred_encoding_type_t encoding_type;
1095 identification_t *subject;
1096 time_t not_before, not_after;
1097
1098 encoding_type = (type == CERT_TRUSTED_PUBKEY) ? PUBKEY_SPKI_ASN1_DER :
1099 CERT_ASN1_DER;
1100
1101 enumerator = certs->create_enumerator(certs);
1102 while (enumerator->enumerate(enumerator, &cert))
1103 {
1104 if (cert->get_encoding(cert, encoding_type, &encoding))
1105 {
1106 b = vici_builder_create();
1107 b->add_kv(b, "type", "%N", certificate_type_names, type);
1108 if (has_privkey(cert))
1109 {
1110 b->add_kv(b, "has_privkey", "yes");
1111 }
1112 b->add(b, VICI_KEY_VALUE, "data", encoding);
1113 free(encoding.ptr);
1114
1115 if (type == CERT_TRUSTED_PUBKEY)
1116 {
1117 subject = cert->get_subject(cert);
1118 if (subject->get_type(subject) != ID_KEY_ID)
1119 {
1120 b->add_kv(b, "subject", "%Y", cert->get_subject(cert));
1121 }
1122 cert->get_validity(cert, NULL, &not_before, &not_after);
1123 if (not_before != UNDEFINED_TIME)
1124 {
1125 t_ch = asn1_from_time(&not_before, ASN1_GENERALIZEDTIME);
1126 b->add(b, VICI_KEY_VALUE, "not-before", chunk_skip(t_ch, 2));
1127 chunk_free(&t_ch);
1128 }
1129 if (not_after != UNDEFINED_TIME)
1130 {
1131 t_ch = asn1_from_time(&not_after, ASN1_GENERALIZEDTIME);
1132 b->add(b, VICI_KEY_VALUE, "not-after", chunk_skip(t_ch, 2));
1133 chunk_free(&t_ch);
1134 }
1135 }
1136 this->dispatcher->raise_event(this->dispatcher, "list-cert", id,
1137 b->finalize(b));
1138 }
1139 }
1140 enumerator->destroy(enumerator);
1141 }
1142
1143 /**
1144 * Enumerate all certificates of a given type
1145 */
1146 static void enum_certs(private_vici_query_t *this, u_int id,
1147 cert_filter_t *filter, certificate_type_t type)
1148 {
1149 enumerator_t *e1, *e2;
1150 certificate_t *cert, *current;
1151 linked_list_t *certs;
1152 bool found;
1153
1154 if (filter->type != CERT_ANY && filter->type != type)
1155 {
1156 return;
1157 }
1158 certs = linked_list_create();
1159
1160 e1 = lib->credmgr->create_cert_enumerator(lib->credmgr, type, KEY_ANY,
1161 filter->subject, FALSE);
1162 while (e1->enumerate(e1, &cert))
1163 {
1164 found = FALSE;
1165
1166 e2 = certs->create_enumerator(certs);
1167 while (e2->enumerate(e2, &current))
1168 {
1169 if (current->equals(current, cert))
1170 {
1171 found = TRUE;
1172 break;
1173 }
1174 }
1175 e2->destroy(e2);
1176
1177 if (!found)
1178 {
1179 certs->insert_last(certs, cert->get_ref(cert));
1180 }
1181 }
1182 e1->destroy(e1);
1183
1184 if (type == CERT_X509)
1185 {
1186 enum_x509(this, id, certs, filter, X509_NONE);
1187 enum_x509(this, id, certs, filter, X509_CA);
1188 enum_x509(this, id, certs, filter, X509_AA);
1189 enum_x509(this, id, certs, filter, X509_OCSP_SIGNER);
1190 }
1191 else
1192 {
1193 enum_others(this, id, certs, type);
1194 }
1195 certs->destroy_offset(certs, offsetof(certificate_t, destroy));
1196 }
1197
1198 CALLBACK(list_certs, vici_message_t*,
1199 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
1200 {
1201 cert_filter_t filter = {
1202 .type = CERT_ANY,
1203 .flag = X509_ANY,
1204 .subject = NULL
1205 };
1206 vici_builder_t *b;
1207 char *str;
1208
1209 str = request->get_str(request, "ANY", "type");
1210 if (enum_from_name(certificate_type_names, str, &filter.type))
1211 {
1212 if (filter.type == CERT_X509)
1213 {
1214 str = request->get_str(request, "ANY", "flag");
1215 if (!enum_from_name(x509_flag_names, str, &filter.flag))
1216 {
1217 DBG1(DBG_CFG, "invalid certificate flag '%s'", str);
1218 goto finalize;
1219 }
1220 }
1221 }
1222 else if (!vici_cert_info_from_str(str, &filter.type, &filter.flag))
1223 {
1224 DBG1(DBG_CFG, "invalid certificate type '%s'", str);
1225 goto finalize;
1226 }
1227
1228 str = request->get_str(request, NULL, "subject");
1229 if (str)
1230 {
1231 filter.subject = identification_create_from_string(str);
1232 }
1233
1234 enum_certs(this, id, &filter, CERT_TRUSTED_PUBKEY);
1235 enum_certs(this, id, &filter, CERT_X509);
1236 enum_certs(this, id, &filter, CERT_X509_AC);
1237 enum_certs(this, id, &filter, CERT_X509_CRL);
1238 enum_certs(this, id, &filter, CERT_X509_OCSP_RESPONSE);
1239 DESTROY_IF(filter.subject);
1240
1241 finalize:
1242 b = vici_builder_create();
1243 return b->finalize(b);
1244 }
1245
1246 /**
1247 * Add a key/value pair of ALG => plugin
1248 */
1249 static void add_algorithm(vici_builder_t *b, enum_name_t *alg_names,
1250 int alg_type, const char *plugin_name)
1251 {
1252 char alg_name[BUF_LEN];
1253
1254 sprintf(alg_name, "%N", alg_names, alg_type);
1255 b->add_kv(b, alg_name, (char*)plugin_name);
1256 }
1257
1258 CALLBACK(get_algorithms, vici_message_t*,
1259 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
1260 {
1261 vici_builder_t *b;
1262 enumerator_t *enumerator;
1263 encryption_algorithm_t encryption;
1264 integrity_algorithm_t integrity;
1265 hash_algorithm_t hash;
1266 pseudo_random_function_t prf;
1267 ext_out_function_t xof;
1268 drbg_type_t drbg;
1269 diffie_hellman_group_t group;
1270 rng_quality_t quality;
1271 const char *plugin_name;
1272
1273 b = vici_builder_create();
1274
1275 b->begin_section(b, "encryption");
1276 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
1277 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1278 {
1279 add_algorithm(b, encryption_algorithm_names, encryption, plugin_name);
1280 }
1281 enumerator->destroy(enumerator);
1282 b->end_section(b);
1283
1284 b->begin_section(b, "integrity");
1285 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1286 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
1287 {
1288 add_algorithm(b, integrity_algorithm_names, integrity, plugin_name);
1289 }
1290 enumerator->destroy(enumerator);
1291 b->end_section(b);
1292
1293 b->begin_section(b, "aead");
1294 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
1295 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1296 {
1297 add_algorithm(b, encryption_algorithm_names, encryption, plugin_name);
1298 }
1299 enumerator->destroy(enumerator);
1300 b->end_section(b);
1301
1302 b->begin_section(b, "hasher");
1303 enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
1304 while (enumerator->enumerate(enumerator, &hash, &plugin_name))
1305 {
1306 add_algorithm(b, hash_algorithm_names, hash, plugin_name);
1307 }
1308 enumerator->destroy(enumerator);
1309 b->end_section(b);
1310
1311 b->begin_section(b, "prf");
1312 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
1313 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
1314 {
1315 add_algorithm(b, pseudo_random_function_names, prf, plugin_name);
1316 }
1317 enumerator->destroy(enumerator);
1318 b->end_section(b);
1319
1320 b->begin_section(b, "xof");
1321 enumerator = lib->crypto->create_xof_enumerator(lib->crypto);
1322 while (enumerator->enumerate(enumerator, &xof, &plugin_name))
1323 {
1324 add_algorithm(b, ext_out_function_names, xof, plugin_name);
1325 }
1326 enumerator->destroy(enumerator);
1327 b->end_section(b);
1328
1329 b->begin_section(b, "drbg");
1330 enumerator = lib->crypto->create_drbg_enumerator(lib->crypto);
1331 while (enumerator->enumerate(enumerator, &drbg, &plugin_name))
1332 {
1333 add_algorithm(b, drbg_type_names, drbg, plugin_name);
1334 }
1335 enumerator->destroy(enumerator);
1336 b->end_section(b);
1337
1338 b->begin_section(b, "dh");
1339 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1340 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1341 {
1342 add_algorithm(b, diffie_hellman_group_names, group, plugin_name);
1343 }
1344 enumerator->destroy(enumerator);
1345 b->end_section(b);
1346
1347 b->begin_section(b, "rng");
1348 enumerator = lib->crypto->create_rng_enumerator(lib->crypto);
1349 while (enumerator->enumerate(enumerator, &quality, &plugin_name))
1350 {
1351 add_algorithm(b, rng_quality_names, quality, plugin_name);
1352 }
1353 enumerator->destroy(enumerator);
1354 b->end_section(b);
1355
1356 b->begin_section(b, "nonce-gen");
1357 enumerator = lib->crypto->create_nonce_gen_enumerator(lib->crypto);
1358 while (enumerator->enumerate(enumerator, &plugin_name))
1359 {
1360 b->add_kv(b, "NONCE_GEN", (char*)plugin_name);
1361 }
1362 enumerator->destroy(enumerator);
1363 b->end_section(b);
1364
1365 return b->finalize(b);
1366 }
1367
1368 /**
1369 * Make sure we have the counters query interface
1370 */
1371 static inline bool ensure_counters(private_vici_query_t *this)
1372 {
1373 if (this->counters)
1374 {
1375 return TRUE;
1376 }
1377 return (this->counters = lib->get(lib, "counters")) != NULL;
1378 }
1379
1380 /**
1381 * Add a single set of counters to the message
1382 *
1383 * Frees the array of counter values
1384 */
1385 static void add_counters(vici_builder_t *b, char *name, uint64_t *counters)
1386 {
1387 char buf[BUF_LEN];
1388 counter_type_t i;
1389
1390 b->begin_section(b, name ?: "");
1391 for (i = 0; i < COUNTER_MAX; i++)
1392 {
1393 snprintf(buf, sizeof(buf), "%N", vici_counter_type_names, i);
1394 b->add_kv(b, buf, "%"PRIu64, counters[i]);
1395 }
1396 b->end_section(b);
1397 free(counters);
1398 }
1399
1400 CALLBACK(get_counters, vici_message_t*,
1401 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
1402 {
1403 vici_builder_t *b;
1404 enumerator_t *enumerator;
1405 uint64_t *counters;
1406 char *conn, *errmsg = NULL;
1407 bool all;
1408
1409 b = vici_builder_create();
1410
1411 if (ensure_counters(this))
1412 {
1413 conn = request->get_str(request, NULL, "name");
1414 all = request->get_bool(request, FALSE, "all");
1415
1416 b->begin_section(b, "counters");
1417 if (all)
1418 {
1419 enumerator = this->counters->get_names(this->counters);
1420 while (enumerator->enumerate(enumerator, &conn))
1421 {
1422 counters = this->counters->get_all(this->counters, conn);
1423 if (counters)
1424 {
1425 add_counters(b, conn, counters);
1426 }
1427 }
1428 enumerator->destroy(enumerator);
1429 }
1430 else
1431 {
1432 counters = this->counters->get_all(this->counters, conn);
1433 if (counters)
1434 {
1435 add_counters(b, conn, counters);
1436 }
1437 else
1438 {
1439 errmsg = "no counters found for this connection";
1440 }
1441 }
1442 b->end_section(b);
1443 }
1444 else
1445 {
1446 errmsg = "no counters available (plugin missing?)";
1447 }
1448
1449 b->add_kv(b, "success", errmsg ? "no" : "yes");
1450 if (errmsg)
1451 {
1452 b->add_kv(b, "errmsg", "%s", errmsg);
1453 }
1454 return b->finalize(b);
1455 }
1456
1457 CALLBACK(reset_counters, vici_message_t*,
1458 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
1459 {
1460 vici_builder_t *b;
1461 char *conn, *errmsg = NULL;
1462 bool all;
1463
1464 b = vici_builder_create();
1465
1466 if (ensure_counters(this))
1467 {
1468 conn = request->get_str(request, NULL, "name");
1469 all = request->get_bool(request, FALSE, "all");
1470
1471 if (all)
1472 {
1473 this->counters->reset_all(this->counters);
1474 }
1475 else
1476 {
1477 this->counters->reset(this->counters, conn);
1478 }
1479 }
1480 else
1481 {
1482 errmsg = "no counters available (plugin missing?)";
1483 }
1484
1485 b->add_kv(b, "success", errmsg ? "no" : "yes");
1486 if (errmsg)
1487 {
1488 b->add_kv(b, "errmsg", "%s", errmsg);
1489 }
1490 return b->finalize(b);
1491 }
1492
1493 CALLBACK(version, vici_message_t*,
1494 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
1495 {
1496 vici_builder_t *b;
1497
1498 b = vici_builder_create();
1499 b->add_kv(b, "daemon", "%s", lib->ns);
1500 b->add_kv(b, "version", "%s", VERSION);
1501
1502 #ifdef WIN32
1503 {
1504 OSVERSIONINFOEX osvie;
1505
1506 memset(&osvie, 0, sizeof(osvie));
1507 osvie.dwOSVersionInfoSize = sizeof(osvie);
1508
1509 if (GetVersionEx((LPOSVERSIONINFO)&osvie))
1510 {
1511 b->add_kv(b, "sysname", "Windows %s",
1512 osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server");
1513 b->add_kv(b, "release", "%d.%d.%d (SP %d.%d)",
1514 osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber,
1515 osvie.wServicePackMajor, osvie.wServicePackMinor);
1516 b->add_kv(b, "machine", "%s",
1517 #ifdef WIN64
1518 "x86_64");
1519 #else
1520 "x86");
1521 #endif /* !WIN64 */
1522 }
1523 }
1524 #else /* !WIN32 */
1525 {
1526 struct utsname utsname;
1527
1528 if (uname(&utsname) == 0)
1529 {
1530 b->add_kv(b, "sysname", "%s", utsname.sysname);
1531 b->add_kv(b, "release", "%s", utsname.release);
1532 b->add_kv(b, "machine", "%s", utsname.machine);
1533 }
1534 }
1535 #endif /* !WIN32 */
1536 return b->finalize(b);
1537 }
1538
1539 CALLBACK(stats, vici_message_t*,
1540 private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
1541 {
1542 vici_builder_t *b;
1543 enumerator_t *enumerator;
1544 plugin_t *plugin;
1545 time_t since, now;
1546 int i;
1547
1548 b = vici_builder_create();
1549
1550 now = time_monotonic(NULL);
1551 since = time(NULL) - (now - this->uptime);
1552
1553 b->begin_section(b, "uptime");
1554 b->add_kv(b, "running", "%V", &now, &this->uptime);
1555 b->add_kv(b, "since", "%T", &since, FALSE);
1556 b->end_section(b);
1557
1558 b->begin_section(b, "workers");
1559 b->add_kv(b, "total", "%d",
1560 lib->processor->get_total_threads(lib->processor));
1561 b->add_kv(b, "idle", "%d",
1562 lib->processor->get_idle_threads(lib->processor));
1563 b->begin_section(b, "active");
1564 for (i = 0; i < JOB_PRIO_MAX; i++)
1565 {
1566 b->add_kv(b, enum_to_name(job_priority_names, i), "%d",
1567 lib->processor->get_working_threads(lib->processor, i));
1568 }
1569 b->end_section(b);
1570 b->end_section(b);
1571
1572 b->begin_section(b, "queues");
1573 for (i = 0; i < JOB_PRIO_MAX; i++)
1574 {
1575 b->add_kv(b, enum_to_name(job_priority_names, i), "%d",
1576 lib->processor->get_job_load(lib->processor, i));
1577 }
1578 b->end_section(b);
1579
1580 b->add_kv(b, "scheduled", "%d",
1581 lib->scheduler->get_job_load(lib->scheduler));
1582
1583 b->begin_section(b, "ikesas");
1584 b->add_kv(b, "total", "%u",
1585 charon->ike_sa_manager->get_count(charon->ike_sa_manager));
1586 b->add_kv(b, "half-open", "%u",
1587 charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
1588 NULL, FALSE));
1589 b->end_section(b);
1590
1591 b->begin_list(b, "plugins");
1592 enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
1593 while (enumerator->enumerate(enumerator, &plugin, NULL))
1594 {
1595 b->add_li(b, "%s", plugin->get_name(plugin));
1596 }
1597 enumerator->destroy(enumerator);
1598 b->end_list(b);
1599
1600 #ifdef WIN32
1601 {
1602 DWORD lasterr = ERROR_INVALID_HANDLE;
1603 HANDLE heaps[32];
1604 int i, count;
1605 char buf[16];
1606 size_t total = 0;
1607 int allocs = 0;
1608
1609 b->begin_section(b, "mem");
1610 count = GetProcessHeaps(countof(heaps), heaps);
1611 for (i = 0; i < count; i++)
1612 {
1613 PROCESS_HEAP_ENTRY entry = {};
1614 size_t heap_total = 0;
1615 int heap_allocs = 0;
1616
1617 if (HeapLock(heaps[i]))
1618 {
1619 while (HeapWalk(heaps[i], &entry))
1620 {
1621 if (entry.wFlags & PROCESS_HEAP_ENTRY_BUSY)
1622 {
1623 heap_total += entry.cbData;
1624 heap_allocs++;
1625 }
1626 }
1627 lasterr = GetLastError();
1628 HeapUnlock(heaps[i]);
1629 }
1630 if (lasterr != ERROR_NO_MORE_ITEMS)
1631 {
1632 break;
1633 }
1634 snprintf(buf, sizeof(buf), "heap-%d", i);
1635 b->begin_section(b, buf);
1636 b->add_kv(b, "total", "%zu", heap_total);
1637 b->add_kv(b, "allocs", "%d", heap_allocs);
1638 b->end_section(b);
1639
1640 total += heap_total;
1641 allocs += heap_allocs;
1642 }
1643 if (lasterr == ERROR_NO_MORE_ITEMS)
1644 {
1645 b->add_kv(b, "total", "%zu", total);
1646 b->add_kv(b, "allocs", "%d", allocs);
1647 }
1648 b->end_section(b);
1649 }
1650 #endif
1651
1652 #ifdef HAVE_MALLINFO
1653 {
1654 struct mallinfo mi = mallinfo();
1655
1656 b->begin_section(b, "mallinfo");
1657 b->add_kv(b, "sbrk", "%u", mi.arena);
1658 b->add_kv(b, "mmap", "%u", mi.hblkhd);
1659 b->add_kv(b, "used", "%u", mi.uordblks);
1660 b->add_kv(b, "free", "%u", mi.fordblks);
1661 b->end_section(b);
1662 }
1663 #endif /* HAVE_MALLINFO */
1664
1665 return b->finalize(b);
1666 }
1667
1668 static void manage_command(private_vici_query_t *this,
1669 char *name, vici_command_cb_t cb, bool reg)
1670 {
1671 this->dispatcher->manage_command(this->dispatcher, name,
1672 reg ? cb : NULL, this);
1673 }
1674
1675 /**
1676 * (Un-)register dispatcher functions
1677 */
1678 static void manage_commands(private_vici_query_t *this, bool reg)
1679 {
1680 this->dispatcher->manage_event(this->dispatcher, "list-sa", reg);
1681 this->dispatcher->manage_event(this->dispatcher, "list-policy", reg);
1682 this->dispatcher->manage_event(this->dispatcher, "list-conn", reg);
1683 this->dispatcher->manage_event(this->dispatcher, "list-cert", reg);
1684 this->dispatcher->manage_event(this->dispatcher, "ike-updown", reg);
1685 this->dispatcher->manage_event(this->dispatcher, "ike-rekey", reg);
1686 this->dispatcher->manage_event(this->dispatcher, "child-updown", reg);
1687 this->dispatcher->manage_event(this->dispatcher, "child-rekey", reg);
1688 manage_command(this, "list-sas", list_sas, reg);
1689 manage_command(this, "list-policies", list_policies, reg);
1690 manage_command(this, "list-conns", list_conns, reg);
1691 manage_command(this, "list-certs", list_certs, reg);
1692 manage_command(this, "get-algorithms", get_algorithms, reg);
1693 manage_command(this, "get-counters", get_counters, reg);
1694 manage_command(this, "reset-counters", reset_counters, reg);
1695 manage_command(this, "version", version, reg);
1696 manage_command(this, "stats", stats, reg);
1697 }
1698
1699 METHOD(listener_t, ike_updown, bool,
1700 private_vici_query_t *this, ike_sa_t *ike_sa, bool up)
1701 {
1702 vici_builder_t *b;
1703 time_t now;
1704
1705 if (!this->dispatcher->has_event_listeners(this->dispatcher, "ike-updown"))
1706 {
1707 return TRUE;
1708 }
1709
1710 now = time_monotonic(NULL);
1711
1712 b = vici_builder_create();
1713
1714 if (up)
1715 {
1716 b->add_kv(b, "up", "yes");
1717 }
1718
1719 b->begin_section(b, ike_sa->get_name(ike_sa));
1720 list_ike(this, b, ike_sa, now);
1721 b->end_section(b);
1722
1723 this->dispatcher->raise_event(this->dispatcher,
1724 "ike-updown", 0, b->finalize(b));
1725
1726 return TRUE;
1727 }
1728
1729 METHOD(listener_t, ike_rekey, bool,
1730 private_vici_query_t *this, ike_sa_t *old, ike_sa_t *new)
1731 {
1732 vici_builder_t *b;
1733 time_t now;
1734
1735 if (!this->dispatcher->has_event_listeners(this->dispatcher, "ike-rekey"))
1736 {
1737 return TRUE;
1738 }
1739
1740 now = time_monotonic(NULL);
1741
1742 b = vici_builder_create();
1743 b->begin_section(b, old->get_name(old));
1744 b->begin_section(b, "old");
1745 list_ike(this, b, old, now);
1746 b->end_section(b);
1747 b->begin_section(b, "new");
1748 list_ike(this, b, new, now);
1749 b->end_section(b);
1750 b->end_section(b);
1751
1752 this->dispatcher->raise_event(this->dispatcher,
1753 "ike-rekey", 0, b->finalize(b));
1754
1755 return TRUE;
1756 }
1757
1758 METHOD(listener_t, child_updown, bool,
1759 private_vici_query_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up)
1760 {
1761 vici_builder_t *b;
1762 time_t now;
1763 char buf[BUF_LEN];
1764
1765 if (!this->dispatcher->has_event_listeners(this->dispatcher, "child-updown"))
1766 {
1767 return TRUE;
1768 }
1769
1770 now = time_monotonic(NULL);
1771 b = vici_builder_create();
1772
1773 if (up)
1774 {
1775 b->add_kv(b, "up", "yes");
1776 }
1777
1778 b->begin_section(b, ike_sa->get_name(ike_sa));
1779 list_ike(this, b, ike_sa, now);
1780 b->begin_section(b, "child-sas");
1781
1782 snprintf(buf, sizeof(buf), "%s-%u", child_sa->get_name(child_sa),
1783 child_sa->get_unique_id(child_sa));
1784
1785 b->begin_section(b, buf);
1786 list_child(this, b, child_sa, now);
1787 b->end_section(b);
1788
1789 b->end_section(b);
1790 b->end_section(b);
1791
1792 this->dispatcher->raise_event(this->dispatcher,
1793 "child-updown", 0, b->finalize(b));
1794
1795 return TRUE;
1796 }
1797
1798 METHOD(listener_t, child_rekey, bool,
1799 private_vici_query_t *this, ike_sa_t *ike_sa, child_sa_t *old,
1800 child_sa_t *new)
1801 {
1802 vici_builder_t *b;
1803 time_t now;
1804
1805 if (!this->dispatcher->has_event_listeners(this->dispatcher, "child-rekey"))
1806 {
1807 return TRUE;
1808 }
1809
1810 now = time_monotonic(NULL);
1811 b = vici_builder_create();
1812
1813 b->begin_section(b, ike_sa->get_name(ike_sa));
1814 list_ike(this, b, ike_sa, now);
1815 b->begin_section(b, "child-sas");
1816
1817 b->begin_section(b, old->get_name(old));
1818
1819 b->begin_section(b, "old");
1820 list_child(this, b, old, now);
1821 b->end_section(b);
1822 b->begin_section(b, "new");
1823 list_child(this, b, new, now);
1824 b->end_section(b);
1825
1826 b->end_section(b);
1827
1828 b->end_section(b);
1829 b->end_section(b);
1830
1831 this->dispatcher->raise_event(this->dispatcher,
1832 "child-rekey", 0, b->finalize(b));
1833
1834 return TRUE;
1835 }
1836
1837 METHOD(vici_query_t, destroy, void,
1838 private_vici_query_t *this)
1839 {
1840 manage_commands(this, FALSE);
1841 free(this);
1842 }
1843
1844 /**
1845 * See header
1846 */
1847 vici_query_t *vici_query_create(vici_dispatcher_t *dispatcher)
1848 {
1849 private_vici_query_t *this;
1850
1851 INIT(this,
1852 .public = {
1853 .listener = {
1854 .ike_updown = _ike_updown,
1855 .ike_rekey = _ike_rekey,
1856 .child_updown = _child_updown,
1857 .child_rekey = _child_rekey,
1858 },
1859 .destroy = _destroy,
1860 },
1861 .dispatcher = dispatcher,
1862 .uptime = time_monotonic(NULL),
1863 );
1864
1865 manage_commands(this, TRUE);
1866
1867 return &this->public;
1868 }