為什麼 localhost 解析為 ::1 而不是 127.0.0.1
有了
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
編輯:
localhost
我的/etc/hosts
.
找到這並不容易(但很有趣:))。
簡短的回答
使用 __lookup_name() 的 gethostbyname2() 具有一些用於 loopback (’lo’) 介面的硬編碼值。當您為“getent hosts”命令指定“localhost”時,它最終會在嘗試 IPv4 之前使用 IPv6 的預設值,因此您最終會得到 ::1。您可以更改 getent 的程式碼以獲得 127.0.0.1 ,如下所示:
- 從github下載getent原始碼
- 在 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 工具使用由musl 庫定義和實現的函式。當我們執行命令時
$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 值。
如果您希望更改功能以返回 localhost 的 IPv4 地址,最好的辦法是送出/請求修復,以便 getent 先搜尋 IPv4。
希望這可以幫助!