![操作系统如何解析连接 0.0.0.0 的请求?](https://linux22.com/image/1556608/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%A6%82%E4%BD%95%E8%A7%A3%E6%9E%90%E8%BF%9E%E6%8E%A5%200.0.0.0%20%E7%9A%84%E8%AF%B7%E6%B1%82%EF%BC%9F.png)
据我了解,0.0.0.0 表示该主机的所有网络接口(包括 127.0.0.1)。
假设我在某个主机(OS Linux)上有三个接口 192.0.2.40、203.0.113.150 和 127.0.0.1。
在 192.0.2.40:777 上,我有 ServerA。在 203.0.113.150:777 上,我有 ServerB。操作系统如何解析连接到 0.0.0.0 的请求?我的意思是,当同一端口 (777) 正在监听不同的接口时,我将在主机终端执行什么操作,以及为什么会连接哪个服务器(ServerA 或 serverB this
)telnet 0.0.0.0 777
答案1
正式来说,它只是意味着作为源地址(即当捆绑本地接口的套接字)。作为目标地址,它没有这个含义——从技术上讲它是一个非法地址。
然而,BSD 最初似乎是这样处理的作为环回连接Linux 继续延续这一传统:
UNIX 系统管理员手册 – 4.3BSD 中的内核更改 –第 7.1 节(SMM:13-21)(
/usr/doc/smm/13.kchanges
在 4.3BSD 源代码树中):在PCB中
目标地址连接可以给出 INADDR_ANY (0) 作为“此主机”的简写符号。这简化了连接到本地服务器(例如将主机名转换为地址的名称域服务器)的过程。
net/ipv4/route.c
在 Linux 中,全零的 IPv4 目标在路由查找时处理:
struct rtable *ip_route_output_key_hash_rcu(...) {
...
if (!fl4->daddr) {
fl4->daddr = fl4->saddr;
if (!fl4->daddr)
fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
dev_out = net->loopback_dev;
fl4->flowi4_oif = LOOPBACK_IFINDEX;
res->type = RTN_LOCAL;
flags |= RTCF_LOCAL;
goto make_route;
}
...
}
意思是“如果目的地为空,则填写 127.0.0.1 并通过接口路由lo
”。操作系统会假装您尝试连接到本地主机。
IPv6 中的相同内容在协议级别处理(分别由 TCP 和 UDP 处理)。例如,net/ipv6/tcp_ipv6.c
包含:
static int tcp_v6_connect(...) {
...
/*
* connect() to INADDR_ANY means loopback (BSD'ism).
*/
if (ipv6_addr_any(&usin->sin6_addr)) {
if (ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr))
ipv6_addr_set_v4mapped(htonl(INADDR_LOOPBACK),
&usin->sin6_addr);
else
usin->sin6_addr = in6addr_loopback;
}
...
}
同时在net/ipv6/udp.c
:
int udpv6_sendmsg(...) {
...
if (!ipv6_addr_any(daddr))
fl6.daddr = *daddr;
else
fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
...
}
答案2
假设我在某个主机(OS Linux)上有三个接口 192.0.2.40、203.0.113.150 和 127.0.0.1。
我创建了两个适配器,如以下命令,eth1
为其中一个 IP 创建虚拟适配器:
sudo modprobe dummy
sudo ip link add eth1 type dummy
sudo ip addr add 203.0.113.150/24 dev eth1
sudo ip link set dev eth1 up
我的所有请求都0.0.0.0
发给那些绑定的应用程序127.0.0.1
。如果我停止它,那么我会看到Connection refused
错误(即使 203.0.113.150 上的应用程序正在运行)。
我相信@user1686 的答案是正确的,并且它只路由到环回接口127.0.0.1
。