跳转至

通过Zerotier实现异地设备访问局域网自动配置防火墙脚本

📝 ZeroTier 转发脚本优化笔记

1. 脚本目标

  • 自动检测物理网卡和 ZeroTier 虚拟网卡
  • 开启 IP 转发
  • 添加 NAT 和 FORWARD 规则,实现 ZeroTier 与物理网络互通
  • 保证规则持久化,不影响现有防火墙规则

2. 优化思路

  1. 安全性

  2. 使用

    set -euo pipefail
    
    • -e:命令出错立即退出
    • -u:引用未定义变量时报错
    • -o pipefail:管道中任一命令失败即退出
  3. 检查 $EUID 确保以 root 运行

  4. 网卡检测

  5. 物理网卡:排除 lodockerbr-zt

  6. ZeroTier 网卡:匹配 ^zt
  7. 检测不到直接退出,避免空变量执行 iptables

  8. 交互选择

  9. 多个网卡时使用 select 让用户选择

  10. 验证输入是否为空

  11. IP 转发

  12. sysctl -w net.ipv4.ip_forward=1

  13. /etc/sysctl.conf 中追加配置(避免重复)

  14. iptables 规则

  15. 添加前先用 iptables -C 检查是否已存在

  16. NAT:POSTROUTING -o $PHY_IFACE -j MASQUERADE
  17. FORWARD:

    • ZeroTier → 物理网卡:ACCEPT
    • 物理网卡 → ZeroTier:RELATED,ESTABLISHED
  18. 规则持久化

  19. 优先 netfilter-persistent save(Debian/Ubuntu)

  20. 其次 service iptables save(CentOS)
  21. 最后 iptables-save > /etc/iptables.rules 手动加载

3. 优化后脚本结构

#!/bin/bash
set -euo pipefail

# 1. 检查 root 权限
# 2. 检测物理网卡 & ZeroTier 网卡
# 3. 用户选择(多网卡情况)
# 4. 开启 IP 转发
# 5. 添加 iptables 规则(仅在不存在时添加)
# 6. 保存规则(多种方式兼容)

4. 脚本

#!/bin/bash
set -euo pipefail

# 必须以 root 运行
if [[ $EUID -ne 0 ]]; then
    echo "❌ 请使用 root 权限运行此脚本"
    exit 1
fi

# 自动检测物理网卡(排除 lo、docker、br-、zt 开头)
PHY_CANDIDATES=($(ip -o link show | awk -F': ' '{print $2}' | grep -Ev '^(lo|docker|br-|zt)'))
ZT_CANDIDATES=($(ip -o link show | awk -F': ' '{print $2}' | grep -E '^zt'))

# 检查是否找到网卡
if [[ ${#PHY_CANDIDATES[@]} -eq 0 ]]; then
    echo "❌ 未检测到物理网卡"
    exit 1
fi
if [[ ${#ZT_CANDIDATES[@]} -eq 0 ]]; then
    echo "❌ 未检测到 ZeroTier 网卡"
    exit 1
fi

# 选择物理网卡
if [[ ${#PHY_CANDIDATES[@]} -eq 1 ]]; then
    PHY_IFACE=${PHY_CANDIDATES[0]}
else
    echo "检测到多个物理网卡,请选择:"
    select opt in "${PHY_CANDIDATES[@]}"; do
        [[ -n "$opt" ]] && PHY_IFACE=$opt && break
    done
fi

# 选择 ZeroTier 网卡
if [[ ${#ZT_CANDIDATES[@]} -eq 1 ]]; then
    ZT_IFACE=${ZT_CANDIDATES[0]}
else
    echo "检测到多个 ZeroTier 网卡,请选择:"
    select opt in "${ZT_CANDIDATES[@]}"; do
        [[ -n "$opt" ]] && ZT_IFACE=$opt && break
    done
fi

echo "✅ 使用物理网卡: $PHY_IFACE"
echo "✅ 使用 ZeroTier 网卡: $ZT_IFACE"

# 开启 IP 转发
if sysctl -w net.ipv4.ip_forward=1 >/dev/null; then
    grep -q "net.ipv4.ip_forward=1" /etc/sysctl.conf || echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
else
    echo "❌ 无法开启 IP 转发"
    exit 1
fi

# 添加 iptables 规则(仅在不存在时添加)
iptables -t nat -C POSTROUTING -o "$PHY_IFACE" -j MASQUERADE 2>/dev/null || \
iptables -t nat -A POSTROUTING -o "$PHY_IFACE" -j MASQUERADE

iptables -C FORWARD -i "$ZT_IFACE" -o "$PHY_IFACE" -j ACCEPT 2>/dev/null || \
iptables -A FORWARD -i "$ZT_IFACE" -o "$PHY_IFACE" -j ACCEPT

iptables -C FORWARD -i "$PHY_IFACE" -o "$ZT_IFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
iptables -A FORWARD -i "$PHY_IFACE" -o "$ZT_IFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT

# 保存规则
if command -v netfilter-persistent >/dev/null 2>&1; then
    netfilter-persistent save
elif command -v service >/dev/null 2>&1 && service iptables save >/dev/null 2>&1; then
    service iptables save
elif command -v iptables-save >/dev/null 2>&1; then
    iptables-save > /etc/iptables.rules
    echo "⚠️ 已保存到 /etc/iptables.rules,请在启动时加载"
else
    echo "⚠️ 未检测到 iptables 持久化工具,请手动保存规则"
fi

echo "🎯 ZeroTier 转发规则已添加且不会影响现有防火墙规则"

5. 使用建议

  • 首次运行:建议手动确认网卡选择
  • 系统重启后:确保持久化规则已加载
  • 调试:可在脚本开头加 set -x 查看执行过程
  • 备份规则iptables-save > backup.rules