Repository: avahi/avahi

Issue #243: RFE: Always advertise link-local addresses
Created: 2019-08-27T21:11:57Z
Avahi doesn't advertise a link-local address if a global address is available. This was queried many years ago on the mailing list: https://lists.freedesktop.org/archives/avahi/2010-March/001863.html
It does in fact cause problems in some circumstances, where some machines have e.g. static global addresses assigned, and others have link local only. For example, Pidgin's Bonjour module is unable to match the source address on an incoming connection with the address that was originally advertised: https://bugs.launchpad.net/ubuntu/+source/pidgin/+bug/1841621
There's an old patch in Launchpad to change this behaviour, but a quick review suggests it is not quite correct: https://bugs.launchpad.net/ubuntu/+source/avahi/+bug/1102906

Duplicate issue #654: avahi-core/server: incoming_probe: Erroneous conflict detection if TXT data is changed
Created: 2024-11-06T13:40:58Z
Avahi version
v0.8+x
Distribution
Yocto Linux
Describe the bug
Sometimes (during automated power-on testing) I get a
Received conflicting probe [MyService._MyServiceType._tcp.local	IN	TXT "MyAlternatingServiceData"; ttl=4500]. Local host lost. Withdrawing.
message when I update my service's TXT data (via the EntryGroups's "UpdateServiceTxt" D-Bus call).
Normally the Avahi daemon is able to detect that an incoming probe was originally sent from the local system. But if the local TXT entry is updated shortly after a previous probe request (containing the previous TXT value) has been sent out, the received echo frame (due to multicast communication) doesn't match the stored value anymore and is detected as a conflict:
static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface *i) {
    AvahiEntry *e, *n;
    int ours = 0, won = 0, lost = 0;
    ...

    /* Handle incoming probes and check if they conflict our own probes */

    for (e = avahi_hashmap_lookup(s->entries_by_key, record->key); e; e = n) {
        int cmp;
        n = e->by_key_next;

        if (e->dead)
            continue;

        /* !!! doesn't match ... !!! */
        if ((cmp = avahi_record_lexicographical_compare(e->record, record)) == 0) {
            ours = 1;
            break;
        } else {

            /* !!! this depends on the timing (current state of the record's announcer on this interface) !!! */
            if (avahi_entry_is_probing(s, e, i)) {
                if (cmp > 0)
                    won = 1;
                else /* cmp < 0 */
                    lost = 1;
            }
        }
    }

    if (!ours) {
        char *t = avahi_record_to_string(record);

        if (won)
            avahi_log_debug("Received conflicting probe [%s]. Local host won.", t);
        else if (lost) {
            /* !!! Usually I end up here ... !!! */
            avahi_log_debug("Received conflicting probe [%s]. Local host lost. Withdrawing.", t);
            withdraw_rrset(s, record->key);
        }

        avahi_free(t);
    }
}
To Reproduce
I can reproduce this only by automated power cycle testing. Additionally it is necessary that the TXT data is updated shortly after the service has been comitted.
Expected behavior

Avahi should detect that the incoming probe frame originated from the local system.
No conflict shall be detected in this case.

Conflicts are handled by my application (as described in defs.h), but this leads to (needless) renaming of my service.


This service shall not be withdrawn.

As the original service is withdrawn, the remote application with depends on my service is interrupted (for some seconds).



Avahi config files if applicable
Nothing special I think.
Avahi debug logs if applicable
Nov  2 03:33:58.115 MyHost daemon.debug avahi-daemon[180]: /usr/src/debug/avahi/0.8/avahi-daemon/dbus-protocol.c: interface=org.freedesktop.Avahi.Server, path=/, member=EntryGroupNew
...
Nov  2 03:33:58.377 MyHost daemon.debug avahi-daemon[180]: /usr/src/debug/avahi/0.8/avahi-daemon/dbus-entry-group.c: interface=org.freedesktop.Avahi.EntryGroup, path=/Client0/EntryGroup2, member=AddServiceSubtype
Nov  2 03:33:58.430 MyHost daemon.debug avahi-daemon[180]: /usr/src/debug/avahi/0.8/avahi-daemon/dbus-entry-group.c: interface=org.freedesktop.Avahi.EntryGroup, path=/Client0/EntryGroup2, member=Commit
...
Nov  2 03:33:59.435 MyHost daemon.debug avahi-daemon[180]: /usr/src/debug/avahi/0.8/avahi-daemon/dbus-entry-group.c: interface=org.freedesktop.Avahi.EntryGroup, path=/Client0/EntryGroup2, member=UpdateServiceTxt
Nov  2 03:33:59.436 MyHost daemon.debug avahi-daemon[180]: reannounce: current_state = 0   #announcer state, own debug message
Nov  2 03:33:59.436 MyHost daemon.debug avahi-daemon[180]: reannounce: new_state = 0       #announcer state, own debug message
Nov  2 03:33:59.436 MyHost daemon.debug avahi-daemon[180]: reannounce: current_state = 0   #announcer state, own debug message
Nov  2 03:33:59.436 MyHost daemon.debug avahi-daemon[180]: reannounce: new_state = 0       #announcer state, own debug message
Nov  2 03:33:59.476 MyHost daemon.debug avahi-daemon[180]: Received conflicting probe [MyService._MyServiceType._tcp.local	IN	TXT "MyAlternatingServiceData"; ttl=4500]. Local host lost. Withdrawing.

Additional context
I already tried to solve the problem by not updating my service's TXT data shortly after committing the EntryGroup. But as there are individual announcers for each network interface (and protocol), it seems to be impossible to foresee if all announcers have reached the ESTABLISHED state (in this state, avahi_entry_is_probing() would return false and the received probe message is not further handled as conflict).

Closing comment (2024-12-09T05:23:29Z): It's a known issue: #554 (comment). That part of the RFC isn't implemented yet. If it was implemented it would also help with spurious name conflicts where avahi conflicts with its own link-local addresses. The full fix there would be to advertise all the link-local addresses according to the RFC (it's tracked in #243)