In an earlier discussion on the topic of IPv6 Link-local addresses I saw a comment which stated:
Some would argue that using addresses instead of host names should be discouraged, for any type of addresses. Using mDNS to map to link-local addresses works fine.
The context of the discussion was that you need to specify an interface when using a link-local address.
I found the above comment surprising because I didn't expect mDNS to supply link information, thus I didn't expect it to "work fine". I constructed a simple test (below) to see if the information supplied by getaddrinfo
included a link and I found the following:
Passing an address and link (eg:
fe80::a:a:a:a%wlp3s0
) to getaddrinfo resulted in a sockaddr_in6 withsin6_scope_id
set to3
(the index of my wlan card). This shows that getaddrinfo can supply link information.Passing a hostname only resolvable by mDNS (which resolves to the same link-local address) resulted in a sockaddr_in6 with
sin6_scope_id
set to0
, i.e. no link was specifiedFurther I've confirmed that programs including SSH which rely on
getaddrinfo
to specify a link will fail when mDNS resolves a link-local address. But they will succeed if the IP address and link are specified explicitly.
Was the above comment wrong, or have I made a mistake in the way I test this? Can mDNS resolve to link-local address and specify the link?
For reference I'm testing on Debian Buster Linux version 4.19.0-5-amd647
My nsswitch.conf
contains
hosts: files mdns4_minimal [NOTFOUND=return] dns myhostname
Testcode.c:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
int main(int arg_count, char ** args)
{
struct addrinfo hints, *servinfo, *p;
for (int i=1; i<arg_count; i++)
{
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET6; // to force IPv6
hints.ai_socktype = SOCK_STREAM;
printf("Checking %s\n", args[i]);
if (getaddrinfo(args[i], "https", &hints, &servinfo)) {
perror("getaddrinfo");
continue;
}
for(p = servinfo; p != NULL; p = p->ai_next) {
struct sockaddr_in6 * address = ((struct sockaddr_in6 *)p->ai_addr);
printf("family %d scope %d\n", address->sin6_family, address->sin6_scope_id);
}
freeaddrinfo(servinfo);
}
return 0;
}