diff options
author | Lennart Poettering <lennart@poettering.net> | 2023-06-12 16:40:59 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2023-06-12 22:21:26 +0200 |
commit | e0930aa6ffabb0931d7e9e387b180fca8756ad8e (patch) | |
tree | 27c42af2cee415357bc5046997805bb0d8d3468c /src | |
parent | json: add json_dispatch_variant_noref() helper (diff) | |
download | systemd-e0930aa6ffabb0931d7e9e387b180fca8756ad8e.tar.xz systemd-e0930aa6ffabb0931d7e9e387b180fca8756ad8e.zip |
resolved: add DumpCache varlink call for acquiring a complete dump of all of resolved's RR caches
This adds a simple varlink call io.systemd.Resolve.Monitor.DumpCache to
the existing io.systemd.Resolve.Monitor service. It compiles a JSON
object containing the per-scope cache entries and returns it.
Replaces: #20053 #19104
Fixes: #14796
Diffstat (limited to 'src')
-rw-r--r-- | src/resolve/resolved-dns-cache.c | 80 | ||||
-rw-r--r-- | src/resolve/resolved-dns-cache.h | 2 | ||||
-rw-r--r-- | src/resolve/resolved-dns-scope.c | 20 | ||||
-rw-r--r-- | src/resolve/resolved-dns-scope.h | 2 | ||||
-rw-r--r-- | src/resolve/resolved-varlink.c | 40 |
5 files changed, 141 insertions, 3 deletions
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 2f97cf7730..089ed3aa0a 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -1351,6 +1351,86 @@ void dns_cache_dump(DnsCache *cache, FILE *f) { } } +int dns_cache_dump_to_json(DnsCache *cache, JsonVariant **ret) { + _cleanup_(json_variant_unrefp) JsonVariant *c = NULL; + DnsCacheItem *i; + int r; + + assert(cache); + assert(ret); + + HASHMAP_FOREACH(i, cache->by_key) { + _cleanup_(json_variant_unrefp) JsonVariant *d = NULL, *k = NULL; + + r = dns_resource_key_to_json(i->key, &k); + if (r < 0) + return r; + + if (i->rr) { + _cleanup_(json_variant_unrefp) JsonVariant *l = NULL; + + LIST_FOREACH(by_key, j, i) { + _cleanup_(json_variant_unrefp) JsonVariant *rj = NULL, *item = NULL; + + assert(j->rr); + + r = dns_resource_record_to_json(j->rr, &rj); + if (r < 0) + return r; + + r = dns_resource_record_to_wire_format(j->rr, /* canonical= */ false); /* don't use DNSSEC canonical format, since it removes casing, but we want that for DNS_SD compat */ + if (r < 0) + return r; + + r = json_build(&item, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_VARIANT("rr", rj), + JSON_BUILD_PAIR_BASE64("raw", j->rr->wire_format, j->rr->wire_format_size))); + if (r < 0) + return r; + + r = json_variant_append_array(&l, item); + if (r < 0) + return r; + } + + if (!l) { + r = json_variant_new_array(&l, NULL, 0); + if (r < 0) + return r; + } + + r = json_build(&d, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_VARIANT("key", k), + JSON_BUILD_PAIR_VARIANT("rrs", l), + JSON_BUILD_PAIR_UNSIGNED("until", i->until))); + } else if (i->type == DNS_CACHE_NODATA) { + r = json_build(&d, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_VARIANT("key", k), + JSON_BUILD_PAIR_EMPTY_ARRAY("rrs"), + JSON_BUILD_PAIR_UNSIGNED("until", i->until))); + } else + r = json_build(&d, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_VARIANT("key", k), + JSON_BUILD_PAIR_STRING("type", dns_cache_item_type_to_string(i)), + JSON_BUILD_PAIR_UNSIGNED("until", i->until))); + if (r < 0) + return r; + + r = json_variant_append_array(&c, d); + if (r < 0) + return r; + } + + if (!c) + return json_variant_new_array(ret, NULL, 0); + + *ret = TAKE_PTR(c); + return 0; +} + bool dns_cache_is_empty(DnsCache *cache) { if (!cache) return true; diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index 42e744a910..bc045bc80c 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -50,6 +50,8 @@ int dns_cache_lookup( int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address); void dns_cache_dump(DnsCache *cache, FILE *f); +int dns_cache_dump_to_json(DnsCache *cache, JsonVariant **ret); + bool dns_cache_is_empty(DnsCache *cache); unsigned dns_cache_size(DnsCache *cache); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 45f1d36311..35085a6ef5 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -1643,3 +1643,23 @@ bool dns_scope_is_default_route(DnsScope *scope) { * volunteer as default route. */ return !dns_scope_has_route_only_domains(scope); } + +int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret) { + _cleanup_(json_variant_unrefp) JsonVariant *cache = NULL; + int r; + + assert(scope); + assert(ret); + + r = dns_cache_dump_to_json(&scope->cache, &cache); + if (r < 0) + return r; + + return json_build(ret, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_STRING("protocol", dns_protocol_to_string(scope->protocol)), + JSON_BUILD_PAIR_CONDITION(scope->family != AF_UNSPEC, "family", JSON_BUILD_INTEGER(scope->family)), + JSON_BUILD_PAIR_CONDITION(scope->link, "ifindex", JSON_BUILD_INTEGER(scope->link ? scope->link->ifindex : 0)), + JSON_BUILD_PAIR_CONDITION(scope->link, "ifname", JSON_BUILD_STRING(scope->link ? scope->link->ifname : NULL)), + JSON_BUILD_PAIR_VARIANT("cache", cache))); +} diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 1f9d22b7d1..ca33fd007a 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -110,3 +110,5 @@ int dns_scope_add_dnssd_services(DnsScope *scope); int dns_scope_remove_dnssd_services(DnsScope *scope); bool dns_scope_is_default_route(DnsScope *scope); + +int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret); diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index f878d9ee3f..fc224f627e 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -563,6 +563,40 @@ static int vl_method_subscribe_dns_resolves(Varlink *link, JsonVariant *paramete return 1; } +static int vl_method_dump_cache(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { + _cleanup_(json_variant_unrefp) JsonVariant *list = NULL; + Manager *m; + int r; + + assert(link); + + if (json_variant_elements(parameters) > 0) + return varlink_error_invalid_parameter(link, parameters); + + m = ASSERT_PTR(varlink_server_get_userdata(varlink_get_server(link))); + + LIST_FOREACH(scopes, s, m->dns_scopes) { + _cleanup_(json_variant_unrefp) JsonVariant *j = NULL; + + r = dns_scope_dump_cache_to_json(s, &j); + if (r < 0) + return r; + + r = json_variant_append_array(&list, j); + if (r < 0) + return r; + } + + if (!list) { + r = json_variant_new_array(&list, NULL, 0); + if (r < 0) + return r; + } + + return varlink_replyb(link, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("dump", JSON_BUILD_VARIANT(list)))); +} + static int varlink_monitor_server_init(Manager *m) { _cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL; int r; @@ -578,10 +612,10 @@ static int varlink_monitor_server_init(Manager *m) { varlink_server_set_userdata(server, m); - r = varlink_server_bind_method( + r = varlink_server_bind_method_many( server, - "io.systemd.Resolve.Monitor.SubscribeQueryResults", - vl_method_subscribe_dns_resolves); + "io.systemd.Resolve.Monitor.SubscribeQueryResults", vl_method_subscribe_dns_resolves, + "io.systemd.Resolve.Monitor.DumpCache", vl_method_dump_cache); if (r < 0) return log_error_errno(r, "Failed to register varlink methods: %m"); |