resolved: resolve possible conflicts for DNS-SD RRs
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.
This commit is contained in:
parent
d686f15c9e
commit
e7c1b0e456
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue