ArchLinux下NetworkManager导入OpenVPN及Mihomo分流配置
在 Linux (以 Arch 为例) 使用 NetworkManager 管理 OpenVPN 时,默认配置往往会强制接管所有流量,导致与 Mihomo (Clash) 等代理软件冲突。 本文记录如何优雅地将 OpenVPN 配置文件导入 NetworkManager,并通过脚本提取路由表,实现精确分流:既能访问公司/内网资源,又不影响梯子和日常外网访问。
组件安装
首先确保 NetworkManager 具备 OpenVPN 支持。
sudo pacman -S networkmanager-openvpn --noconfirm --needed
导入与配置连接
拿到 .ovpn 文件后,不要直接用 openvpn 命令启动,建议导入 NetworkManager 管理。
导入配置文件
# 将 profile-599.ovpn 替换为你的文件名
nmcli connection import type openvpn file profile-599.ovpn
关键配置(防流量接管)
这是最重要的一步。导入后,必须禁止 VPN 服务器下发 0.0.0.0/0 默认路由,否则所有流量(包括 YouTube、Google)都会被吸入 VPN 隧道。
<连接名>通常就是导入时的文件名(不带后缀),可以用nmcli c show查看。
# 禁止 VPN 成为默认网关
nmcli connection modify <连接名> ipv4.never-default yes
# 预设用户名
nmcli connection modify <连接名> vpn.user-name <用户名>
# 启动连接
nmcli connection up <连接名> --ask
提取分流网段
当系统中运行着 Mihomo (Tun模式) 时,我们需要将 VPN 服务器 IP 和 VPN 推送的内网网段 加入到 Mihomo 的
fake-ip-filter 或直接分流规则中,防止流量回环或被误代理。
手动查看路由表太麻烦,这里写了个脚本 explain-openvpn-routes.sh,直接解析 NM 的连接信息并分类输出。
创建脚本
创建文件 explain-openvpn-routes.sh 并赋予执行权限:
cat <<\EOF> explain-openvpn-routes.sh && chmod +x explain-openvpn-routes.sh
#!/bin/bash
# 读取输入
INPUT=$(cat "${1:-/dev/stdin}")
# 表头
printf "%-20s %-30s\n" "IP/网段" "描述 (类型)"
printf "%-20s %-30s\n" "--------------------" "------------------------------"
# 临时文件用于存放处理结果,以便最后统一排序输出
TEMP_OUTPUT=$(mktemp)
# ==========================================
# 1. 提取 VPN 服务器地址 (最高优先级)
# ==========================================
# 提取 remote 字段中的 IP
SERVER_IPS=$(echo "$INPUT" | grep "remote =" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | sort -u)
for ip in $SERVER_IPS; do
# 统一加上 /32 后缀
printf "%-20s %-30s\n" "${ip}/32" "VPN服务器 (连接必须)" >> "$TEMP_OUTPUT"
done
# ==========================================
# 2. 提取 VPN 推送的路由表 (IP4.ROUTE)
# ==========================================
ROUTES=$(echo "$INPUT" | grep "IP4.ROUTE" | sed -n 's/.*dst = \([0-9./]\+\).*/\1/p' | sort -u)
for cidr in $ROUTES; do
# 提取 IP 的第一段和第二段用于判断 (例如 172.27)
ip_addr=${cidr%%/*}
IFS='.' read -r oct1 oct2 oct3 oct4 <<< "$ip_addr"
# 判断是否为 VPN 服务器 (避免重复)
if echo "$SERVER_IPS" | grep -q "$ip_addr"; then
continue
fi
# 判断是否为私有内网地址 (RFC 1918)
# 10.0.0.0/8
# 172.16.0.0/12 (172.16 - 172.31)
# 192.168.0.0/16
is_private=0
if [[ "$oct1" -eq 10 ]]; then
is_private=1
elif [[ "$oct1" -eq 172 && "$oct2" -ge 16 && "$oct2" -le 31 ]]; then
is_private=1
elif [[ "$oct1" -eq 192 && "$oct2" -eq 168 ]]; then
is_private=1
fi
if [[ "$is_private" -eq 1 ]]; then
printf "%-20s %-30s\n" "$cidr" "VPN内网 (办公网/服务器)" >> "$TEMP_OUTPUT"
else
printf "%-20s %-30s\n" "$cidr" "VPN专用公网 (云服务/白名单)" >> "$TEMP_OUTPUT"
fi
done
# 输出结果并排序 (让相同描述的在一起,看起来更整洁)
cat "$TEMP_OUTPUT" | sort -k 2
rm "$TEMP_OUTPUT"
EOF
使用方法
通过 nmcli 获取连接详情,并通过管道传给脚本:
nmcli connection show <连接名> | ./explain-openvpn-routes.sh
输出示例
脚本会输出类似如下内容:
IP/CIDR 类型说明
---------------------- ------------------------------
203.0.113.5/32 VPN服务器 (必须直连)
10.8.0.0/24 VPN内网 (办公网/服务器)
172.16.100.0/24 VPN内网 (办公网/服务器)
1.1.1.1/32 VPN专用公网 (云服务/白名单)
拿到这份列表后,你就可以将这些网段配置到 Mihomo Party 或其他代理软件的 Exclude Custom Networks 中,确保这些流量由系统路由表处理,而不是被代理软件劫持。