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

GRE 隧道配置(OpenWrt 实战篇)

1、基本参数

  • OpenWrt 版本:22.03.4(GL-XE300 路由器)

  • 客户 GRE IP/专线接口 IP:120.236.136.227/29、专线网关:120.236.136.225,对等 IP:10.250.0.1/30

  • 5G UPF 核心网侧 IP:183.235.54.118,对等 IP:10.250.0.2/30

  • 终端地址池(物联网卡)静态 IP:10.60.0.0/19

该固件 缺少 /lib/netifd/proto/gre.sh 协议脚本,netifd 无法处理 proto 'gre',因此无法通过 /etc/config/network 持久化 GRE 隧道和路由。

通过 uci set network.route_gre1=route 的方式添加路由无效。

解决方案:采用 纯 Shell 脚本 + rc.local 管理隧道创建和路由,防火墙用 UCI 管理。

2、配置静态 IP、放行 ICMP

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

放行 ICMP(未持久化):

# 防火墙放行 ICMP
nft insert rule inet fw4 input_wan meta l4proto icmp accept

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

# 使用手机 Termux ping(外部网络)
ping -c 3 -W 2 120.236.136.227

放行 ICMP(持久化):

# ping 放行
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


# 验证(有输出证明OK)
uci show firewall.allow_ping
uci show firewall | grep -A5 "allow_ping"

# 删除(扩展、后需 commit、restart)
uci delete firewall.allow_ping

手机/电脑连接路由器 wifi,百度搜索 ip。如果显示的是专线 ip,也能说明配置没问题。

3、启动 IP 转发

OpenWrt 默认已启用 IP 转发,确认一下:

cat /proc/sys/net/ipv4/ip_forward
# 应返回 1,若不是则执行:
echo 1 > /proc/sys/net/ipv4/ip_forward
uci set network.globals.ip_forward=1
uci commit network

4、GRE、路由、防火墙(非持久)

(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

(2)创建 GRE 隧道

# 1、主隧道
ip tunnel add gre-pgw1 mode gre remote 183.235.54.118 local 120.236.136.227 ttl 255
ip addr add 10.250.0.2/30 dev gre-pgw1
ip link set gre-pgw1 up mtu 1400

(3)添加路由

# 主路由(metric 100)
ip route add 10.60.0.0/19 via 10.250.0.1 dev gre-pgw1 metric 100

# 备用路由(metric 200)
# ip route add 10.6.0.0/22 via 172.16.0.1 dev gre-pgw2 metric 200

(4)防火墙放行

OpenWrt 使用 firewall4(基于 nftables),而非 iptables:

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

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

5、GRE、路由、防火墙(持久)

(0)GRE 配置持久化(废弃)

该配置无效。

因精简版固件缺少 /lib/netifd/proto/gre.sh 协议脚本,

netifd 无法处理 proto 'gre' 配置,

故采用脚本绕过 netifd,直接使用 iproute2 命令管理 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

# 或者单独重启 GRE 接口(不重启整个网络)
ifdown gre_pgw1 && sleep 2 && ifup gre_pgw1

(1)GRE Shell 模板脚本

GRE 隧道、路由创建脚本:

i)通过 vi 创建:

  • 编辑: vi /root/gre-template

  • 到开头 + 从当前行删除到末尾:gg dG

ii)通过 cat << EOF 创建:

脚本变量双引号的作用:

  • 无引号:变量值会被 Shell 按空格、Tab、换行拆分成多个词,且 *、? 等通配符会被展开为匹配的文件名

  • 有引号:变量值作为整体传递,保留空格和特殊字符,防止意外拆分和解释

PS:脚本不要用 Tab 缩进,用空格。Tab 会被解析为指令补全,导致命令异常中断。

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

(2)通过 GRE Shell 模板脚本创建隧道脚本

# 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

(3)设置权限

chmod +x /etc/init.d/gre-*

(4)开机自启(rc.local)

# 一、只有一条隧道:通过指令在 /etc/rc.local 里添加:
if ! grep -q "gre-tunnel start" /etc/rc.local 2>/dev/null; then
    sed -i '/exit 0/i # Start GRE tunnel\n/etc/init.d/gre-tunnel start &' /etc/rc.local
fi

# 立即启动(start 是幂等的,重复执行 = 先删后建)
/etc/init.d/gre-tunnel start
/etc/init.d/gre-tunnel status

# 二、多条隧道:vi /etc/rc.local,在 exit 0 前添加
# Start all GRE tunnels
/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'

(3)防火墙持久化

# 添加防火墙规则
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

# 验证(有输出证明OK)
uci show firewall | grep -A5 "Allow-GRE"

# 删除(扩展、13 是 show 看到的序号 rule[13]、后需 commit、restart)
uci delete firewall.@rule[13] 2>/dev/null

6、连通验证

(1)通过命令检测

# 0、查看防火墙规则(有字眼 Allow-GRE)
# 配好后查一两次就行,日常不用看
nft list ruleset | grep -A5 -B5 "gre"

# 1、查看隧道状态
ip addr show gre-pgw1
ip link show gre-pgw1
ip link show

# 2、查看路由是否添加成功
ip route show | grep 10.60
ip route show

# 3. 查看日志(可选,shell 脚本我们自己 logger 打的日志)
# 启动成功:GRE tunnel started
# 这个是轮转/内存日志,一开始有,后续就查询为空了(正常现象)
logread | grep gre-tunnel | tail -20

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

# 测试目标网络(卡终端需开机)
ping -c 3 10.60.0.1

# 持久化测试:重启,重复上述指令
reboot

(2)通过脚本检测

  • 保存:vi /root/check_gre.sh

  • 赋予执行权限:chmod +x /root/check_gre.sh

#!/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 ====="

二、扩展

1、Win11 放行 ICMP(PING)

操作步骤:

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

  • 在左侧导航栏中,单击 【入站规则】。

  • 在右侧的操作面板中,单击 【按组筛选】,然后从下拉列表中选择 【核心网络诊断】。

  • 在筛选出的规则列表中,找到 ICMPv4 的入站规则。此时你会看到两条名称相似但远程地址不同的规则:

    • 一条的远程地址为 “任何”

    • 另一条的远程地址为 “本地子网”

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

  • 属性 > 高级,把专用、公用勾上,应用(默认的网络都是公用,不勾上也 ping 不通)。

  • 可用手机 Termux ping(外部网络):ping -c 3 -W 2 120.1.1.227

2、Openwrt init 脚本参数介绍

GRE 配置原计划通过 init 脚本实现,但因精简版固件中 USE_PROCD=0(非守护进程模式)无法生效,故改用普通 Shell 脚本执行。

这里简要记录 init 脚本的相关配置与使用,权作学习笔记。

init 脚本开头格式:

#!/bin/sh /etc/rc.common

START=99
USE_PROCD=1

参数说明:

  • /etc/init.d/gre-tunnel enable 执行后,系统会在 /etc/rc.d/ 下创建一个指向脚本的链接。如 /etc/rc.d/S99gre-tunnel -> ../init.d/gre-tunnel

  • S = Start(启动时执行)

  • 99 = 启动顺序(数字越大,越晚执行)

  • 系统启动时,会按顺序执行 /etc/rc.d/S* 脚本。S99 意味着它会在启动流程的最后阶段执行,确保网络等其他服务已经就绪。


评论