mirror of
https://github.com/p4gefau1t/trojan-go.git
synced 2026-10-19 16:15:38 +00:00
add double tls options, update build script
This commit is contained in:
@@ -141,9 +141,11 @@ Trojan-Go支持并且兼容Trojan-GFW的绝大多数功能,包括但不限于
|
||||
例如,交叉编译一个在mips处理器,linux操作系统上运行的,只有客户端功能的Trojan-Go,只需执行下面的命令即可
|
||||
|
||||
```shell
|
||||
CGO_ENABLE=0 GOOS=linux GOARCH=mips go build -tags "client"
|
||||
CGO_ENABLE=0 GOOS=linux GOARCH=mips go build -tags "client" -ldflags "-s -w"
|
||||
```
|
||||
|
||||
得到的可执行文件可以直接在目标平台运行。
|
||||
|
||||
完整的tag说明参见[Trojan-Go 文档](https://p4gefau1t.github.io/trojan-go)。
|
||||
|
||||
### 易用
|
||||
|
||||
+19
-1
@@ -35,7 +35,7 @@ for PLATFORM in $PLATFORMS; do
|
||||
GOOS=${PLATFORM%/*}
|
||||
GOARCH=${PLATFORM#*/}
|
||||
ZIP_FILENAME="trojan-go-${GOOS}-${GOARCH}.zip"
|
||||
CMD="CGO_ENABLE=0 GOOS=${GOOS} GOARCH=${GOARCH} go build -tags \"full\" -o temp $@ -ldflags=\"-s -w\""
|
||||
CMD="CGO_ENABLE=0 GOOS=${GOOS} GOARCH=${GOARCH} go build -tags \"full\" -o temp -ldflags=\"-s -w\""
|
||||
echo "${CMD}"
|
||||
eval $CMD || FAILURES="${FAILURES} ${PLATFORM}"
|
||||
zip -j release/$ZIP_FILENAME temp/* ./*.dat
|
||||
@@ -44,6 +44,24 @@ for PLATFORM in $PLATFORMS; do
|
||||
rm temp/*
|
||||
done
|
||||
|
||||
# arm
|
||||
PLATFORMS_ARM="windows linux freebsd netbsd"
|
||||
for GOOS in $PLATFORMS_ARM; do
|
||||
# build for each ARM version
|
||||
GOARCH="arm"
|
||||
for GOARM in 7 6 5; do
|
||||
ZIP_FILENAME="trojan-go-${GOOS}-${GOARCH}v${GOARM}.zip"
|
||||
CMD="CGO_ENABLE=0 GOARM=${GOARM} GOOS=${GOOS} GOARCH=${GOARCH} go build -o temp -ldflags \"-s -w\""
|
||||
echo "${CMD}"
|
||||
eval "${CMD}" || FAILURES="${FAILURES} ${GOOS}/${GOARCH}v${GOARM}"
|
||||
zip -j release/$ZIP_FILENAME temp/* ./*.dat
|
||||
zip release/$ZIP_FILENAME example/*
|
||||
sha1sum release/$ZIP_FILENAME > release/$ZIP_FILENAME.sha1
|
||||
rm temp/*
|
||||
done
|
||||
done
|
||||
|
||||
|
||||
# eval errors
|
||||
if [[ "${FAILURES}" != "" ]]; then
|
||||
echo ""
|
||||
|
||||
+24
-24
@@ -28,24 +28,24 @@ const (
|
||||
)
|
||||
|
||||
type TLSConfig struct {
|
||||
Verify bool `json:"verify"`
|
||||
VerifyHostname bool `json:"verify_hostname"`
|
||||
CertPath string `json:"cert"`
|
||||
KeyPath string `json:"key"`
|
||||
KeyPassword string `json:"key_password"`
|
||||
Cipher string `json:"cipher"`
|
||||
CipherTLS13 string `json:"cipher_tls13"`
|
||||
PreferServerCipher bool `json:"prefer_server_cipher"`
|
||||
SNI string `json:"sni"`
|
||||
HTTPFile string `json:"plain_http_response"`
|
||||
FallbackHost string `json:"fallback_addr"`
|
||||
FallbackPort int `json:"fallback_port"`
|
||||
ReuseSession bool `json:"reuse_session"`
|
||||
ALPN []string `json:"alpn"`
|
||||
Curves string `json:"curves"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
ServePlainText bool `json:"serve_plain_text"`
|
||||
RedirectWithTLS bool `json:"redirect_with_tls"`
|
||||
Verify bool `json:"verify"`
|
||||
VerifyHostname bool `json:"verify_hostname"`
|
||||
CertPath string `json:"cert"`
|
||||
KeyPath string `json:"key"`
|
||||
KeyPassword string `json:"key_password"`
|
||||
Cipher string `json:"cipher"`
|
||||
CipherTLS13 string `json:"cipher_tls13"`
|
||||
PreferServerCipher bool `json:"prefer_server_cipher"`
|
||||
SNI string `json:"sni"`
|
||||
HTTPResponseFileName string `json:"plain_http_response"`
|
||||
FallbackHost string `json:"fallback_addr"`
|
||||
FallbackPort int `json:"fallback_port"`
|
||||
ReuseSession bool `json:"reuse_session"`
|
||||
ALPN []string `json:"alpn"`
|
||||
Curves string `json:"curves"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
ServePlainText bool `json:"serve_plain_text"`
|
||||
RedirectWithTLS bool `json:"redirect_with_tls"`
|
||||
|
||||
ClientHelloID *utls.ClientHelloID
|
||||
FallbackAddress *common.Address
|
||||
@@ -130,12 +130,12 @@ type RouterConfig struct {
|
||||
}
|
||||
|
||||
type WebsocketConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
HostName string `json:"hostname"`
|
||||
Path string `json:"path"`
|
||||
ObfuscationPassword string `json:"obfuscation_password"`
|
||||
DoubleTLS bool `json:"double_tls"`
|
||||
DoubleTLSVerify bool `json:"double_tls_verify"`
|
||||
Enabled bool `json:"enabled"`
|
||||
HostName string `json:"hostname"`
|
||||
Path string `json:"path"`
|
||||
ObfuscationPassword string `json:"obfuscation_password"`
|
||||
DoubleTLS bool `json:"double_tls"`
|
||||
TLS TLSConfig `json:"ssl"`
|
||||
|
||||
ObfuscationKey []byte
|
||||
}
|
||||
|
||||
+97
-67
@@ -18,6 +18,78 @@ import (
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
func loadCert(tlsConfig *TLSConfig) error {
|
||||
if tlsConfig.CertPath == "" {
|
||||
log.Info("Cert of the remote server is unspecified. Using default CA list")
|
||||
} else {
|
||||
caCertByte, err := ioutil.ReadFile(tlsConfig.CertPath)
|
||||
if err != nil {
|
||||
return common.NewError("failed to load cert file").Base(err)
|
||||
}
|
||||
pool := x509.NewCertPool()
|
||||
ok := pool.AppendCertsFromPEM(caCertByte)
|
||||
if !ok {
|
||||
log.Warn("Invalid CA cert list")
|
||||
}
|
||||
log.Info("Using custom CA list")
|
||||
pemCerts := caCertByte
|
||||
for len(pemCerts) > 0 {
|
||||
tlsConfig.CertPool = pool
|
||||
var block *pem.Block
|
||||
block, pemCerts = pem.Decode(pemCerts)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||
continue
|
||||
}
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
log.Trace("Issuer:", cert.Issuer, "Subject:", cert.Subject)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadCertAndKey(tlsConfig *TLSConfig) error {
|
||||
if tlsConfig.KeyPassword != "" {
|
||||
keyFile, err := ioutil.ReadFile(tlsConfig.KeyPath)
|
||||
if err != nil {
|
||||
return common.NewError("Failed to load key file").Base(err)
|
||||
}
|
||||
keyBlock, _ := pem.Decode(keyFile)
|
||||
if keyBlock == nil {
|
||||
return common.NewError("Failed to decode key file").Base(err)
|
||||
}
|
||||
decryptedKey, err := x509.DecryptPEMBlock(keyBlock, []byte(tlsConfig.KeyPassword))
|
||||
if err == nil {
|
||||
return common.NewError("Failed to decrypt key").Base(err)
|
||||
}
|
||||
|
||||
certFile, err := ioutil.ReadFile(tlsConfig.CertPath)
|
||||
certBlock, _ := pem.Decode(certFile)
|
||||
if certBlock == nil {
|
||||
return common.NewError("Failed to decode cert file").Base(err)
|
||||
}
|
||||
|
||||
keyPair, err := tls.X509KeyPair(certBlock.Bytes, decryptedKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConfig.KeyPair = []tls.Certificate{keyPair}
|
||||
} else {
|
||||
keyPair, err := tls.LoadX509KeyPair(tlsConfig.CertPath, tlsConfig.KeyPath)
|
||||
if err != nil {
|
||||
return common.NewError("Failed to load key pair").Base(err)
|
||||
}
|
||||
tlsConfig.KeyPair = []tls.Certificate{keyPair}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadCommonConfig(config *GlobalConfig) error {
|
||||
//log settigns
|
||||
log.SetLogLevel(log.LogLevel(config.LogLevel))
|
||||
@@ -207,38 +279,9 @@ func loadClientConfig(config *GlobalConfig) error {
|
||||
log.Warn("SNI is unspecified, using remote_addr as SNI")
|
||||
config.TLS.SNI = config.RemoteHost
|
||||
}
|
||||
if config.TLS.CertPath == "" {
|
||||
log.Info("Cert of the remote server is unspecified. Using default CA list")
|
||||
} else {
|
||||
caCertByte, err := ioutil.ReadFile(config.TLS.CertPath)
|
||||
if err != nil {
|
||||
return common.NewError("failed to load cert file").Base(err)
|
||||
}
|
||||
pool := x509.NewCertPool()
|
||||
ok := pool.AppendCertsFromPEM(caCertByte)
|
||||
if !ok {
|
||||
log.Warn("Invalid CA cert list")
|
||||
}
|
||||
log.Info("Using custom CA list")
|
||||
pemCerts := caCertByte
|
||||
for len(pemCerts) > 0 {
|
||||
config.TLS.CertPool = pool
|
||||
var block *pem.Block
|
||||
block, pemCerts = pem.Decode(pemCerts)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||
continue
|
||||
}
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
log.Trace("Issuer:", cert.Issuer, "Subject:", cert.Subject)
|
||||
}
|
||||
if err := loadCert(&config.TLS); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//forward proxy settings
|
||||
if config.ForwardProxy.Enabled {
|
||||
log.Info("Forward proxy enabled")
|
||||
@@ -246,6 +289,17 @@ func loadClientConfig(config *GlobalConfig) error {
|
||||
log.Debug("Forward proxy", config.ForwardProxy.ProxyAddress.String())
|
||||
}
|
||||
|
||||
if config.Websocket.DoubleTLS {
|
||||
if config.Websocket.TLS.CertPath == "" {
|
||||
log.Warn("Empty double TLS settings, using default ssl settings")
|
||||
config.Websocket.TLS = config.TLS
|
||||
} else {
|
||||
if err := loadCert(&config.Websocket.TLS); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -265,44 +319,15 @@ func loadServerConfig(config *GlobalConfig) error {
|
||||
//tls settings
|
||||
if config.TLS.ServePlainText {
|
||||
log.Warn("Server will now use plain text. TLS config is ignored")
|
||||
} else if config.TLS.KeyPassword != "" {
|
||||
keyFile, err := ioutil.ReadFile(config.TLS.KeyPath)
|
||||
if err != nil {
|
||||
return common.NewError("Failed to load key file").Base(err)
|
||||
}
|
||||
keyBlock, _ := pem.Decode(keyFile)
|
||||
if keyBlock == nil {
|
||||
return common.NewError("Failed to decode key file").Base(err)
|
||||
}
|
||||
decryptedKey, err := x509.DecryptPEMBlock(keyBlock, []byte(config.TLS.KeyPassword))
|
||||
if err == nil {
|
||||
return common.NewError("Failed to decrypt key").Base(err)
|
||||
}
|
||||
|
||||
certFile, err := ioutil.ReadFile(config.TLS.CertPath)
|
||||
certBlock, _ := pem.Decode(certFile)
|
||||
if certBlock == nil {
|
||||
return common.NewError("Failed to decode cert file").Base(err)
|
||||
}
|
||||
|
||||
keyPair, err := tls.X509KeyPair(certBlock.Bytes, decryptedKey)
|
||||
if err != nil {
|
||||
} else {
|
||||
if err := loadCertAndKey(&config.TLS); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config.TLS.KeyPair = []tls.Certificate{keyPair}
|
||||
} else {
|
||||
keyPair, err := tls.LoadX509KeyPair(config.TLS.CertPath, config.TLS.KeyPath)
|
||||
if err != nil {
|
||||
return common.NewError("Failed to load key pair").Base(err)
|
||||
}
|
||||
config.TLS.KeyPair = []tls.Certificate{keyPair}
|
||||
}
|
||||
|
||||
if config.TLS.HTTPFile != "" {
|
||||
payload, err := ioutil.ReadFile(config.TLS.HTTPFile)
|
||||
if config.TLS.HTTPResponseFileName != "" {
|
||||
payload, err := ioutil.ReadFile(config.TLS.HTTPResponseFileName)
|
||||
if err != nil {
|
||||
log.Warn("Failed to load http response file", err)
|
||||
return common.NewError("Failed to load http response file").Base(err)
|
||||
}
|
||||
config.TLS.HTTPResponse = payload
|
||||
}
|
||||
@@ -330,8 +355,13 @@ func ParseJSON(data []byte) (*GlobalConfig, error) {
|
||||
Concurrency: 8,
|
||||
},
|
||||
Websocket: WebsocketConfig{
|
||||
DoubleTLS: true,
|
||||
DoubleTLSVerify: true,
|
||||
DoubleTLS: true,
|
||||
TLS: TLSConfig{
|
||||
Verify: true,
|
||||
VerifyHostname: true,
|
||||
SessionTicket: true,
|
||||
ReuseSession: true,
|
||||
},
|
||||
},
|
||||
MySQL: MySQLConfig{
|
||||
CheckRate: 60,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
public/
|
||||
themes/
|
||||
@@ -8,7 +8,6 @@ weight: 2
|
||||
|
||||
Trojan-Go支持使用TLS+Websocket承载Trojan协议,使得利用CDN进行流量中转成为可能。这个特性的设计考虑了将来GFW部署大规模HTTPS中间人攻击的情景。开启Websocket后,因为Trojan-Go支持使用多重TLS,即使遭受GFW的HTTPS中间人攻击,**在正确的配置下**,连接的安全性依然能得到保证。
|
||||
|
||||
|
||||
服务器和客户端配置文件中同时添加websocket选项,并将其```enabled```字段设置为true,并填写```path```字段和```hostname```字段即可启用Websocket支持。下面是一个完整的Websocket选项
|
||||
|
||||
```json
|
||||
|
||||
@@ -78,7 +78,7 @@ sudo ./trojan-go -autocert renew
|
||||
|
||||
- 如果TLS握手成功,并且被确认是Trojan协议头部,并且其中的密码正确,那么服务器将解析来自客户端的请求并进行代理,否则和上一步的处理方法相同。
|
||||
|
||||
- 如果TLS握手失败了,说明对方使用的不是TLS协议进行主动连接。此时Trojan-Go将这个TCP连接代理到本地127.0.0.1:1234上运行的HTTPS服务,本地HTTPS服务器也会检测到连接不是TLS连接,返回一个400 Bad Reqeust的HTTP页面。```fallback_port```是一个可选选项,如果没有填写,Trojan-Go会直接终止连接。虽然是可选的,但是还是强烈建议填写。
|
||||
- 如果TLS握手失败,说明对方使用的不是TLS协议进行连接。此时Trojan-Go将这个TCP连接代理到本地127.0.0.1:1234上运行的HTTPS服务,本地HTTPS服务器也会检测到连接不是TLS连接,返回一个400 Bad Reqeust的HTTP页面。```fallback_port```是一个可选选项,如果没有填写,Trojan-Go会直接终止连接。虽然是可选的,但是还是强烈建议填写。
|
||||
|
||||
你可以通过使用浏览器访问你的域名```https://your_domain_name```来验证。如果工作正常,你的浏览器会显示一个正常的HTTPS保护的Web页面,页面内容与服务器本机80端口上的页面一致。你还可以使用```http://your_domain_name:443```验证```fallback_port```工作是否正常。
|
||||
|
||||
|
||||
@@ -79,7 +79,19 @@ weight: 30
|
||||
"path": "",
|
||||
"hostname": "",
|
||||
"obfuscation_password": "",
|
||||
"double_tls": true
|
||||
"double_tls": true,
|
||||
"ssl": {
|
||||
"verify": true,
|
||||
"verify_hostname": true,
|
||||
"cert": "",
|
||||
"key": "",
|
||||
"key_password": "",
|
||||
"prefer_server_cipher": false,
|
||||
"sni": "",
|
||||
"session_ticket": true,
|
||||
"reuse_session": true,
|
||||
"plain_http_response": "",
|
||||
}
|
||||
},
|
||||
"forward_proxy": {
|
||||
"enabled": false,
|
||||
@@ -125,7 +137,7 @@ weight: 30
|
||||
|
||||
```password```可以填入多个密码。除了使用配置文件配置密码之外,trojan-go还支持使用mysql配置密码,参见下文。客户端的密码,只有与服务端配置文件中或者在数据库中的密码记录一致,才能通过服务端的校验,正常使用代理服务。
|
||||
|
||||
```dns```指定trojan-go使用的DNS服务器列表,如果不指定则使用主机默认DNS。如果指定了服务器,按照列表顺序依次查询,支持UDP/TCP/DOH/DOT,查询结果会被缓存五分钟。使用URL格式描述服务器,例如
|
||||
```dns```指定trojan-go使用的DNS服务器列表,如果不指定则使用主机默认DNS。如果指定了服务器,按照列表顺序依次查询,支持UDP/TCP/DOT类型的DNS,查询结果会被缓存五分钟。使用URL格式描述服务器,例如
|
||||
|
||||
- "udp://1.1.1.1",基于UDP的DNS服务器,默认53端口
|
||||
|
||||
@@ -235,6 +247,8 @@ Websocket传输是trojan-go的特性。在**正常的直接连接代理节点**
|
||||
|
||||
```double_tls```是否开启双重TLS,默认开启。开启后在TLS+Websocket上将会再承载一次TLS连接。双重TLS的意义在于即使第一层TLS遭到中间人攻击也能保证通信安全。第二层TLS的证书校验被强制打开。客户端和服务端设置必须相同。这个选项对性能有一定影响,请自行斟酌安全性和性能的平衡。
|
||||
|
||||
```ssl```如果```double_tls```启用,这个选项用于配置第二层TLS,如果没有填写则使用全局的```ssl```填充。各字段定义与全局```ssl```相同。
|
||||
|
||||
```obfuscation_password```指定混淆密码。用于混淆内层连接以降低遭到国内无良CDN运营商识别的概率。如果需要使用混淆,服务端和客户端必须同时设置相同密码。这个选项对性能有一定影响,请自行斟酌安全性和性能的平衡。
|
||||
|
||||
### ```tcp```选项
|
||||
@@ -14,4 +14,4 @@ Trojan-Go基于grpc实现了API,使用protobuf交换数据。客户端可获
|
||||
}
|
||||
```
|
||||
|
||||
目前API处于开发阶段,使用方法可以参考api文件夹下api.proto文件。
|
||||
目前API处于开发阶段,服务和rpc定义可以参考api文件夹下api.proto文件。
|
||||
|
||||
@@ -4,7 +4,9 @@ draft: false
|
||||
weight: 50
|
||||
---
|
||||
|
||||
SimpleSocks协议是无认证机制的简单代理协议,本质上就是去除了sha224的Trojan协议,设计的目的是减少多路复用时的overhead。只有启用多路复用之后,被复用的连接才会使用这个协议。
|
||||
SimpleSocks协议是无认证机制的简单代理协议,本质上是去除了sha224的Trojan协议。使用该协议的目的是减少多路复用时的overhead。
|
||||
|
||||
只有启用多路复用之后,被复用的连接才会使用这个协议。
|
||||
|
||||
SimpleSocks甚至比Socks5更简单,下面是头部结构。
|
||||
|
||||
@@ -16,4 +18,4 @@ SimpleSocks甚至比Socks5更简单,下面是头部结构。
|
||||
+-----+------+----------+----------+-----------+
|
||||
```
|
||||
|
||||
各字段定义与Socks5相同,不再赘述。
|
||||
各字段含义与Socks5相同,不再赘述。
|
||||
|
||||
@@ -6,17 +6,17 @@ weight: 40
|
||||
|
||||
由于使用CDN中转时,HTTPS对CDN透明,CDN可以审查Websocket传输内容,而Trojan协议明文的头部特征过于明显,而TLS握手特征也很明显。为了保证Websocket传输的隐蔽和安全,默认情况下还会进行一次AES加密(混淆层)和TLS连接(双重TLS)。其中TLS用于保证传输的安全性,AES加密仅仅只是用于混淆流量。
|
||||
|
||||
**如果你使用的是国内的CDN,务必保证两者均开启。最坏情况下也应当保持混淆和双重TLS之一是打开的。**
|
||||
**如果你使用的是国内CDN,务必保证两者均开启。最坏情况下也应当保持混淆和双重TLS之一是打开的。**
|
||||
|
||||
开启Websocket模块的客户端可以使用```obfuscation```字段开启混淆,以及使用```double_tls```启用双重TLS以确保连接安全性和隐蔽性。
|
||||
开启Websocket模块的客户端可以使用```obfuscation_password```字段开启混淆,以及使用```double_tls```启用双重TLS以确保信道安全性。
|
||||
|
||||
混淆层使用AES-CTR-128密码系统。加密主密钥派生自```obfuscation_password```,使用16字节的盐和sha1散列算法,使用pbkdf2对```obfuscation_password```密码进行32次迭代,派生得到16字节的主密钥。盐为硬编码的随机字节,定义为
|
||||
混淆层使用AES-CTR-128密码系统。加密主密钥派生自```obfuscation_password```:使用16字节的盐和sha1散列算法,使用pbkdf2对```obfuscation_password```密码进行32次迭代,派生得到16字节的主密钥。盐为硬编码的随机字节,定义为
|
||||
|
||||
```go
|
||||
salt := []byte{48, 149, 6, 18, 13, 193, 247, 116, 197, 135, 236, 175, 190, 209, 146, 48}
|
||||
```
|
||||
|
||||
在每次连接开始时,生成16字节的随机IV。根据主密钥和IV,使用AES-CTR-128密码系统对后续流量进行加密。Websocket承载的客户端到服务端的头部结构如下(IV随着Payload一起发送,避免了长度特征):
|
||||
在每次连接开始时,生成16字节的随机IV。根据主密钥和IV,使用AES-CTR-128密码系统对后续流量进行加密。Websocket承载的客户端到服务端的头部结构如下(IV随着Payload同时发送以避免长度特征):
|
||||
|
||||
```text
|
||||
+----+-------------------+
|
||||
@@ -28,14 +28,6 @@ salt := []byte{48, 149, 6, 18, 13, 193, 247, 116, 197, 135, 236, 175, 190, 209,
|
||||
|
||||
服务端用同样的方法得到主密钥,接收IV后进行解密和后续的双向通讯。服务端到客户端的流量无头部,均为密文。
|
||||
|
||||
```text
|
||||
+------------------------+
|
||||
| Encrypted Payload |
|
||||
+------------------------+
|
||||
| Variable |
|
||||
+------------------------+
|
||||
```
|
||||
|
||||
注意,这层加密作用仅仅是增加数据流的熵,混淆流量特征,而不是保护数据安全。CTR加密模式不保证数据完整性和身份认证,因此可能遭受CDN或者中间人的重放攻击。如果CDN不可信,或者遭受了基于HTTPS劫持的中间人攻击,应启用双重TLS保证数据传输安全。
|
||||
|
||||
如果使用了双重TLS,握手造成的延迟可能略有增加,但是只要开启```session_reuse```,```session_ticket```复用TLS连接,以及开启```mux```启用TLS多路复用,只会在开启Trojan-Go时的最初几秒察觉明显的延迟。
|
||||
|
||||
@@ -132,12 +132,12 @@ func NewOutboundWebosocket(conn net.Conn, config *conf.GlobalConfig) (io.ReadWri
|
||||
}
|
||||
log.Debug("ws double tls enabled")
|
||||
tlsConfig := &tls.Config{
|
||||
CipherSuites: config.TLS.CipherSuites,
|
||||
RootCAs: config.TLS.CertPool,
|
||||
ServerName: config.TLS.SNI,
|
||||
SessionTicketsDisabled: !config.TLS.SessionTicket,
|
||||
CipherSuites: config.Websocket.TLS.CipherSuites,
|
||||
RootCAs: config.Websocket.TLS.CertPool,
|
||||
ServerName: config.Websocket.TLS.SNI,
|
||||
SessionTicketsDisabled: !config.Websocket.TLS.SessionTicket,
|
||||
InsecureSkipVerify: !config.Websocket.TLS.Verify,
|
||||
ClientSessionCache: tlsSessionCache,
|
||||
InsecureSkipVerify: !config.Websocket.DoubleTLSVerify,
|
||||
}
|
||||
tlsConn := tls.Client(transport, tlsConfig)
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
@@ -149,7 +149,7 @@ func NewOutboundWebosocket(conn net.Conn, config *conf.GlobalConfig) (io.ReadWri
|
||||
log.Trace("Websocket double TLS handshaked", "cipher:", tls.CipherSuiteName(state.CipherSuite), "resume:", state.DidResume)
|
||||
for i := range chain {
|
||||
for j := range chain[i] {
|
||||
log.Trace("subject:", chain[i][j].Subject, ", issuer:", chain[i][j].Issuer)
|
||||
log.Trace("Subject:", chain[i][j].Subject, "Issuer:", chain[i][j].Issuer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -64,7 +64,7 @@ func (m *MuxManager) newMuxClient() (*muxClientInfo, error) {
|
||||
|
||||
client, err := smux.Client(conn, nil)
|
||||
common.Must(err)
|
||||
log.Info("Mux TLS tunnel established, id:", id)
|
||||
log.Info("Mux TLS tunnel established, client id:", id)
|
||||
return &muxClientInfo{
|
||||
client: client,
|
||||
id: id,
|
||||
@@ -146,9 +146,7 @@ func (m *MuxManager) checkAndCloseIdleMuxClient() {
|
||||
log.Info("Mux", id, "is closed due to inactive")
|
||||
}
|
||||
}
|
||||
if len(m.muxPool) != 0 {
|
||||
log.Info("Current mux pool clients: ", len(m.muxPool))
|
||||
}
|
||||
log.Debug("Current mux pool clients: ", len(m.muxPool))
|
||||
m.Unlock()
|
||||
case <-m.ctx.Done():
|
||||
log.Debug("Shutting down mux manager..")
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ func (m *TLSManager) printConnInfo(conn net.Conn) {
|
||||
log.Trace("TLS handshaked", "cipher:", tls.CipherSuiteName(state.CipherSuite), "resume:", state.DidResume)
|
||||
for i := range chain {
|
||||
for j := range chain[i] {
|
||||
log.Trace("subject:", chain[i][j].Subject, ", issuer:", chain[i][j].Issuer)
|
||||
log.Trace("Subject:", chain[i][j].Subject, "Issuer:", chain[i][j].Issuer)
|
||||
}
|
||||
}
|
||||
case *utls.UConn:
|
||||
@@ -50,7 +50,7 @@ func (m *TLSManager) printConnInfo(conn net.Conn) {
|
||||
log.Trace("UTLS handshaked", "cipher:", tls.CipherSuiteName(state.CipherSuite), "resume:", state.DidResume)
|
||||
for i := range chain {
|
||||
for j := range chain[i] {
|
||||
log.Trace("subject:", chain[i][j].Subject, ", issuer:", chain[i][j].Issuer)
|
||||
log.Trace("Subject:", chain[i][j].Subject, "Issuer:", chain[i][j].Issuer)
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user