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