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
155KB
3.5K 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