在之前关于 IPv6 链路本地地址主题的讨论中,我看到了一条评论,其中指出:
有些人会争辩说,对于任何类型的地址,都不应该使用地址而不是主机名。使用 mDNS 映射到链接本地地址可以正常工作。
讨论的上下文是在使用链接本地地址时需要指定接口。
我发现上面的评论令人惊讶,因为我没想到 mDNS 会提供链接信息,因此我没想到它会“正常工作”。我构建了一个简单的测试(如下),以查看提供的信息是否getaddrinfo包含链接,我发现以下内容:
将地址和链接(例如:)传递
fe80::a:a:a:a%wlp3s0给 getaddrinfo 会导致sockaddr_in6设置sin6_scope_id为3(我的 wlan 卡的索引)。这表明 getaddrinfo 可以提供链接信息。传递一个只能由 mDNS 解析的主机名(它解析到相同的链接本地地址)导致 sockaddr_in6
sin6_scope_id设置为0,即没有指定链接此外,我已经确认,当 mDNS 解析链接本地地址时,包括 SSH 在内的依赖
getaddrinfo指定链接的程序将失败。但如果明确指定 IP 地址和链接,它们将成功。
上面的评论是错误的,还是我在测试的方式上犯了错误?mDNS 可以解析为链接本地地址并指定链接吗?
作为参考,我正在 Debian Buster Linux 版本 4.19.0-5-amd647 上进行测试
我的nsswitch.conf包含
hosts: files mdns4_minimal [NOTFOUND=return] dns myhostname
测试代码.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;
}