Linux 下解决 Netbird 和 Mihomo(Tun Mode) 共存问题

在 Linux 上同时跑 NetBird(组网)和 Mihomo(Tun Mode)时,两个工具都会接管路由。结果是 NetBird 能连接,但一直停在中继(Relayed)模式,无法建立点对点(P2P)直连。有时甚至连中继也连不上。

问题背景

  • OS: Arch Linux
  • NetBird: 使用默认的内核模式 (Kernel Mode)
  • Mihomo: 开启 TUN 模式,接管系统流量
  • 现象: netbird status -d 显示连接类型为 Relayed,ICE 协商失败,延迟高且无法打洞。

关键信息的获取

在实施方案前,必须确认 NetBird 实际监听的 WireGuard 端口。

获取 NetBird 监听端口的方法:

sudo cat /var/lib/netbird/default.json | grep WgPort

通常默认是 51820。如果显示为 0 或其他,建议手动修改该文件固定为 51820 并重启服务。

如果你安装了 wireguard-tools,也可以通过以下命令验证内核接口的实际端口:

sudo wg show wt0 listen-port

最终解决方案

核心路由思路

  1. Mark: 在 Output 链识别源端口为 51820 的 UDP 包,打上标记 0x100
  2. Route: 通过策略路由,强制带有 0x100 标记的包走主路由表 (main),绕过 Mihomo。
  3. Masquerade: 在 Postrouting 链对标记包做源地址伪装,修复被 Mihomo 改过的源 IP,让包看起来是从物理网卡发出的。

操作步骤

使用 Systemd 配置来持久化这些规则,执行下方命令。

sudo mkdir -p /etc/systemd/system/netbird.service.d/
echo "[Service]
# --- 1. 基础环境 ---
# 既然用了内核模式,这里不需要任何 Environment 变量 (如 NB_WG_KERNEL_DISABLED)

# --- 2. 核心修复:给 NetBird 流量打标记 (Mangle Output) ---
# 作用:识别出从 51820 端口发出的所有加密包,打上 0x100 标记
ExecStartPost=/usr/bin/iptables -t mangle -A OUTPUT -p udp --sport 51820 -j MARK --set-mark 0x100
ExecStartPost=/usr/bin/ip6tables -t mangle -A OUTPUT -p udp --sport 51820 -j MARK --set-mark 0x100

# --- 3. 核心修复:策略路由 (Policy Routing) ---
# 作用:看到 0x100 标记的包,强制走物理网卡 (main 表),直接绕过 Mihomo
ExecStartPost=/usr/bin/ip rule add fwmark 0x100 lookup main prio 50
ExecStartPost=/usr/bin/ip -6 rule add fwmark 0x100 lookup main prio 50

# --- 4. 核心修复:源地址伪装 (NAT Masquerade) ---
# 作用:修复被 Mihomo 改写的源 IP (198.18...),将其改回物理网卡真实 IP,确保 P2P 回包能收到
ExecStartPost=/usr/bin/iptables -t nat -A POSTROUTING -m mark --mark 0x100 -j MASQUERADE
ExecStartPost=/usr/bin/ip6tables -t nat -A POSTROUTING -m mark --mark 0x100 -j MASQUERADE

# --- 5. 停止后清理 (Cleanup) ---
# 作用:保持系统整洁,防止规则堆积
ExecStopPost=/usr/bin/iptables -t mangle -D OUTPUT -p udp --sport 51820 -j MARK --set-mark 0x100
ExecStopPost=/usr/bin/ip6tables -t mangle -D OUTPUT -p udp --sport 51820 -j MARK --set-mark 0x100
ExecStopPost=/usr/bin/ip rule del fwmark 0x100 lookup main prio 50
ExecStopPost=/usr/bin/ip -6 rule del fwmark 0x100 lookup main prio 50
ExecStopPost=/usr/bin/iptables -t nat -D POSTROUTING -m mark --mark 0x100 -j MASQUERADE
ExecStopPost=/usr/bin/ip6tables -t nat -D POSTROUTING -m mark --mark 0x100 -j MASQUERADE
" | sudo tee /etc/systemd/system/netbird.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart netbird

还需要配置 Mihomo,在 tun 部分增加如下配置

tun:
  exclude-interface:
    - wt0
  endpoint-independent-nat: true
  inet4-route-exclude-address:
    - 100.64.0.0/10
  inet6-route-exclude-address:
    - fd00::/8

重启 mihomo

验证结果

稍等片刻,运行状态检查:

sudo netbird status -d

此时你应该能看到:

  • Interface type: Kernel
  • Connection type: P2P (不再是 Relayed)