AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 55611
Accepted
adopilot
adopilot
Asked: 2009-08-19 07:16:37 +0800 CST2009-08-19 07:16:37 +0800 CST 2009-08-19 07:16:37 +0800 CST

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

  • 772
想要改进这篇文章?提供这个问题的详细答案,包括引文和解释为什么你的答案是正确的。没有足够细节的答案可能会被编辑或删除。

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

这个问题的一般形式是:

我们有一个包含客户端、服务器和 NAT 路由器的网络。路由器上有到服务器的端口转发,因此它的一些服务可以在外部使用。我们有指向外部 IP 的 DNS。本地网络客户端无法连接,但外部工作。

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

这个问题的答案是从多个其他问题合并而来的。他们最初引用了 FreeBSD、D-Link、Microtik 和其他设备。然而,他们都试图解决同样的问题。

networking
  • 12 12 个回答
  • 86930 Views

12 个回答

  • Voted
  1. MadHatter
    2013-11-28T04:20:32+08:002013-11-28T04:20:32+08:00

    由于这已被提升为关于发夹 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链中的设置,可能需要额外的规则来允许经过 NAT 的流量流动。所有此类讨论都超出了此答案的范围。

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

    • 66
  2. Best Answer
    Evan Anderson
    2009-08-19T07:30:27+08:002009-08-19T07:30:27+08:00

    您正在寻找的是所谓的“发夹 NAT”。来自内部接口对分配给外部接口的 IP 地址的请求应该进行 NAT,就好像它们来自外部接口一样。

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

    我会考虑采用水平分割 DNS 的路线,而不是在内部使用 URL 中的 IP 地址,而是使用名称。

    • 21
  3. PEra
    2009-10-11T03:32:00+08:002009-10-11T03:32:00+08:00

    这里的问题是,您的路由器不会对您的内部客户端地址进行 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 并超时。
    • 13
  4. Ryaner
    2009-08-21T00:42:03+08:002009-08-21T00:42:03+08:00

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

    • 4
  5. adopilot
    2009-08-21T00:37:32+08:002009-08-21T00:37:32+08:00

    生病回答我的问题只是为了拓宽那些有类似问题的人的视野。

    我联系了我的 ISP 并要求他们尝试解决我的问题。他们为我提供的是另一个仅用于服务器的公共 IP 地址,现在我在 FreeBSD 的 WAN 端有本地流量,我们制作了特定的管道,以提高本地流量到服务器公共 IP 的吞吐量

    • 2
  6. David
    2012-03-11T18:37:59+08:002012-03-11T18:37:59+08:00

    如果它是原始的 D-Link 路由器(即,不是来自 Virgin Media 的 Rev. D / 固件版本 1.00VG),您应该能够调整设置以解决此问题。(不过,我同意之前发帖人对DD-WRT的建议,还有很多其他的原因!)

    1. 登录路由器的网页界面
    2. 单击顶部的高级选项卡
    3. 单击左侧的防火墙设置选项卡
    4. 单击TCP Endpoint Filtering下的Endpoint Independent单选按钮,如下面的屏幕截图所示(或查看D-Link 网站上的路由器模拟器)
    5. 保存更改; 你完成了

    D-Link 路由器网页界面截图

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

    • 2
  7. Sergio
    2015-11-04T03:14:12+08:002015-11-04T03:14:12+08:00

    最近回答了一个类似的问题:Cisco static NAT not working on LAN side,刚刚意识到这是一个规范问题。所以请允许我在这里总结一下解决方案。

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

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

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

    对于那些与 TCP 三向握手有关的人:它在建议的配置中可以正常工作。

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

    • 2
  8. kasperd
    2018-11-06T03:57:11+08:002018-11-06T03:57:11+08:00

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

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

    在世界大部分地区也启用 IPv6 之前,您仍然需要现有的 IPv4 NAT 用于传出连接和端口转发用于传入连接。

    它也更快。

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

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

    使用 IPv6,您可以避免 NAT,而是直接通过客户端和服务器之间的交换机发送数据包。这意味着在往返过程中,您将通过交换机的次数从 4 次减少到 2 次,并且避免了 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,这充其量是慢一点,或者最坏的情况不会发生。

    • 1
  9. Jens
    2017-03-24T22:02:54+08:002017-03-24T22:02:54+08:00

    因为我也问过这个问题(请参阅如何使用外部 IP 从内部访问 NATed 防火墙后面的网络服务?)并被重定向到这里,但这里的答案没有提供解决方案(与一般解释相反)让我在这里提供我的 Linux(iptables特定)解决方案,以节省大家几个小时的实验时间。这个文件是有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.local和替换web.local为web.public.com您的本地网络(例如 10.0.x.0/24)、您的网络服务器的本地 IP(例如 10.0.1.2)和您的路由器的公共 IP(例如 4.5.6.7)。这-4只是为了允许同一文件中的 IPv6 和 IPv4 规则(这些行被 忽略ip6tables)。此外,当 IPv6 地址包含端口声明时,请记住将它们放在 [括号] 中,例如[fe0a:bd52::2]:80.

    这些都是导致我在尝试实际实施这个问题的解释时拔出头发的所有事情。我希望我什么都没遗漏。

    • 0
  10. Russell Stuart
    2017-06-22T21:45:49+08:002017-06-22T21:45:49+08:00

    我会在这里添加一个答案,因为这里的评论没有解决我的特定问题。我怀疑那是因为我遇到了一个讨厌的 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 下,虽然我们的网关盒可以访问互联网,但 LAN 上的机器试图通过 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
    

    我当然很受诱惑——这是我的第一次尝试。一旦我这样做了,局域网上的机器就可以访问互联网,所以它可以工作一段时间。然后发生了以下情况(我不想重复实验):

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

    唯一的出路是重新启动建筑物中的每台机器。一个例外是硬件开关,无法重新启动。他们必须重新上电。

    • 0

相关问题

  • 谁能指出我的 802.11n 范围扩展器?

  • 我怎样才能得到一个网站的IP地址?

  • 在一个 LAN 中使用两台 DHCP 服务器

  • 如何在 Linux 下监控每个进程的网络 I/O 使用情况?

  • 为本地网络中的名称解析添加自定义 dns 条目

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    从 IP 地址解析主机名

    • 8 个回答
  • Marko Smith

    如何按大小对 du -h 输出进行排序

    • 30 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    Windows 中执行反向 DNS 查找的命令行实用程序是什么?

    • 14 个回答
  • Marko Smith

    如何检查 Windows 机器上的端口是否被阻塞?

    • 4 个回答
  • Marko Smith

    我应该打开哪个端口以允许远程桌面?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    MikeN 在 Nginx 中,如何在维护子域的同时将所有 http 请求重写为 https? 2009-09-22 06:04:43 +0800 CST
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    0x89 bash中的双方括号和单方括号有什么区别? 2009-08-10 13:11:51 +0800 CST
  • Martin Hope
    kch 如何更改我的私钥密码? 2009-08-06 21:37:57 +0800 CST
  • Martin Hope
    Kyle Brandt IPv4 子网如何工作? 2009-08-05 06:05:31 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve