You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于WireGuard(wg-quick)的特定用户VPN分流/绕过方案咨询

基于WireGuard(wg-quick)的特定用户VPN分流/绕过方案咨询

你好,针对你遇到的特定用户绕过WireGuard VPN的需求,我来帮你梳理下现有尝试的问题,并给出几个可行的解决方案:

一、先说说你之前尝试的问题所在

1. nftables标记时机错误

你之前用route hook output priority mangle设置标记,这个hook的触发时机是系统完成路由决策之后,此时数据包已经被分配到wg0接口了,再设置mark自然无法改变路由方向。要让标记生效,必须把动作放在路由决策之前。

2. 路由规则缺失回程处理

你添加的ip rule add uidrange 1003-1003 lookup main确实能让该用户的出站流量走eth0,但问题是:响应包从外网回来时,系统不知道该把它转发给uid1003的进程——因为回程包没有携带用户标识,导致流量无法正确回到发起进程,所以你看不到响应。

3. 网络命名空间的DNS问题

macvlan是二层隔离的,确实无法直接访问主机命名空间的服务(比如你的本地DNS)。要解决这个问题,换用veth pair来连接命名空间和主机就行,它支持跨命名空间的网络互通。

二、推荐的可行方案

方案1:调整nftables标记时机+完善路由规则(最直接)

既然你的WireGuard用fwmark来控制路由(wg-quick默认会添加ip rule add fwmark <wg-mark> lookup <wg-table>的规则),我们只需要让uid1003的流量避开这个标记,或者直接让它们走main路由表。

具体步骤:

  1. 先确认WireGuard的fwmark和路由表:
    执行ip rule show,你会看到类似这样的规则:

    32764:  from all fwmark 0x76BA lookup 51820
    

    这里0x76BA是WireGuard用的mark,51820是它的专用路由表。

  2. 修改nftables规则,在路由决策前给uid1003的流量设置标记:
    创建/修改nftables的mangle表规则:

    table ip mangle {
        chain outbound_mark {
            type route hook output priority -300; policy accept;
            # 给uid1003的流量设置一个自定义mark(比如0x100),优先级设为-300确保比WireGuard的处理更早
            meta skuid 1003 meta mark set 0x100;
        }
    }
    

    加载规则:nft -f <你的规则文件>

  3. 添加路由规则,让带这个mark的流量走main表:

    ip rule add fwmark 0x100 lookup main priority 100
    

    优先级设为100,确保比WireGuard的规则(通常是32764)更早生效。

  4. 处理回程流量:
    为了让响应包能正确回到uid1003的进程,需要给关联的回程包打上同样的mark,在nftables里添加:

    table ip mangle {
        chain prerouting_mark {
            type filter hook prerouting priority -300; policy accept;
            # 给已建立/关联的回程包打同样的mark,确保走main路由表
            ct state related,established meta mark set 0x100;
        }
    }
    

    这样一来,去程和回程流量都会走eth0,就能正常收发数据了。

方案2:改进网络命名空间方案(解决DNS问题)

如果你想要完全隔离的环境,把用户进程放到命名空间里,换用veth pair代替macvlan就能解决DNS访问问题。

具体步骤:

  1. 创建命名空间:

    ip netns add no_vpn_ns
    
  2. 创建veth pair(一对虚拟网卡,分别连接主机和命名空间):

    ip link add veth_host type veth peer name veth_ns
    
  3. 将veth_ns放到命名空间:

    ip link set veth_ns netns no_vpn_ns
    
  4. 配置主机侧veth的IP并启用:

    ip addr add 192.168.100.1/24 dev veth_host
    ip link set veth_host up
    
  5. 配置命名空间内的网络:

    # 设置命名空间内veth的IP
    ip netns exec no_vpn_ns ip addr add 192.168.100.2/24 dev veth_ns
    # 启用网卡
    ip netns exec no_vpn_ns ip link set veth_ns up
    # 设置默认网关为主机侧veth的IP
    ip netns exec no_vpn_ns ip route add default via 192.168.100.1 dev veth_ns
    
  6. 配置主机的NAT转发,让命名空间的流量能通过eth0访问外网:

    table ip nat {
        chain postrouting {
            type nat hook postrouting priority srcnat; policy accept;
            # 对命名空间的流量做masquerade
            oifname "eth0" ip saddr 192.168.100.0/24 masquerade;
        }
    }
    
  7. 配置命名空间的DNS:

    # 指向主机的IP,这样就能访问主机上的DNS服务了
    ip netns exec no_vpn_ns echo "nameserver 192.168.100.1" > /etc/resolv.conf
    
  8. 让用户no_vpn默认进入命名空间:
    可以写个简单的脚本,比如:

    #!/bin/bash
    ip netns exec no_vpn_ns su - no_vpn
    

    以后运行这个脚本就能直接进入命名空间的用户环境,所有流量都会绕过VPN。

方案3:修改WireGuard配置(适合深度自定义)

如果你想完全掌控路由规则,可以在/etc/wireguard/wg0.conf里添加Table = off,这样wg-quick就不会自动添加默认路由,你可以手动添加路由规则,只让特定流量走VPN,其他流量走默认的eth0。不过这个方法需要重新规划路由,适合有一定网络基础的用户。

总结

如果只是简单实现特定用户分流,方案1最直接,改动小见效快;如果需要完全隔离的环境,方案2更可靠,解决DNS问题后体验很好。

备注:内容来源于stack exchange,提问作者uhsl_m

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 23:21:13