问题现象

配置了 RouterOS 端口转发后,从外网访问服务正常;但连在家里的 Wi-Fi 时,使用公网固定 IP 和同一个端口访问,浏览器一直加载,页面没有内容。直接使用服务器的内网 IP 和端口则能正常打开。

上游光猫持有公网固定 IP,并把入站连接通过 DMZ 转给 RouterOS。RouterOS 上也已经有对应的 TCP DNAT 规则,将外部端口转发到内网服务器。

这类现象很容易先归因于路由器不支持 NAT 回环(Hairpin NAT)。但这次检查发现,NAT 回环规则实际上已经存在;真正的问题是策略路由把流量送错了出口。

文中的公网 IP、内网网段、设备地址和端口均为示例,请替换成自己的配置。

先确认服务和转发规则

先从同一台 Wi-Fi 设备直接访问内网地址,例如:

1
http://192.168.10.20:8789/

如果能打开,说明服务本身在内网可用。接着检查 RouterOS 上的 DNAT 规则是否启用,目标地址和目标端口是否正确。

排查时,转发规则的包计数确实增加了。这说明请求命中了 DNAT 规则,但计数增加不代表数据包已经到达服务器:后续路由决策仍可能把数据包送到错误的出口。

根因:策略路由标记早于目的地址转换

RouterOS 的相关处理顺序可以简化为:

  1. 数据包进入路由器的 PREROUTING 链。
  2. Mangle 根据目标 IP 所在的地址列表给数据包打路由标记。
  3. 执行目的地址转换(DNAT),把公网 IP 和端口改成内网服务器 IP 和端口。
  4. 根据仍然保留的路由标记查路由表并转发数据包。

这台路由器有一条基于运营商地址列表的策略路由规则。公网固定 IP 所属网段也在该列表里,所以局域网客户端访问这个公网 IP 时,Mangle 先把请求标记到运营商专用路由表。之后 DNAT 虽然把目的地址改成了内网服务器,但已经打上的路由标记没有消失,最终数据包还是按策略路由送往 PPPoE 出口,没有从 LAN 接口转发给服务器。

现象因此变成:

  • 外网访问正常:上游光猫把连接经 DMZ 转给 RouterOS,DNAT 后按入站路径送往服务器。
  • 局域网直接访问内网 IP 正常:请求不经过公网地址的策略路由。
  • 局域网访问公网 IP 失败:请求命中 DNAT,但路由标记把它导向 WAN。

路由器上已有的全局 masquerade 规则可以负责回程源地址转换,但它不能修正错误的出口选择。先路由到错误的 WAN,再有正确的源 NAT 规则也无法让连接回到内网服务器。

修复:为固定公网 IP 添加 Mangle 例外

在策略路由标记规则之前,添加一条只匹配 LAN 入站、目标为本机公网固定 IP 的 Mangle 例外:

1
2
3
4
5
/ip firewall mangle
add chain=prerouting action=accept \
in-interface=<LAN接口> \
dst-address=<公网固定IP> \
comment="Hairpin bypass PBR"

然后把这条规则移动到第一条活动的策略路由标记规则之前:

1
2
3
/ip firewall mangle
move [find where comment="Hairpin bypass PBR"] \
destination=[find where comment="<第一条策略路由规则备注>"]

这里的 accept 是 Mangle 链中的动作:匹配后停止继续处理后面的 Mangle 规则,不再给这类流量打策略路由标记。后续 DNAT 仍会照常执行,路由器再按主路由表查找转换后的内网目标地址。

例外规则没有限定目标端口,所以适用于同一个公网固定 IP 上的其他端口转发。它只影响从 LAN 发往这个公网 IP 的流量;访问其他目标 IP 的流量仍按原有策略路由处理。

验证结果

修改规则顺序后,重新加载公网地址页面,局域网 Wi-Fi 下可以正常打开;从外网访问也继续正常。验证时可以同时观察:

  • 内网 IP 加端口是否能打开服务。
  • DNAT 规则计数是否增加。
  • Mangle 例外是否排在策略路由标记规则之前。
  • 从 LAN 访问公网 IP 时,转换后的目标是否走主路由表并从 LAN 接口到达服务器。

这次问题的关键不是 DNAT 规则缺失,而是 Mangle 路由标记发生在 DNAT 之前,并在地址转换后继续影响路由表选择。排查端口转发的局域网回环问题时,除了检查 NAT 规则和 masquerade,也要检查策略路由规则的匹配范围与顺序。