WatchGuard 是一种傻逼网关设备。
Web UI
Network Diagnostics
通过 Web UI 可以使用 ping / traceroute / dns lookup / tcp dump 等网络测试工具。
位置:Web UI => SYSTEM STATUS => Diagnostics => "Network" tab
端口映射配置
这傻逼 WatchGuard 设备配置端口映射要弄两个地方!进入 Web UI,默认管理员 admin。(这傻逼设备 Web UI 默认是 https,用了自欺欺人的自签名证书)
步骤1: 创建 Static NAT 规则
Web UI -> Firewall -> SNAT
(注意这里的 "SNAT" 的含义是 "Static NAT",而不是指通常意义的 "修改 src 信息的 NAT",傻逼 WatchGuard!。)
点击 ADD(或者选中一条已有的规则,点击“EDIT”)以打开 Add SNAT 或 Edit SNAT 界面,选择 “Type”为“Static NAT”(即默认值);在“SNAT MEMBERS”区域点击“ADD”或“EDIT”,然后在打开的“Add Member”或“Edit Member”对话框里:
- 设置“External/Optional IP Address”为“Any-External”
- 设置“Internal IP Address”为内网服务器的 IP,如 192.168.1.2;
- 选中“Set internal port to a different port”复选框,在其后的文本框里输入内网服务器监听端口,如 80。
然后点击“OK”关闭对话框,点击“SAVE”保存 SNAT 规则。
这样就设置了一个 TYPE = SNAT, Any-External --> 192.168.1.2:80 的 SNAT 映射规则。记住其 name。
如果准备在外网和内网使用相同端口,那么在创建时的“Add Member”对话框里可以不选择 "Set internal port to a different port"。(如果这样,那么之后的步骤可以创建端口段映射?)
步骤2: 创建防火墙规则
Web UI -> Firewall -> Firewall Policies
Add Policy -> 选择 Custom,然后点击右侧的 Add 去创建一个 "Policy Template"
在 Add Policy Template 界面,输入 name,选择 Type 为 Proxy - TCP-UDP,在下面的 PROTOCOLS 区域点击 “Add”打开“Add Member”对话框(如果修改已有记录,则点击“Edit”打开“Edit Member”对话框),在 Server Port 里输入映射的公网端口,比如 3000,然后点击 "OK"(其它默认选项为 Simple Port,TCP),点击 Save。
现在回到了 Add Firewall Policy 界面,点击 Add Policy(如果需要修改已有规则,选中规则然后点击 Action -> "Edit Policy")。
现在回到了 "Firewall Policies / Add" 界面。将第一个 Tab 页 "From" 区域里默认的 "Any-Trusted" Remove 掉,增加一个 "Any External";然后将 "To" 区域的 "Any-Trusted" 也 Remove 掉,点击 Add, 选择 Member type 为 "Static NAT",在列表里选择之前第一步 "步骤1: 创建 Static NAT 规则" 里创建的 Static NAT 策略名字,点击 OK。
最后点击 SAVE 即可。这样就创建了一个从路由器公网 tcp/3000 到 192.168.1.2:tcp/80 的端口映射。
结论
这个 WatchGuard 的系统配置方法纯属傻逼。Linux 路由器配置端口映射只需一条规则:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 3000 -j DNAT --to 192.168.1.2:80
而在这个弱智 WatchGuard 里竟然需要配置这么多步骤!
内网访问备注
上面方法配置的端口映射默认无法从“内网”访问。
例如,假设路由器 LAN IP 192.168.1.1,WAN IP 1.2.3.4,内网里服务运行在 192.168.1.2:80 (tcp),配置了 1.2.3.4:3000 -> 192.168.1.2:80 的端口映射。
那么 1.2.3.4:3000 这个地址只能从“外部”访问,无法在内网里(192.168.1.0/24) 直接访问 1.2.3.4:3000。(当然,在内网里仍然可以通过 "192.168.1.2:80" 这个“原始”地址访问)
原因有两个。
这种情况下 WatchGuard 根本没有做 DNAT。
即使做了 DNAT,但是对于 src IP 是内网的情况下路由器还需要做 SNAT,具体说明如下:
(假设 src 是 192.168.1.3)
- src 发出的原始 request: 192.168.1.3:45678 -> 1.2.3.4:3000
- 路由器 DNAT 后的 request: 192.168.1.3:45678 -> 192.168.1.2:80 (这也是 192.168.1.2:80 上服务器实际收到的 request)
- 192.168.1.2:80 服务器发送的 response: 192.168.1.2:80 -> 192.168.1.3:45678(这个 response 包因为 src / dst 都是 LAN IP,不会经过路由器,直接发给了 192.168.1.3!)
- 最后,192.168.1.3 收到了 response,但是 response 的 src IP 变成了 192.168.1.2,与自己之前发送的 request 的 dst IP 1.2.3.4 不一致,所以内核会直接丢弃 response 包,不会把它传给上层 App。
这种情况标准解决方法是在路由器上对于这种情况(除了做 DNAT 还)同时做 SNAT,将来自 LAN 的 request 的 src IP 重写为路由器 LAN IP。
# LAN 网段:192.168.1.0/24
# 路由器 LAN IP:192.168.1.1
# 内网的 Web 服务器:192.168.1.2:80 (tcp)
iptables -t nat -A POSTROUTING -d 192.168.1.2 -p tcp --dport 80 -s 192.168.1.0/24 -j SNAT --to 192.168.1.1
# Because the PREROUTING (DNAT) rule gets run first, the packets will already be destined for the internal web server: we can tell which ones are internally sourced by the source IP addresses.
# 注意在 POSTROUTING 里无法用 -i eth0 来指定流量来源网卡。(类似的,PREROUTING 里不能用 -o)
Netfilter 文档里对于这种 "Destination NAT Onto the Same Network" 情形有详细说明。
解决方法
经过测试,要想在 WatchGuard 上实现能够“从内网访问”的端口映射,需要在之前的“端口映射配置”过程中的步骤里做一些小调整,具体如下:
在“步骤1: 创建 Static NAT 规则”的“Add Policy Template”界面的“Add Member”或“Edit Member”对话框里,选中“Set source IP”复选框,在之后的文本框里输入路由器的 LAN IP "192.168.167.1"。
在“步骤2: 创建防火墙规则”里“Add Policy”或“Edit Policy”界面,在设置"From"区域时用“Any”代替“Any External”。
这种做法的缺点是:内网的应用服务器所接收到的 request 的 "src IP" 始终是网关 IP (192.168.167.1),即使访问请求来自“外部”。更好的解决方法是创建两个 "Static NAT",分别对应来自外部和内部的访问请求,只对来自“外部”的访问“Set source IP”为网关IP,然后再创建对应的两个防火墙规则。