avahi
avahi copied to clipboard
Support IPv6 link local address zone identifiers
Currently, Avahi prioritises larger-scoped IPv6 addresses over locally-scoped ones when returning resolver results. However, if a peer only has a locally-scoped IPv6 address (fe80:…
), that will still be returned.
Naive use of the parameters from the AvahiServiceResolverCallback
callback means that consumers of Avahi results will use the address
but not its zone identifier (or scope ID), which is the interface
argument. A link-local IPv6 address without a scope ID is useless, since the same address can be used by different peers on different interfaces. connect()
will error if passed such an address.
Looking into the Avahi code, it looks like AvahiAddress
has no concept of zone IDs for link-local IPv6 addresses, since it internally stores only the struct in6_addr
, rather than the full struct sockaddr
which, for IPv6 addresses, contains the sin6_scope_id
field. This means that anything operating on just an AvahiAddress
is not going to work with link-local IPv6 addresses.
Unfortunately AvahiAddress
is public, so it can’t be changed to include the scope ID without breaking ABI. I think the best which can be done here is documenting the treatment of IPv6 addresses, and ensuring that all the Avahi utilities (like avahi-browse
) correctly output scope IDs on addresses where appropriate.
I actually plan to improve / fix handling of interface scope generally within Avahi and nss-mdns. Specifically its super important for nss-mdns when using link local addresses where it's otherwise useless.
We always provide the interface ID to the same callback (as AvahiIfIndex interface) which, at least on linux, is always the same as sin6_scope_id. Ideally (but I admit, in practice people don't) these flags would be taken and passed into network API calls.
I can see from the code in the commit you linked that you are then doing exactly this. So the information is always there but it's a matter of consuming it better.
So the question is, what would you propose we actually change to make this more intuitive. Are you thinking for example, that ideally a function like avahi_address_snprint would exist that always renders the scope?
I think as a secondary goal we should update not only all of our utilities but also the examples to show explicitly how to make use of this information.
So the question is, what would you propose we actually change to make this more intuitive. Are you thinking for example, that ideally a function like avahi_address_snprint would exist that always renders the scope?
A function like that would make sense. It should always take the interface/scope ID as input, and should include it in the output if the address is IPv6 and locally scoped (but not otherwise).
The old avahi_address_snprint()
should be deprecated in favour of the new one, to avoid people accidentally continuing to use it and omitting scope IDs. Similarly for avahi_address_parse()
, I guess: a new version of it should deprecate the old one, and should output a parsed scope ID.
Do non-Linux platforms use a different way of identifying scope IDs? IIRC they all do something similar, but this should be checked.
I think as a secondary goal we should update not only all of our utilities but also the examples to show explicitly how to make use of this information.
Agreed.
Hello,
I believe my use case is failing as a result of this problem.
I have a remote computer and my host connected on the same link and able to ping each other with ipv6 link local addresses. Avahi is enabled and working to discover each other's ipv6 address.
However, if I try to use a name resolution in a command to ssh, the name resolution doesn't include the scope id. Then, ssh fails because ssh requires the scope id.
host:
$ avahi-browse -ar
= enx70886b89975e IPv6 nvidia-desktop [...] Workstation local
hostname = [nvidia-desktop.local]
address = [fe80::204:4bff:fec5:a1cf]
$ ip a show enx70886b89975e
11: enx70886b89975e: ...
inet6 fe80::9f3e:e46c:d000:aa85/64 scope link noprefixroute
valid_lft forever preferred_lft forever
$ ping -6 fe80::9f3e:e46c:d000:aa85%enx70886b89975e
PING fe80::9f3e:e46c:d000:aa85%enx70886b89975e(fe80::9f3e:e46c:d000:aa85%enx70886b89975e) 56 data bytes
64 bytes from fe80::9f3e:e46c:d000:aa85%enx70886b89975e: icmp_seq=1 ttl=64 time=0.053 ms
$ avahi-resolve -n nvidia-desktop.local
nvidia-desktop.local fe80::204:4bff:fec5:a1cf
$ ssh [email protected] -p 2222 -v
OpenSSH_7.6p1 Ubuntu-4ubuntu0.3, OpenSSL 1.0.2n 7 Dec 2017
debug1: Reading configuration data /home/ryan/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: Connecting to nvidia-desktop.local [fe80::204:4bff:fec5:a1cf] port 2222.
debug1: connect to address fe80::204:4bff:fec5:a1cf port 2222: Invalid argument
ssh: connect to host nvidia-desktop.local port 2222: Invalid argument
$ ssh nvidia@fe80::204:4bff:fec5:a1cf%enx70886b89975e -p 2222
Welcome to Ubuntu ...
As seen in the above capture, the name resolution fails to include the interface. Is there a workaround to this issue? I cannot statically configure any IP's.
The one thing I have figured out is to also supply a -b
bind address to the ssh command, where I supply the hosts's interface ipv6 link local and interface name, which are both known by the host.
$ ssh [email protected] -p 2222 -b fe80::9f3e:e46c:d000:aa85%enx70886b89975e -v
Thus, avahi is still performing name resolution to find the remote ipv6 address, while the binding tells the kernel which interface to use.
As far as I understand things (and I'm a newcomer to avahi), avahi-publish-address fails, and could not possibly work as coded, for complete link-local addresses such as fe80::1%eth0
. That's because it calls inet_pton()
which doesn't understand the zone identifier. You'd need to split the address at "%" and then call if_nametoindex()
to get the correct interface index.
This matters as we see IPv6-only networks emerging. A bit of background is at https://www.ietf.org/archive/id/draft-carpenter-6man-zone-ui-03.html . A bit of slightly related hackery is at https://github.com/becarpenter/misc/tree/main/zelect#linux-a-tale-of-woe .
@pwithnall, you said "Do non-Linux platforms use a different way of identifying scope IDs? IIRC they all do something similar, but this should be checked."
On Windows, you see things like fe80::1%7
where the relevant interface has interface index 7. So that '7' is a name for interface number 7. (Windows makes things tricky for a programmer, because if_indextoname()
returns a different internal name that's of no use to anybody, and there are other forms of interface name too.)
For the theory, please read RFC4007.
I've done some more hacking at this, reported at https://github.com/becarpenter/misc/tree/main/zelect#linux-a-tale-of-woe