diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2014-07-11 07:23:31 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2014-07-11 07:23:31 +0200 |
commit | 81c63b0eed39432878f78727f60a1e7499645199 (patch) | |
tree | 82387d8fecd1c20788fd8bd784a9b0bde091fb6b /src/libcharon/plugins/vici/vici_query.c | |
parent | c5ebfc7b9c16551fe825dc1d79c3f7e2f096f6c9 (diff) | |
download | vyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.tar.gz vyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.zip |
Imported Upstream version 5.2.0
Diffstat (limited to 'src/libcharon/plugins/vici/vici_query.c')
-rw-r--r-- | src/libcharon/plugins/vici/vici_query.c | 1039 |
1 files changed, 1039 insertions, 0 deletions
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c new file mode 100644 index 000000000..54833abde --- /dev/null +++ b/src/libcharon/plugins/vici/vici_query.c @@ -0,0 +1,1039 @@ +/* + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "vici_query.h" +#include "vici_builder.h" + +#include <inttypes.h> +#include <time.h> +#ifndef WIN32 +#include <sys/utsname.h> +#endif +#ifdef HAVE_MALLINFO +#include <malloc.h> +#endif + +#include <daemon.h> + +typedef struct private_vici_query_t private_vici_query_t; + +/** + * Private data of an vici_query_t object. + */ +struct private_vici_query_t { + + /** + * Public vici_query_t interface. + */ + vici_query_t public; + + /** + * Dispatcher + */ + vici_dispatcher_t *dispatcher; + + /** + * Daemon startup timestamp + */ + time_t uptime; +}; + +/** + * List details of a CHILD_SA + */ +static void list_child(private_vici_query_t *this, vici_builder_t *b, + child_sa_t *child, time_t now) +{ + time_t t; + u_int64_t bytes, packets; + u_int16_t alg, ks; + proposal_t *proposal; + enumerator_t *enumerator; + traffic_selector_t *ts; + + b->add_kv(b, "reqid", "%u", child->get_reqid(child)); + b->add_kv(b, "state", "%N", child_sa_state_names, child->get_state(child)); + b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child)); + if (child->get_state(child) == CHILD_INSTALLED || + child->get_state(child) == CHILD_REKEYING) + { + b->add_kv(b, "protocol", "%N", protocol_id_names, + child->get_protocol(child)); + if (child->has_encap(child)) + { + b->add_kv(b, "encap", "yes"); + } + b->add_kv(b, "spi-in", "%.8x", ntohl(child->get_spi(child, TRUE))); + b->add_kv(b, "spi-out", "%.8x", ntohl(child->get_spi(child, FALSE))); + + if (child->get_ipcomp(child) != IPCOMP_NONE) + { + b->add_kv(b, "cpi-in", "%.4x", ntohs(child->get_cpi(child, TRUE))); + b->add_kv(b, "cpi-out", "%.4x", ntohs(child->get_cpi(child, FALSE))); + } + proposal = child->get_proposal(child); + if (proposal) + { + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, + &alg, &ks) && alg != ENCR_UNDEFINED) + { + b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg); + if (ks) + { + b->add_kv(b, "encr-keysize", "%u", ks); + } + } + if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, + &alg, &ks) && alg != ENCR_UNDEFINED) + { + b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg); + if (ks) + { + b->add_kv(b, "integ-keysize", "%u", ks); + } + } + if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, + &alg, NULL)) + { + b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg); + } + if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + &alg, NULL)) + { + b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg); + } + if (proposal->get_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, + &alg, NULL) && alg == EXT_SEQ_NUMBERS) + { + b->add_kv(b, "esn", "1"); + } + } + + child->get_usestats(child, TRUE, &t, &bytes, &packets); + b->add_kv(b, "bytes-in", "%" PRIu64, bytes); + b->add_kv(b, "packets-in", "%" PRIu64, packets); + if (t) + { + b->add_kv(b, "use-in", "%"PRIu64, (u_int64_t)(now - t)); + } + + child->get_usestats(child, FALSE, &t, &bytes, &packets); + b->add_kv(b, "bytes-out", "%"PRIu64, bytes); + b->add_kv(b, "packets-out", "%"PRIu64, packets); + if (t) + { + b->add_kv(b, "use-out", "%"PRIu64, (u_int64_t)(now - t)); + } + + t = child->get_lifetime(child, FALSE); + if (t) + { + b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now)); + } + t = child->get_lifetime(child, TRUE); + if (t) + { + b->add_kv(b, "life-time", "%"PRId64, (int64_t)(t - now)); + } + t = child->get_installtime(child); + b->add_kv(b, "install-time", "%"PRId64, (int64_t)(now - t)); + } + + b->begin_list(b, "local-ts"); + enumerator = child->create_ts_enumerator(child, TRUE); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + b->end_list(b /* local-ts */); + + b->begin_list(b, "remote-ts"); + enumerator = child->create_ts_enumerator(child, FALSE); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + b->end_list(b /* remote-ts */); +} + +/** + * List tasks in a specific queue + */ +static void list_task_queue(private_vici_query_t *this, vici_builder_t *b, + ike_sa_t *ike_sa, task_queue_t q, char *name) +{ + enumerator_t *enumerator; + bool has = FALSE; + task_t *task; + + enumerator = ike_sa->create_task_enumerator(ike_sa, q); + while (enumerator->enumerate(enumerator, &task)) + { + if (!has) + { + b->begin_list(b, name); + has = TRUE; + } + b->add_li(b, "%N", task_type_names, task->get_type(task)); + } + enumerator->destroy(enumerator); + if (has) + { + b->end_list(b); + } +} + +/** + * List details of an IKE_SA + */ +static void list_ike(private_vici_query_t *this, vici_builder_t *b, + ike_sa_t *ike_sa, time_t now) +{ + time_t t; + ike_sa_id_t *id; + identification_t *eap; + proposal_t *proposal; + u_int16_t alg, ks; + + b->add_kv(b, "uniqueid", "%u", ike_sa->get_unique_id(ike_sa)); + b->add_kv(b, "version", "%u", ike_sa->get_version(ike_sa)); + b->add_kv(b, "state", "%N", ike_sa_state_names, ike_sa->get_state(ike_sa)); + + b->add_kv(b, "local-host", "%H", ike_sa->get_my_host(ike_sa)); + b->add_kv(b, "local-id", "%Y", ike_sa->get_my_id(ike_sa)); + + b->add_kv(b, "remote-host", "%H", ike_sa->get_other_host(ike_sa)); + b->add_kv(b, "remote-id", "%Y", ike_sa->get_other_id(ike_sa)); + + eap = ike_sa->get_other_eap_id(ike_sa); + + if (!eap->equals(eap, ike_sa->get_other_id(ike_sa))) + { + if (ike_sa->get_version(ike_sa) == IKEV1) + { + b->add_kv(b, "remote-xauth-id", "%Y", eap); + } + else + { + b->add_kv(b, "remote-eap-id", "%Y", eap); + } + } + + id = ike_sa->get_id(ike_sa); + if (id->is_initiator(id)) + { + b->add_kv(b, "initiator", "yes"); + } + b->add_kv(b, "initiator-spi", "%.16"PRIx64, id->get_initiator_spi(id)); + b->add_kv(b, "responder-spi", "%.16"PRIx64, id->get_responder_spi(id)); + + proposal = ike_sa->get_proposal(ike_sa); + if (proposal) + { + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &ks)) + { + b->add_kv(b, "encr-alg", "%N", encryption_algorithm_names, alg); + if (ks) + { + b->add_kv(b, "encr-keysize", "%u", ks); + } + } + if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, &ks)) + { + b->add_kv(b, "integ-alg", "%N", integrity_algorithm_names, alg); + if (ks) + { + b->add_kv(b, "integ-keysize", "%u", ks); + } + } + if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL)) + { + b->add_kv(b, "prf-alg", "%N", pseudo_random_function_names, alg); + } + if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &alg, NULL)) + { + b->add_kv(b, "dh-group", "%N", diffie_hellman_group_names, alg); + } + } + + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED) + { + t = ike_sa->get_statistic(ike_sa, STAT_ESTABLISHED); + b->add_kv(b, "established", "%"PRId64, (int64_t)(now - t)); + t = ike_sa->get_statistic(ike_sa, STAT_REKEY); + if (t) + { + b->add_kv(b, "rekey-time", "%"PRId64, (int64_t)(t - now)); + } + t = ike_sa->get_statistic(ike_sa, STAT_REAUTH); + if (t) + { + b->add_kv(b, "reauth-time", "%"PRId64, (int64_t)(t - now)); + } + } + + list_task_queue(this, b, ike_sa, TASK_QUEUE_QUEUED, "tasks-queued"); + list_task_queue(this, b, ike_sa, TASK_QUEUE_ACTIVE, "tasks-active"); + list_task_queue(this, b, ike_sa, TASK_QUEUE_PASSIVE, "tasks-passive"); +} + +CALLBACK(list_sas, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + vici_builder_t *b; + enumerator_t *isas, *csas; + ike_sa_t *ike_sa; + child_sa_t *child_sa; + time_t now; + char *ike; + u_int ike_id; + bool bl; + + bl = request->get_str(request, NULL, "noblock") == NULL; + ike = request->get_str(request, NULL, "ike"); + ike_id = request->get_int(request, 0, "ike-id"); + + isas = charon->controller->create_ike_sa_enumerator(charon->controller, bl); + while (isas->enumerate(isas, &ike_sa)) + { + if (ike && !streq(ike, ike_sa->get_name(ike_sa))) + { + continue; + } + if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa)) + { + continue; + } + + now = time_monotonic(NULL); + + b = vici_builder_create(); + b->begin_section(b, ike_sa->get_name(ike_sa)); + + list_ike(this, b, ike_sa, now); + + b->begin_section(b, "child-sas"); + csas = ike_sa->create_child_sa_enumerator(ike_sa); + while (csas->enumerate(csas, &child_sa)) + { + b->begin_section(b, child_sa->get_name(child_sa)); + list_child(this, b, child_sa, now); + b->end_section(b); + } + csas->destroy(csas); + b->end_section(b /* child-sas */ ); + + b->end_section(b); + + this->dispatcher->raise_event(this->dispatcher, "list-sa", id, + b->finalize(b)); + } + isas->destroy(isas); + + b = vici_builder_create(); + return b->finalize(b); +} + +/** + * Raise a list-policy event for given CHILD_SA + */ +static void raise_policy(private_vici_query_t *this, u_int id, child_sa_t *child) +{ + enumerator_t *enumerator; + traffic_selector_t *ts; + vici_builder_t *b; + + b = vici_builder_create(); + b->begin_section(b, child->get_name(child)); + + b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child)); + + b->begin_list(b, "local-ts"); + enumerator = child->create_ts_enumerator(child, TRUE); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + b->end_list(b /* local-ts */); + + b->begin_list(b, "remote-ts"); + enumerator = child->create_ts_enumerator(child, FALSE); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + b->end_list(b /* remote-ts */); + + b->end_section(b); + + this->dispatcher->raise_event(this->dispatcher, "list-policy", id, + b->finalize(b)); +} + +/** + * Raise a list-policy event for given CHILD_SA config + */ +static void raise_policy_cfg(private_vici_query_t *this, u_int id, + child_cfg_t *cfg) +{ + enumerator_t *enumerator; + linked_list_t *list; + traffic_selector_t *ts; + vici_builder_t *b; + + b = vici_builder_create(); + b->begin_section(b, cfg->get_name(cfg)); + + b->add_kv(b, "mode", "%N", ipsec_mode_names, cfg->get_mode(cfg)); + + b->begin_list(b, "local-ts"); + list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + b->end_list(b /* local-ts */); + + b->begin_list(b, "remote-ts"); + list = cfg->get_traffic_selectors(cfg, FALSE, NULL, NULL); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &ts)) + { + b->add_li(b, "%R", ts); + } + enumerator->destroy(enumerator); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + b->end_list(b /* remote-ts */); + + b->end_section(b); + + this->dispatcher->raise_event(this->dispatcher, "list-policy", id, + b->finalize(b)); +} + +CALLBACK(list_policies, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + enumerator_t *enumerator; + vici_builder_t *b; + child_sa_t *child_sa; + child_cfg_t *child_cfg; + bool drop, pass, trap; + char *child; + + drop = request->get_str(request, NULL, "drop") != NULL; + pass = request->get_str(request, NULL, "pass") != NULL; + trap = request->get_str(request, NULL, "trap") != NULL; + child = request->get_str(request, NULL, "child"); + + if (trap) + { + enumerator = charon->traps->create_enumerator(charon->traps); + while (enumerator->enumerate(enumerator, NULL, &child_sa)) + { + if (child && !streq(child, child_sa->get_name(child_sa))) + { + continue; + } + raise_policy(this, id, child_sa); + } + enumerator->destroy(enumerator); + } + + if (drop || pass) + { + enumerator = charon->shunts->create_enumerator(charon->shunts); + while (enumerator->enumerate(enumerator, &child_cfg)) + { + if (child && !streq(child, child_cfg->get_name(child_cfg))) + { + continue; + } + switch (child_cfg->get_mode(child_cfg)) + { + case MODE_DROP: + if (drop) + { + raise_policy_cfg(this, id, child_cfg); + } + break; + case MODE_PASS: + if (pass) + { + raise_policy_cfg(this, id, child_cfg); + } + break; + default: + break; + } + } + enumerator->destroy(enumerator); + } + + b = vici_builder_create(); + return b->finalize(b); +} + +/** + * Build sections for auth configs, local or remote + */ +static void build_auth_cfgs(peer_cfg_t *peer_cfg, bool local, vici_builder_t *b) +{ + enumerator_t *enumerator, *rules; + auth_rule_t rule; + auth_cfg_t *auth; + union { + uintptr_t u; + identification_t *id; + certificate_t *cert; + char *str; + } v; + + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); + while (enumerator->enumerate(enumerator, &auth)) + { + b->begin_section(b, local ? "local" : "remote"); + + rules = auth->create_enumerator(auth); + while (rules->enumerate(rules, &rule, &v)) + { + switch (rule) + { + case AUTH_RULE_AUTH_CLASS: + b->add_kv(b, "class", "%N", auth_class_names, v.u); + break; + case AUTH_RULE_EAP_TYPE: + b->add_kv(b, "eap-type", "%N", eap_type_names, v.u); + break; + case AUTH_RULE_EAP_VENDOR: + b->add_kv(b, "eap-vendor", "%u", v.u); + break; + case AUTH_RULE_XAUTH_BACKEND: + b->add_kv(b, "xauth", "%s", v.str); + break; + case AUTH_RULE_CRL_VALIDATION: + b->add_kv(b, "revocation", "%N", cert_validation_names, v.u); + break; + case AUTH_RULE_IDENTITY: + b->add_kv(b, "id", "%Y", v.id); + break; + case AUTH_RULE_AAA_IDENTITY: + b->add_kv(b, "aaa_id", "%Y", v.id); + break; + case AUTH_RULE_EAP_IDENTITY: + b->add_kv(b, "eap_id", "%Y", v.id); + break; + case AUTH_RULE_XAUTH_IDENTITY: + b->add_kv(b, "xauth_id", "%Y", v.id); + break; + default: + break; + } + } + rules->destroy(rules); + + b->begin_list(b, "groups"); + rules = auth->create_enumerator(auth); + while (rules->enumerate(rules, &rule, &v)) + { + if (rule == AUTH_RULE_GROUP) + { + b->add_li(b, "%Y", v.id); + } + } + rules->destroy(rules); + b->end_list(b); + + b->begin_list(b, "certs"); + rules = auth->create_enumerator(auth); + while (rules->enumerate(rules, &rule, &v)) + { + if (rule == AUTH_RULE_SUBJECT_CERT) + { + b->add_li(b, "%Y", v.cert->get_subject(v.cert)); + } + } + rules->destroy(rules); + b->end_list(b); + + b->begin_list(b, "cacerts"); + rules = auth->create_enumerator(auth); + while (rules->enumerate(rules, &rule, &v)) + { + if (rule == AUTH_RULE_CA_CERT) + { + b->add_li(b, "%Y", v.cert->get_subject(v.cert)); + } + } + rules->destroy(rules); + b->end_list(b); + + b->end_section(b); + } + enumerator->destroy(enumerator); +} + +CALLBACK(list_conns, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + enumerator_t *enumerator, *tokens, *selectors, *children; + peer_cfg_t *peer_cfg; + ike_cfg_t *ike_cfg; + child_cfg_t *child_cfg; + char *ike, *str; + linked_list_t *list; + traffic_selector_t *ts; + vici_builder_t *b; + + ike = request->get_str(request, NULL, "ike"); + + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + NULL, NULL, NULL, NULL, IKE_ANY); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + if (ike && !streq(ike, peer_cfg->get_name(peer_cfg))) + { + continue; + } + + b = vici_builder_create(); + b->begin_section(b, peer_cfg->get_name(peer_cfg)); + + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + + b->begin_list(b, "local_addrs"); + str = ike_cfg->get_my_addr(ike_cfg); + tokens = enumerator_create_token(str, ",", " "); + while (tokens->enumerate(tokens, &str)) + { + b->add_li(b, "%s", str); + } + tokens->destroy(tokens); + b->end_list(b); + + b->begin_list(b, "remote_addrs"); + str = ike_cfg->get_other_addr(ike_cfg); + tokens = enumerator_create_token(str, ",", " "); + while (tokens->enumerate(tokens, &str)) + { + b->add_li(b, "%s", str); + } + tokens->destroy(tokens); + b->end_list(b); + + b->add_kv(b, "version", "%N", ike_version_names, + peer_cfg->get_ike_version(peer_cfg)); + + build_auth_cfgs(peer_cfg, TRUE, b); + build_auth_cfgs(peer_cfg, FALSE, b); + + b->begin_section(b, "children"); + + children = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (children->enumerate(children, &child_cfg)) + { + b->begin_section(b, child_cfg->get_name(child_cfg)); + + b->add_kv(b, "mode", "%N", ipsec_mode_names, + child_cfg->get_mode(child_cfg)); + + b->begin_list(b, "local-ts"); + list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + selectors = list->create_enumerator(list); + while (selectors->enumerate(selectors, &ts)) + { + b->add_li(b, "%R", ts); + } + selectors->destroy(selectors); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + b->end_list(b /* local-ts */); + + b->begin_list(b, "remote-ts"); + list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); + selectors = list->create_enumerator(list); + while (selectors->enumerate(selectors, &ts)) + { + b->add_li(b, "%R", ts); + } + selectors->destroy(selectors); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + b->end_list(b /* remote-ts */); + + b->end_section(b); + } + children->destroy(children); + + b->end_section(b); /* children */ + + b->end_section(b); /* name */ + + this->dispatcher->raise_event(this->dispatcher, "list-conn", id, + b->finalize(b)); + } + enumerator->destroy(enumerator); + + b = vici_builder_create(); + return b->finalize(b); +} + +/** + * Do we have a private key for given certificate + */ +static bool has_privkey(private_vici_query_t *this, certificate_t *cert) +{ + private_key_t *private; + public_key_t *public; + identification_t *keyid; + chunk_t chunk; + bool found = FALSE; + + public = cert->get_public_key(cert); + if (public) + { + if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk)) + { + keyid = identification_create_from_encoding(ID_KEY_ID, chunk); + private = lib->credmgr->get_private(lib->credmgr, + public->get_type(public), keyid, NULL); + if (private) + { + found = TRUE; + private->destroy(private); + } + keyid->destroy(keyid); + } + public->destroy(public); + } + return found; +} + +CALLBACK(list_certs, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + enumerator_t *enumerator, *added; + linked_list_t *list; + certificate_t *cert, *current; + chunk_t encoding; + identification_t *subject = NULL; + int type; + vici_builder_t *b; + bool found; + char *str; + + str = request->get_str(request, "ANY", "type"); + if (!enum_from_name(certificate_type_names, str, &type)) + { + b = vici_builder_create(); + return b->finalize(b); + } + str = request->get_str(request, NULL, "subject"); + if (str) + { + subject = identification_create_from_string(str); + } + + list = linked_list_create(); + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + type, KEY_ANY, subject, FALSE); + while (enumerator->enumerate(enumerator, &cert)) + { + found = FALSE; + added = list->create_enumerator(list); + while (added->enumerate(added, ¤t)) + { + if (current->equals(current, cert)) + { + found = TRUE; + break; + } + } + added->destroy(added); + + if (!found && cert->get_encoding(cert, CERT_ASN1_DER, &encoding)) + { + b = vici_builder_create(); + b->add_kv(b, "type", "%N", + certificate_type_names, cert->get_type(cert)); + if (has_privkey(this, cert)) + { + b->add_kv(b, "has_privkey", "yes"); + } + b->add(b, VICI_KEY_VALUE, "data", encoding); + free(encoding.ptr); + + this->dispatcher->raise_event(this->dispatcher, "list-cert", id, + b->finalize(b)); + list->insert_last(list, cert->get_ref(cert)); + } + } + enumerator->destroy(enumerator); + + list->destroy_offset(list, offsetof(certificate_t, destroy)); + DESTROY_IF(subject); + + b = vici_builder_create(); + return b->finalize(b); +} + +CALLBACK(version, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + vici_builder_t *b; + + b = vici_builder_create(); + + b->add_kv(b, "daemon", "%s", lib->ns); + b->add_kv(b, "version", "%s", VERSION); + +#ifdef WIN32 + { + OSVERSIONINFOEX osvie; + + memset(&osvie, 0, sizeof(osvie)); + osvie.dwOSVersionInfoSize = sizeof(osvie); + + if (GetVersionEx((LPOSVERSIONINFO)&osvie)) + { + b->add_kv(b, "sysname", "Windows %s", + osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server"); + b->add_kv(b, "release", "%d.%d.%d (SP %d.%d)", + osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber, + osvie.wServicePackMajor, osvie.wServicePackMinor); + b->add_kv(b, "machine", "%s", +#ifdef WIN64 + "x86_64"); +#else + "x86"); +#endif /* !WIN64 */ + } + } +#else /* !WIN32 */ + { + struct utsname utsname; + + if (uname(&utsname) == 0) + { + b->add_kv(b, "sysname", "%s", utsname.sysname); + b->add_kv(b, "release", "%s", utsname.release); + b->add_kv(b, "machine", "%s", utsname.machine); + } + } +#endif /* !WIN32 */ + return b->finalize(b); +} + +/** + * Callback function for memusage summary + */ +CALLBACK(sum_usage, void, + vici_builder_t *b, int count, size_t bytes, int whitelisted) +{ + b->begin_section(b, "mem"); + b->add_kv(b, "total", "%zu", bytes); + b->add_kv(b, "allocs", "%d", count); + b->end_section(b); +} + +CALLBACK(stats, vici_message_t*, + private_vici_query_t *this, char *name, u_int id, vici_message_t *request) +{ + vici_builder_t *b; + enumerator_t *enumerator; + plugin_t *plugin; + time_t since, now; + int i; + + b = vici_builder_create(); + + now = time_monotonic(NULL); + since = time(NULL) - (now - this->uptime); + + b->begin_section(b, "uptime"); + b->add_kv(b, "running", "%V", &now, &this->uptime); + b->add_kv(b, "since", "%T", &since, FALSE); + b->end_section(b); + + b->begin_section(b, "workers"); + b->add_kv(b, "total", "%d", + lib->processor->get_total_threads(lib->processor)); + b->add_kv(b, "idle", "%d", + lib->processor->get_idle_threads(lib->processor)); + b->begin_section(b, "active"); + for (i = 0; i < JOB_PRIO_MAX; i++) + { + b->add_kv(b, enum_to_name(job_priority_names, i), "%d", + lib->processor->get_working_threads(lib->processor, i)); + } + b->end_section(b); + b->end_section(b); + + b->begin_section(b, "queues"); + for (i = 0; i < JOB_PRIO_MAX; i++) + { + b->add_kv(b, enum_to_name(job_priority_names, i), "%d", + lib->processor->get_job_load(lib->processor, i)); + } + b->end_section(b); + + b->add_kv(b, "scheduled", "%d", + lib->scheduler->get_job_load(lib->scheduler)); + + b->begin_section(b, "ikesas"); + b->add_kv(b, "total", "%u", + charon->ike_sa_manager->get_count(charon->ike_sa_manager)); + b->add_kv(b, "half-open", "%u", + charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager, + NULL)); + b->end_section(b); + + b->begin_list(b, "plugins"); + enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); + while (enumerator->enumerate(enumerator, &plugin, NULL)) + { + b->add_li(b, "%s", plugin->get_name(plugin)); + } + enumerator->destroy(enumerator); + b->end_list(b); + + if (lib->leak_detective) + { + lib->leak_detective->usage(lib->leak_detective, NULL, sum_usage, b); + } +#ifdef WIN32 + else + { + DWORD lasterr = ERROR_INVALID_HANDLE; + HANDLE heaps[32]; + int i, count; + char buf[16]; + size_t total = 0; + int allocs = 0; + + b->begin_section(b, "mem"); + count = GetProcessHeaps(countof(heaps), heaps); + for (i = 0; i < count; i++) + { + PROCESS_HEAP_ENTRY entry = {}; + size_t heap_total = 0; + int heap_allocs = 0; + + if (HeapLock(heaps[i])) + { + while (HeapWalk(heaps[i], &entry)) + { + if (entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) + { + heap_total += entry.cbData; + heap_allocs++; + } + } + lasterr = GetLastError(); + HeapUnlock(heaps[i]); + } + if (lasterr != ERROR_NO_MORE_ITEMS) + { + break; + } + snprintf(buf, sizeof(buf), "heap-%d", i); + b->begin_section(b, buf); + b->add_kv(b, "total", "%zu", heap_total); + b->add_kv(b, "allocs", "%d", heap_allocs); + b->end_section(b); + + total += heap_total; + allocs += heap_allocs; + } + if (lasterr == ERROR_NO_MORE_ITEMS) + { + b->add_kv(b, "total", "%zu", total); + b->add_kv(b, "allocs", "%d", allocs); + } + b->end_section(b); + } +#endif + +#ifdef HAVE_MALLINFO + { + struct mallinfo mi = mallinfo(); + + b->begin_section(b, "mallinfo"); + b->add_kv(b, "sbrk", "%d", mi.arena); + b->add_kv(b, "mmap", "%d", mi.hblkhd); + b->add_kv(b, "used", "%d", mi.uordblks); + b->add_kv(b, "free", "%d", mi.fordblks); + b->end_section(b); + } +#endif /* HAVE_MALLINFO */ + + return b->finalize(b); +} + +static void manage_command(private_vici_query_t *this, + char *name, vici_command_cb_t cb, bool reg) +{ + this->dispatcher->manage_command(this->dispatcher, name, + reg ? cb : NULL, this); +} + +/** + * (Un-)register dispatcher functions + */ +static void manage_commands(private_vici_query_t *this, bool reg) +{ + this->dispatcher->manage_event(this->dispatcher, "list-sa", reg); + this->dispatcher->manage_event(this->dispatcher, "list-policy", reg); + this->dispatcher->manage_event(this->dispatcher, "list-conn", reg); + this->dispatcher->manage_event(this->dispatcher, "list-cert", reg); + manage_command(this, "list-sas", list_sas, reg); + manage_command(this, "list-policies", list_policies, reg); + manage_command(this, "list-conns", list_conns, reg); + manage_command(this, "list-certs", list_certs, reg); + manage_command(this, "version", version, reg); + manage_command(this, "stats", stats, reg); +} + +METHOD(vici_query_t, destroy, void, + private_vici_query_t *this) +{ + manage_commands(this, FALSE); + free(this); +} + +/** + * See header + */ +vici_query_t *vici_query_create(vici_dispatcher_t *dispatcher) +{ + private_vici_query_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + }, + .dispatcher = dispatcher, + .uptime = time_monotonic(NULL), + ); + + manage_commands(this, TRUE); + + return &this->public; +} |