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