在无 TUN / 无 iptables 的容器环境中实现内网穿透 + DNS 劫持 + SSH 代理
本文最后更新于 115 天前,其中的信息可能已经有所发展或是发生改变。

在使用某算力平台的过程中,我有一个需求,我不希望在访问我自己的服务的时候,使用我内网穿透服务器中转流量,这成本太高,我希望使用我现有的 EasyTier 虚拟网络来访问,这样走的是 P2P。

但是这个平台提供的是容器,存在以下限制:

  • 无法使用 TUN 实现透明代理
  • 无法使用 iptables 劫持 DNS 流量

因此需要一些手段。

使用 EasyTier + Mihomo 提供访问其他节点的能力

首先完成 EasyTier 组网,并使用以下配置让 EasyTier 启用 SOCK5 代理。

socks5_proxy = "socks5://127.0.0.1:1080"

这将允许其他应用通过 EasyTier 访问其他节点。

接下来,在 Mihomo 的配置中添加一个节点和代理组:

proxies:
  - name: EasyTier SOCKS5
    type: socks5
    server: 127.0.0.1
    port: 1080
    udp: true

proxy-groups:
  - name: EasyTier
    type: select
    proxies:
      - EasyTier SOCKS5

然后添加规则:

rules:
  - IP-CIDR,192.168.6.0/24,EasyTier SOCKS5,no-resolve

其中 192.168.6.0/24 是我 EasyTier 代理的子网。

经过以上操作,就能实现仅将代理的子网网段转发到 EasyTier 了。

最后设置环境变量 ALL_PROXY 设置为 Mihomo 的代理端口即可。

本地 DNS 解析

我这里使用的是 MosDNS,可以智能转发 DNS 请求,主要配置思路就是将我的域名直接返回固定的内网 IP,其他域名转发到 Mihomo 的 DNS 服务,当 Mihomo 不可用时 fallback 到上游 DNS。具体如何配置请参阅 MosDNS 官方文档。

接下来是使用 socat 将本地 53 端口转发到 MosDNS(安装 socatapt install socat):

socat UDP-LISTEN:53,fork UDP:127.0.0.1:15353 # 我这里 MosDNS 配置的监听 15353 端口

最后修改 /etc/resolv.conf

nameserver 127.0.0.1
search .

这种方法虽然仍可能出现 DNS 泄漏,但大多数情况已经能正确应对了。

SSH 配置

经过以上配置,环境已经具备了劫持指定域名、使用 P2P 访问其他节点的能力了,但是 SSH 似乎并不会使用本地 DNS,而是直接使用了上游 DNS,因此还需要对 SSH 进行配置。

首先安装 nc

sudo apt install netcat-openbsd

然后创建脚本 ~/local/bin/ssh-sock5

#!/usr/bin/env sh

host="$1"
port="$2"

# ===== 本地 DNS 解析 =====
ip=$(getent ahostsv4 "$host" | awk 'NR==1{print $1}')
[ -z "$ip" ] && exit 1

# ===== 判断是否有 ALL_PROXY =====
if [ -n "$ALL_PROXY" ]; then
    proxy="${ALL_PROXY#*://}"
    proxy="${proxy#*@}"
    proxy_host="${proxy%%:*}"
    proxy_port="${proxy##*:}"

    exec nc -x "$proxy_host:$proxy_port" "$ip" "$port"
else
    exec nc "$ip" "$port"
fi

这段脚本的能力就是,先使用本地 DNS 解析域名,然后根据是否配置了 ALL_PROXY 选择是否使用代理完成请求。

最后在 ~/.ssh/config 的最前面添加 ProxyCommand 使用这个脚本。

Host *
    ProxyCommand ~/local/bin/ssh-sock5 %h %p

改完即刻生效,经实测 git 使用 SSH 时已不再使用中转服务器,而是使用 EasyTier 的隧道。

上一篇
下一篇