diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 5448575d5a..7a5143d8ac 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -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) diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 2813f6ee40..983e6c091a 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -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; + char *n; - assert(m); - - 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; - r = dns_name_concat(h, "local", &k); - if (r < 0) { - free(h); + *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) 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; +} diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index e16d6a4732..d964742921 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -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);