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