Skip to content

Commit

Permalink
update v2
Browse files Browse the repository at this point in the history
  • Loading branch information
ihciah committed Oct 2, 2022
1 parent 277907e commit 229a567
Show file tree
Hide file tree
Showing 16 changed files with 1,263 additions and 314 deletions.
Binary file added .github/resources/shadow-tls.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
109 changes: 96 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
[package]
authors = ["ihciah <[email protected]>"]
description = "A proxy to expose real tls handshake to the firewall."
edition = "2021"
keywords = ["proxy", "tls", "shadowsocks"]
license = "MIT/Apache-2.0"
name = "shadow-tls"
version = "0.1.0"
readme = "README.md"
repository = "https://github.com/ihciah/shadow-tls"
version = "0.2.0"

[dependencies]
monoio = {version = "0.0.8"}
monoio-rustls = {version = "0.0.6"}

anyhow = "1"
clap = {version = "3", features = ["derive"]}
hmac = "0.12"
pin-project-lite = "0.2"
rustls = {version = "0.20", default-features = false}
sha1 = "0.10"
tracing = "0.1"
tracing-subscriber = "0.3"
webpki-roots = "0.22"

[features]
default = ["zero-copy"]

# Relay data with splice syscall for linux.
zero-copy = ["monoio/splice"]

[profile.release]
lto = true
opt-level = 3
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ENV LISTEN=""
ENV SERVER=""
ENV TLS=""
ENV THREADS=""
ENV PASSWORD=""

COPY ./entrypoint.sh /
RUN chmod +x /entrypoint.sh && apk add --no-cache ca-certificates
Expand Down
40 changes: 37 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,49 @@
# Shadow TLS
一个**可以使用别人的受信证书**的 TLS 伪装代理。

它和 [trojan](https://github.com/trojan-gfw/trojan) 的表现类似,但它在做真实 TLS 握手的同时,可以直接使用别人的受信证书(如某些大公司或机构的域名),而不需要自己签发证书。当直接使用浏览器打开时,可以正常显示对应可信域名的网页内容。

---

A proxy to expose real tls handshake to the firewall.

It works like [trojan](https://github.com/trojan-gfw/trojan) but it does not require signing certificate. The firewall will see **real** tls handshake with **valid certificate** that you choose.

## Run
Check comments in `docker-compose.yml`.
## How to Use It
这个服务需要双边部署,并且它一般需要搭配一个加密代理(因为本项目不包含数据加密和代理请求封装功能,这不是我们的目标)。

通常,你可以在同机部署 shadowsocks-server 和 shadowtls-server;之后在防火墙的另一端部署 shadowsocks-client 和 shadowtls-client。

有两种方式部署这个服务。
1. 使用 Docker + Docker Compose

修改 `docker-compose.yml` 后直接 `docker-compose up -d`
2. 使用预编译的二进制

[Release 页面](https://github.com/ihciah/shadow-tls/releases)下载对应平台的二进制文件, 然后运行即可。运行指南可以 `./shadow-tls client --help``./shadow-tls server --help` 看到。
---

Normally you need to deploy this service on both sides of the firewall. And it is usually used with an encryption proxy (because this project does not include encryption and proxy request encapsulation, which is not our goal).

1. Run with Docker + Docker Compose
Modfy `docker-compose.yml` and run `docker-compose up -d`.

2. Use prebuilt binary
Download the binary from [Release page](https://github.com/ihciah/shadow-tls/releases) and run it.


## How it Works
On client side, just do tls handshake. And for server, we have to relay data as well as parsing tls handshake to handshaking server which will provide valid certificate. We need to know when the tls handshaking is finished. Once finished, we can relay data to our real server.

[Full design doc is here](./docs/protocol-en.md).

[完整的协议设计点这](./docs/protocol-cn.md).

## Note
This project relies on [Monoio](https://github.com/bytedance/monoio) which is a high performance rust async runtime with io_uring. However, it does not support windows yet. So this project does not support windows.

However, if this project is used widely, we will support it by conditional compiling.
However, if this project is used widely, we will support it by conditional compiling.

Also, you may need to [modify some system limitations](https://github.com/bytedance/monoio/blob/master/docs/en/memlock.md) to make it work. If it does not work, you can add environ `MONOIO_FORCE_LEGACY_DRIVER=1` to use epoll instead of io_uring.

你可能需要修改某些系统设置来让它工作,[参考这里](https://github.com/bytedance/monoio/blob/master/docs/en/memlock.md)。如果它不起作用,您可以添加环境变量 `MONOIO_FORCE_LEGACY_DRIVER=1` 以使用 epoll 而不是 io_uring。
4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ services:
- LISTEN=
- SERVER=
- TLS=
- PASSWORD=

# Mode: client or server
# LISTEN: local listen address with port
# SERVER: remote address with port
# TLS: server name in sni for client mode(like xxx.com.cn)
# server address with port for server mode(like xxx.com.cn:443)
# THREADS(optional): set threads number
# PASSWORD: shadow-tls password
# THREADS(optional): set threads number
60 changes: 60 additions & 0 deletions docs/protocol-cn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
title: ShadowTLS 协议设计
date: 2022-10-02 11:00:00
author: ihciah
---

# 协议

ShadowTLS 协议有两个版本。

第一个版本是一个简单的协议,只能将真正的 TLS 握手暴露给中间人,但不能防御主动检测,而且 TLS 握手后的流量也很容易区分。

第二个版本比较复杂,但是可以防御主动检测,tls握手后的流量很难区分。如果攻击者使用浏览器访问服务端,它能将像真正的 Web 服务器一样工作。

![protocol design](../.github/resources/shadow-tls.png)

## V1
在这个版本中,我们只想让中间人观测到 TLS 握手,并且握手使用其他人的合法证书。这是我们最初的目标。

中间人将看到有效的受信任证书的握手流量。如果假设中间人不会主动探测,并且不会分析在 TLS 握手完成后的流量,这个版本可以用来防御:
1. 基于流量特征的封锁:我们看起来像正常的 TLS 流量,而不是 shadowsocks 那样的无法理解的随机数据。
2. 基于 SNI 的封锁:我们使用合法且受信任的证书(比如可能某些大型公司或政府机构的域名是被标记为受信任的),因此会被认为是合法数据。

V1 版本的最后一个实现是 [v0.1.4](https://github.com/ihciah/shadow-tls/releases/tag/v0.1.4).

### 客户端
客户端连接服务器并进行 TLS 握手。握手后,所有客户端流量将不加修改地发送到服务器(包括加密和数据封装等)。

1. 与 example.trusted-server.domain 进行 TLS 握手。
2. 中继流量(不加修改)。

但是,TLS 握手后的实际流量是带有 Application Data 封装的数据包,所以流量很容易区分。

现在流量看起来像是与受信任服务器的 TLS 连接(因为我们可以使用受信任的域和证书),但实际上它不是 http 服务,而使用 TLS 但不使用 http 的服务器非常少,这可能也会是一个特征。

### 服务端
服务器在客户端和 2 个后端之间中继数据。一个后端是 TLS 握手服务器,它提供有效的证书(不属于我们);另一个后端是我们的数据服务器。握手完成后,服务器将在客户端和数据服务器之间中继流量。

1. 接受连接。
2. 在客户端和 TLS 握手服务器之间中继流量(例如 example.trusted-server.domain:443)。它还将监视流量以查看握手是否完成。
3. 握手完成后在客户端和我们的真实服务器之间中继流量。

由于我们需要感知握手结束,所以这个版本我们只能使用 TLS1.2。

## V2
该版本旨在解决流量分析和主动检测问题。此外,它可以支持 TLS 1.3。

### 客户端
客户端连接服务器并进行 TLS 握手。 握手后:
1. 所有数据都将打包在 TLS Application Data 中。
2. 在第一个 Application Data 包的数据的最前面插入一个 8 字节的 hmac。

hmac 是使用服务器发送的所有数据计算的(服务器发送的所有数据被用作 challenge,因为客户端无法完全控制它,并且有一定随机性)。hmac 可以被视为对 challenge 的响应,用于识别。

### 服务端
服务器在客户端和 2 个后端(模式和 V1 一样)之间中继数据。 不同的是:我们不会观察流量来查看握手是否完成;相反,我们使用 hmac。所以我们更容易解析流量和切换后端。此外,还支持 TLS1.3 或其他版本。

1. 接受连接。
2. 在客户端和 tls 握手服务器之间中继流量(例如 example.trusted-server.domain:443)。服务器发送的所有数据将用于计算 hmac。如果客户端发送的某个 Application Data 包的前缀有有效的hmac,我们会将流量切换到我们的数据服务器。
3. 如果不切换,流量将被中继到 TLS 握手服务器。使用浏览器访问服务器的用户将能够访问握手服务器上的 http 服务。为了效率,我们只能对前 N 个数据包进行 hmac 检查(在我们的实现中 N = 3,hmac 算法为 HMAC-SHA1)。
Loading

0 comments on commit 229a567

Please sign in to comment.