玩路由器 · 2025年12月30日 0

华硕路由器 FullConeNAT 的研究,附 免费完整脚本

开启 FullConeNAT 前 iptables 表

admin@TUF-AX4200Q-7586:/tmp/home/root# iptables -S -t nat
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DNSFILTER
-N GAME_VSERVER
-N LOCALSRV
-N MAPE
-N PCREDIRECT
-N VPN_FUSION
-N VSERVER
-N VUPNP
-A PREROUTING -d 10.1.12.116/32 -j GAME_VSERVER
-A PREROUTING -d 10.1.12.116/32 -j VSERVER
-A POSTROUTING ! -s 10.1.12.116/32 -o eth1 -j MASQUERADE
-A POSTROUTING -s 192.168.50.0/24 -d 192.168.50.0/24 -o br0 -j FULLCONENAT
-A VSERVER -j VUPNP
admin@TUF-AX4200Q-7586:/tmp/home/root# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N ACCESS_RESTRICTION
-N DNSFILTER_DOT
-N FUPNP
-N INPUT_ICMP
-N INPUT_PING
-N IPSEC_DROP_SUBNET_ICMP
-N IPSEC_STRONGSWAN
-N OUTPUT_DNS
-N OUTPUT_IP
-N OVPNCF
-N OVPNCI
-N OVPNSF
-N OVPNSI
-N PControls
-N PTCSRVLAN
-N PTCSRVWAN
-N SECURITY
-N VPNCF
-N VPNCI
-N WGCF
-N WGCI
-N WGNPControls
-N WGSF
-N WGSI
-N default_block
-N logaccept
-N logdrop
-N logdrop_dns
-N logdrop_ip
-A INPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -i lo -p tcp -m tcp --dport 50235 -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -j INPUT_PING
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m state --state INVALID -j DROP
-A INPUT ! -i br0 -j PTCSRVWAN
-A INPUT -i br0 -j PTCSRVLAN
-A INPUT -i br0 -m state --state NEW -j ACCEPT
-A INPUT -i lo -m state --state NEW -j ACCEPT
-A INPUT -p udp -m udp --sport 67 --dport 68 -j ACCEPT
-A INPUT -p icmp -j INPUT_ICMP
-A INPUT -p gre -j ACCEPT
-A INPUT -p udp -m udp --dport 1701 -j ACCEPT
-A INPUT -j WGSI
-A INPUT -j WGCI
-A INPUT -j OVPNSI
-A INPUT -j OVPNCI
-A INPUT -j DROP
-A FORWARD -j IPSEC_DROP_SUBNET_ICMP
-A FORWARD -j IPSEC_STRONGSWAN
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -j WGSF
-A FORWARD -j OVPNSF
-A FORWARD ! -i br0 -o eth1 -j DROP
-A FORWARD -i br0 -o br0 -j ACCEPT
-A FORWARD -m state --state INVALID -j DROP
-A FORWARD -m conntrack --ctstate DNAT -j ACCEPT
-A FORWARD -j WGCF
-A FORWARD -j OVPNCF
-A FORWARD -j VPNCF
-A FORWARD -j VPNCF
-A FORWARD -i br0 -j ACCEPT
-A FORWARD -j DROP
-A OUTPUT -p udp -m udp --dport 53 -m u32 --u32 "0x0>>0x16&0x3c@0x8>>0xf&0x1=0x0" -j OUTPUT_DNS
-A OUTPUT -p tcp -m tcp --dport 53 -m u32 --u32 "0x0>>0x16&0x3c@0xc>>0x1a&0x3c@0x8>>0xf&0x1=0x0" -j OUTPUT_DNS
-A OUTPUT -j OUTPUT_IP
-A INPUT_ICMP -p icmp -m icmp --icmp-type 8 -j RETURN
-A INPUT_ICMP -p icmp -m icmp --icmp-type 13 -j RETURN
-A INPUT_ICMP -p icmp -j ACCEPT
-A INPUT_PING -i eth1 -p icmp -j DROP
-A OUTPUT_DNS -m string --hex-string "|10706f697579747975696f706b6a666e6603636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0d72666a656a6e666a6e65666a6503636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|1131306166646d617361787373736171726b03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0f376d667364666173646d6b676d726b03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0d386d617361787373736171726b03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0f3966646d617361787373736171726b03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|1265666274686d6f6975796b6d6b6a6b6a677403636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|086861636b7563647403636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|076c696e77756469056633333232036e657400|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0f6c6b6a68676664736174727975696f03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0b6d6e627663787a7a7a313203636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|077131313133333303746f7000|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|057371353230056633333232036e657400|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|077563746b6f6e6503636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0e7a786376626d6e6e666a6a66777103636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0a65756d6d6167766e627003636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_IP -d 193.201.224.0/24 -j logdrop_ip
-A OUTPUT_IP -d 51.15.120.245/32 -j logdrop_ip
-A OUTPUT_IP -d 45.33.73.134/32 -j logdrop_ip
-A OUTPUT_IP -d 190.115.18.28/32 -j logdrop_ip
-A OUTPUT_IP -d 51.159.52.250/32 -j logdrop_ip
-A OUTPUT_IP -d 190.115.18.86/32 -j logdrop_ip
-A SECURITY -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m limit --limit 1/sec -j RETURN
-A SECURITY -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j DROP
-A SECURITY -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK RST -m limit --limit 1/sec -j RETURN
-A SECURITY -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK RST -j DROP
-A SECURITY -p icmp -m icmp --icmp-type 8 -m limit --limit 1/sec -j RETURN
-A SECURITY -p icmp -m icmp --icmp-type 8 -j DROP
-A SECURITY -j RETURN
-A logaccept -m state --state NEW -j LOG --log-prefix "ACCEPT " --log-tcp-sequence --log-tcp-options --log-ip-options
-A logaccept -j ACCEPT
-A logdrop -m state --state NEW -j LOG --log-prefix "DROP " --log-tcp-sequence --log-tcp-options --log-ip-options
-A logdrop -j DROP
-A logdrop_dns -j LOG --log-prefix "DROP_DNS " --log-tcp-sequence --log-tcp-options --log-ip-options
-A logdrop_dns -j DROP
-A logdrop_ip -j LOG --log-prefix "DROP_IP " --log-tcp-sequence --log-tcp-options --log-ip-options
-A logdrop_ip -j DROP
admin@TUF-AX4200Q-7586:/tmp/home/root# iptables -S -t mangle
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT

开启后的表

admin@TUF-AX4200Q-7586:/tmp/home/root# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N ACCESS_RESTRICTION
-N DNSFILTER_DOT
-N FUPNP
-N INPUT_ICMP
-N INPUT_PING
-N IPSEC_DROP_SUBNET_ICMP
-N IPSEC_STRONGSWAN
-N OUTPUT_DNS
-N OUTPUT_IP
-N OVPNCF
-N OVPNCI
-N OVPNSF
-N OVPNSI
-N PControls
-N PTCSRVLAN
-N PTCSRVWAN
-N SECURITY
-N VPNCF
-N VPNCI
-N WGCF
-N WGCI
-N WGNPControls
-N WGSF
-N WGSI
-N default_block
-N logaccept
-N logdrop
-N logdrop_dns
-N logdrop_ip
-A INPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -i lo -p tcp -m tcp --dport 50235 -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -j INPUT_PING
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m state --state INVALID -j DROP
-A INPUT ! -i br0 -j PTCSRVWAN
-A INPUT -i br0 -j PTCSRVLAN
-A INPUT -i br0 -m state --state NEW -j ACCEPT
-A INPUT -i lo -m state --state NEW -j ACCEPT
-A INPUT -p udp -m udp --sport 67 --dport 68 -j ACCEPT
-A INPUT -p icmp -j INPUT_ICMP
-A INPUT -p gre -j ACCEPT
-A INPUT -p udp -m udp --dport 1701 -j ACCEPT
-A INPUT -j WGSI
-A INPUT -j WGCI
-A INPUT -j OVPNSI
-A INPUT -j OVPNCI
-A INPUT -j DROP
-A FORWARD -j IPSEC_DROP_SUBNET_ICMP
-A FORWARD -j IPSEC_STRONGSWAN
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -j WGSF
-A FORWARD -j OVPNSF
-A FORWARD ! -i br0 -o eth1 -j DROP
-A FORWARD -i br0 -o br0 -j ACCEPT
-A FORWARD -m state --state INVALID -j DROP
-A FORWARD -m conntrack --ctstate DNAT -j ACCEPT
-A FORWARD -j WGCF
-A FORWARD -j OVPNCF
-A FORWARD -j VPNCF
-A FORWARD -j VPNCF
-A FORWARD -i br0 -j ACCEPT
-A FORWARD -j DROP
-A OUTPUT -p udp -m udp --dport 53 -m u32 --u32 "0x0>>0x16&0x3c@0x8>>0xf&0x1=0x0" -j OUTPUT_DNS
-A OUTPUT -p tcp -m tcp --dport 53 -m u32 --u32 "0x0>>0x16&0x3c@0xc>>0x1a&0x3c@0x8>>0xf&0x1=0x0" -j OUTPUT_DNS
-A OUTPUT -j OUTPUT_IP
-A INPUT_ICMP -p icmp -m icmp --icmp-type 8 -j RETURN
-A INPUT_ICMP -p icmp -m icmp --icmp-type 13 -j RETURN
-A INPUT_ICMP -p icmp -j ACCEPT
-A INPUT_PING -i eth1 -p icmp -j DROP
-A OUTPUT_DNS -m string --hex-string "|10706f697579747975696f706b6a666e6603636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0d72666a656a6e666a6e65666a6503636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|1131306166646d617361787373736171726b03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0f376d667364666173646d6b676d726b03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0d386d617361787373736171726b03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0f3966646d617361787373736171726b03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|1265666274686d6f6975796b6d6b6a6b6a677403636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|086861636b7563647403636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|076c696e77756469056633333232036e657400|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0f6c6b6a68676664736174727975696f03636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0b6d6e627663787a7a7a313203636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|077131313133333303746f7000|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|057371353230056633333232036e657400|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|077563746b6f6e6503636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0e7a786376626d6e6e666a6a66777103636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_DNS -m string --hex-string "|0a65756d6d6167766e627003636f6d00|" --algo bm --to 65535 --icase -j logdrop_dns
-A OUTPUT_IP -d 193.201.224.0/24 -j logdrop_ip
-A OUTPUT_IP -d 51.15.120.245/32 -j logdrop_ip
-A OUTPUT_IP -d 45.33.73.134/32 -j logdrop_ip
-A OUTPUT_IP -d 190.115.18.28/32 -j logdrop_ip
-A OUTPUT_IP -d 51.159.52.250/32 -j logdrop_ip
-A OUTPUT_IP -d 190.115.18.86/32 -j logdrop_ip
-A SECURITY -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m limit --limit 1/sec -j RETURN
-A SECURITY -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j DROP
-A SECURITY -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK RST -m limit --limit 1/sec -j RETURN
-A SECURITY -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK RST -j DROP
-A SECURITY -p icmp -m icmp --icmp-type 8 -m limit --limit 1/sec -j RETURN
-A SECURITY -p icmp -m icmp --icmp-type 8 -j DROP
-A SECURITY -j RETURN
-A logaccept -m state --state NEW -j LOG --log-prefix "ACCEPT " --log-tcp-sequence --log-tcp-options --log-ip-options
-A logaccept -j ACCEPT
-A logdrop -m state --state NEW -j LOG --log-prefix "DROP " --log-tcp-sequence --log-tcp-options --log-ip-options
-A logdrop -j DROP
-A logdrop_dns -j LOG --log-prefix "DROP_DNS " --log-tcp-sequence --log-tcp-options --log-ip-options
-A logdrop_dns -j DROP
-A logdrop_ip -j LOG --log-prefix "DROP_IP " --log-tcp-sequence --log-tcp-options --log-ip-options
-A logdrop_ip -j DROP
admin@TUF-AX4200Q-7586:/tmp/home/root# iptables -S -t mangle
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
admin@TUF-AX4200Q-7586:/tmp/home/root# iptables -S -t nat
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DNSFILTER
-N GAME_VSERVER
-N LOCALSRV
-N MAPE
-N PCREDIRECT
-N VPN_FUSION
-N VSERVER
-N VUPNP
-A PREROUTING -i eth1 -j FULLCONENAT
-A PREROUTING -d 10.1.12.116/32 -j GAME_VSERVER
-A PREROUTING -d 10.1.12.116/32 -j VSERVER
-A PREROUTING -i br0 -j FULLCONENAT
-A POSTROUTING ! -s 10.1.12.116/32 -o eth1 -j FULLCONENAT
-A POSTROUTING -s 192.168.50.0/24 -d 192.168.50.0/24 -o br0 -j FULLCONENAT
-A VSERVER -j VUPNP
admin@TUF-AX4200Q-7586:/tmp/home/root# 

分析对比

1️⃣ 出口 NAT:MASQUERADE 被彻底替换

🔴 开启前(关键规则)

-A POSTROUTING ! -s 10.1.12.116/32 -o eth1 -j MASQUERADE

这是标准 Linux 对称 NAT


🟢 开启后

-A POSTROUTING ! -s 10.1.12.116/32 -o eth1 -j FULLCONENAT

结论非常明确:

  • 公网出口 不再使用 MASQUERADE
  • 改为 FULLCONE NAT 模块
  • 这是 fullcone 能“真正工作”的核心

NAT 类型已经从 Symmetric → Full Cone


2️⃣ PREROUTING:这是“激进”的地方

新增了两条 非常关键、也非常危险的规则

-A PREROUTING -i eth1 -j FULLCONENAT -A PREROUTING -i br0 -j FULLCONENAT

这意味着什么?

  • WAN 进来的所有包 → 先过 FULLCONENAT
  • LAN 内部的包 → 也过 FULLCONENAT
  • 不区分:
    • 协议(TCP / UDP)
    • 端口
    • 是否 VPN
    • 是否 DNAT

⚠️ 这是“粗暴型 fullcone”,不是精细实现


3️⃣ Hairpin NAT:仍然存在,但被统一到 FULLCONENAT

-A POSTROUTING -s 192.168.50.0/24 -d 192.168.50.0/24 -o br0 -j FULLCONENAT

说明:

  • ASUS 没有单独写 hairpin 逻辑
  • 直接复用 FULLCONENAT
  • 对 LAN 内访问公网映射地址是友好的

4️⃣ filter / mangle 表:完全没动(这点反而“干净”)

你可以看到:

  • filter一字未改
  • mangle全空

这说明:

  • FULLCONE 完全靠 conntrack + nat 扩展
  • 没有配合任何 state / mark / policy routing

➡ 好处:不影响你现有防火墙结构
➡ 坏处:对复杂场景缺乏保护

真的假的 FullconeNAT ?

从行为上看,它满足:

条件是否满足
Endpoint-Independent Mapping
Endpoint-Independent Filtering
出口端口保持
不依赖 DNAT

结论:STUN / 游戏 / P2P 会识别为 Full Cone NAT


风险”在哪里(很重要)

⚠️ 1. 对 VPN 的潜在影响

由于这条规则:

-A PREROUTING -i eth1 -j FULLCONENAT

它会 先于

  • WireGuard
  • IPSec
  • L2TP
  • OpenVPN

进行 conntrack 重写,可能导致:

  • 某些 UDP VPN 端口保持异常
  • IPSec NAT-T 行为变化
  • 双向重连时端口不稳定

(你现在没出问题 ≠ 长期无问题)


⚠️ 2. TCP 被一起 fullcone 了

这个实现 没有限定 -p udp,意味着:

  • TCP 也可能被 endpoint-independent 映射
  • 某些服务器会认为这是异常 NAT
  • 在高并发 TCP(BT、PT、CDN)下,可能出现:
    • 会话错配
    • 重连异常

⚠️ 3. WAN 入站面扩大了(但仍受 filter 限制)

FULLCONE ≠ 防火墙放行
但:

  • conntrack 允许更多“非原始目的地”的回包
  • filter 表仍然兜底
  • 日志排错会更困难

更完整的脚本,添加到开机自启脚本

#!/bin/sh
# =========================================================
# Safe FullCone NAT Script (UDP only, WAN only, VPN excluded)
# Platform: ASUSWRT-Merlin / MTK
# =========================================================

WAN_IF="eth1"
LAN_IF="br0"

# VPN interfaces (adjust if you have custom ones)
VPN_IFACES="wg+ tun+ tap+ ppp+ ipsec+"

echo "[*] Applying SAFE FullCone NAT (UDP only, WAN only)..."

# ---------------------------------------------------------
# 1. 清理可能存在的旧 FULLCONENAT 规则(防止叠加)
# ---------------------------------------------------------
iptables -t nat -D POSTROUTING -o ${WAN_IF} -j FULLCONENAT 2>/dev/null
iptables -t nat -D POSTROUTING -o ${WAN_IF} -j MASQUERADE 2>/dev/null
iptables -t nat -D PREROUTING -j FULLCONENAT 2>/dev/null
iptables -t nat -D PREROUTING -i ${WAN_IF} -j FULLCONENAT 2>/dev/null
iptables -t nat -D PREROUTING -i ${LAN_IF} -j FULLCONENAT 2>/dev/null

# ---------------------------------------------------------
# 2. VPN 流量绕过 FULLCONENAT(UDP)
# ---------------------------------------------------------
for IF in ${VPN_IFACES}; do
    iptables -t nat -I POSTROUTING 1 -p udp -o ${IF} -j RETURN
done

# ---------------------------------------------------------
# 3. WAN 出口 UDP 使用 FULLCONENAT
# ---------------------------------------------------------
iptables -t nat -A POSTROUTING -p udp -o ${WAN_IF} -j FULLCONENAT

# ---------------------------------------------------------
# 4. WAN 出口 TCP 仍使用传统 MASQUERADE
# ---------------------------------------------------------
iptables -t nat -A POSTROUTING -p tcp -o ${WAN_IF} -j MASQUERADE

# ---------------------------------------------------------
# 5. LAN 内 Hairpin NAT(可选,保留更友好)
# ---------------------------------------------------------
iptables -t nat -A POSTROUTING -p udp -s 192.168.50.0/24 -d 192.168.50.0/24 -o ${LAN_IF} -j FULLCONENAT

echo "[✓] SAFE FullCone NAT applied successfully."