jan*_*jan 10 networking hosts ipv6
有了getent hosts localhost
,我才得到::1
,虽然我期待127.0.0.1
。我禁用了 IPv6,所以得到::1
更令人惊讶。更令人困惑的是,当 I 时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
Run Code Online (Sandbox Code Playgroud)
编辑:localhost
我的/etc/hosts
.
小智 4
找到这个并不容易(但很有趣:))。
简短回答
gethostbyname2() 使用 __lookup_name(),具有一些环回('lo')接口的硬编码值。当您为“getent ports”命令指定“localhost”时,它最终会在尝试 IPv4 之前使用 IPv6 的默认值,因此最终会得到 ::1。您可以更改 getent 的代码以获得 127.0.0.1,如下所示:
结果:
$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
Run Code Online (Sandbox Code Playgroud)
更多细节
getent 工具使用musl 库定义和实现的函数。当我们运行命令时
$getent hosts localhost
Run Code Online (Sandbox Code Playgroud)
该工具调用getent.c 下的hosts_keys() 函数来解析提供的密钥。该函数尝试通过 4 种方法进行解析:
所有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;
}
Run Code Online (Sandbox Code Playgroud)
最后,我们可以看到,当 family == AF_INET6 时,我们将得到硬编码值::1。由于 getent 在 IPv4 之前尝试 IPv6,因此这将是返回值。正如我上面所示,在 getent 中强制解析为 IPv4 将导致上面函数中的硬编码 127.0.0.1 值。
如果您希望更改功能以返回 localhost 的 IPv4 地址,最好的办法是提交/请求修复 getent 以首先搜索 IPv4。
希望这可以帮助!