我正在学习私有/公共 IP、端口转发和 NAT,但仍然找不到一个简单问题的答案:
假设同一网络上的两个用户正在与其网络外的单个服务器通信(例如,我和我的妻子向 yahoo.com 发送 http 请求)。服务器将两个用户视为单个公共 IP,并且通常(如本例)在同一个端口上通信。路由器如何根据两个不同的连接路由数据包?数据包中除了 IP/端口之外还有其他路由信息吗?是否有某个地方维护着某个“会话表”?由谁维护,它到底包含什么?
答案1
在计算机内部、进程之间
首先让我们看看单身的计算机区分并发连接。
大多数传输协议,如 TCP、UDP、SCTP使用二港口、来源地和目的地– 即连接两端各一个。也就是说,数据包不要只需“穿过”港口即可;相反,他们从端口 X到港口 Y。
这目的地端口通常是众所周知的(HTTP 为 80,DNS 为 53……),但来源端口通常由操作系统本身随机选择,这也确保了 src/dst 组合是唯一的。
因此,当你的浏览器多次连接到“Yahoo 的 80 端口”时,它们实际上都有不同的源端口,并且操作系统会保留一个套接字表,例如:
PROCESS PROTO LOCAL REMOTE STATE
9894/firefox tcp 192.168.6.175:39163 google.server:80 established
9894/firefox tcp 192.168.6.175:52909 yahoo.server:80 established
17463/chrome tcp 192.168.6.175:64981 yahoo.server:80 established
9894/firefox udp 192.168.6.175:4984 8.8.8.8:53 --
因此,当操作系统从yahoo.server:80
本地端口 52909 接收到 TCP 数据包时,它可以将其映射到 Firefox 建立的特定连接。
需要注意的是,这与 NAT 无关然而,即使您直接连接,也会发生同样的事情。(但是,NAT 会利用它。)
(您可以使用netstat -n
或 Windows 上的各种图形工具查看此表。“本地/远程”通常标记为“源/目标”,尽管这并不完全准确。)
在 NAT 网络内,计算机之间
关于 NAT 的问题的答案非常相似,只是一切都是在更大规模上进行的。
执行 NAT 的路由器会保留一个包含内部和外部地址及端口的“状态”表。例如,如果您的两个 HTTP 请求使用了单独的 TCP 连接,则它们可能会被跟踪为:
PROTO ORIG-SRC ORIG-DST REPLY-SRC REPLY-DST
6/tcp 192.168.6.42:52909 yahoo.server:80 yahoo.server:80 your.public.ip.addr:52909
6/tcp 192.168.6.175:39163 yahoo.server:80 yahoo.server:80 your.public.ip.addr:39163
6/tcp 192.168.6.175:52909 yahoo.server:80 yahoo.server:80 your.public.ip.addr:28330
17/udp 192.168.6.175:4984 8.8.8.8:53 8.8.8.8:53 your.public.ip.addr:4984
当路由器收到来自 REPLY-SRC(雅虎)发往 REPLY-DST(你的公网 IP 地址)的数据包时,它知道真实的为了撤消 NAT,必须从 ORIG-SRC 列中获取目的地。
(如果没有匹配状态,则处理手动配置的端口转发规则。如果仍然不匹配,则该数据包实际上是发往路由器本身的。)
注意状态表包含地址和端口,允许通过端口组合区分到同一服务器的多个连接。在我的示例中,两台计算机意外使用了相同的端口组合,因此第二个连接的端口也进行了转换。
(事实上,一些 NAT 看起来仅有的在端口处并完全忽略源地址;这减少了可能的连接数,但使对等程序更容易执行“NAT 打洞”。)
即使对于无连接协议(例如 UDP 或 ICMP),也会保留这种状态,因此即使没有明确的“关闭连接”数据包,这些条目也会在一段时间不活动后过期。(状态表实际上是防火墙的一部分,因此即使没有完成 NAT,路由器仍可能使用它来区分“活动”连接和杂散数据包。)
(如果您的路由器是基于 Linux 的,conntrack -L
或cat /proc/net/nf_conntrack
将显示此表。对于 OpenBSD 或 pfSense,请尝试pfctl -s state
。)