背景

  • 组网拓扑:本机(Mac)通过 EasyTier 虚拟网连接一台 Linux 网关节点,该节点所在局域网内有一台 GitLab 服务器。
  • 目标:在 Mac 浏览器中直接访问 GitLab 的 Web 页面和 git 服务。
  • 方案选型:使用 EasyTier 的子网代理(subnet proxy)功能,让网关节点把 GitLab 地址代理进虚拟网。相比逐端口转发,一次配置全局受益,浏览器、HTTP、SSH 全部透明可用。

过程

(1)声明代理网段

在已通过 easytier 连接的 Linux 节点上的 easytier 配置文件中加入:

1
2
[[proxy_network]]
cidr = "GITLAB_IP/32"

需要注意的是:子网代理支持多个 cidr(多个 [[proxy_network]] 段),掩码为 /32 时可以只代理单台主机。

修改后重启服务,并在两个层面确认配置真正生效:

1
2
3
4
5
# 本节点应看到 Proxy CIDRs 列出代理网段
sudo easytier-cli node

# 所有节点都会自动学到这条路由,proxy_cidrs 列应显示代理网段
sudo easytier-cli route

(2)开启内核 IP 转发

子网代理的本质是网关节点把虚拟网流量转发到局域网,Linux 默认不转发数据包,必须显式开启:

1
2
3
4
5
# 运行时生效
sudo sysctl -w net.ipv4.ip_forward=1

# 持久化:写入独立配置文件,重启后依然生效
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-ipforward.conf

验证:

1
2
sysctl net.ipv4.ip_forward
# 输出 net.ipv4.ip_forward = 1 即为开启

(3)配置防火墙地址伪装

来自虚拟网的流量源地址是虚拟网段(如 10.x.x.x),局域网内的被代理主机不认识这个网段,通常会因为路由不可达或防火墙策略丢弃。需要在网关节点把转发流量的源地址伪装成网关自己的内网地址。

以 firewalld 为例:

1
2
3
4
5
6
# public zone 开启 masquerade
sudo firewall-cmd --zone=public --add-masquerade --permanent
sudo firewall-cmd --reload

# 确认已开启,输出 yes
sudo firewall-cmd --zone=public --query-masquerade

注意:firewalld 使用 nftables 后端,iptables 命令看不到这些规则,验证要用 sudo nft list ruleset 查找 masquerade 条目。

另外一个容易忽略的点:虚拟网卡(如 tun0)默认没有被 firewalld 划入任何 zone,如果流量被默认丢弃策略拦下,可显式将其加入 public zone:

1
2
sudo firewall-cmd --zone=public --add-interface=tun0 --permanent
sudo firewall-cmd --reload

配置生效后,Mac ping GitLab 地址正常,但 curl 访问 Web 端口直接超时,分层排查为:

  1. Mac 本机:无代理环境变量干扰,路由表已正确学到代理网段(目标地址指向 EasyTier 虚拟网卡)。
  2. 网关节点:已开启 IP 转发并持久化,firewalld 已开启 masquerade(ICMP 抓包确认源地址伪装正常)。
  3. 关键实验:从网关节点本机 curl GitLab 正常返回,从另一台虚拟网节点 curl 同样超时,且在网关节点物理网卡上完全抓不到 TCP 包,即 SYN 包根本没到达网关。

现象特征: ICMP 能走通整条链路并被正确伪装转发,TCP 的 SYN 却在 EasyTier 内部凭空消失。

查证后确认这是 EasyTier 的已知缺陷(issue #1355):子网代理节点使用内核网络栈时,内置 NAT 在处理 TCP 回包时会改错源地址和端口,导致内核 TCP 连接跟踪不匹配、会话被 RST 终止;ICMP 不走 TCP 连接跟踪,所以幸免。

(4)启用用户态网络栈

解决方案: 在网关节点配置的 [flags] 中启用用户态网络栈:

1
2
[flags]
use_smoltcp = true

修改后重启服务,Mac 访问 GitLab 的 80 端口立即恢复,git SSH 端口也验证连通。

(5)端到端验证

回到发起访问的客户端节点逐项验证:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# ICMP 层:路由已通
ping GITLAB_IP

# TCP 层:Web 服务,出现 302 跳转或 200 即为成功
curl -sk -o /dev/null -w "%{http_code}\n" http://GITLAB_IP

# git 服务(SSH 协议):看到 GitLab 欢迎信息即成功
ssh git@GITLAB_IP

# 浏览器直接访问 http://GITLAB_IP

常见异常对照:

  • ping 不通:检查网关节点 proxy_cidrs 是否同步(easytier-cli route)、内核 IP 转发是否开启
  • ping 通但 TCP 超时:大概率命中内核栈 NAT 缺陷,启用 use_smoltcp;同时确认防火墙 masquerade 已开启
  • TCP 通但页面跳转到错误地址:GitLab 的 external_url 配置的是内网主机名或 IP,需在客户端 /etc/hosts 增加解析,或调整 external_url