resolve: Add GetMulticastHosts() D-Bus method

GetMulticastHosts() returns an array of hostnames/addresses discovered via
LLMNR or Multicast DNS. It does not trigger any discovery on its own.
Instead, it simply returns whatever is already in resolved's cache.
This commit is contained in:
Daan De Meyer 2021-01-23 17:33:24 +00:00
parent d8067d4041
commit 69988fee43
5 changed files with 146 additions and 13 deletions

View file

@ -115,6 +115,7 @@ node /org/freedesktop/resolve1 {
ResetStatistics();
FlushCaches();
ResetServerFeatures();
GetMulticastHosts(out a(stiiay) UNNAMED);
properties:
readonly s LLMNRHostname = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
@ -164,6 +165,8 @@ node /org/freedesktop/resolve1 {
<!--method ResetServerFeatures is not documented!-->
<!--method GetMulticastHosts is not documented!-->
<!--property DNSSECNegativeTrustAnchors is not documented!-->
<!--Autogenerated cross-references for systemd.directives, do not edit-->
@ -212,6 +215,8 @@ node /org/freedesktop/resolve1 {
<variablelist class="dbus-method" generated="True" extra-ref="ResetServerFeatures()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetMulticastHosts()"/>
<variablelist class="dbus-property" generated="True" extra-ref="LLMNRHostname"/>
<variablelist class="dbus-property" generated="True" extra-ref="LLMNR"/>

View file

@ -132,15 +132,17 @@ static int reply_query_state(DnsQuery *q) {
}
}
static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex, bool is_container) {
int r;
assert(reply);
assert(rr);
r = sd_bus_message_open_container(reply, 'r', "iiay");
if (r < 0)
return r;
if (is_container) {
r = sd_bus_message_open_container(reply, 'r', "iiay");
if (r < 0)
return r;
}
r = sd_bus_message_append(reply, "i", ifindex);
if (r < 0)
@ -165,9 +167,11 @@ static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifin
if (r < 0)
return r;
r = sd_bus_message_close_container(reply);
if (r < 0)
return r;
if (is_container) {
r = sd_bus_message_close_container(reply);
if (r < 0)
return r;
}
return 0;
}
@ -216,7 +220,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
if (r == 0)
continue;
r = append_address(reply, rr, ifindex);
r = append_address(reply, rr, ifindex, true);
if (r < 0)
goto finish;
@ -851,7 +855,7 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr)
if (r == 0)
continue;
r = append_address(reply, zz, ifindex);
r = append_address(reply, zz, ifindex, true);
if (r < 0)
return r;
}
@ -2000,6 +2004,76 @@ static int bus_method_unregister_service(sd_bus_message *message, void *userdata
return call_dnssd_method(m, message, bus_dnssd_method_unregister, error);
}
static int bus_method_get_multicast_hosts(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
DnsScope *s;
Manager *m = userdata;
int r;
assert(message);
assert(m);
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;
r = sd_bus_message_open_container(reply, 'a', "(stiiay)");
if (r < 0)
return r;
LIST_FOREACH(scopes, s, m->dns_scopes) {
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
DnsResourceRecord *rr;
DnsAnswerFlags flags;
int ifindex;
if (s->protocol == DNS_PROTOCOL_DNS)
continue;
r = dns_cache_dump_to_answer(&s->cache, &answer);
if (r < 0)
return r;
if (r == 0)
continue;
DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) {
_cleanup_free_ char *normalized = NULL;
bool authenticated = FLAGS_SET(flags, DNS_ANSWER_AUTHENTICATED);
r = dns_name_normalize(dns_resource_key_name(rr->key), 0, &normalized);
if (r < 0)
return r;
r = sd_bus_message_open_container(reply, 'r', "stiiay");
if (r < 0)
return r;
r = sd_bus_message_append(
reply,
"st",
normalized,
SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, authenticated));
if (r < 0)
return r;
r = append_address(reply, rr, ifindex, false);
if (r < 0)
return r;
r = sd_bus_message_close_container(reply);
if (r < 0)
return r;
}
}
r = sd_bus_message_close_container(reply);
if (r < 0)
return r;
return sd_bus_reply(message, reply);
}
/* clang-format off */
static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@ -2138,9 +2212,14 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_NO_RESULT,
bus_method_reset_server_features,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("GetMulticastHosts",
SD_BUS_NO_ARGS,
SD_BUS_RESULT("a(stiiay)", addresses),
bus_method_get_multicast_hosts,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};
/* clang-format on */
const BusObjectImplementation manager_object = {
"/org/freedesktop/resolve1",

View file

@ -1066,7 +1066,55 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
return 0;
}
void dns_cache_dump(DnsCache *cache, FILE *f) {
int dns_cache_dump_to_answer(DnsCache *cache, DnsAnswer **ret) {
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
DnsCacheItem *i;
size_t n = 0;
int r;
assert(cache);
assert(ret);
HASHMAP_FOREACH(i, cache->by_key) {
DnsCacheItem *j;
LIST_FOREACH(by_key, j, i) {
if (!j->rr)
continue;
n++;
}
}
if (n == 0) {
*ret = NULL;
return 0;
}
answer = dns_answer_new(n);
if (!answer)
return -ENOMEM;
HASHMAP_FOREACH(i, cache->by_key) {
DnsCacheItem *j;
LIST_FOREACH(by_key, j, i) {
if (!j->rr)
continue;
r = dns_answer_add(
answer, j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0);
if (r < 0)
return r;
}
}
*ret = TAKE_PTR(answer);
return n;
}
void dns_cache_dump_to_file(DnsCache *cache, FILE *f) {
DnsCacheItem *i;
if (!cache)

View file

@ -27,7 +27,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcod
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);
void dns_cache_dump_to_file(DnsCache *cache, FILE *f);
int dns_cache_dump_to_answer(DnsCache *cache, DnsAnswer **answer);
bool dns_cache_is_empty(DnsCache *cache);
unsigned dns_cache_size(DnsCache *cache);

View file

@ -1159,7 +1159,7 @@ void dns_scope_dump(DnsScope *s, FILE *f) {
if (!dns_cache_is_empty(&s->cache)) {
fputs("CACHE:\n", f);
dns_cache_dump(&s->cache, f);
dns_cache_dump_to_file(&s->cache, f);
}
}