标准 Linux 启用 ZeroTier 局域网转发

 

初期准备

  1. 首先将需要作为内部跳板的局域网机器加入ZeroTier网络中,这一步网上的教程比较多,不多做赘述
  2. 根据下面这个简单的脚本查询当前机器对应的默认网络CIDR信息1

    # 提取默认路由的接口名称
    iface=$(route | grep default | awk '{print $8}')

    # 使用接口名称获取默认网关
    gateway=$(ip route show default | grep -oP "default via \K\S+")

    # 使用相同接口获取子网掩码
    netmask=$(ip -o -f inet addr show $iface | awk '{print $4}' | sed 's/.*\///')

    # 输出默认网关和子网掩码
    echo "${gateway}/${netmask}"
    BASH这里为了做示范,假设输出的内容为192.168.1.1/24,机器在ZeroTier子网对应的IP为10.242.231.123
  3. 将输出的默认网关填入ZeroTier控制台的Manage Routes处。其中Destination填入我们上面查询到的192.168.1.1/24Via填入机器对应的网关IP:10.242.231.123在这里设置之后,ZeroTier子网下其他设备就会将192.168.1.x网段的请求都转发给10.242.231.123。因此如果有多个物理局域网需要转发,最好确定彼此之间的网段不会冲突

设置转发

在初期准备完成之后,会发现此时如果想从虚拟局域网的其他设备直接通过192.168.1.x的网段访问内网其他设备,是无法成功通信的。这是因为默认的Linux发行版一般都会禁用路由转发的功能来确保安全。因此还需要我们给当前系统启用路由转发

  • 开启sysctl的路由转发1
    sudo sysctl -w net.ipv4.ip_forward=1

但是在完成了上面的步骤以后,也会发现只有跳板机本身的192.168.1.x可以访问,局域网内其他设备不一定能直接访问。这个时候就还需要我们对防火墙的规则进行修改,放行ZeroTier的网络请求

对于这一步,根据官方的文档,理论上直接执行下面的步骤就能成功

Configure iptables

Assign some shell variables (personalize these)

1 PHY_IFACE=eth0; ZT_IFACE=zt7nnig26BASH

Add rules to iptables

1 sudo iptables -t nat -A POSTROUTING -o $PHY_IFACE -j MASQUERADE sudo iptables -A FORWARD -i $PHY_IFACE -o $ZT_IFACE -m state --state RELATED,ESTABLISHED -j ACCEPT sudo iptables -A FORWARD -i $ZT_IFACE -o $PHY_IFACE -j ACCEPTBASH

Save iptables rules for next boot

1 sudo apt install iptables-persistent sudo bash -c iptables-save > /etc/iptables/rules.v4BASH

但是在实践的过程中,发现在物理机刚启动的时候,ZeroTier的网卡并不会立马被添加到系统当中。因此写了一个开机自启动的轮训脚本,在监测到网卡正确加载之后,再对接口进行修改放行

  1. /etc/systemd/system下创建服务zerotier-nat.service1

    [Unit]
    Description=Setup IP forwarding and iptables rules for ZeroTier
    Wants=zerotier-one.service
    After=zerotier-one.service network.target

    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/enable-zerotier-nat.sh
    RemainAfterExit=yes

    [Install]
    WantedBy=multi-user.target
  2. 创建文件/usr/local/bin/enable-zerotier-nat.sh,写入下列内容1

    #!/bin/bash
    # Enable IP forwarding
    sysctl -w net.ipv4.ip_forward=1

    # Get the interface with the default route (assumed to be PHY_IFACE)
    PHY_IFACE=$(ip route | grep default | awk '{print $5}')
    echo "Physical interface detected: $PHY_IFACE"

    # Initialize attempt counter
    attempt=0

    # Try to find the ZeroTier interface, retry up to 10 times every 5 seconds
    while [ $attempt -lt 10 ]; do
    ZT_IFACE=$(ip link show | grep -o 'zt[a-zA-Z0-9]*')
    if [ ! -z "$ZT_IFACE" ]; then
    echo "ZeroTier interface detected: $ZT_IFACE"
    break
    else
    echo "ZeroTier interface not found, retrying in 5 seconds..."
    sleep 5
    ((attempt++))
    fi
    done

    # Check if ZT_IFACE was found
    if [ -z "$ZT_IFACE" ]; then
    echo "Failed to find ZeroTier interface after 10 attempts."
    exit 1
    fi

    # Set up NAT
    iptables -t nat -A POSTROUTING -o $PHY_IFACE -j MASQUERADE

    # Set up IP forwarding rules
    iptables -A FORWARD -i $PHY_IFACE -o $ZT_IFACE -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -A FORWARD -i $ZT_IFACE -o $PHY_IFACE -j ACCEPT
  3. 为刚刚编辑的脚本添加可执行权限,并设置脚本的开机自启动
    chmod +x /usr/local/bin/enable-zerotier-nat.sh
    systemctl enable --now zerotier-nat

经过上面的操作之后,理论上就完成了,可以在ZeroTier其他设备上直接访问192.168.1.x的家庭内网设备啦