在折腾 HomeLab 的过程中,我们经常会遇到各种奇怪的网络现象。

最近我在调试 Proxmox VE (PVE) 网络时发现了一个非常有趣的案例:我的 LXC 容器配置了一个看似“错误”的 DNS,却在旁路由环境下跑得飞快;而一旦切换回主路由,网络瞬间断连。

这背后的原理,其实是一个关于“路径依赖”和“DNS 劫持”的精彩故事。

现象描述

我的网络环境是这样的:

  • 宿主机:PVE,安装了 Tailscale。
  • 容器:若干 LXC 容器(未安装 Tailscale)。
  • 网关:指向旁路由(跑着 mihomo 核心组件)。
  • DNS 设置:PVE 和 LXC 的 DNS 都填了 100.100.100.100

奇怪的现象:

  1. 当网关指向旁路由时,LXC 容器可以正常上网,甚至可以访问外网。
  2. 一旦我将 LXC 的网关指向主路由(普通硬路由),LXC 立刻无法上网。

核心疑问

熟悉 Tailscale 的朋友都知道,100.100.100.100 是 Tailscale 的 MagicDNS 专用 IP。它只存在于安装了 Tailscale 的设备的虚拟网卡(tailscale0)上。

问题来了: 我的 LXC 容器根本没有安装 Tailscale,它没有虚拟网卡,理论上它根本不认识 100.100.100.100,也不可能 ping 通这个 IP。

那为什么在旁路由下,它居然能用这个 IP 解析域名并上网呢?

原理解析:一场完美的“欺骗”

真相是:你的 LXC 容器从来没有真正连接到 100.100.100.100,它只是被旁路由“劫持”了。

1. 旁路由模式下的数据流(The Hijack)

当你配置网关为旁路由时,DNS 解析过程是这样的:

  1. 发起请求:LXC 想访问 google.com,它根据配置,向 100.100.100.100:53 发送了一个 UDP 数据包。
  2. 路由查找:LXC 查路由表,发现自己不在 100.x.x.x 网段,于是把包扔给了网关(旁路由)。
  3. 强制劫持:旁路由收到这个包。由于旁路由上运行着 mihomo,这类工具通常默认开启了 DNS 劫持 (DNS Hijacking) 功能(如 Redir-Host 或 Fake-IP 模式的配合)。
    • mihomo 的逻辑是:“我不管你想发给谁,只要是 53 端口的 DNS 查询,统统扣下!”
  4. 代为解析:旁路由扣下请求,用它自己内置的 DNS 策略去解析 google.com
  5. 伪造回复:旁路由拿到 IP 后,伪装100.100.100.100 的身份,把结果发回给 LXC。

结果:LXC 以为是 MagicDNS 回答了它,实际上是旁路由演了一出戏。

2. 主路由模式下的数据流(The Crash)

当你把网关切回主路由(通常是光猫或普通路由器)时,保护层消失了:

  1. 发起请求:LXC 依然顽固地向 100.100.100.100:53 发起请求。
  2. 路由转发:主路由收到包。它没有 mihomo 的 DNS 劫持功能,它很老实。它看着目标 IP 100.100.100.100(这属于 Carrier Grade NAT 保留段),以为你要访问公网上的某台机器。
  3. 丢弃/超时:主路由把包扔给运营商(ISP)。运营商一看这奇怪的内网保留 IP,直接丢弃(或者发出去也没人理)。
  4. 断连:LXC 等不到回应,DNS 解析超时(Timeout),导致无法上网。

为什么这很危险?

这种配置方式虽然能用,但它是一种脆弱的路径依赖

你的网络可用性完全建立在“旁路由必须开启 mihomo 劫持”这个前提下。一旦旁路由挂了、mihomo 没启动,或者你想临时切回主路由排除故障,你的所有 LXC 容器网络会瞬间全崩。

这就像你的车其实没有轮子,全靠底下的传送带在拖着跑。一旦离开传送带,车就动不了了。

最佳实践方案

为了让网络更健壮,我们应该让 LXC 使用“真实存在”的 DNS。

方案一:回归通用(推荐)

将 LXC 的 DNS 修改为公共 DNS。这样无论走主路由还是旁路由,都能解析。

  • 国内223.5.5.5 (阿里云), 119.29.29.29 (腾讯云)
  • 国外8.8.8.8, 1.1.1.1

效果

  • 走旁路由时:依然会被劫持去走 mihomo 代理(因为 53 端口劫持通常是全局的),不影响 mihomo 的分流规则。
  • 走主路由时:正常连接阿里云 DNS,不影响国内上网。

方案二:指向局域网 DNS

如果你希望保留一些局域网解析功能,可以将 LXC 的 DNS 指向主路由的 LAN IP 或者 旁路由的 LAN IP(例如 192.168.1.1)(需要旁路由开启dns请求接受功能)。

方案三:只有一种情况该用 100.100.100.100

只有当你在 LXC 容器内部 也安装了 Tailscale 客户端,并且你确实需要使用 MagicDNS 解析 my-server.tailnet.ts.net 这种域名时,才应该在容器里填 100.100.100.100

总结

看似玄学的网络故障,往往源于我们对数据包流向的误解。

  • PVE 宿主机可以用 100.100.100.100,因为它真的装了 Tailscale。
  • LXC 容器不该用 100.100.100.100,除非它也装了。
  • 旁路由就像一个爱管闲事的中间人,它掩盖了配置错误,但也带来了脆弱性。

记住:不要依赖网络设备的“副作用”来维持网络的连通性。

Leave a comment