标准 Linux 启用 ZeroTier 局域网转发

参考文章

需要解决的问题

在使用非OpenWRT这种路由器类型的Linux发行版的时候,如果想要使用ZeroTier自带的路由转发的功能,需要进行一系列的操作来启用内部的路由转发机制。

解决这个问题原本应该十分简单,只需要在sysctl启用对应的forward设置然后设置防火墙即可。但是在CentOS 8上实践的过程中,遇到了iptables-save无法保存防火墙规则的问题。因为对iptables的使用也不是很频繁,这里就写了一个小脚本,通过systemd的方式曲线救国,并记录一下脚本的内容

启用路由转发的流程

初期准备

  1. 首先将需要作为内部跳板的局域网机器加入ZeroTier网络中,这一步网上的教程比较多,不多做赘述

  2. 根据下面这个简单的脚本查询当前机器对应的默认网络CIDR信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 提取默认路由的接口名称
    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}"

    这里为了做示范,假设输出的内容为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=zt7nnig26

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 ACCEPT

Save iptables rules for next boot

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    #!/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. 为刚刚编辑的脚本添加可执行权限,并设置脚本的开机自启动

    1
    2
    chmod +x /usr/local/bin/enable-zerotier-nat.sh
    systemctl enable --now zerotier-nat

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


标准 Linux 启用 ZeroTier 局域网转发
https://halc.top/p/d556ca0e
作者
HalcyonAzure
发布于
2024年4月26日
许可协议