示例中的域名、地址和接口名需要按自己的部署替换。
我需要把部分 Xray 出站送进 WireGuard/WARP,同时保留服务器原来的网络出口。这类配置的关键是区分应用连接的 mark与WireGuard 外层 UDP 包的 FwMark,再分别处理 IPv4 和 IPv6 的策略路由。
本文针对 Linux wg-quick,假设已有能握手的 wgcf.conf。WARP 的注册、地址和 Endpoint 由自己的有效配置提供,不使用本文的占位值注册账号。这里不比较内核 WireGuard、warp-go 或代理内置实现的性能;速度和兼容性要在具体版本与网络上测量。
两个 mark 与一张路由表
下面统一使用:
| 项目 | 值 | 作用 |
|---|---|---|
| 应用连接 mark | 51820 |
Xray 给选定的出站 socket 设置 SO_MARK |
| 路由表 | 51820 |
保存指向 wgcf 的默认路由 |
| WireGuard FwMark | 51821 |
标记发往 Endpoint 的外层 UDP 包,避免再次送回隧道 |
路由表号与 mark 是两种不同的对象,这里应用 mark 和表号相同只是方便记忆。FwMark 不会自动给经过隧道的所有业务包打上同一个应用 mark。wg 与 wg-quick 手册
先用 ip -4/-6 rule 和 ip -4/-6 route show table 51820 确认优先级 100、110 及表号没有被其他工具占用。多个隧道、TPROXY、容器网络要分配不同编号。PostUp 中途失败可能留下已经添加的规则,不能假定 wg-quick 会完整回滚;按实际成功项执行对应删除,再重新读取路由和规则,不要盲目重复 up。以下手动方案的接口字段为:
[Interface]
PrivateKey = YOUR_EXISTING_PRIVATE_KEY
Address = YOUR_EXISTING_IPV4_ADDRESS, YOUR_EXISTING_IPV6_ADDRESS
Table = off
FwMark = 51821
[Peer]
PublicKey = YOUR_EXISTING_PEER_PUBLIC_KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = YOUR_EXISTING_ENDPOINT
保留原配置中的必要字段。Table = off 只关闭 wg-quick 自动添加路由,不改变 Peer 的 AllowedIPs;接口、规则和路由仍由下面的 hooks 管理。
四种场景
1. IPv4 与 IPv6 都只接管选定的出站
将下面内容放在 [Interface] 内。未打 mark 的连接继续使用原来的路由,只有 mark 为 51820 的连接查表 51820。
PostUp = ip -4 route add default dev %i table 51820
PostUp = ip -4 rule add pref 100 fwmark 51820 lookup 51820
PostUp = ip -6 route add default dev %i table 51820
PostUp = ip -6 rule add pref 100 fwmark 51820 lookup 51820
PostDown = ip -4 rule del pref 100 fwmark 51820 lookup 51820
PostDown = ip -4 route del default dev %i table 51820
PostDown = ip -6 rule del pref 100 fwmark 51820 lookup 51820
PostDown = ip -6 route del default dev %i table 51820
这里不能额外加入 not fwmark 51821 lookup 51820,否则该地址族的普通连接也会被接管。旧版“IPv6 不接管全局”的示例包含这种兜底规则,实际行为与标题不符。
2. IPv4 与 IPv6 都接管默认路由
这种需求优先使用 wg-quick 的自动路由:把 Table = off 改为 Table = auto,删除所有手动路由 hooks,保留 AllowedIPs = 0.0.0.0/0, ::/0。wg-quick 会为默认路由配置策略路由,并处理 Linux IPv4 的 mark/回程相关防火墙设置。FwMark 可以保持 51821,此时自动模式所用的表号由它决定,不再按手动方案假定为 51820。
全局默认路由仍会保留主表中的更具体路由,例如直连 LAN 和静态路由。它不是阻止隧道断开后流量回到物理出口的 kill switch;需要该行为时另行配置防火墙。
3. IPv4 只接管选定出站,IPv6 接管默认路由
保留 Table = off,使用如下 hooks:
PostUp = ip -4 route add default dev %i table 51820
PostUp = ip -4 rule add pref 100 fwmark 51820 lookup 51820
PostUp = ip -6 route add default dev %i table 51820
PostUp = ip -6 rule add pref 100 lookup main suppress_prefixlength 0
PostUp = ip -6 rule add pref 110 not fwmark 51821 lookup 51820
PostDown = ip -4 rule del pref 100 fwmark 51820 lookup 51820
PostDown = ip -4 route del default dev %i table 51820
PostDown = ip -6 rule del pref 110 not fwmark 51821 lookup 51820
PostDown = ip -6 rule del pref 100 lookup main suppress_prefixlength 0
PostDown = ip -6 route del default dev %i table 51820
IPv6 先保留主表里的非默认路由,其他普通连接进入隧道;FwMark 51821 的外层包跳过隧道规则,继续使用物理默认路由。
4. IPv4 接管默认路由,IPv6 只接管选定出站
PostUp = ip -4 route add default dev %i table 51820
PostUp = ip -4 rule add pref 100 lookup main suppress_prefixlength 0
PostUp = ip -4 rule add pref 110 not fwmark 51821 lookup 51820
PostUp = ip -6 route add default dev %i table 51820
PostUp = ip -6 rule add pref 100 fwmark 51820 lookup 51820
PostDown = ip -4 rule del pref 110 not fwmark 51821 lookup 51820
PostDown = ip -4 rule del pref 100 lookup main suppress_prefixlength 0
PostDown = ip -4 route del default dev %i table 51820
PostDown = ip -6 rule del pref 100 fwmark 51820 lookup 51820
PostDown = ip -6 route del default dev %i table 51820
这是手动配置 IPv4 全局路由,不能自动获得 wg-quick Table=auto 的所有配套防火墙行为。若出现握手正常但回包被丢弃,要检查 rp_filter、mark 保存/恢复与现有防火墙:严格反向路径过滤可能不适合这种非对称路由。按实际接口选用 loose mode 或实现相应 connmark 规则,不要清空整机防火墙来排障。wg-quick Linux 实现、Linux rp_filter 与 src_valid_mark
Xray 选择出站
在已有配置中添加一个带 mark 的 Freedom 出站,再让需要 WARP 的 routing 规则指向 warp-out。下面是严格 JSON 的出站片段:
{
"outbounds": [
{
"tag": "warp-out",
"protocol": "freedom",
"settings": {},
"streamSettings": {
"sockopt": {
"mark": 51820,
"domainStrategy": "UseIP"
}
}
}
]
}
SO_MARK 只适用于 Linux,服务必须拥有所需的 CAP_NET_ADMIN 权限;应用配置文件能解析不代表操作系统一定允许设置 socket mark。IPv4/IPv6 的选择还取决于 DNS 策略和目标是否有相应记录,不能靠路由表创造不存在的地址。Xray Sockopt
Xray 也支持 sockopt.interface = "wgcf",但绑定接口不会替代路由、Peer AllowedIPs 和地址族检查。本文以 mark 为主线,避免把不同内核的接口绑定行为混在同一份配置里。DNS 查询有独立的出站选择,业务走 WARP 也不表示解析一定走 WARP。
检查路由与回程
wg show wgcf
ip -4 rule
ip -6 rule
ip -4 route show table 51820
ip -6 route show table 51820
ip -4 route get 1.1.1.1
ip -4 route get 1.1.1.1 mark 51820
ip -6 route get 2606:4700:4700::1111
ip -6 route get 2606:4700:4700::1111 mark 51820
curl -4 --noproxy '*' https://api.ipify.org
curl -6 --noproxy '*' https://api6.ipify.org
手动模式下还要用实际 Endpoint IP 检查 ip route get 地址 mark 51821,确认外层 UDP 不回到 wgcf。通过 Xray 客户端访问查询地址,才是在检查带 mark 的出站;直接运行未打 mark 的 curl 只能验证普通系统出口。curl --interface wgcf 也不能证明策略规则已正确生效。
全局接管后,公网 SSH/服务响应可能从隧道回去。需要保留管理回程时,在优先级 100 之前增加匹配实际公网源地址的主表规则,并配置对应清理 hook;例如 ip -6 rule add pref 90 from 2001:db8::10/128 lookup main 中的文档地址必须替换成服务器真实地址。这会让该源地址的连接绕过 WARP,需要明确接受这个例外。
IPv6 不通时依次检查原生出口、隧道握手、地址、路由与防火墙;启用转发而出口依赖 RA 时检查物理接口 accept_ra。不要仅凭故障现象关闭所有 RA,也不要反复重启代替检查。四种方案都应从控制台应用,并验证隧道停止后规则被清理,避免远程连接因路由变化失去回程。
评论区