Administrator
发布于 2026-07-16 / 57 阅读
0
0

GRE 隧道配置(OpenWrt 实战篇)

一、简介

适用设备:GL-XE300 路由器 / OpenWrt 系统

OpenWrt 版本:OpenWrt 22.03.4

目标:在 OpenWrt 设备上完成 GRE 隧道配置,实现 4G/5G 多链路主备。

版本限制说明

该固件存在以下限制,需采用特殊方案绕开:

问题

说明

说明

缺少 GRE 协议脚本

/lib/netifd/proto/gre.sh 不存在,netifd 无法处理 proto 'gre'

纯 Shell 脚本 + rc.local 或 init 脚本

UCI 路由无法持久化

uci set network.route_gre1=route 方式添加的路由重启丢失

路由跟随隧道脚本一并创建

最终方案:Shell 脚本(/etc/init.d/gre-*)管理隧道创建与路由,UCI 管理防火墙,rc.local 实现开机自启。

二、基本配置

2.1 基本参数

参数

说明

专线接口 IP

120.236.136.227/29

WAN 口静态 IP

专线网关

120.236.136.225

默认网关

UPF 核心网侧 IP

183.235.54.118

对端公网 IP(4G 备用)

本端隧道 IP

10.250.0.2

GRE 虚拟接口本端

对端隧道 IP

10.250.0.1

GRE 虚拟接口对端

终端地址池

10.60.0.0/19

专网卡静态 IP 段

2.2 配置静态 IP

登录路由器管理面板,找到【互联网】>【以太网】配置项,填入专线提供的网络参数:

  • 静态 IP:120.236.136.227

  • 掩码:255.255.255.248

  • 网关:120.236.136.225

  • DNS:211.136.192.6

验证外网连通性(手机/电脑连接路由器 WiFi,访问 https://ip.sb 或搜索"IP"),显示为 120.236.136.227 即配置成功。

2.3 IP 转发

OpenWrt 默认已启用,确认即可:

# 应返回 1
cat /proc/sys/net/ipv4/ip_forward

若返回 0,执行:

# 若返回 0, 执行:
echo 1 > /proc/sys/net/ipv4/ip_forward
uci set network.globals.ip_forward=1 && uci commit network

2.4 防火墙:放行 GRE 协议

临时放行(重启后失效):

# 放行 GRE 协议(在输入链)
nft add rule inet fw4 input meta l4proto gre accept

# 查看规则
nft list ruleset | grep -A5 -B5 gre

UCI 持久化:

uci add firewall rule
uci set firewall.@rule[-1].name='Allow-GRE'
uci set firewall.@rule[-1].proto='gre'
uci set firewall.@rule[-1].src='wan'
uci set firewall.@rule[-1].target='ACCEPT'
uci commit firewall
/etc/init.d/firewall restart

验证:

uci show firewall | grep -A5 "Allow-GRE"

删除规则(扩展):

uci delete firewall.@rule[13] 2>/dev/null   # 序号以 uci show 输出为准
uci commit firewall && /etc/init.d/firewall restart

2.5 防火墙:放行 ICMP(可选,用于排障)

临时放行(重启后失效):

nft insert rule inet fw4 input_wan meta l4proto icmp accept

# 查看 input_wan 链
nft list chain inet fw4 input_wan | grep icmp

UCI 持久化:

uci set firewall.allow_ping=rule
uci set firewall.allow_ping.name='Allow-Ping-WAN'
uci set firewall.allow_ping.proto='icmp'
uci set firewall.allow_ping.src='wan'
uci set firewall.allow_ping.target='ACCEPT'
uci commit firewall && /etc/init.d/firewall restart

验证:

uci show firewall.allow_ping
uci show firewall | grep -A5 "allow_ping"

# 从手机 Termux 或外部机器 ping 专线 IP(使用外部网络)
ping -c 3 -W 2 120.236.136.227

三、GRE 隧道部署

3.1 加载 GRE 内核模块

# 确认 GRE 模块是否已加载
lsmod | grep gre
# 已加载的输出:gre                     2552  1 ip_gre

# 如果没有输出,执行加载
modprobe ip_gre

# 提示没有设备,则安装模块
opkg update
opkg list | grep -i gre   # 查看有没有 GRE 的包
opkg install kmod-gre

3.2 创建模板脚本

GRE 隧道和路由通过 Shell 脚本 统一管理(非 netifd 方式)

cat > /root/gre-template << 'EOF'
#!/bin/sh
NAME="gre-xxx"                    # 隧道名称(唯一)
LOCAL_IP="120.236.136.227"        # 本端物理 IP(所有隧道共用)
REMOTE_IP="183.235.54.118"        # 对端物理 IP
TUNNEL_IP="10.250.0.2/30"         # 本端隧道 IP
PEER_IP="10.250.0.1"              # 对端隧道 IP
ROUTE_NET="10.60.0.0/19"          # 目标网段
METRIC="100"                      # 路由优先级

case "$1" in
    start)
        logger -t "$NAME" "Starting GRE tunnel..."
        
        # Wait for local IP to be ready (max 60 seconds)
        retry=0
        while ! ip addr show | grep -q "$LOCAL_IP" && [ $retry -lt 60 ]; do
            sleep 1
            retry=$((retry + 1))
        done
        
        if ! ip addr show | grep -q "$LOCAL_IP"; then
            logger -t "$NAME" "ERROR: Local IP $LOCAL_IP not found, aborting"
            exit 1
        fi
        
        logger -t "$NAME" "Local IP $LOCAL_IP found, creating tunnel..."
        
        # Load GRE kernel module
        modprobe ip_gre 2>/dev/null
        
        # Remove existing tunnel if present
        ip tunnel del "$NAME" 2>/dev/null
        
        # Create GRE tunnel
        ip tunnel add "$NAME" mode gre remote $REMOTE_IP local $LOCAL_IP ttl 255
        
        # Assign tunnel IP
        ip addr add "$TUNNEL_IP" dev "$NAME"
        
        # Bring tunnel up
        ip link set "$NAME" up mtu 1400
        
        # Add or replace route (Does not impact other metric routes)
        ip route replace "$ROUTE_NET" via $PEER_IP dev "$NAME" metric "$METRIC" table main 2>/dev/null
        
        if ip link show "$NAME" > /dev/null 2>&1; then
            logger -t "$NAME" "GRE tunnel started"
        else
            logger -t "$NAME" "GRE tunnel failed"
            exit 1
        fi
        ;;
        
    stop)
        ip route del "$ROUTE_NET" 2>/dev/null
        ip link set "$NAME" down 2>/dev/null
        ip tunnel del "$NAME" 2>/dev/null
        logger -t "$NAME" "GRE tunnel removed"
        ;;
        
    status)
        if ip link show "$NAME" > /dev/null 2>&1; then
            echo "✅ $NAME is UP"
            echo ""
            ip link show "$NAME" | grep -E "mtu|state"
            echo ""
            ip addr show "$NAME" | grep inet
            echo ""
            if ip route show | grep -q "$ROUTE_NET"; then
                ip route show | grep "$ROUTE_NET"
            else
                echo "⚠️  Route $ROUTE_NET not found"
            fi
        else
            echo "❌ $NAME is DOWN or does not exist"
        fi
        ;;
        
    *)
        echo "Usage: $0 {start|stop|status}"
        exit 1
        ;;
esac
EOF

⚠️ 脚本编写注意事项:不要使用 Tab 缩进,用空格。Tab 会被 Shell 解析为指令补全,导致命令异常中断。变量值建议使用双引号包裹,防止含空格/特殊字符时被意外拆分。

3.3 基于模板生成各隧道脚本

# 4G 主隧道
cp /root/gre-template /etc/init.d/gre-4g-main
sed -i 's/NAME="gre-xxx"/NAME="gre-4g-main"/' /etc/init.d/gre-4g-main
sed -i 's/REMOTE_IP=".*"/REMOTE_IP="183.235.54.116"/' /etc/init.d/gre-4g-main
sed -i 's/TUNNEL_IP=".*"/TUNNEL_IP="10.250.0.10\/30"/' /etc/init.d/gre-4g-main
sed -i 's/PEER_IP=".*"/PEER_IP="10.250.0.9"/' /etc/init.d/gre-4g-main
sed -i 's/ROUTE_NET=".*"/ROUTE_NET="10.60.32.0\/19"/' /etc/init.d/gre-4g-main
sed -i 's/METRIC=".*"/METRIC="100"/' /etc/init.d/gre-4g-main

# 4G 备用隧道
cp /root/gre-template /etc/init.d/gre-4g-backup
sed -i 's/NAME="gre-xxx"/NAME="gre-4g-backup"/' /etc/init.d/gre-4g-backup
sed -i 's/REMOTE_IP=".*"/REMOTE_IP="183.235.54.118"/' /etc/init.d/gre-4g-backup
sed -i 's/TUNNEL_IP=".*"/TUNNEL_IP="10.250.0.2\/30"/' /etc/init.d/gre-4g-backup
sed -i 's/PEER_IP=".*"/PEER_IP="10.250.0.1"/' /etc/init.d/gre-4g-backup
sed -i 's/ROUTE_NET=".*"/ROUTE_NET="10.60.0.0\/19"/' /etc/init.d/gre-4g-backup
sed -i 's/METRIC=".*"/METRIC="200"/' /etc/init.d/gre-4g-backup

# 5G 主隧道
cp /root/gre-template /etc/init.d/gre-5g-main
sed -i 's/NAME="gre-xxx"/NAME="gre-5g-main"/' /etc/init.d/gre-5g-main
sed -i 's/REMOTE_IP=".*"/REMOTE_IP="183.235.54.68"/' /etc/init.d/gre-5g-main
sed -i 's/TUNNEL_IP=".*"/TUNNEL_IP="10.2.1.10\/30"/' /etc/init.d/gre-5g-main
sed -i 's/PEER_IP=".*"/PEER_IP="10.2.1.9"/' /etc/init.d/gre-5g-main
sed -i 's/ROUTE_NET=".*"/ROUTE_NET="172.16.2.0\/24"/' /etc/init.d/gre-5g-main
sed -i 's/METRIC=".*"/METRIC="100"/' /etc/init.d/gre-5g-main

# 5G 备用隧道
cp /root/gre-template /etc/init.d/gre-5g-backup
sed -i 's/NAME="gre-xxx"/NAME="gre-5g-backup"/' /etc/init.d/gre-5g-backup
sed -i 's/REMOTE_IP=".*"/REMOTE_IP="183.235.54.72"/' /etc/init.d/gre-5g-backup
sed -i 's/TUNNEL_IP=".*"/TUNNEL_IP="10.4.1.10\/30"/' /etc/init.d/gre-5g-backup
sed -i 's/PEER_IP=".*"/PEER_IP="10.4.1.9"/' /etc/init.d/gre-5g-backup
sed -i 's/ROUTE_NET=".*"/ROUTE_NET="172.16.2.0\/24"/' /etc/init.d/gre-5g-backup
sed -i 's/METRIC=".*"/METRIC="200"/' /etc/init.d/gre-5g-backup


# 设置执行权限
chmod +x /etc/init.d/gre-*

3.4 开机自启

编辑 /etc/rc.local,在 exit 0 前添加:

# Start all GRE tunnels in background (parallel execution)
/etc/init.d/gre-4g-main start &
/etc/init.d/gre-4g-backup start &
/etc/init.d/gre-5g-main start &
/etc/init.d/gre-5g-backup start &

批量启停和状态查看:

# 启动所有
ls /etc/init.d/gre-* | xargs -n1 -r sh -c '$0 start'

# 停止所有
ls /etc/init.d/gre-* | xargs -n1 -r sh -c '$0 stop'

# 查看所有状态
ls /etc/init.d/gre-* | xargs -n1 -r sh -c '$0 status'

四、验证

4.1 命令验证

# 1. 查看隧道接口状态
ip link show gre-4g-main
ip addr show gre-4g-main

# 2. 查看路由是否添加成功
ip route show | grep -E "10.60|172.16.2"

# 3. 测试隧道对端 IP
ping -c 3 10.250.0.1

# 4. 测试目标网段(终端需开机)
ping -c 3 10.60.0.1

# 5. 查看脚本日志(logger 打印的内存轮转日志)
logread | grep gre-4g-main | tail -20

# 6. 持久化验证:重启后重复上述命令
reboot

4.2 自动检测脚本

保存以下内容为 /root/check_gre.sh 并赋予执行权限(chmod +x):

#!/bin/sh

LOCAL_IP="120.236.136.227"
echo "===== GRE Tunnel Health Check ====="
echo ""

# 1. 检查本地IP是否存在
echo "[1] Local IP Check"
if ip addr show | grep -q "$LOCAL_IP"; then
    echo "    ✅ $LOCAL_IP found"
else
    echo "    ❌ $LOCAL_IP not found, aborting"
    exit 1
fi
echo ""

# 2. 路由检测函数
check_route() {
    local net=$1
    printf "    %-20s " "$net"
    if ip route show | grep -q "$net"; then
        echo "✅ FOUND"
        ip route show | grep "$net" | head -1
    else
        echo "❌ NOT FOUND"
    fi
}

echo "[2] Static Routes Check"
check_route "10.60.0.0/19"
check_route "10.60.32.0/19"
check_route "172.16.2.0/24"
echo ""

# 3. GRE隧道连通性检测
echo "[3] GRE Tunnel Connectivity"
echo "    (ping -c 3 -W 2)"

check_ping() {
    local ip=$1
    printf "    %-16s " "$ip"
    if ping -c 3 -W 2 "$ip" > /dev/null 2>&1; then
        echo "✅ OK"
    else
        echo "❌ FAILED"
    fi
}

# GRE远端IP(公网)
echo ""
echo "    --- Remote Public IPs ---"
for ip in 183.235.54.118 183.235.54.116 183.235.54.68 183.235.54.72; do
    check_ping "$ip"
done

# GRE隧道内网IP
echo ""
echo "    --- Tunnel Internal IPs ---"
for ip in 10.250.0.1 10.250.0.9 10.2.1.9 10.4.1.9; do
    check_ping "$ip"
done

echo ""
echo "===== Check Completed ====="

五、内网互访验证

详见:《GRE 隧道转发与抓包分析》

六、附录

6.1 Win11 放行 ICMP(测试专线静态 IP 连通性)

本机(Win11)直连光猫时,需放行 ICMP 入站规则,才能从外部(如手机 Termux)ping 通专线静态 IP 120.236.136.227,用于验证物理链路是否正常。

操作步骤:

  • 按下 Win + R 键,输入 wf.msc,然后按回车,打开 高级安全 Windows Defender 防火墙

  • 左侧导航栏单击 入站规则

  • 右侧操作面板单击 按组筛选 -> 选择 【核心网络诊断】

  • 找到 ICMPv4 入站规则,右键单击远程地址为 任何 的那条规则,选择 启用规则

  • 右键单击远程地址为 【任何】 的那条规则,然后选择 【启用规则】。

  • 右键 属性 → 高级 → 勾选 专用、公用 → 确定

6.2 备选方案:标准 init 脚本

除正文提到的 Shell + rc.local 方案外,也可使用 OpenWrt 标准 init 脚本(USE_PROCD=0 + start_service())实现开机自启。

💡 两种方案选其一即可。init 脚本方案管理更规范(支持 enable/disable),Shell + rc.local 方案更直观。本手册以 Shell + rc.local 方案为主,init 脚本方案供参考。

OpenWrt init 脚本机制简介:

  • START=99:启动顺序,数字越大越晚执行

  • USE_PROCD=0:非守护进程模式,需使用 start_service()/stop_service() 函数

  • /etc/init.d/<脚本> enable:在 /etc/rc.d/ 下创建 S99<脚本> 符号链接,开机自动执行

cat > /etc/init.d/gre-4g-main << 'EOF'
#!/bin/sh /etc/rc.common

START=99
USE_PROCD=0

NAME="gre-4g-main"
LOCAL_IP="120.236.136.227"
REMOTE_IP="183.235.54.116"
TUNNEL_IP="10.250.0.10/30"
PEER_IP="10.250.0.9"
ROUTE_NET="10.60.32.0/19"
METRIC="100"

start_service() {
    logger -t "$NAME" "Starting GRE tunnel..."
    
    # 等待本地 IP 就绪
    retry=0
    while ! ip addr show | grep -q "$LOCAL_IP" && [ $retry -lt 30 ]; do
        sleep 1
        retry=$((retry + 1))
    done
    
    modprobe ip_gre 2>/dev/null
    ip tunnel del "$NAME" 2>/dev/null
    ip tunnel add "$NAME" mode gre remote $REMOTE_IP local $LOCAL_IP ttl 255
    ip addr add "$TUNNEL_IP" dev "$NAME"
    ip link set "$NAME" up mtu 1400
    ip route replace "$ROUTE_NET" via $PEER_IP dev "$NAME" metric "$METRIC" 2>/dev/null
    
    if ip link show "$NAME" > /dev/null 2>&1; then
        logger -t "$NAME" "GRE tunnel started"
    else
        logger -t "$NAME" "GRE tunnel failed"
    fi
}

stop_service() {
    ip route del "$ROUTE_NET" 2>/dev/null
    ip link set "$NAME" down 2>/dev/null
    ip tunnel del "$NAME" 2>/dev/null
    logger -t "$NAME" "GRE tunnel removed"
}

status_service() {
    if ip link show "$NAME" > /dev/null 2>&1; then
        echo "✅ $NAME is UP"
        ip link show "$NAME" | grep -E "mtu|state"
        ip addr show "$NAME" | grep inet
        ip route show | grep "$ROUTE_NET" || echo "⚠️  Route not found"
    else
        echo "❌ $NAME is DOWN"
    fi
}
EOF

chmod +x /etc/init.d/gre-4g-main

# 启用开机自启
/etc/init.d/gre-4g-main enable

# 手动管理
/etc/init.d/gre-4g-main start
/etc/init.d/gre-4g-main stop
/etc/init.d/gre-4g-main status

6.3 废弃:/etc/config/network 方式

因精简版固件缺少 /lib/netifd/proto/gre.sh 协议脚本,netifd 无法处理 proto 'gre' 配置,以下配置无效,仅作记录。

vi /etc/config/network

# 在文件末尾添加:
config interface 'gre_pgw1'
    option proto 'tunnel'
    option tunnel 'gre'
    option remote '183.235.54.118'
    option local '120.236.136.227'
    option mtu '1400'
    option ipaddr '10.250.0.2'
    option peeraddr '10.250.0.1'
    option metric '100'

# 保存后,重启网络测试:
/etc/init.d/network restart


评论