#tcp-udp #dns-server #dns #tunnel #tcp #tls #udp

bin+lib tunneler

通过 TCP、(双向) TLS 或 DNS (授权服务器或直接连接) 隧道传输 TCP 或 UDP 流量

5 个版本 (3 个破坏性更新)

0.4.1 2021 年 10 月 15 日
0.4.0 2021 年 10 月 13 日
0.3.0 2021 年 9 月 22 日
0.2.0 2021 年 9 月 3 日
0.1.0 2021 年 8 月 6 日

#dns-server 中排名 35

MIT 许可协议

155KB
3.5K SLoC

Rust 3K SLoC Python 661 SLoC // 0.0% comments Shell 120 SLoC

Tunneler

本仓库包含客户端和服务器,允许您通过其他网络协议隧道传输 TCP 和 UDP 流量。

目前支持的隧道包括

  • DNS (授权服务器或直接连接)
  • TLS (双向认证)
  • TCP

主工具是用 Rust 编写的,端到端测试是用 Python 编写的。

安装

选项 1:客户端和服务器 Docker 镜像

docker pull ghcr.io/dlemel8/tunneler-server:latest
docker pull ghcr.io/dlemel8/tunneler-client:latest

选项 2:从源代码编译

cargo --version || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --release

如果您更喜欢构建本地 Docker 镜像,还可以找到Dockerfile

用法

选项 1:客户端和服务器 Docker 镜像

docker run -e LOCAL_PORT=45301 \
           -e REMOTE_PORT=5201 \
           -e REMOTE_ADDRESS=localhost \
           -e TUNNELED_TYPE=udp \
           --rm -p 45301:45301 ghcr.io/dlemel8/tunneler-server:latest tcp

选项 2:本地编译的二进制文件

./target/release/client \
  --tunneled-type tcp \
  --remote-address 1.1.1.1 \
  --remote-port 53 \
  --log-level debug \
  dns \
  --read-timeout-in-milliseconds 100 \
  --idle-client-timeout-in-milliseconds 30000

运行 Docker 镜像或编译的二进制文件,使用 --help 获取更多信息

测试

运行单元测试

cargo test --all-targets

运行端到端测试

python3 -m pip install -r e2e_tests/requirements.txt
PYTHONPATH=. python3 -m pytest -v

示例

本仓库包含一些使用 Docker Compose 部署服务器示例

  • 速度测试 - 通过所有支持的隧道公开 iperf3 服务器,允许您比较隧道速度。
  • 授权 DNS - 通过端口 UDP/53 的 DNS 隧道公开 Redis 服务器。由于隧道不验证客户端,因此需要 Redis 认证。
  • 管道 - 通过 TLS 隧道公开 Redis 服务器,该 TLS 隧道本身通过 DNS 隧道公开。由于隧道验证客户端,因此不使用 Redis 认证。

您可以在本地运行每个示例或使用 Terraform 和 Ansible 部署它。更多信息请参阅 此处

架构

架构 每个可执行文件包含 2 个组件,通过客户端流通道(字节读取器和写入器的元组)进行通信

  • 客户端监听器绑定套接字并将传入和传出流量转换为新的流。
  • 客户端隧道器将流读取器和写入器转换为隧道协议。
  • 服务器隧道解绑根据隧道协议绑定套接字,并将隧道流量转换回原始流。
  • 服务器转发器将流写入器和读取器转换回流量。

基于TCP的流量可以简单地转换为流。基于UDP的流量转换取决于隧道协议。

基于UDP的流量还需要一种方法来识别现有客户端以继续其会话。解决方案是一个内存中的客户端缓存,它将客户端的标识符映射到其流。

协议

隧道UDP

为了将UDP流量转换为流,每个数据包的有效负载前有一个2字节大小的头(大端序)。

UDP监听器使用传入数据包的对等地址作为其客户端缓存的关键。

DNS隧道

这里我们有一些挑战

  • DNS负载必须是字母数字的。
  • 在我们可以发送下一条消息之前,每个消息都需要一个响应。
  • 每个DNS查询都使用随机源端口和事务ID,因此我们不能将它们用作客户端缓存键。

为了解决这些挑战,每个客户端会话从生成一个随机的客户端ID(4个字母数字字符)开始。客户端读取要隧道的数据,并通过编码器管道运行。

  • 数据以十六进制编码。
  • 客户端ID被附加。
  • 客户端后缀被附加。如果服务器运行在您的授权DNS服务器上,后缀是".<your domain>"。

编码数据被用作TXT DNS查询的名称。

如果您拥有授权DNS服务器,客户端可以将请求发送到递归DNS解析器。解析器将从您的域名注册商那里获取您的IP并将请求转发到您的IP。另一个选项(更快但更容易被任何流量分析器察觉)是配置客户端直接将请求发送到您的IP(在UDP/53或服务器监听的任何其他端口)。

服务器解码数据(忽略任何非客户端流量)并使用客户端ID作为其客户端缓存的关键。

为了处理大量服务器响应和空的TCP ACK,客户端和服务器都使用了读取超时。如果读取超时已过期,将发送空消息。客户端和服务器都使用空闲超时来停止转发并清理本地资源。

TLS隧道

为了实现相互认证,我们使用一个私有证书颁发机构

  • 从私有密钥生成自签名CA证书。
  • 服务器私有密钥是随机生成的,其公共部分用于由CA证书签名的证书。
  • 客户端私有密钥是随机生成的,其公共部分用于由CA证书签名的证书。

客户端和服务器都配置为在TLS握手中使用他们的密钥和证书。CA证书用作根证书。

由于使用了服务器名称指示扩展,客户端正在请求特定的服务器名称,并且只有在请求该名称时,服务器才会提供其证书。服务器名称也必须是证书的一部分,例如作为主题备用名称。

依赖项

~22–35MB
~629K SLoC