]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: add DumpCache varlink call for acquiring a complete dump of all of resolved...
authorLennart Poettering <lennart@poettering.net>
Mon, 12 Jun 2023 14:40:59 +0000 (16:40 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 12 Jun 2023 20:21:26 +0000 (22:21 +0200)
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
src/resolve/resolved-dns-cache.c
src/resolve/resolved-dns-cache.h
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-scope.h
src/resolve/resolved-varlink.c

index 2f97cf7730db71434e945ed05c03d1404aaebaff..089ed3aa0a97180b873a0b2b4e01bd995e10ef2d 100644 (file)
@@ -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;
index 42e744a9108477921698b6ed4c657373f83d0644..bc045bc80c8a165a4c07ab295d295c6a2fbb44ae 100644 (file)
@@ -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);
index 45f1d3631196564bc5d61674e3dca19400b10d77..35085a6ef57deb94e4a9266da3697e463d21ee08 100644 (file)
@@ -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)));
+}
index 1f9d22b7d18a0b721330aa1e5a9c33b08ac6c8d6..ca33fd007a6aeaf077d0364061242e6336440910 100644 (file)
@@ -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);
index f878d9ee3fe57e804084a547f01b5614e7c2ed9f..fc224f627e8f71a56c4ba7ea492e78e29c7cdd55 100644 (file)
@@ -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");