A proxy to expose real tls handshake to the firewall。
www.ihcblog.com/a-better-tls-obfs-proxy/
Shadow TLS
一个可以使用别人的受信证书的 TLS 伪装代理。
它和 trojan 的表现类似,但它在做真实 TLS 握手的同时,可以直接使用别人的受信证书(如某些大公司或机构的域名),而不需要自己签发证书。当直接使用浏览器打开时,可以正常显示对应可信域名的网页内容。
A proxy to expose real tls handshake to the firewall.It works like trojan but it does not require signing certificate. The firewall will see real tls handshake with valid certificate that you choose.
How to Use It
这个服务需要双边部署,并且它一般需要搭配一个加密代理(因为本项目不包含数据加密和代理请求封装功能,这不是我们的目标)。
通常,你可以在同机部署 shadowsocks-server 和 shadowtls-server;之后在防火墙的另一端部署 shadowsocks-client 和 shadowtls-client。
有两种方式部署这个服务。
-
使用 Docker + Docker Compose
修改
docker-compose.yml
后直接docker-compose up -d
。 -
使用预编译的二进制
从 Release 页面下载对应平台的二进制文件, 然后运行即可。运行指南可以
./shadow-tls client --help
或./shadow-tls server --help
看到。
更详细的使用指南请参考 Wiki。
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).-
Run with Docker + Docker Compose Modfy
docker-compose.yml
and rundocker-compose up -d
. -
Use prebuilt binary Download the binary from Release page and run it.
For more detailed usage guide, please refer to Wiki.
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: v2 | v3.
Note
This project relies on 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.
Also, you may need to modify some system limitations 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.
你可能需要修改某些系统设置来让它工作,参考这里。如果它不起作用,您可以添加环境变量 MONOIO_FORCE_LEGACY_DRIVER=1
以使用 epoll 而不是 io_uring。
from https://github.com/ihciah/shadow-tls
(https://github.com/SagerNet/sing-shadowtls)
https://github.com/ihciah/shadow-tls/wiki/V3-Protocol
-------------------------------------------------------------------------------------------
ShadowTLS——更好的 TLS 伪装代理
本文主要分析当前流行的 Trojan 协议,并针对当前中间人的特点,尝试提出一个更好的解决方案。
该方案的实现是 ShadowTLS,你可以在 Github 上找到完整代码和预编译二进制。
要隐藏流量特征,一个方式是不暴露任何特征,即 shadowsocks 这类:这类协议将协议头也加密传输,所以观测不到任何明显的特征。第二个方式是将自己隐藏在众人之中,最简单的是伪装为 HTTP 或 TLS 流量,分别对应 simple-obfs 和 Trojan 的做法。
方式一现在已经比较容易识别了,未命中任何协议且时序特征符合 web 流量,无脑认为是该类型流量即可。方式二近年来越来越成为主流方式,其中使用最广的就是 Trojan 协议(simple-obfs 只是在最开始加一个 http 协议头,过于容易识别,在此不做分析)。
Trojan 是怎么工作的
Trojan 想做到的事情是将流量封装为一个正常的 TLS 流量。由于 TLS 流量是加密的,所以中间人不易识别出这到底是普通 web 流量还是封装过一层的代理流量。为了更像一点,Trojan 还对主动探测做了防御,浏览器直接打开对应网页可以正常响应。
那么这里它要解决的问题主要是这几个:
- 代理请求承载:要能够将代理请求编码为二进制,server 侧要能解码这个请求,并根据请求来建立远程连接并中继流量。
- 区分客户端和主动探测者的流量:需要某种手段来区分客户端的请求和主动探测者的请求,并做不同的处理。
- 对客户端和主动探测者流量的后续处理:对区分后的流量做分别处理。客户端流量需要用 TLS 协议承载,主动探测者的流量也需要能够 act like http。
官方的协议规范在这里有写:The Trojan Protocol。解决问题 1 很简单,因为上层暴露是 socks5 代理,所以直接把 socks5 代理请求头打包进去就可以了(和 shadowsocks 类似)。
重点在于问题 2 和 3。这里的方式是先建立 TLS session,之后在 TLS 连接内发通过前 56 byte 做鉴权,如果这 56 byte 符合我们 preshared key 的某种 hash 结果,那么我们就认为这个流量是我们 client 发出的。
这里很明显会让人注意到一个问题:我作为一个攻击者,在建立 TLS session 后发送一个小于 56 byte 的 HTTP 请求,就可以通过判定是否卡住来判别是否是 Trojan server 了呀?因为需要 56 byte 才能区分我是谁,那在数据到达 56 byte 之前是不能做路由的。
事实上这个问题并不存在。我们来看一下协议设计的细节:这个 56 byte 是 hex(SHA224(password)),后面会发送 CRLF。是不是很奇怪?一个二进制协议为什么要 CRLF 这种文本协议才会使用的东西?并且直接发 SHA224 二进制结果不是要比发 hex 效率更高?其实这就是协议设计的精妙所在。
这个 CRLF 其实是为了对应 HTTP 流量的。在 server 侧处理时,直接 read_until CRLF,之后就可以做路由。因为 HTTP 流量要得到处理,一定是在其发送了 CRLF 之后。
所以读到第一个 CRLF 后,要么 hex(SHA224(password)) 发完了,要么 HTTP 请求的第一行发完了。无论哪一种情况,我们都已经可以做路由区分了。比如如果我们发现数据不够 56 byte,那么可以直接判定为主动探测流量,而不用非要等待接收完 56 byte。而为什么要 hex,就是为了避免 hash 结果中意外包含 CRLF 影响我们的判定。
顺便说一个题外话:在调研这个协议时,我读了 trojan c 和 go 版本的实现。事实上 golang 版本的实现是有问题的,可能作者没有 get 到协议设计里的这些 trick,它直接做了一次 read,如果数据不够或 hash 不符就判定为主动探测流量。但我们并不能将 read 一次读够 56 byte 视为理所当然,tcp 是流协议,一次读 1 byte 就是符合 posix 规范的返回结果。
勘误:经网友 RPRX 指正,这里的说法确实有误。此处读写的不是裸 TCP 流而是 TLS 流量。TLS 流量本身分帧,理论上有保证读写一对一对应的能力。
Golang 官方 TLS 库对外暴露
io.Reader
,io.Writer
接口,该接口是流式接口且官方实现的 TLS 库并不保证对应关系,所以此处说法应当纠正为对特定条件下的特定行为而非接口的依赖。
Trojan 有什么问题
看起来一切正常?我们将所有的数据全部包装进 TLS,外界区分不出加密的数据到底是什么,仿佛我们一直在请求某个 web 站,并且如果我们浏览网页的话,代理流量的时序特征也是 web 流量。
如果不考虑实现上的一些特征,这里唯一暴露的东西是 SNI 和对应证书。在 TLS Client Hello 中会暴露我们请求的目标域名,而长时间大流量地请求一个小众域名,这可能并不正常。
更好地伪装方式
还有更好的伪装方式吗?我们要用 TLS,就得自己处理握手;要握手就得用自己的域名签发证书。似乎是个无解的问题。。
诶等等!我们只是伪装为 TLS 流量,谁说真的要用 TLS 了?
那么我们能不能做一次 “TLS 表演” 给中间人看呢?server 可以直接将这个表演数据代理到某些大公司或机构的白名单的服务器上,这样中间人看到的握手就是证书合法的、和白名单域名的握手。在握手结束后,client 和 server 切换模式,利用已建立的连接传输自定义数据即可。
切换模式需要双方都能感知到握手结束,这里我们强制使用 TLS1.2,在观测到一次 Change Cipher Spec 包后,再读一个 Handshake 包即标记握手完成。
我们不想自己实现数据加密和代理协议封装,所以这里的自定义数据就直接采用了 shadowsocks 来处理。我们的 ShadowTLS 作为 shadowsocks 流量的一层 wrapper 工作,对于 client 就是在流量上加一层握手数据,对于 server 就是把这层握手数据剥除掉。
到此为止,如果我们假定中间人:
- 不对握手后的流量做分析
- 不进行主动探测
那么我们的协议可以很有效地工作。抓包可以看出,中间人视角下我们真的在和一个受信任的域名进行 TLS 通信。根据反馈,这个版本从 2022 年 8 月末到 10 月初已经帮助了一些人摆脱了针对域名的 QoS 的问题。
ShadowTLS 协议(v1)的问题
前面我们只做了一层很简单的“表演”,并有两个假定,但事实上这两个假定并不成立。我们需要能够应对这两个问题。
应对流量分析
正常的 TLS 数据,在握手结束后会使用 Application Data 封装包来进行通信。而直接转发 shadowsocks 数据流完全不符合 TLS 协议,甚至 wireshark 会将后续的数据包高亮出来以表示有问题。解决这个问题并不难,我们只需要在双边分别做封装和解封装即可。
应对主动探测
如果要能应对主动探测,我们就要能够做两件事(和 Trojan 需要做的一样):
- 区分客户端流量和主动探测流量
- 正确响应主动探测流量
我们需要客户端给出一个特殊的东西,以此来判断这个是我们的客户端流量。为了避免主动探测,我们必须引入一个预共享 key。但是怎么做呢?
Trojan 协议中,直接发送密码的 hash 即可。但是我们这里只有明文信道可以用,所以直接发送密码的 hash 显然暴露了密码,等于说密码不再有意义;并且完全无法防御数据重放。
ShadowTLS v2 协议设计
Server Challenge
基于明文信道我们只能通过 challenge-response 的形式做鉴定。正常来讲,我们要鉴定 client,就需要 server 侧发送一个 challenge。但事实上我们并不能这么做,因为正常的 https server 不可能在 TLS 握手后就发回一个 challenge。
那么能不能将 challenge 藏在正常的握手中呢?对 challenge 的要求很简单,随机且 client 不可控就行。我的思路是,其实握手过程本身中 server 发送的数据就可以作为 challenge:它有随机数据,如 server random,它也不是 client 可控的。
这里我将握手过程中 server 发送的所有数据作为 challenge(当然也可以使用 server random,但是这样需要 parse TLS 包,需要感知 TLS 协议细节,实现上有点麻烦并且可能引入细节上的特征区分性),这样可以尽可能地弱化对 TLS 协议细节的依赖,所以不再需要依赖 TLS1.2 的握手行为细节。
Client Response
我们有个 challenge,那么如何 response 呢?显然我们需要鉴定预共享 key,那么我们直接使用 hmac(data, key)
作为 response 即可(可以简单理解为 hash(data+key)
,但安全性上更好,都可以流式计算得到,不需要缓存数据)。
这个 Response 数据怎么发回呢?如果作为单独的数据包,则会引入新的区分性特征。所以我们这里将这个 Response 放在第一个 Application Data 包的头部发送至 Server 侧。
这个 hmac 我这里使用 hmac-sha1 的前 8 byte,安全性已经足够良好。
Application Data
在数据转发的过程中,会做 Application Data 封装和解封装。这里需要考虑的问题是,正常情况下单个 Application Data 数据包是多大?当前实现中直接拍脑袋定了一个 buffer size,但是为了避免这个包大小成为特征,后续需要调研一下 TLS 库的实现并抓包观测一下,定一个合理的最大值。
处理主动探测流量
我们可以将服务端模型简化为:默认连接至 handshake server;如果 hmac 鉴定通过则切换至 data server。
对于主动探测流量,它是不可能刚好猜对 8 byte 的 hmac 的,所以它永远不会切换至 data server。为了避免不必要的 hash 计算,在前 N 个 Application Data 包验证 hmac 不通过的时候(这里取 N 而不是取 1 是因为不确定是不是发送了 Application Data 就一定标记握手结束),会直接切换至直接代理,后续不再尝试 hmac 计算和验证。
详细的协议设计写在 这里 了,感兴趣可以参考。
ShadowTLS 与 Trojan 的对比
对比 Trojan,ShadowTLS 不需要自行签发证书(可以直接使用大公司或机构的可信域名),也不需要自行启动伪装的 HTTP 服务(因为数据直接转发至可信域名对应网站),使用可信域名可以进一步弱化特征,藏木于林。
ShadowTLS 和 Trojan 都可以应对主动探测,当使用浏览器直接打开时,都可以正常访问到 HTTP 页面。
更进一步
UPDATED AT 2022-11-13
距离 v2 实现发布一个多月过去了,ShadowTLS 取得了不错的结果:在过去一段时间 Trojan 被大规模封禁时,ShadowTLS 依旧可用。当前 ShadowRocket 和 Surge 都支持了这个协议(虽然我还是没钱买 Surge)。
但其实也有很多可以完善的地方:
TLS 指纹问题
对于 Server,我们直接转发流量,不存在指纹问题;但 Client 是我们自己实现的,我们预期它看起来和浏览器或其他正常客户端一样,但事实上可能并没有足够地像。如果抓包查看 Chrome 发出的 Client Hello 包,可以明显看出里面包含了非常多的 Extension 字段,而这些字段在我们使用 rustls 时是不会自动附加的;并且,不同客户端的默认选择的 Cipher、Hash 列表等是有差别的。
所以一个可以改进的地方是,提供多份 Client TLS Profile 供用户选择使用。
流量劫持问题
这个 issue 里提到了一个确实存在的问题:如果有人将 Client 侧的流量劫持到握手服务器上怎么办?
首先是 Client 信任谁?在它完成 TLS 握手前,它的表现其实和普通的 TLS Client 一样。要得到 Client 的信任,首先需要能过证书验证,能完成 TLS 握手。能做这件事的人除了我们的 Server,还有握手服务器本身,以及其他代理握手的中间人。
我认为我们这里可以假定握手服务器是中间人不可控的,其证书也不可能被中间人持有。所以现在重点就在于和我们一样代理握手的中间人了。中间人不需要解密流量,它的目标是鉴别我们是不是正常的连接。所以虽然它没有拿到解密 key,它依旧可以对流量做劫持和重放来达到目的:
- 直接劫持整个连接到握手服务器(这个是 issue 里提到的攻击方式):在 Client 完成协议切换后就会露馅,握手服务器会返回 Encrypted Alert。
- 正常代理流量,但偷偷丢掉或者乱序一个 Application Data:正常应当返回 Encrypted Alert,但因为我们并不做消息 Authentication,也不做 Encryption,所以我们其实是感知不到这件事的,这件事会被丢给下层服务。我们依赖下层服务断开连接来返回 Encrypted Alert。
- 观测连接断开:2 中也提到,我们需要妥善处理连接断开的问题,无论是正常关闭还是异常关闭。但当前实现上并没有发送 Encrypted Alert。
- 合并相邻 Application Data:正常情况下 TLS 协议内部会有序列号和 MAC,但我们的封装当前是没有的,所以如果劫持者合并了相邻的 Application Data 后连接仍旧正常,那么也可以发现是伪装的 TLS。
但是这些问题(除了问题 3)需要能够在主链路上劫持流量才能生效,如果没有其他 hint 的话,对所有出国 tls 流量做劫持,还是有很高风险的。所以该问题我认为其实问题并不大。
What’s Better Protocol?
我们可以简单 fix 前面提到的一部分问题(这些是一些实现问题,而非协议问题):提供 Client TLS Profile、连接关闭时发送 Encrypted Alert。但如何应对剩下的流量劫持问题呢?
针对直接劫持至握手服务器的攻击
我们可以看出,问题的关键在于 Client 没有对 Server 做鉴权(只鉴定了证书)。Server 需要表明身份,如果放在 Server Hello 中的某个 Extension 中则可能会成为明显特征;如果直接夹带在后续流量中,则同样会使探测者困惑,无法正常解密。
我们需要这么一个地方:它是 Server 发送的,本身就是随机数,并且我们修改它没什么影响,最好是在发送完 Server Random 后发送的(这样可以利用 Server Random 防御重放攻击)。在 IP 包上其实我们可以藏一些东西,但这样就要求我们有系统管理员权限,会引入更强的环境限制,所以我们尽可能地在 TCP 之上寻找这样的地方。
于是我们可以找到一个符合条件的隐藏点:Session ID(仅限 TLS 1.3 的 Session ID)。由于我们完全信任 Server Random 一定是 Random 的,所以这里可以做的更简单:如果中继的 Server Hello 包中包含一个 32 位的 Session ID,则替换该 ID 为 Server Random 的 HMAC。由于 TLS 1.2 默认这个字段是空的,所以我们不能贸然地为 TLS 1.2 插入这个值,以避免成为特征。
针对流量的 Reshape
我们的 Application Data 封装可以被 reshape,但真实的 TLS 流量不行,所以我们需要在这层封装内也参考 TLS 的做法,携带一些数据用于校验。这种校验有助于发现前面提到的问题 2 和 4,之后只需要响应 Alert 并断开连接即可。
当然,这些都还没实现(until 2022-11-13),如果你感兴趣,欢迎提 issue 认领贡献!
实现 fix 和对直接劫持至握手服务器的防御可以对旧版本 Client 保持兼容,但要向增加 Application Data 增加 MAC 就不得不改协议啦(可能是 v3 了)~
总结
ShadowTLS 基于 Rust + Monoio 实现,基于 io_uring 和 thread-per-core 模型可以带来更好的 IO 性能(但是由于目前 Monoio 尚未支持 Windows,所以 Windows 用户暂时无法使用,建议使用 wsl)。
综上,本文尝试分析了主流的基于 TLS 的代理协议,并针对它的可能缺陷提出了更好的协议设计,并提供了对应的实现,你可以在 这里 找到对应代码。
from https://www.ihcblog.com/a-better-tls-obfs-proxy/
--------------------------------------------------------------------
ShadowTLS v3
- Install dependencies:
- apt update && apt -y install wget libc6-dev build-essential zlib1g-dev libssl-dev libevent-dev mingw-w64
- Install go:
- wget -c https://go.dev/dl/go1.20.5.linux-amd64.tar.gz -O - | tar -xz -C /usr/local && echo 'export PATH=$PATH:/usr/local/go/bin' > /etc/profile && source /etc/profile && go version
- Install sing-box :
- go install -v -tags with_dhcp,with_wireguard,with_shadowsocksr,with_ech,with_utls,with_gvisor,with_clash_api,with_lwip,github.com/sagernet/sing-box/cmd/sing-box@latest
- Download sing-box.service and config.json:
- cp ~/go/bin/sing-box /usr/local/bin/ && wget -P /etc/systemd/system https://raw.githubusercontent.com/TinrLin/ShadowTLS-v3-build-tutorial/main/sing-box.service && mkdir /usr/local/etc/sing-box && wget -P /usr/local/etc/sing-box https://raw.githubusercontent.com/TinrLin/ShadowTLS-v3-build-tutorial/main/config.json
- Test if it works
/usr/local/bin/sing-box run -c /usr/local/etc/sing-box/config.json
- Check the current status:
- systemctl daemon-reload && systemctl enable --now sing-box && systemctl status sing-box
- from https://github.com/Cathy2001/ShadowTLS-v3-build-tutorial
- ----------------------------------------------------------------------------------
Sing-box + ShadowTLS 一键管理脚本
wget -N --no-check-certificate https://raw.githubusercontent.com/blog-misaka/singbox-shadowtls/main/sing-box.sh && bash sing-box.sh
频道及交流群
from https://github.com/Alvin9999/singbox-shadowtls
-------------------------------------------------------------------
利用 Sing-box 部署 ShadowTLS v3 节点的一键脚本
sing-shadowtls-3
利用 Sing-box 部署 ShadowTLS v3 节点的一键脚本
一键脚本
from https://github.com/Misaka-blog/sing-shadowtls-3wget -N https://raw.githubusercontent.com/Misaka-blog/sing-shadowtls-3/main/sing-box.sh && bash sing-box.sh
- -------------------------------------------------------------------
利用sing-box搭建ShadowTLS v3节点
以debian12为例:
下载最新版sing-box
curl -s https://api.github.com/repos/SagerNet/sing-box/releases/latest | grep "browser_download_url.*amd64.deb" | grep linux | cut -d'"' -f4 | wget -i -
安装sing-box
dpkg -i *amd64.deb
生成密码
sing-box generate rand --base64 16
修改配置
nano /etc/sing-box/config.json
复制一下配置
{
"log": {
"disabled": true
},
"dns": {
"servers": [
{
"address": "tls://8.8.8.8"
}
]
},
"inbounds": [
{
"type": "shadowtls",
"listen": "::",
"listen_port": 服务器端口,
"version": 3,
"users": [
{
"name": "sekai",
"password": "shadowtls的密码"
}
],
"handshake": {
"server": "伪装握手网址",
"server_port": 443
},
"strict_mode": true,
"detour": "shadowsocks-in"
},
{
"type": "shadowsocks",
"tag": "shadowsocks-in",
"listen": "127.0.0.1",
"network": "tcp",
"method": "2022-blake3-aes-128-gcm",
"password": "ss的密码"
}
],
"outbounds": [
{
"type": "direct"
},
{
"type": "dns",
"tag": "dns-out"
}
],
"route": {
"rules": [
{
"protocol": "dns",
"outbound": "dns-out"
}
]
}
}
(ss和tls的密码可以生成不同密码,伪装网址需要支持 TLS1.3可以参考官方推荐https://github.com/ihciah/shadow-tls/wiki/V3-Protocol)
重启服务
systemctl restart sing-box
设置客户端使用
可以使用shadowsocks客户端+shadowtls插件的的方式 安卓ss+tls 、微软ss + tls 、苹果 Shadowrocket
也可以使用sing-box各平台客户端 nekoray 、 NekoBox 、 SFI
还可以使用Clash.Meta各平台客户端 https://clash-meta.wiki/client/
最后贴一下sing-box客户端配置
{
"dns": {
"rules": [],
"servers": [
{
"address": "tls://1.1.1.1",
"tag": "dns-remote",
"detour": "ss",
"strategy": "ipv4_only"
}
]
},
"inbounds": [
{
"type": "tun",
"interface_name": "ipv4-tun",
"inet4_address": "172.19.0.1/28",
"mtu": 1500,
"stack": "gvisor",
"endpoint_independent_nat": true,
"auto_route": true,
"strict_route": true,
"sniff": true
}
],
"outbounds": [
{
"type": "shadowsocks",
"tag": "ss",
"method": "2022-blake3-aes-128-gcm",
"password": "ss的密码",
"detour": "shadowtls-out",
"udp_over_tcp": {
"enabled": true,
"version": 2
}
},
{
"type": "shadowtls",
"tag": "shadowtls-out",
"server": "服务器地址",
"server_port": 服务器端口,
"version": 3,
"password": ""shadowtls的密码",
"tls": {
"enabled": true,
"server_name": "伪装握手网址",
"utls": {
"enabled": true,
"fingerprint": "firefox"
}
}
},
{
"tag": "dns-out",
"type": "dns"
}
],
"route": {
"auto_detect_interface": true,
"final": "ss",
"rules": [
{
"protocol": "dns",
"outbound": "dns-out"
}
]
}
}
-----------------------------------------------------------------------------------
Download the precompiled version of sing-box
- AMD core
wget -c "https://github.com/SagerNet/sing-box/releases/download/v1.3.0/sing-box-1.3.0-linux-amd64.tar.gz" -O - | tar -xz -C /usr/local/bin --strip-components=1 && chmod +x /usr/local/bin/sing-box
- ARM core
wget -c "https://github.com/SagerNet/sing-box/releases/download/v1.3.0/sing-box-1.3.0-linux-arm64.tar.gz" -O - | tar -xz -C /usr/local/bin --strip-components=1 && chmod +x /usr/local/bin/sing-box
Configure the systemd service of sing-box
wget -P /etc/systemd/system https://raw.githubusercontent.com/TinrLin/ShadowTLS-v3-build-tutorial/main/sing-box.service
Download and modify the sing-box configuration file
mkdir /usr/local/etc/sing-box && wget -P /usr/local/etc/sing-box https://raw.githubusercontent.com/TinrLin/ShadowTLS-v3-build-tutorial/main/config.json
Start and run sing-box:
systemctl daemon-reload && systemctl enable --now sing-box && systemctl status sing-box
from https://github.com/Jackie16888/ShadowTLS-v3-build-tutorial
--------------------------------------------------------------------------------
Sing-Box VLESS+Reality/ShadowTLS/Hysteria2的配置
Proxy Config
安装cloudflare warp
修改Clash内核使其支持Vless等协议
from https://github.com/clhlc/ProxyConfig
---------------------------------------------------------
Hysteria2, TUIC, Reality, ShadowTLS, WebSocket and Warp installer script + client side config examples.
apt install curl
bash <(curl -fsSL https://bit.ly/config-installer)
客户端程序:
-
Android
-
Windows
-
Windows, Linux, macOS
-
iOS
Special Thanks
hawshemi - For server optimizer
misaka - For warp config and key generator
from https://github.com/TheyCallMeSecond/config-examples
No comments:
Post a Comment