← 返回首页

通过 .sh 脚本在 Linux 上添加路由

NetRoute Pro 生成包含 ip route add 命令的简单 Bash 脚本。一条命令即可应用。持久化根据发行版需一步额外操作。

命令语法

语法(幂等 — 脚本中使用此形式):

ip route replace <CIDR> via <GATEWAY> dev <VPN_IF>

示例:

ip route replace 1.1.1.0/24 via 10.0.0.1 dev wg0

以 root 身份运行或使用 sudo。NetRoute Pro 将命令生成为 .sh 脚本 — 通过 bash routes.sh 应用。replace 在路由不存在时创建、存在时更新,因此重复运行是安全的;add 在重复时会失败并报 RTNETLINK answers: File exists,配合 set -e 会中止脚本。

准备工作

步骤 1. 在 NetRoute Pro 中生成 .sh

  1. 在 Chrome 中打开目标网站
  2. 启动 NetRoute Pro,选择 Linux 平台
  3. 设置 VPN 接口的 IP 作为网关(例如 10.8.0.1
  4. 选择聚合掩码(推荐 /24
  5. 点击 Analyze Website
  6. 下载 routes.sh
提示:启用 RIPE BGP 优化 — 它会用公告的 BGP 前缀替换单个 IP,当 CDN 轮换地址时路由保持有效。注意:RIPE BGP 会返回该 AS 公告的所有前缀 — 对于多租户 CDN(Cloudflare AS13335、AWS AS16509、DigitalOcean AS14061)可能是数万个 IP,涵盖无关站点。BGP 优化适合单租户 AS;多租户 CDN 请保持常规 /24 CIDR 聚合。

步骤 2. 应用脚本

chmod +x routes.sh
sudo bash routes.sh

路由立即应用,一直保留到下次重启。要使路由在重启后保留,请执行步骤 3。

步骤 3. 使路由持久化

根据您的发行版选择方法:

systemd-networkd

创建 drop-in 文件 /etc/systemd/network/10-vpn.network.d/routes.conf

[Route]
Destination=104.21.32.0/24
Gateway=10.8.0.1

[Route]
Destination=172.67.0.0/16
Gateway=10.8.0.1

应用:

sudo systemctl restart systemd-networkd

NetworkManager dispatcher

创建脚本 /etc/NetworkManager/dispatcher.d/99-vpn-routes(不要忘记可执行位):

#!/bin/bash
# $1 — interface, $2 — action
if [ "$1" = "wg0" ] && [ "$2" = "up" ]; then
    /usr/local/bin/routes.sh
fi
sudo chmod +x /etc/NetworkManager/dispatcher.d/99-vpn-routes

systemd oneshot 服务(推荐)

适用于任何 systemd 发行版(Ubuntu、Debian、Fedora、Arch、RHEL、openSUSE — 几乎所有现代发行版)。在添加路由前正确等待 VPN 隧道建立 — 没有竞态条件,无需 sleep 黑科技。

sudo mv routes.sh /usr/local/bin/routes.sh
sudo chmod +x /usr/local/bin/routes.sh

sudo tee /etc/systemd/system/vpn-routes.service > /dev/null <<'EOF'
[Unit]
Description=Apply VPN split-tunnel routes
After=network-online.target wg-quick@wg0.service
Wants=network-online.target
Requisite=wg-quick@wg0.service
BindsTo=wg-quick@wg0.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/routes.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now vpn-routes.service

wg-quick@wg0.service 替换为你实际的 VPN 单元:

检查服务:

systemctl status vpn-routes.service
journalctl -u vpn-routes.service
为什么不用 @reboot cron? cron 守护进程通常在 VPN 隧道建立前启动 — ip route add 对尚不存在的接口运行,悄悄失败,你只在下次重启时才发现路由失效。systemd 的 After=Requisite= 会等待 VPN 单元,消除竞态。BindsTo= 也在 VPN 关闭时停止路由。

DNS 泄漏 — 必读

本指南按 IP 路由流量。它不路由 DNS。浏览器仍然向系统解析器(通常是 ISP 的,通过 DHCP 获得)询问 example.com 的 IP — 只有结果 IP 流量才通过 VPN 加密。即使数据加密,ISP 仍能看到你访问哪些站点。

根据你的威胁模型,三种选择:

  1. 对 ISP 完全隐藏 DNS(split-DNS)。在 systemd-resolved 中为隧道域名配置每接口 DNS:
    sudo resolvectl dns wg0 10.0.0.1
    sudo resolvectl domain wg0 ~example.com ~another-site.com
    现在 example.com 查询走 VPN,其他走默认解析器。把 10.0.0.1 替换为你 VPN 提供商的内部 DNS。
  2. 降低 ISP 可见性(公共 DoH/DoT)。把系统解析器指向公共加密解析器:
    sudo resolvectl dns wg0 1.1.1.1#cloudflare-dns.com
    sudo resolvectl dnsovertls wg0 yes
    ISP 不再看到域名查询;公共解析器会看到。
  3. 接受泄漏。如果你的目标是访问内容而非规避监控,这没问题 — 数据路径仍然加密,只有查询元数据泄露。

验证当前状态:dnsleaktest.combrowserleaks.com/dns — 显示的解析器应属于你的 VPN 或所选公共 DoH,而非 ISP。本地用 resolvectl status 查看每接口 DNS 配置。

IPv6 双栈绕过

如果目标有 AAAA 记录(大多数热门站点都有 — Cloudflare、Google、AWS 都是双栈),系统按 RFC 6724 优先选择 IPv6。本指南添加的路由是仅 IPv4 — IPv6 流量完全绕过 VPN,通过 ISP 默认 v6 路由出去。结果:VPN 看起来在工作,但对双栈目标毫无作用。

VPN 启动后快速检查:

curl -6 -s -o /dev/null -w "remote=%{remote_ip}\n" https://example.com
ip -6 route get $(dig +short AAAA example.com | head -1)

如果 IPv6 路径不经过 VPN 接口,说明在绕过隧道。两种解决方案:

故障关闭(kill switch)

当 VPN 隧道断开(网络切换、服务商问题、睡眠/唤醒)时,内核会移除绑定到死接口的路由 — 流向先前隧道化 CIDR 的流量会回退到 ISP 的默认路由。结果:用户看不到任何错误的静默泄漏。强制故障关闭(阻断而非泄漏):

# nftables(现代 Linux)
sudo nft add table inet vpnkill
sudo nft add chain inet vpnkill output { type filter hook output priority 0 \; }
sudo nft add rule inet vpnkill output ip daddr 1.1.1.0/24 oif != wg0 drop
sudo nft add rule inet vpnkill output ip daddr 8.8.8.0/24 oif != wg0 drop
# 为每个隧道化 CIDR 重复。

iptables 等价规则:

sudo iptables -I OUTPUT ! -o wg0 -d 1.1.1.0/24 -j REJECT
sudo iptables -I OUTPUT ! -o wg0 -d 8.8.8.0/24 -j REJECT

现在流向这些前缀的流量经任何非 wg0 接口都会被丢弃 — VPN 断开 = 阻断,而非泄漏。用户看到连接错误(VPN 不工作的明确信号),而不是静默经 ISP 出去。这是更安全的故障模式。

验证

ip route show | grep 10.8.0.1

您应该看到所有通过 VPN 网关路由的子网。

回滚

脚本在应用更改前会将路由表快照保存到 /tmp/route-table.<timestamp>.txt — 用于诊断变化。要删除 NetRoute Pro 添加的路由,逐个删除前缀:

for cidr in 1.1.1.0/24 8.8.8.0/24 162.159.0.0/16; do
    sudo ip route del "$cidr" 2>/dev/null || true
done

或更保守地,从 routes.sh 生成反向列表,将 replace(或 add)替换为 del

awk '/ip route /{ sub(/^ip route (replace|add)/, "ip route del"); print }' routes.sh | sudo bash

如果出现严重问题,/tmp/route-table.<timestamp>.txt 中的快照显示更改前状态 — 可手动恢复需要的部分。

常见问题

Network is unreachable

VPN 接口未启动或没有 IP。检查:

ip link show
ip addr show

Permission denied

修改路由表需要 root 权限。使用 sudo 运行脚本。

配置文件示例

带注释的可编辑模板。将示例路由替换为 NetRoute Pro 为目标网站生成的输出。


#!/bin/bash
# Example Linux routing script for split tunneling.
# Generated by NetRoute Pro: https://alexander2k.github.io/netroute-site/
#
# Run as root or with sudo. Routes added here last until reboot —
# for persistence see the Linux guide (systemd-networkd / NetworkManager).
#
# Idempotent: uses `ip route replace` so re-running the script is safe.
# `add` would fail with "RTNETLINK answers: File exists" on a duplicate;
# combined with `set -e`, the first existing route would abort the script
# and skip the rest. `replace` creates if missing, updates if present.

set -euo pipefail

DEV="wg0"          # VPN interface name (wg0, tun0, ppp0, ...)
GW="10.0.0.1"      # VPN gateway IP (or use only "dev $DEV" if VPN is point-to-point)

# Snapshot current route table — useful for rollback if something breaks.
SNAPSHOT="/tmp/route-table.$(date +%s).txt"
ip route show > "$SNAPSHOT"
echo "Route table snapshot saved to $SNAPSHOT"

ip route replace 1.1.1.0/24    via "$GW" dev "$DEV"
ip route replace 8.8.8.0/24    via "$GW" dev "$DEV"
ip route replace 162.159.0.0/16 via "$GW" dev "$DEV"

# Verify with: ip route show
# Remove a single route: ip route del <CIDR>
# Full rollback (delete all routes added by this script):
#   for cidr in 1.1.1.0/24 8.8.8.0/24 162.159.0.0/16; do
#     ip route del "$cidr" 2>/dev/null || true
#   done

提示:需要不带注释行的配置?在 NetRoute Pro 选项中取消勾选 「在导出文件中包含注释」,扩展将仅导出路由命令。适用于不支持注释的路由器。

在 GitHub 上查看所有示例 →

官方文档

准备好尝试了吗?

NetRoute Pro — 免费的 Chrome 扩展,可从任何网站生成路由。

安装扩展