fix: NAT 检测与安装脚本优先使用 nft,解决 iptables-nft 不兼容问题
- diag_linux: checkMasquerade 改为优先 nft list ruleset,iptables 执行失败时 fall through 到 nft 而非直接返回 - diag_linux: 区分"iptables-nft 与原生 nft 表不兼容"与"权限不足"两种失败场景 - install_linux.sh: NAT 工具优先级反转为 nft 优先,iptables 回退,解决 Debian 12+ 上 iptables-nft 包装器操作原生 nft nat 表报 incompatible 的问题 - install_linux.sh: nft 分支增加 /etc/nftables.conf include 配置与 systemctl enable nftables,确保重启后规则自动加载
This commit is contained in:
+27
-23
@@ -48,7 +48,7 @@ net.ipv4.ip_forward = 1
|
|||||||
EOF
|
EOF
|
||||||
sysctl -p /etc/sysctl.d/99-lmvpn.conf >/dev/null
|
sysctl -p /etc/sysctl.d/99-lmvpn.conf >/dev/null
|
||||||
|
|
||||||
echo ">>> 配置 iptables NAT 与转发规则..."
|
echo ">>> 配置 NAT 与转发规则..."
|
||||||
# 自动检测默认路由出口网卡
|
# 自动检测默认路由出口网卡
|
||||||
WAN_IFACE=$(ip route show default 2>/dev/null | awk '{print $5; exit}')
|
WAN_IFACE=$(ip route show default 2>/dev/null | awk '{print $5; exit}')
|
||||||
if [ -z "$WAN_IFACE" ]; then
|
if [ -z "$WAN_IFACE" ]; then
|
||||||
@@ -56,18 +56,38 @@ if [ -z "$WAN_IFACE" ]; then
|
|||||||
else
|
else
|
||||||
echo "出口网卡: $WAN_IFACE"
|
echo "出口网卡: $WAN_IFACE"
|
||||||
|
|
||||||
# 选择可用的防火墙前端:优先 iptables,回退 nft
|
# 选择可用的防火墙前端:优先 nft(原生,Debian 12+ 的 iptables 是 nft 包装器,操作原生 nft nat 表会不兼容)
|
||||||
NAT_TOOL=""
|
NAT_TOOL=""
|
||||||
if command -v iptables >/dev/null 2>&1; then
|
if command -v nft >/dev/null 2>&1; then
|
||||||
NAT_TOOL="iptables"
|
|
||||||
elif command -v nft >/dev/null 2>&1; then
|
|
||||||
NAT_TOOL="nft"
|
NAT_TOOL="nft"
|
||||||
|
elif command -v iptables >/dev/null 2>&1; then
|
||||||
|
NAT_TOOL="iptables"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$NAT_TOOL" ]; then
|
if [ -z "$NAT_TOOL" ]; then
|
||||||
echo "警告: 未找到 iptables 或 nft,跳过 NAT 配置"
|
echo "警告: 未找到 nft 或 iptables,跳过 NAT 配置"
|
||||||
echo " 客户端将无法上外网。请安装: apt install iptables iptables-persistent"
|
echo " 客户端将无法上外网。请安装: apt install nftables"
|
||||||
echo " 安装后重新执行本脚本即可自动配置"
|
echo " 安装后重新执行本脚本即可自动配置"
|
||||||
|
elif [ "$NAT_TOOL" = "nft" ]; then
|
||||||
|
echo "使用 nft 配置 NAT..."
|
||||||
|
# 幂等:先删除旧表(忽略错误),再创建
|
||||||
|
nft delete table inet lmvpn_nat 2>/dev/null || true
|
||||||
|
nft add table inet lmvpn_nat
|
||||||
|
nft 'add chain inet lmvpn_nat postrouting { type nat hook postrouting priority 100 ; }'
|
||||||
|
nft add rule inet lmvpn_nat postrouting oifname "$WAN_IFACE" ip saddr "$VPN_SUBNET" masquerade
|
||||||
|
nft 'add chain inet lmvpn_nat forward { type filter hook forward priority 0 ; policy accept ; }'
|
||||||
|
nft add rule inet lmvpn_nat forward ip saddr "$VPN_SUBNET" accept
|
||||||
|
nft add rule inet lmvpn_nat forward ip daddr "$VPN_SUBNET" accept
|
||||||
|
|
||||||
|
# 持久化 nft 规则
|
||||||
|
mkdir -p /etc/nftables.d
|
||||||
|
nft list ruleset > /etc/nftables.d/lmvpn.nft
|
||||||
|
# 确保主配置文件 include 该目录
|
||||||
|
if [ -f /etc/nftables.conf ] && ! grep -q 'include "/etc/nftables.d' /etc/nftables.conf; then
|
||||||
|
echo 'include "/etc/nftables.d/*.nft"' >> /etc/nftables.conf
|
||||||
|
fi
|
||||||
|
systemctl enable nftables 2>/dev/null || true
|
||||||
|
echo "nft 规则已写入 /etc/nftables.d/lmvpn.nft"
|
||||||
elif [ "$NAT_TOOL" = "iptables" ]; then
|
elif [ "$NAT_TOOL" = "iptables" ]; then
|
||||||
echo "使用 iptables 配置 NAT..."
|
echo "使用 iptables 配置 NAT..."
|
||||||
# 幂等:先删除旧规则(忽略错误),再添加
|
# 幂等:先删除旧规则(忽略错误),再添加
|
||||||
@@ -91,22 +111,6 @@ else
|
|||||||
else
|
else
|
||||||
echo "警告: 未找到 iptables-save,规则仅在本次运行有效,请手动持久化"
|
echo "警告: 未找到 iptables-save,规则仅在本次运行有效,请手动持久化"
|
||||||
fi
|
fi
|
||||||
elif [ "$NAT_TOOL" = "nft" ]; then
|
|
||||||
echo "使用 nft 配置 NAT..."
|
|
||||||
# 幂等:先删除旧表(忽略错误),再创建
|
|
||||||
nft delete table inet lmvpn_nat 2>/dev/null || true
|
|
||||||
nft add table inet lmvpn_nat
|
|
||||||
nft 'add chain inet lmvpn_nat postrouting { type nat hook postrouting priority 100 ; }'
|
|
||||||
nft add rule inet lmvpn_nat postrouting oifname "$WAN_IFACE" ip saddr "$VPN_SUBNET" masquerade
|
|
||||||
nft 'add chain inet lmvpn_nat forward { type filter hook forward priority 0 ; policy accept ; }'
|
|
||||||
nft add rule inet lmvpn_nat forward ip saddr "$VPN_SUBNET" accept
|
|
||||||
nft add rule inet lmvpn_nat forward ip daddr "$VPN_SUBNET" accept
|
|
||||||
|
|
||||||
# 持久化 nft 规则
|
|
||||||
mkdir -p /etc/nftables.d
|
|
||||||
nft list ruleset > /etc/nftables.d/lmvpn.nft
|
|
||||||
echo "nft 规则已写入 /etc/nftables.d/lmvpn.nft"
|
|
||||||
echo "注意: 需确保系统启动时加载 nftables 规则,编辑 /etc/nftables.conf 添加: include \"/etc/nftables.d/lmvpn.nft\""
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+21
-17
@@ -75,14 +75,32 @@ func findExecutable(names ...string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkMasquerade 检测 NAT masquerade 规则,优先 iptables,回退 nft
|
// checkMasquerade 检测 NAT masquerade 规则,优先 nft(原生、无兼容问题),回退 iptables
|
||||||
// 返回 (结果, 说明);结果为 nil 表示无法判定
|
// 返回 (结果, 说明);结果为 nil 表示无法判定
|
||||||
func checkMasquerade() (*bool, string) {
|
func checkMasquerade() (*bool, string) {
|
||||||
// 优先 iptables
|
// 优先 nft:Debian 12+ 的 iptables 是 nft 包装器,操作原生 nft nat 表会 "incompatible"
|
||||||
|
nftPath := findExecutable("nft")
|
||||||
|
if nftPath != "" {
|
||||||
|
out, err := exec.Command(nftPath, "list", "ruleset").Output()
|
||||||
|
if err == nil {
|
||||||
|
has := strings.Contains(string(out), "masquerade")
|
||||||
|
if has {
|
||||||
|
return &has, ""
|
||||||
|
}
|
||||||
|
return &has, "未检测到 masquerade 规则,客户端无法出网"
|
||||||
|
}
|
||||||
|
// nft 存在但执行失败(权限不足等),仍回退 iptables 尝试
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回退 iptables(老系统或 nft 不可用时)
|
||||||
iptPath := findExecutable("iptables")
|
iptPath := findExecutable("iptables")
|
||||||
if iptPath != "" {
|
if iptPath != "" {
|
||||||
out, err := exec.Command(iptPath, "-t", "nat", "-L", "POSTROUTING", "-n").Output()
|
out, err := exec.Command(iptPath, "-t", "nat", "-L", "POSTROUTING", "-n").Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// iptables-nft 与原生 nft 表不兼容时,若 nft 也读不到则判定为无法检测
|
||||||
|
if nftPath != "" {
|
||||||
|
return nil, "iptables 与原生 nft 表不兼容且 nft 不可执行,无法检测 MASQUERADE"
|
||||||
|
}
|
||||||
return nil, "iptables 不可执行(权限不足?),无法检测 MASQUERADE"
|
return nil, "iptables 不可执行(权限不足?),无法检测 MASQUERADE"
|
||||||
}
|
}
|
||||||
has := strings.Contains(string(out), "MASQUERADE")
|
has := strings.Contains(string(out), "MASQUERADE")
|
||||||
@@ -92,19 +110,5 @@ func checkMasquerade() (*bool, string) {
|
|||||||
return &has, "未检测到 MASQUERADE 规则,客户端无法出网"
|
return &has, "未检测到 MASQUERADE 规则,客户端无法出网"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回退 nft
|
return nil, "iptables 与 nft 均未安装,无法检测 NAT 规则。Debian/Ubuntu 安装: apt install nftables"
|
||||||
nftPath := findExecutable("nft")
|
|
||||||
if nftPath != "" {
|
|
||||||
out, err := exec.Command(nftPath, "list", "ruleset").Output()
|
|
||||||
if err != nil {
|
|
||||||
return nil, "nft 不可执行(权限不足?),无法检测 MASQUERADE"
|
|
||||||
}
|
|
||||||
has := strings.Contains(string(out), "masquerade")
|
|
||||||
if has {
|
|
||||||
return &has, ""
|
|
||||||
}
|
|
||||||
return &has, "未检测到 masquerade 规则,客户端无法出网"
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, "iptables 与 nft 均未安装,无法检测 NAT 规则。Debian/Ubuntu 安装: apt install iptables iptables-persistent"
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user