这是一个典型问题关于 Hairpin NAT(Loopback NAT)。
这个问题的通用形式是:
我们有一个包含客户端、服务器和 NAT 路由器的网络。路由器上有到服务器的端口转发功能,因此服务器的某些服务可供外部使用。我们的 DNS 指向外部 IP。本地网络客户端无法连接,但外部网络可以连接。
- 为什么会失败?
- 如何创建统一的命名方案(在本地和外部均可使用的 DNS 名称)?
这个问题的答案合并了其他多个问题。它们最初提到了 FreeBSD、D-Link、Microtik 和其他设备。但它们都在尝试解决同一个问题。
答案1
您正在寻找的就是“发夹式 NAT”。来自内部接口的对分配给外部接口的 IP 地址的请求应该被 NAT,就像它们来自外部接口一样。
我对 FreeBSD 一点都不熟悉,但是我读过 OpenBSD 的“pf”手册(http://www.openbsd.org/faq/pf/rdr.html) 提出的分割水平 DNS、使用 DMZ 网络或 TCP 代理的解决方案使我相信“pf”不支持发夹 NAT。
我会考虑采用分割水平 DNS 的路线,而不是在 URL 内部使用 IP 地址,而是使用名称。
答案2
由于这已被提升为关于发夹式 NAT 的典型问题,我认为它应该有一个比目前接受的答案更普遍有效的答案,该答案(虽然很优秀)特别与 FreeBSD 有关。
这个问题适用于 RFC1918 寻址 IPv4 网络上的服务器提供的服务,通过在网关处引入目标 NAT (DNAT),这些服务可供外部用户使用。然后,内部用户尝试通过外部地址访问这些服务。他们的数据包从客户端发出到网关设备,网关设备重写目标地址并立即将其重新注入内部网络。正是数据包在网关处进行的这种急剧转变导致了该名称的产生发夹型NAT,与发夹弯。
当网关设备重写目标地址而不是源地址时,就会出现问题。然后,服务器会收到一个数据包,该数据包具有内部目标地址(它自己的)和内部源地址(客户端的);它知道它可以直接回复这样的地址,所以它这样做了。由于该回复是直接的,它不会通过网关,因此网关永远没有机会通过重写返回数据包的源地址来平衡入站目标 NAT 对初始数据包的影响。
因此,客户端会将数据包发送到外部的IP 地址,但收到来自内部的IP 地址。它不知道这两个数据包是同一次对话的一部分,因此不会发生任何对话。
解决方案是对于需要此类目标 NAT 且从内部网络到达网关的数据包,也对入站数据包执行源 NAT (SNAT),通常是通过将源地址重写为网关的地址。然后服务器认为客户端是网关本身,并直接回复它。这反过来又使网关有机会通过在返回数据包上重写源地址和目标地址来平衡 DNAT 和 SNAT 对入站数据包的影响。
客户端认为它正在与外部服务器对话。服务器认为它正在与网关设备对话。各方都很开心。此时,一张图可能会有所帮助:
一些消费者网关设备足够聪明,能够识别出需要第二个 NAT 步骤的数据包,并且这些数据包在发夹 NAT 场景中可能开箱即用。其他则不然,因此不会,并且不太可能使它们工作。关于哪些是消费者级设备的讨论与 Server Fault 无关。
通常可以命令适当的网络设备工作,但是 - 因为它们不负责猜测管理员的工作 - 必须命令它们这样做。Linux 用来iptables
执行 DNAT 的方式如下:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.3.11
这将为 HTTP 端口启用简单 DNAT,以连接到 上的内部服务器192.168.3.11
。但要启用发夹式 NAT,还需要一条规则,例如:
iptables -t nat -A POSTROUTING -d 192.168.3.11 -p tcp --dport 80 -j MASQUERADE
请注意,此类规则需要位于相关链中的正确位置才能正常工作,并且根据链中的设置filter
,可能需要其他规则来允许 NAT 流量流动。所有此类讨论都不在本回答的讨论范围内。
但正如其他人所说,正确启用发夹式 NAT 并不是解决问题的最佳方法。最好的方法是水平分割 DNS其中,您的组织根据请求客户端的位置为原始查找提供不同的答案,可以通过为内部用户和外部用户提供不同的物理服务器,或者通过配置 DNS 服务器以根据请求客户端的地址做出不同的响应。
答案3
这里的问题是,你的路由器没有对内部客户端的地址进行 NAT。因此,TCP 握手失败。
假设以下 IP
- 客户端:192.168.1.3
- 服务器:192.168.1.2
- 路由器内部:192.168.1
- 路由器外部:123.123.123.1
事情的经过如下:
- 客户端(192.168.1.3)向您的外部 IP、端口 80(123.123.123.1:80)发送 TCP-SYN
- 路由器看到端口转发规则,将数据包转发到服务器(192.168.1.2:80),而不改变源 IP(192.168.1.3)
- 客户端等待来自外部 IP 的 SYN-ACK
- 服务器直接将答案发回给客户端,因为它们位于同一子网中。它不会将数据包发送到路由器,因为路由器会逆转 NAT。
- 客户端收到来自 192.168.1.2 而非 123.123.123.1 的 SYN-ACK。并将其丢弃。
- 客户端仍在等待来自 123.123.123.1 的 SYN-ACK 并超时。
答案4
最近回答过类似的问题:Cisco 静态 NAT 在 LAN 端不起作用刚刚意识到这是一个典型问题。所以请允许我在这里总结一下解决方案。
首先:忘掉 NAT(如果可以的话)——问题根本不在于配置 NAT。而是关于从 Internet 和 LAN 访问位于 NAT 后面的服务器。采用两个 DNS 区域是一种可行的替代方案,但并非总是解决方案。但解决方案确实存在,而且非常简单(尽管可能并不完美):
(1)在服务器上:在服务器的网络接口上将公共 IP 地址添加为辅助 IP 地址,掩码为 255.255.255.255(服务器上的 Web 服务或任何您想要的服务也应该监听这个 IP 地址);所有现代操作系统都允许您执行此操作(或者可以使用分配了公共 IP 地址的环回接口,而不是将辅助 IP 添加到主接口)。
(2)在局域网主机上:为公网 IP 地址添加主机路由,例如,对于 Windows 主机使用以下命令:路线-p添加203.0.113.130掩码255.255.255.255 192.168.1.11(您也可以使用 DHCP“静态路由”选项来分配路由)。或者,如果客户端和面向 Internet 的路由器之间有 L3 交换机/路由器,则在此(这些)中间交换机/路由器上(而不是在客户端上)配置该主机路由。
对于那些关注 TCP 三次握手的人来说:它将在建议的配置中正常工作。
请提供反馈(至少投票)。