操作系统如何解决连接到 0.0.0.0 的请求?

Pav*_*l_K 2 networking linux ip

据我了解,0.0.0.0 表示该主机的所有网络接口(包括 127.0.0.1)。

假设我在某个主机(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)在不同的接口上侦听什么服务器(服务器A或服务器B)以及为什么当我在this主机终端上做时会连接telnet 0.0.0.0 777

use*_*686 7

它仅表示作为源地址(即当将套接字绑定到本地接口时)。作为目标地址,它没有这个含义——从技术上讲,它是一个非法地址。

然而,似乎最初 BSD 将其视为环回连接,而 Linux 则继续进行。

对于 IPv4,net/ipv4/route.c在路由查找时处理全零目标:

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;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

这意味着“如果目的地为空,则用 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;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

同时在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) */
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 对于“操作系统如何[...]”的问题,该操作系统的源代码尽可能具体。 (4认同)