resolved: put DNS-SD records to mDNS-enabled zones.
authorDmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
Wed, 4 Oct 2017 08:34:39 +0000 (11:34 +0300)
committerDmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
Fri, 8 Dec 2017 12:29:27 +0000 (14:29 +0200)
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-scope.h
src/resolve/resolved-dns-zone.c
src/resolve/resolved-dns-zone.h
src/resolve/resolved-dnssd.c
src/resolve/resolved-dnssd.h
src/resolve/resolved-link.c
src/resolve/resolved-manager.c

index a9071ee..5b7ac0e 100644 (file)
@@ -27,6 +27,7 @@
 #include "hostname-util.h"
 #include "missing.h"
 #include "random-util.h"
+#include "resolved-dnssd.h"
 #include "resolved-dns-scope.h"
 #include "resolved-llmnr.h"
 #include "resolved-mdns.h"
@@ -1123,3 +1124,58 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
 
         return 0;
 }
+
+int dns_scope_add_dnssd_services(DnsScope *scope) {
+        Iterator i;
+        DnssdService *service;
+        int r;
+
+        assert(scope);
+
+        if (hashmap_size(scope->manager->dnssd_services) == 0)
+                return 0;
+
+        scope->announced = false;
+
+        HASHMAP_FOREACH(service, scope->manager->dnssd_services, i) {
+                r = dns_zone_put(&scope->zone, scope, service->ptr_rr, false);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to add PTR record to MDNS zone: %m");
+
+                r = dns_zone_put(&scope->zone, scope, service->srv_rr, true);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to add SRV record to MDNS zone: %m");
+
+                r = dns_zone_put(&scope->zone, scope, service->txt_rr, true);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to add TXT record to MDNS zone: %m");
+        }
+
+        return 0;
+}
+
+int dns_scope_remove_dnssd_services(DnsScope *scope) {
+        _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
+        Iterator i;
+        DnssdService *service;
+        int r;
+
+        assert(scope);
+
+        key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_PTR,
+                                   "_services._dns-sd._udp.local");
+        if (!key)
+                return log_oom();
+
+        r = dns_zone_remove_rrs_by_key(&scope->zone, key);
+        if (r < 0)
+                return r;
+
+        HASHMAP_FOREACH(service, scope->manager->dnssd_services, i) {
+                dns_zone_remove_rr(&scope->zone, service->ptr_rr);
+                dns_zone_remove_rr(&scope->zone, service->srv_rr);
+                dns_zone_remove_rr(&scope->zone, service->txt_rr);
+        }
+
+        return 0;
+}
index d3da8e5..d46ccd8 100644 (file)
@@ -119,3 +119,7 @@ bool dns_scope_network_good(DnsScope *s);
 int dns_scope_ifindex(DnsScope *s);
 
 int dns_scope_announce(DnsScope *scope, bool goodbye);
+
+int dns_scope_add_dnssd_services(DnsScope *scope);
+
+int dns_scope_remove_dnssd_services(DnsScope *scope);
index 2c32bb4..8080c3e 100644 (file)
@@ -119,6 +119,22 @@ void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr) {
                 dns_zone_item_remove_and_free(z, i);
 }
 
+int dns_zone_remove_rrs_by_key(DnsZone *z, DnsResourceKey *key) {
+        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
+        DnsResourceRecord *rr;
+        bool tentative;
+        int r;
+
+        r = dns_zone_lookup(z, key, 0, &answer, &soa, &tentative);
+        if (r < 0)
+                return r;
+
+        DNS_ANSWER_FOREACH(rr, answer)
+                dns_zone_remove_rr(z, rr);
+
+        return 0;
+}
+
 static int dns_zone_init(DnsZone *z) {
         int r;
 
index f654537..55702fb 100644 (file)
@@ -68,6 +68,7 @@ void dns_zone_flush(DnsZone *z);
 
 int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe);
 void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr);
+int dns_zone_remove_rrs_by_key(DnsZone *z, DnsResourceKey *key);
 
 int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **answer, DnsAnswer **soa, bool *tentative);
 
index e025a53..f565460 100644 (file)
@@ -119,6 +119,10 @@ static int dnssd_service_load(Manager *manager, const char *filename) {
 
         service->manager = manager;
 
+        r = dnssd_update_rrs(service);
+        if (r < 0)
+                return r;
+
         service = NULL;
 
         return 0;
@@ -192,6 +196,73 @@ int dnssd_load(Manager *manager) {
         return 0;
 }
 
+int dnssd_update_rrs(DnssdService *s) {
+        _cleanup_free_ char *n = NULL;
+        _cleanup_free_ char *service_name = NULL;
+        _cleanup_free_ char *full_name = NULL;
+        int r;
+
+        assert(s);
+        assert(s->txt);
+        assert(s->manager);
+
+        s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
+        s->srv_rr = dns_resource_record_unref(s->srv_rr);
+        s->txt_rr = dns_resource_record_unref(s->txt_rr);
+
+        r = dnssd_render_instance_name(s, &n);
+        if (r < 0)
+                return r;
+
+        r = dns_name_concat(s->type, "local", &service_name);
+        if (r < 0)
+                return r;
+        r = dns_name_concat(n, service_name, &full_name);
+        if (r < 0)
+                return r;
+
+        s->txt_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_TXT,
+                                                 full_name);
+        if (!s->txt_rr)
+                goto oom;
+
+        s->txt_rr->ttl = MDNS_DEFAULT_TTL;
+        s->txt_rr->txt.items = dns_txt_item_copy(s->txt);
+        if (!s->txt_rr->txt.items)
+                goto oom;
+
+        s->ptr_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR,
+                                                 service_name);
+        if (!s->ptr_rr)
+                goto oom;
+
+        s->ptr_rr->ttl = MDNS_DEFAULT_TTL;
+        s->ptr_rr->ptr.name = strdup(full_name);
+        if (!s->ptr_rr->ptr.name)
+                goto oom;
+
+        s->srv_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SRV,
+                                                 full_name);
+        if (!s->srv_rr)
+                goto oom;
+
+        s->srv_rr->ttl = MDNS_DEFAULT_TTL;
+        s->srv_rr->srv.priority = s->priority;
+        s->srv_rr->srv.weight = s->weight;
+        s->srv_rr->srv.port = s->port;
+        s->srv_rr->srv.name = strdup(s->manager->mdns_hostname);
+        if (!s->srv_rr->srv.name)
+                goto oom;
+
+        return 0;
+
+oom:
+        s->txt_rr = dns_resource_record_unref(s->txt_rr);
+        s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
+        s->srv_rr = dns_resource_record_unref(s->srv_rr);
+        return -ENOMEM;
+}
+
 int dnssd_txt_item_new_from_string(const char *key, const char *value, DnsTxtItem **ret_item) {
         size_t length;
         DnsTxtItem *i;
index 0c0e1cd..b723698 100644 (file)
@@ -55,3 +55,4 @@ int dnssd_render_instance_name(DnssdService *s, char **ret_name);
 int dnssd_load(Manager *manager);
 int dnssd_txt_item_new_from_string(const char *key, const char *value, DnsTxtItem **ret_item);
 int dnssd_txt_item_new_from_data(const char *key, const void *value, const size_t size, DnsTxtItem **ret_item);
+int dnssd_update_rrs(DnssdService *s);
index a0128aa..ed7bdc8 100644 (file)
@@ -191,9 +191,41 @@ void link_allocate_scopes(Link *l) {
 
 void link_add_rrs(Link *l, bool force_remove) {
         LinkAddress *a;
+        int r;
 
         LIST_FOREACH(addresses, a, l->addresses)
                 link_address_add_rrs(a, force_remove);
+
+        if (!force_remove &&
+            l->mdns_support == RESOLVE_SUPPORT_YES &&
+            l->manager->mdns_support == RESOLVE_SUPPORT_YES) {
+
+                if (l->mdns_ipv4_scope) {
+                        r = dns_scope_add_dnssd_services(l->mdns_ipv4_scope);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to add IPv4 DNS-SD services: %m");
+                }
+
+                if (l->mdns_ipv6_scope) {
+                        r = dns_scope_add_dnssd_services(l->mdns_ipv6_scope);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to add IPv6 DNS-SD services: %m");
+                }
+
+        } else {
+
+                if (l->mdns_ipv4_scope) {
+                        r = dns_scope_remove_dnssd_services(l->mdns_ipv4_scope);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to remove IPv4 DNS-SD services: %m");
+                }
+
+                if (l->mdns_ipv6_scope) {
+                        r = dns_scope_remove_dnssd_services(l->mdns_ipv6_scope);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to remove IPv6 DNS-SD services: %m");
+                }
+        }
 }
 
 int link_process_rtnl(Link *l, sd_netlink_message *m) {
index 91bed0a..2813f6e 100644 (file)
@@ -1104,6 +1104,7 @@ int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_a
 void manager_refresh_rrs(Manager *m) {
         Iterator i;
         Link *l;
+        DnssdService *s;
 
         assert(m);
 
@@ -1112,6 +1113,11 @@ void manager_refresh_rrs(Manager *m) {
         m->mdns_host_ipv4_key = dns_resource_key_unref(m->mdns_host_ipv4_key);
         m->mdns_host_ipv6_key = dns_resource_key_unref(m->mdns_host_ipv6_key);
 
+        if (m->mdns_support == RESOLVE_SUPPORT_YES)
+                HASHMAP_FOREACH(s, m->dnssd_services, i)
+                        if (dnssd_update_rrs(s) < 0)
+                                log_warning("Failed to refresh DNS-SD service '%s'", s->name);
+
         HASHMAP_FOREACH(l, m->links, i) {
                 link_add_rrs(l, true);
                 link_add_rrs(l, false);