]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: resolve possible conflicts for DNS-SD RRs
authorDmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
Tue, 31 Oct 2017 07:47:37 +0000 (09:47 +0200)
committerDmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
Fri, 8 Dec 2017 12:29:27 +0000 (14:29 +0200)
It might happen that a DNS-SD service doesn't include local host's
name in its RR keys and still conflicts with a remote service.

In this case try to resolve the conflict by changing name for
this particular service.

src/resolve/resolved-dns-scope.c
src/resolve/resolved-manager.c
src/resolve/resolved-manager.h

index 5448575d5a24056fddfeb03a190a31ed258b7691..7a5143d8ac2d27f5f1037962a9aa9e983ddcf834 100644 (file)
@@ -1085,6 +1085,10 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
                 if (DNS_TRANSACTION_IS_LIVE(t->state))
                         return 0;
 
+        /* Check if there're services pending conflict resolution. */
+        if (manager_next_dnssd_names(scope->manager))
+                return 0; /* we reach this point only if changing hostname didn't help */
+
         /* Calculate answer's size. */
         HASHMAP_FOREACH(z, scope->zone.by_key, iterator) {
                 if (z->state != DNS_ZONE_ITEM_ESTABLISHED)
index 2813f6ee402fcdcbcd1692fabf7c8bded5e80c59..983e6c091a79d8f30b1f18adf5079f580cca17ce 100644 (file)
@@ -1124,19 +1124,16 @@ void manager_refresh_rrs(Manager *m) {
         }
 }
 
-int manager_next_hostname(Manager *m) {
+static int manager_next_random_name(const char *old, char **ret_new) {
         const char *p;
         uint64_t u, a;
-        char *h, *k;
-        int r;
-
-        assert(m);
+        char *n;
 
-        p = strchr(m->llmnr_hostname, 0);
+        p = strchr(old, 0);
         assert(p);
 
-        while (p > m->llmnr_hostname) {
-                if (!strchr("0123456789", p[-1]))
+        while (p > old) {
+                if (!strchr(DIGITS, p[-1]))
                         break;
 
                 p--;
@@ -1155,22 +1152,32 @@ int manager_next_hostname(Manager *m) {
         random_bytes(&a, sizeof(a));
         u += 1 + a % 10;
 
-        if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->llmnr_hostname), m->llmnr_hostname, u) < 0)
+        if (asprintf(&n, "%.*s%" PRIu64, (int) (p - old), old, u) < 0)
                 return -ENOMEM;
 
+        *ret_new = n;
+
+        return 0;
+}
+
+int manager_next_hostname(Manager *m) {
+        _cleanup_free_ char *h = NULL, *k = NULL;
+        int r;
+
+        assert(m);
+
+        r = manager_next_random_name(m->llmnr_hostname, &h);
+        if (r < 0)
+                return r;
+
         r = dns_name_concat(h, "local", &k);
-        if (r < 0) {
-                free(h);
+        if (r < 0)
                 return r;
-        }
 
         log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->llmnr_hostname, h);
 
-        free(m->llmnr_hostname);
-        m->llmnr_hostname = h;
-
-        free(m->mdns_hostname);
-        m->mdns_hostname = k;
+        free_and_replace(m->llmnr_hostname, h);
+        free_and_replace(m->mdns_hostname, k);
 
         manager_refresh_rrs(m);
 
@@ -1504,3 +1511,36 @@ void manager_cleanup_saved_user(Manager *m) {
                 (void) unlink(p);
         }
 }
+
+bool manager_next_dnssd_names(Manager *m) {
+        Iterator i;
+        DnssdService *s;
+        bool tried = false;
+        int r;
+
+        assert(m);
+
+        HASHMAP_FOREACH(s, m->dnssd_services, i) {
+                _cleanup_free_ char * new_name = NULL;
+
+                if (!s->withdrawn)
+                        continue;
+
+                r = manager_next_random_name(s->name_template, &new_name);
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to get new name for service '%s': %m", s->name);
+                        continue;
+                }
+
+                free_and_replace(s->name_template, new_name);
+
+                s->withdrawn = false;
+
+                tried = true;
+        }
+
+        if (tried)
+                manager_refresh_rrs(m);
+
+        return tried;
+}
index e16d6a4732b803bcf46bc07ce45b55b09646751b..d9647429216f36155e3c346ed5780551e012d97e 100644 (file)
@@ -192,3 +192,5 @@ void manager_flush_caches(Manager *m);
 void manager_reset_server_features(Manager *m);
 
 void manager_cleanup_saved_user(Manager *m);
+
+bool manager_next_dnssd_names(Manager *m);