从本地网络环回转发的公共IP地址-发夹NAT


45

这是关于发夹式NAT(环回NAT)的规范问题

这个问题的一般形式是:

我们有一个包含客户端,服务器和NAT路由器的网络。路由器上有到服务器的端口转发功能,因此某些服务可以从外部获得。我们有指向外部IP的DNS。本地网络客户端无法连接,但是需要外部工作。

  • 为什么会失败?
  • 如何创建统一的命名方案(在本地和外部均可使用的DNS名称)?

该问题的答案已与其他多个问题合并。他们最初引用了FreeBSD,D-Link,Microtik和其他设备。他们都在尝试解决相同的问题。


1
如果您的目的是测试来自Internet的访问,则充其量最好不要弄乱路由器的路由和/或DNS设置,这是从内部验证路由器内部是否正常工作。我建议您在外部的某个地方使用代理服务器。

Answers:


16

您正在寻找的被称为“发夹NAT”。来自内部接口的对分配给外部接口的IP地址的请求应该经过NAT处理,就像它们是从外部接口传入的一样。

我完全不熟悉FreeBSD,但是请阅读OpenBSD的“ pf”手册(http://www.openbsd.org/faq/pf/rdr.html)使用水平分割DNS的建议解决方案。 DMZ网络或TCP代理使我相信“​​ pf”不支持发夹式NAT。

我会看一下水平分割DNS的路由,而不是内部使用URL中的IP地址,而是使用名称。


在尝试解决相同的问题时,我遇到了这个线程,虽然确实FreeBSD不支持发夹,但仍有一些方法可以对内部->外部->内部流量进行重定向和NAT。
深红色的白鹭

例如: no nat on $int_if proto tcp from $int_if to $int_netnat on $int_if proto tcp from $int_net to $hairpin_int port $hairpin_ports -> $int_ifrdr on $int_if proto tcp from $int_net to $ext_if port $hairpin_ports -> $hairpin_int
深红色白鹭

48

由于这已经成为发夹式NAT典型问题,我认为它应该比目前接受的答案更普遍有效,后者(尽管非常好)特别与FreeBSD有关。

此问题适用于由RFC1918寻址的IPv4网络上的服务器提供的服务,通过在网关上引入目标NAT(DNAT),外部用户可以使用这些服务。然后,内部用户尝试通过外部地址访问那些服务。他们的数据包从客户端发送到网关设备,网关设备重写目标地址,然后立即将其重新注入内部网络。类似于发夹式转折,正是分组在网关处做出的这种急转弯产生了发夹式NAT名称。

当网关设备重写目标地址而不是源地址时,就会出现问题。然后,服务器接收到一个数据包,该数据包包含一个内部目标地址(自己的地址)和一个内部源地址(客户的地址);它知道它可以直接回复这样的地址,所以就这样做了。由于该答复是直接的,因此它不会通过网关,因此网关永远不会有机会通过重写返回数据包的源地址来平衡入站目标NAT对初始数据包的影响。

客户端因此将数据包发送到外部 IP地址,但从内部 IP地址得到答复。不知道这两个数据包是同一对话的一部分,因此没有对话发生。

解决方案是,对于需要此类目标NAT并从内部网络到达网关的数据包,通常还通过将源地址重写为网关的地址,从而对入站数据包也执行源NAT(SNAT)。然后,服务器认为客户端就是网关本身,并直接对其进行回复。这样,通过在返回数据包上重写源地址和目标地址,网关便有机会平衡DNAT和SNAT对入站数据包的影响。

客户端认为它正在与外部服务器通信。服务器认为它正在与网关设备通信。各方都很高兴。此时,图表可能会有所帮助:

在此处输入图片说明

一些消费者网关设备足够亮,足以识别那些需要第二个NAT步骤的数据包,并且这些数据包可能在发夹式NAT场景中开箱即用。其他的则不是,所以也不会,因此不太可能使其正常工作。讨论哪些消费者级设备对服务器故障不适用。

通常可以告诉适当的网络设备正常工作,但是-因为它们不负责管理员,所以必须告知他们这样做。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链中的设置,可能需要其他规则以允许NATted通信流。所有此类讨论均不在此答案的范围内。

但是,正如其他人所说,正确启用发夹NAT并不是解决问题的最佳方法。最佳的是水平分割DNS,您的组织可以根据请求客户端的位置为原始查询提供不同的答案,方法是为内部用户或外部用户使用不同的物理服务器,或者将DNS服务器配置为根据请求客户的地址。


我想知道网关和服务器之间交换的数据包上的地址。如果服务器将路由器的公共IP地址视为客户端IP,会不会更加一致?从技术上讲,两者都可以工作,但是要与其他服务器看待客户端的方式保持一致,就必须使用公共IP。
kasperd 2014年

1
我保证您所指的是最后一种情况,“适当的发夹式NAT”。关键是重写入站数据包中的源地址,使其返回路由器,然后路由器可以反转DNAT和SNAT,从而避免出现问题。路由器使用它的多个地址中的哪个地址更符合您的口味,如果您使用iptables,则当然可以选择进行配置。
MadHatter 2014年

1
许多管理员,包括我自己在内,都认为水平分割DNS是一种比疾病更糟糕的治疗方法。如果再增加一个SNAT,则完全可以称为疾病。分割视图DNS会使人感到困惑,同时又使路由器的生活更轻松。通过单独的ServerFault问题/答案可以更好地处理此主题。
kubanczyk

我的答案非常关于发夹式NAT。我可以看到打开一个标准的“水平分割DNS”问题的利弊:利弊包括一个专门讨论SHDNS的使用和问题的问题,但是利弊是该问题已经有许多其他问题与它合并到其中,因此您的问题也可能发生。如果是我,我会在meta上提出问题,并寻求共识。如果确实写了这样的问题,我期待着您阅读有关该问题的答案!
MadHatter

@MadHatter我应该在哪里编写iptables命令?在客户端还是网关还是服务器上?
洛基巴尔波亚'18

9

这里的问题是,您的路由器没有对内部客户端的地址进行NAT。因此,TCP握手失败。

假设以下IP

  • 客户端:192.168.1.3
  • 伺服器:192.168.1.2
  • 路由器内部:192.168.1
  • 外部路由器:123.123.123.1

这是正在发生的事情:

  1. 客户端(192.168.1.3)将TCP-SYN发送到您的外部IP端口80(123.123.123.1:80)
  2. 路由器会看到端口转发规则,并将数据包转发到服务器(192.168.1.2:80),而无需更改源IP(192.168.1.3)
  3. 客户端等待来自外部IP的SYN-ACK
  4. 服务器将其答案直接发送回客户端,因为它在同一子网中。它不会将数据包发送到路由器,这将使NAT反向。
  5. 客户端从192.168.1.2而不是123.123.123.1接收SYN-ACK。并丢弃它。
  6. 客户端仍在等待来自123.123.123.1的SYN-ACK并超时。

4

为什么不使用水平分割DNS而不是在各处硬编码IP地址?您将使ext.yourdomain在外部指向217.xxx,然后在内部指向192.xxx。


1
如果您有时间,可以介绍一下什么是水平分割DNS,它如何工作以及主要缺点。现在这是一个规范的问题,很高兴有一个更完整的答案。
克里斯S

2

如果它是原始的D-Link路由器(即不是Virgin Media的Rev. D /固件版本1.00VG),则应该可以调整设置来解决此问题。(但是,出于许多其他原因,我同意上一张海报对DD-WRT的建议!)

  1. 登录路由器的Web界面
  2. 点击顶部的高级标签
  3. 单击左侧的防火墙设置选项卡
  4. 单击“ TCP端点过滤”下的“ 独立端点”单选按钮,如下面的屏幕截图所示(或在D-Link网站上查看路由器仿真器
  5. 保存更改; 你完成了

D-Link路由器Web UI屏幕截图

该屏幕截图来自Rev.C模型;您的可能会略有不同。


2

最近回答了一个类似的问题:Cisco静态NAT在LAN端不起作用,只是意识到这是一个规范问题。因此,请允许我在这里总结解决方案。

首先:忘记NAT(如果可以的话)-问题根本不在于配置NAT。这是关于从Internet和LAN访问位于NAT后面的服务器。使用两个DNS区域是一种可行的选择,但并非总是解决方案。但是解决方案确实存在并且非常简单(尽管可能并不完美):

(1)在服务器上:使用255.255.255.255掩码在服务器的网络接口上将公用IP地址添加为辅助IP地址(Web服务或服务器上您想要的任何内容也应监听该IP地址);所有现代操作系统都允许您执行此操作(或者可以使用分配了公共IP地址的环回接口,而不是在主接口上添加辅助IP)。

(2)在LAN主机上:为公共IP地址添加主机路由,例如,对于Windows主机,请使用以下命令:route -p添加203.0.113.130 mask 255.255.255.255 192.168.1.11(也可以使用DHCP“静态路由”选项来分配路由)。或者,如果在客户端和面向Internet的路由器之间存在一个或多个L3交换机/路由器,则在此(这些)中间交换机/路由器上配置该主机路由,而不是在客户身上。

对于那些涉及TCP三向握手的用户:在建议的配置中它可以正常工作。

请提供反馈(至少是投票)。


要求#2使得此方法在BYOD网络上无法正常运行...
Michael

1

病态回答我的问题仅仅是为了拓宽有类似问题的人的视野。

我与我的ISP联系并要求他们尝试解决我的问题。他们提供给我的是服务器专用的另一个公共IP地址,现在我在FreeBSD的WAN端有本地流量,并且我们制作了特定的管道,以便在本地流量到达Server的公共IP之后实现更快的吞吐量。


2
此解决方案实现了外围网络或DMZ,是发夹式NAT和水平分割DNS的良好替代方案。
克里斯S

1

从技术角度来看,解决此问题的最佳方法是在网络上启用IPv6。启用IPv6后,您需要为您的域创建AAAA记录。保持现有的A记录指向路由器的外部IPv4 。创建一个指向服务器的IPv6地址的AAA​​A记录。

IPv6具有足够的地址来避免NAT,因此您不需要发夹式NAT即可实现IPv6。一旦启用了IPv6并创建了AAAA记录,任何支持RFC 8305的客户端都将在IPv4之前尝试IPv6。这意味着您也不需要IPv4的发夹式NAT,因为客户端不会使用它。

直到世界上大多数地区也启用了IPv6之前,您仍将需要现有的IPv4 NAT用于传出连接和端口转发以用于传入连接。

它也更快。

与发夹式NAT相比,使用IPv6将为您提供更好的性能。

使用发夹式NAT,您的客户端将通过交换机将数据包发送到路由器,然后路由器将执行两轮转换,最后通过交换机将数据包发送到服务器。从服务器到客户端的数据包将反向经过整个路径。

使用IPv6,您可以避免NAT,而是直接通过客户端和服务器之间的交换机发送数据包。这意味着在往返中,将通过交换机的次数从4减少到2,并且避免通过路由器的两次旅行以及路由器执行的4次转换。这转化为更好的性能。

即使您使用与路由器位于同一盒子中的交换机也是如此。

如果ISP没有IPv6怎么办?

如果您使用的是不支持IPv6的ISP,我会质疑您是否应该在该网络上托管服务器。这些是我对ISP当前不支持IPv6时应该怎么做的建议。

首先告诉ISP您需要 IPv6。也许提醒他们,IPv6协议已经存在了20年,因此他们早就应该支持它了。如果这还不足以让ISP认真对待您,请开始寻找其他ISP。

如果找到支持IPv6的ISP,则可以在过渡期内与这两个ISP一起运行。在连接到新ISP的路由器上,可以在LAN端禁用IPv4,然后将两个路由器的LAN端连接到同一交换机。IPv4和IPv6是两个独立的协议,因此,如果这些连接通过不同的路由器,则完全没有问题。附带的好处是,如果其中一个连接中断,它将为您提供一定程度的冗余。

如果找不到支持IPv6的ISP,则应考虑将服务器移至托管设施。在托管设施中使用服务器,您将不再依赖地理位置,因此,提供商之间的竞争会更加激烈,这将有助于确保有一个服务器能够满足您的需求。

将服务器移至托管设施并不会为您的客户端提供IPv6,但移动服务器意味着您不再需要发夹式NAT即可到达服务器。

你不应该做什么

如果您没有路由IPv6流量的方法,请不要打开IPv6并创建AAAA记录。如果您的ISP不支持IPv6,但是您仍然选择在LAN上启用IPv6(也许使用RFC 4193地址)并创建AAAA记录,它将对LAN上的客户端和LAN上的服务器起作用。但是,您的LAN与外部世界之间的通信将首先尝试使用IPv6(该方法无法正常工作),并且您将依赖回落到IPv4,后者最好稍微慢一点,或者最坏的情况不会发生。


0

由于我也问了这个问题(请参阅如何使用外部IP从内部访问在防火墙后面经过NAT的网络服务?)并在此处重定向,但此处的答案没有提供解决方案(与一般说明相反)iptables在此处提供我的Linux(特定)解决方案,以节省每个人几个小时的实验时间。该文件具有iptables-restore格式,可以直接读到iptables中(当然是在编辑IP地址之后)。这是针对Web服务器(端口80)且仅用于IPv4的-IPv6和SSL(端口443)的规则类似。


# Port forwarding for VM / Container access with „hairpin NAT“.
*nat
:PREROUTING ACCEPT [3:205]
:INPUT ACCEPT [59:670]
:OUTPUT ACCEPT [16:172]
:POSTROUTING ACCEPT [20:257]

# This was simple port forwarding - access works from outside but not from inside
#-A PREROUTING  -4 -p tcp -i eth0 --dport 80 -j DNAT --to web.local:80

# This is real hairpin NAT which allows „web.local“ to access itself via the VM hosts external IP.
# First we need to masquerade any traffic going out the external interface:
-A POSTROUTING -o eth0 -j MASQUERADE

# Then we need to reroute incoming traffic on the public IP to the local IP:
-A PREROUTING  -4 -p tcp -d web.public.com --dport  80 -j DNAT --to web.local:80

# And finally we need to tell the router that the source IP of any traffic
# coming from the LAN must be source-rewritten when going to the web server:
-A POSTROUTING -4 -p tcp -s lan.local/24 -d web.local --dport  80 -j SNAT --to-source web.public.com:80

COMMIT

替换为lan.localweb.local并将web.public.com其替换为您的本地网络(例如10.0.x.0 / 24),Web服务器的本地IP(例如10.0.1.2)和路由器的公共IP(例如4.5.6.7)。在-4仅仅允许在同一个文件IPv6和IPv4规则(无视这样的线ip6tables)。另外,请记住在IPv6地址包含端口声明时将它们放在[花括号]中,例如[fe0a:bd52::2]:80

这些都是导致我在尝试实际实施此问题中的解释时拉扯头发的所有事情。我希望我没有遗漏任何东西。


WAN接口上的MASQUERADE通常很有用,但与“发夹NAT”问题无关。规范的答案在lan接口上建议使用MASQUERADE,而您建议使用SNAT(SNAT与MASQUERADE大致相同)。您强制有些奇怪的源IP:端口覆盖。
kubanczyk

0

我将在此处添加答案,因为此处的评论未解决我的特定问题。我怀疑那是因为我遇到了一个讨厌的linux内核错误。设置为:

internet <--> modem 1.1.1.1/30 <--> switch <---> LAN 10.1.1.0/24
                                      ^
        +----------------------+      |
        |              /--eth0 o <----/
        |              |       |           
        | 10.1.1.1/24 br0      |           v (antenna)
        |  1.1.1.2/30  |       |           |
        |              \-wlan0 o ----------/
        +----------------------+ 

尽管外观复杂,但其他注释中涉及的情况的唯一相关更改是增加了软件桥br0。之所以在那里,是因为网关盒也是LAN的无线访问点。

我们的网关仍在为LAN上的计算机执行NAT任务。由于它只有1个以太网端口,因此被迫进行发夹式NAT。我怀疑它应该只与此处其他注释中给出的iptables规则一起使用,但是在Linux内核4.9上至少不是这样。在4.9以下,我们的网关盒可以访问Internet,而试图通过NAT访问它的局域网上的计算机则不能。

tcpdump显示了对到达eth0的传入数据包的响应,但它们并非来自br0。运行此命令可修复以下问题:

ebtables -t brouter -A BROUTING -d 01:00:00:00:00:00/01:00:00:00:00:00 -j ACCEPT
ebtables -t brouter -A BROUTING -p IPv4 --ip-dst 10.1.1.0/24 -j ACCEPT
ebtables -t brouter -A BROUTING -p IPv4 --ip-src 10.1.1.0/24 -j ACCEPT
ebtables -t brouter -A BROUTING -p IPv4 -j DROP

在运行该命令之前,将根据内核的默认行为来处理传入的数据包,即将它们提供给网桥,然后将其传递给内核的路由模块。该命令强制非LAN的数据包绕过网桥,直接进入路由,这意味着网桥没有机会丢弃它们。广播和多播地址必须桥接,否则DHCP和mDNS之类的内容将无法正常工作。如果使用的是IPv6,则还必须为其添加规则。

您可能会尝试使用以下方法解决问题:

brctl hairpin br0 eth0 on
brctl hairpin br0 wlan0 on

我当然很受诱惑-这是我的第一次尝试。我一完成,局域网上的机器就可以访问Internet,因此它可以工作一段时间。然后发生了以下情况(我不在乎重复该实验):

  1. 跨LAN到网关的Ping时间以大约10秒的间隔增加了一倍,从0.1毫秒增加到0.2毫秒,0.4毫秒,0.8毫秒,2毫秒等,直到无法从LAN访问网关盒。它像数据包风暴一样闻起来,但是STP到处都打开了。
  2. 所有无线接入点都死了不久。
  3. 在尝试诊断无线问题时,所有IP电话都重新启动。
  4. 此后不久,有线机器失去了与局域网的所有联系。

唯一的解决方法是重新引导建筑物中的每台计算机。一个例外是硬件交换机,无法重新启动。它们必须重新通电。


0

因为这是规范的问题。如果您有Sonicwall路由器,我会回答。

要知道的表达式是NAT环回策略

本文档介绍了SonicWall LAN上的主机如何使用服务器的FQDN公用IP地址访问SonicWall LAN上的服务器。想象一下一个NSA 4500(SonicOS增强型)网络,其中主LAN子网为10.100.0.0 / 24,主WAN IP为3.3.2.1。假设您有一个供客户使用的网站,其主机名是。您已经编写了所需的策略和规则,以便外部人员可以访问该网站,但是它实际上在私有侧服务器10.100.0.2上运行。现在,假设您是一个使用IP为10.100.0.200的便携式计算机的人。您想使用服务器的公用名访问服务器,因为在旅途中笔记本电脑随身携带时,您会做同样的事情。如果您是坐在私人一侧,并请求http://www.example.com>,即使服务器实际上在本地IP地址上就在您旁边,也可以通过环回使它工作。

要启用此功能,您将需要创建NAT环回策略,也称为NAT反射或发夹。

使用WAN接口IP地址的环回策略

Login to the SonicWall Management GUI.
Navigate to Manage | Rules | NAT Policies submenu.
Click on the Add button.
Create the following NAT Policy.
Original Source: LAN Subnets (or Firewalled Subnets if you want hosts in other zones to be included)
Translated Source: WAN Interface IP
Original Destination: WAN Interface IP
Translated Destination: (LAN server object)
Original Service: Any
Translated Service: Original
Inbound Interface: Any
Outbound Interface: Any

SonicWALL将识别您尝试联系的外部服务,并将重写目标地址以适合服务器内部的地址,因此它将与计算机透明。


-2

在使用PF的FreeBSD中,很容易(在pf.conf文件中):

extif = "tun0"
intif = "em0"
{other rules}...
nat on $intif from any to 192.168.20.8 port 80 -> ($extif)

192.168.20.8将是内部Web服务器。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.