![为什么 localhost 解析为 ::1 而不是 127.0.0.1](https://linux22.com/image/157475/%E4%B8%BA%E4%BB%80%E4%B9%88%20localhost%20%E8%A7%A3%E6%9E%90%E4%B8%BA%20%3A%3A1%20%E8%80%8C%E4%B8%8D%E6%98%AF%20127.0.0.1.png)
有了getent hosts localhost
,我才得到::1
,虽然我期待127.0.0.1
。我已经禁用了 IPv6,所以获得::1
更令人惊讶。更令人困惑的是,当我 时ping localhost
,ping 被发送到127.0.0.1
哪个作品。有人可以解释一下吗?
~: getent hosts localhost
::1 localhost
~: grep 'hosts:' /etc/nsswitch.conf
hosts: files mymachines myhostname resolve [!UNAVAIL=return] dns
~: cat /etc/sysctl.d/disable_ipv6.conf
net.ipv6.conf.all.disable_ipv6=1
~: ping ::1
connect: Network is unreachable
~: ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.022 ms
~: ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.015 ms
编辑:localhost
我的/etc/hosts
.
答案1
找到这个并不容易(但很有趣:))。
简短回答
gethostbyname2() 使用 __lookup_name(),具有一些环回('lo')接口的硬编码值。当您为“getent ports”命令指定“localhost”时,它最终会在尝试 IPv4 之前使用 IPv6 的默认值,因此最终会得到 ::1。您可以更改 getent 的代码以获得 127.0.0.1,如下所示:
- 下载getent源码来自 github
- 在getent.c 下的hosts_keys() 中注释掉以下行(#329): //else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
- 从源代码编译并运行:
结果:
$make clean && make && ./getent hosts localhost
rm -f *.o
rm -f getent
gcc -g -Wall -std=gnu99 -w -c getent.c -o getent.o
gcc getent.o -Wall -lm -o getent
127.0.0.1 localhost
更多细节
getent 工具使用由穆斯林图书馆。当我们运行命令时
$getent hosts localhost
该工具调用getent.c 下的hosts_keys() 函数来解析提供的密钥。该函数尝试通过 4 种方法进行解析:
- IPv6 的 gethostbyaddr(在此实例中失败)。
- IPv4 的 gethostbyaddr(在此实例中失败)。
- IPv6 的 gethostbyname2(由于硬编码值,对于 localhost 总是成功)。
- IPv4 的 gethostbyname2(由于在#3 上成功,所以不尝试)。
所有musl功能都在/src/network/下实现,看这里。 gethostbyname2()(在 gethostbyname2.c 中实现)调用 gethostbyname2_r()(在 gethostbyname2_r.c 中实现),后者调用 __lookup_name()(在lookup_name.c 中)。 __lookup_name() 再次作为如何解析主机名的几个选项,第一个是 name_from_null (在同一文件中):
static int name_from_null(struct address buf[static 2], const char *name, int family, int flags)
{
int cnt = 0;
if (name) return 0;
if (flags & AI_PASSIVE) {
if (family != AF_INET6)
buf[cnt++] = (struct address){ .family = AF_INET };
if (family != AF_INET)
buf[cnt++] = (struct address){ .family = AF_INET6 };
} else {
if (family != AF_INET6)
buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } };
if (family != AF_INET)
buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
}
return cnt;
}
最后,我们可以看到,当 family == AF_INET6 时,我们将得到硬编码值::1。由于 getent 在 IPv4 之前尝试 IPv6,因此这将是返回值。正如我上面所示,在 getent 中强制解析为 IPv4 将导致上面函数中的硬编码 127.0.0.1 值。
如果您希望更改功能以返回本地主机的 IPv4 地址,最好的办法是首先提交/请求修复 getent 以搜索 IPv4。
希望这可以帮助!