mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-24 02:48:02 +08:00
feat: add ech-key
for listeners
This commit is contained in:
parent
dc958e6a39
commit
a1350d4985
143
component/ech/key.go
Normal file
143
component/ech/key.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package ech
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdh"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/cryptobyte"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AEAD_AES_128_GCM = 0x0001
|
||||||
|
AEAD_AES_256_GCM = 0x0002
|
||||||
|
AEAD_ChaCha20Poly1305 = 0x0003
|
||||||
|
)
|
||||||
|
|
||||||
|
const extensionEncryptedClientHello = 0xfe0d
|
||||||
|
const DHKEM_X25519_HKDF_SHA256 = 0x0020
|
||||||
|
const KDF_HKDF_SHA256 = 0x0001
|
||||||
|
|
||||||
|
// sortedSupportedAEADs is just a sorted version of hpke.SupportedAEADS.
|
||||||
|
// We need this so that when we insert them into ECHConfigs the ordering
|
||||||
|
// is stable.
|
||||||
|
var sortedSupportedAEADs = []uint16{AEAD_AES_128_GCM, AEAD_AES_256_GCM, AEAD_ChaCha20Poly1305}
|
||||||
|
|
||||||
|
func marshalECHConfig(id uint8, pubKey []byte, publicName string, maxNameLen uint8) []byte {
|
||||||
|
builder := cryptobyte.NewBuilder(nil)
|
||||||
|
|
||||||
|
builder.AddUint16(extensionEncryptedClientHello)
|
||||||
|
builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
|
||||||
|
builder.AddUint8(id)
|
||||||
|
|
||||||
|
builder.AddUint16(DHKEM_X25519_HKDF_SHA256) // The only DHKEM we support
|
||||||
|
builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
|
||||||
|
builder.AddBytes(pubKey)
|
||||||
|
})
|
||||||
|
builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
|
||||||
|
for _, aeadID := range sortedSupportedAEADs {
|
||||||
|
builder.AddUint16(KDF_HKDF_SHA256) // The only KDF we support
|
||||||
|
builder.AddUint16(aeadID)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
builder.AddUint8(maxNameLen)
|
||||||
|
builder.AddUint8LengthPrefixed(func(builder *cryptobyte.Builder) {
|
||||||
|
builder.AddBytes([]byte(publicName))
|
||||||
|
})
|
||||||
|
builder.AddUint16(0) // extensions
|
||||||
|
})
|
||||||
|
|
||||||
|
return builder.BytesOrPanic()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenECHConfig(publicName string) (configBase64 string, keyPem string, err error) {
|
||||||
|
echKey, err := ecdh.X25519().GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
echConfig := marshalECHConfig(0, echKey.PublicKey().Bytes(), publicName, 0)
|
||||||
|
|
||||||
|
builder := cryptobyte.NewBuilder(nil)
|
||||||
|
builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
|
||||||
|
builder.AddBytes(echConfig)
|
||||||
|
})
|
||||||
|
echConfigList := builder.BytesOrPanic()
|
||||||
|
|
||||||
|
builder2 := cryptobyte.NewBuilder(nil)
|
||||||
|
builder2.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
|
||||||
|
builder.AddBytes(echKey.Bytes())
|
||||||
|
})
|
||||||
|
builder2.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
|
||||||
|
builder.AddBytes(echConfig)
|
||||||
|
})
|
||||||
|
echConfigKeys := builder2.BytesOrPanic()
|
||||||
|
|
||||||
|
configBase64 = base64.StdEncoding.EncodeToString(echConfigList)
|
||||||
|
keyPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH KEYS", Bytes: echConfigKeys}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalECHKeys(raw []byte) ([]tlsC.EncryptedClientHelloKey, error) {
|
||||||
|
var keys []tlsC.EncryptedClientHelloKey
|
||||||
|
rawString := cryptobyte.String(raw)
|
||||||
|
for !rawString.Empty() {
|
||||||
|
var key tlsC.EncryptedClientHelloKey
|
||||||
|
if !rawString.ReadUint16LengthPrefixed((*cryptobyte.String)(&key.PrivateKey)) {
|
||||||
|
return nil, errors.New("error parsing private key")
|
||||||
|
}
|
||||||
|
if !rawString.ReadUint16LengthPrefixed((*cryptobyte.String)(&key.Config)) {
|
||||||
|
return nil, errors.New("error parsing config")
|
||||||
|
}
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return nil, errors.New("empty ECH keys")
|
||||||
|
}
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadECHKey(key string, tlsConfig *tlsC.Config, path ca.Path) error {
|
||||||
|
if key == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
painTextErr := loadECHKey([]byte(key), tlsConfig)
|
||||||
|
if painTextErr == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
key = path.Resolve(key)
|
||||||
|
var loadErr error
|
||||||
|
if !path.IsSafePath(key) {
|
||||||
|
loadErr = path.ErrNotSafePath(key)
|
||||||
|
} else {
|
||||||
|
var echKey []byte
|
||||||
|
echKey, loadErr = os.ReadFile(key)
|
||||||
|
if loadErr == nil {
|
||||||
|
loadErr = loadECHKey(echKey, tlsConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if loadErr != nil {
|
||||||
|
return fmt.Errorf("parse ECH keys failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadECHKey(echKey []byte, tlsConfig *tlsC.Config) error {
|
||||||
|
block, rest := pem.Decode(echKey)
|
||||||
|
if block == nil || block.Type != "ECH KEYS" || len(rest) > 0 {
|
||||||
|
return errors.New("invalid ECH keys pem")
|
||||||
|
}
|
||||||
|
echKeys, err := UnmarshalECHKeys(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("parse ECH keys: %w", err)
|
||||||
|
}
|
||||||
|
tlsConfig.EncryptedClientHelloKeys = echKeys
|
||||||
|
return nil
|
||||||
|
}
|
@ -4,12 +4,14 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Main(args []string) {
|
func Main(args []string) {
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
panic("Using: generate uuid/reality-keypair/wg-keypair")
|
panic("Using: generate uuid/reality-keypair/wg-keypair/ech-keypair")
|
||||||
}
|
}
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "uuid":
|
case "uuid":
|
||||||
@ -33,5 +35,15 @@ func Main(args []string) {
|
|||||||
}
|
}
|
||||||
fmt.Println("PrivateKey: " + privateKey.String())
|
fmt.Println("PrivateKey: " + privateKey.String())
|
||||||
fmt.Println("PublicKey: " + privateKey.PublicKey().String())
|
fmt.Println("PublicKey: " + privateKey.PublicKey().String())
|
||||||
|
case "ech-keypair":
|
||||||
|
if len(args) < 2 {
|
||||||
|
panic("Using: generate ech-keypair <plain_server_name>")
|
||||||
|
}
|
||||||
|
configBase64, keyPem, err := ech.GenECHConfig(args[1])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Println("Config:", configBase64)
|
||||||
|
fmt.Println("Key:", keyPem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@ func UClient(c net.Conn, config *utls.Config, fingerprint UClientHelloID) *UConn
|
|||||||
return utls.UClient(c, config, fingerprint)
|
return utls.UClient(c, config, fingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewListener(inner net.Listener, config *Config) net.Listener {
|
||||||
|
return utls.NewListener(inner, config)
|
||||||
|
}
|
||||||
|
|
||||||
func GetFingerprint(clientFingerprint string) (UClientHelloID, bool) {
|
func GetFingerprint(clientFingerprint string) (UClientHelloID, bool) {
|
||||||
if len(clientFingerprint) == 0 {
|
if len(clientFingerprint) == 0 {
|
||||||
clientFingerprint = globalFingerprint
|
clientFingerprint = globalFingerprint
|
||||||
@ -93,7 +97,9 @@ func init() {
|
|||||||
fingerprints["randomized"] = randomized
|
fingerprints["randomized"] = randomized
|
||||||
}
|
}
|
||||||
|
|
||||||
func UCertificates(it tls.Certificate) utls.Certificate {
|
type Certificate = utls.Certificate
|
||||||
|
|
||||||
|
func UCertificate(it tls.Certificate) utls.Certificate {
|
||||||
return utls.Certificate{
|
return utls.Certificate{
|
||||||
Certificate: it.Certificate,
|
Certificate: it.Certificate,
|
||||||
PrivateKey: it.PrivateKey,
|
PrivateKey: it.PrivateKey,
|
||||||
@ -106,13 +112,15 @@ func UCertificates(it tls.Certificate) utls.Certificate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EncryptedClientHelloKey = utls.EncryptedClientHelloKey
|
||||||
|
|
||||||
type Config = utls.Config
|
type Config = utls.Config
|
||||||
|
|
||||||
func UConfig(config *tls.Config) *utls.Config {
|
func UConfig(config *tls.Config) *utls.Config {
|
||||||
return &utls.Config{
|
return &utls.Config{
|
||||||
Rand: config.Rand,
|
Rand: config.Rand,
|
||||||
Time: config.Time,
|
Time: config.Time,
|
||||||
Certificates: utils.Map(config.Certificates, UCertificates),
|
Certificates: utils.Map(config.Certificates, UCertificate),
|
||||||
VerifyPeerCertificate: config.VerifyPeerCertificate,
|
VerifyPeerCertificate: config.VerifyPeerCertificate,
|
||||||
RootCAs: config.RootCAs,
|
RootCAs: config.RootCAs,
|
||||||
NextProtos: config.NextProtos,
|
NextProtos: config.NextProtos,
|
||||||
|
@ -1155,6 +1155,13 @@ listeners:
|
|||||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||||
# certificate: ./server.crt
|
# certificate: ./server.crt
|
||||||
# private-key: ./server.key
|
# private-key: ./server.key
|
||||||
|
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||||
|
# ech-key: |
|
||||||
|
# -----BEGIN ECH KEYS-----
|
||||||
|
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||||
|
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||||
|
# dC5jb20AAA==
|
||||||
|
# -----END ECH KEYS-----
|
||||||
|
|
||||||
- name: http-in-1
|
- name: http-in-1
|
||||||
type: http
|
type: http
|
||||||
@ -1168,6 +1175,13 @@ listeners:
|
|||||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||||
# certificate: ./server.crt
|
# certificate: ./server.crt
|
||||||
# private-key: ./server.key
|
# private-key: ./server.key
|
||||||
|
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||||
|
# ech-key: |
|
||||||
|
# -----BEGIN ECH KEYS-----
|
||||||
|
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||||
|
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||||
|
# dC5jb20AAA==
|
||||||
|
# -----END ECH KEYS-----
|
||||||
|
|
||||||
- name: mixed-in-1
|
- name: mixed-in-1
|
||||||
type: mixed # HTTP(S) 和 SOCKS 代理混合
|
type: mixed # HTTP(S) 和 SOCKS 代理混合
|
||||||
@ -1182,6 +1196,13 @@ listeners:
|
|||||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||||
# certificate: ./server.crt
|
# certificate: ./server.crt
|
||||||
# private-key: ./server.key
|
# private-key: ./server.key
|
||||||
|
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||||
|
# ech-key: |
|
||||||
|
# -----BEGIN ECH KEYS-----
|
||||||
|
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||||
|
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||||
|
# dC5jb20AAA==
|
||||||
|
# -----END ECH KEYS-----
|
||||||
|
|
||||||
- name: reidr-in-1
|
- name: reidr-in-1
|
||||||
type: redir
|
type: redir
|
||||||
@ -1231,6 +1252,13 @@ listeners:
|
|||||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||||
# certificate: ./server.crt
|
# certificate: ./server.crt
|
||||||
# private-key: ./server.key
|
# private-key: ./server.key
|
||||||
|
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||||
|
# ech-key: |
|
||||||
|
# -----BEGIN ECH KEYS-----
|
||||||
|
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||||
|
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||||
|
# dC5jb20AAA==
|
||||||
|
# -----END ECH KEYS-----
|
||||||
# 如果填写reality-config则开启reality(注意不可与certificate和private-key同时填写)
|
# 如果填写reality-config则开启reality(注意不可与certificate和private-key同时填写)
|
||||||
# reality-config:
|
# reality-config:
|
||||||
# dest: test.com:443
|
# dest: test.com:443
|
||||||
@ -1253,6 +1281,13 @@ listeners:
|
|||||||
# 00000000-0000-0000-0000-000000000001: PASSWORD_1
|
# 00000000-0000-0000-0000-000000000001: PASSWORD_1
|
||||||
# certificate: ./server.crt
|
# certificate: ./server.crt
|
||||||
# private-key: ./server.key
|
# private-key: ./server.key
|
||||||
|
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||||
|
# ech-key: |
|
||||||
|
# -----BEGIN ECH KEYS-----
|
||||||
|
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||||
|
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||||
|
# dC5jb20AAA==
|
||||||
|
# -----END ECH KEYS-----
|
||||||
# congestion-controller: bbr
|
# congestion-controller: bbr
|
||||||
# max-idle-time: 15000
|
# max-idle-time: 15000
|
||||||
# authentication-timeout: 1000
|
# authentication-timeout: 1000
|
||||||
@ -1284,6 +1319,13 @@ listeners:
|
|||||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||||
# certificate: ./server.crt
|
# certificate: ./server.crt
|
||||||
# private-key: ./server.key
|
# private-key: ./server.key
|
||||||
|
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||||
|
# ech-key: |
|
||||||
|
# -----BEGIN ECH KEYS-----
|
||||||
|
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||||
|
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||||
|
# dC5jb20AAA==
|
||||||
|
# -----END ECH KEYS-----
|
||||||
# 如果填写reality-config则开启reality(注意不可与certificate和private-key同时填写)
|
# 如果填写reality-config则开启reality(注意不可与certificate和private-key同时填写)
|
||||||
reality-config:
|
reality-config:
|
||||||
dest: test.com:443
|
dest: test.com:443
|
||||||
@ -1304,6 +1346,13 @@ listeners:
|
|||||||
# "certificate" and "private-key" are required
|
# "certificate" and "private-key" are required
|
||||||
certificate: ./server.crt
|
certificate: ./server.crt
|
||||||
private-key: ./server.key
|
private-key: ./server.key
|
||||||
|
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||||
|
# ech-key: |
|
||||||
|
# -----BEGIN ECH KEYS-----
|
||||||
|
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||||
|
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||||
|
# dC5jb20AAA==
|
||||||
|
# -----END ECH KEYS-----
|
||||||
# padding-scheme: "" # https://github.com/anytls/anytls-go/blob/main/docs/protocol.md#cmdupdatepaddingscheme
|
# padding-scheme: "" # https://github.com/anytls/anytls-go/blob/main/docs/protocol.md#cmdupdatepaddingscheme
|
||||||
|
|
||||||
- name: trojan-in-1
|
- name: trojan-in-1
|
||||||
@ -1320,6 +1369,13 @@ listeners:
|
|||||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||||
certificate: ./server.crt
|
certificate: ./server.crt
|
||||||
private-key: ./server.key
|
private-key: ./server.key
|
||||||
|
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||||
|
# ech-key: |
|
||||||
|
# -----BEGIN ECH KEYS-----
|
||||||
|
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||||
|
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||||
|
# dC5jb20AAA==
|
||||||
|
# -----END ECH KEYS-----
|
||||||
# 如果填写reality-config则开启reality(注意不可与certificate和private-key同时填写)
|
# 如果填写reality-config则开启reality(注意不可与certificate和private-key同时填写)
|
||||||
# reality-config:
|
# reality-config:
|
||||||
# dest: test.com:443
|
# dest: test.com:443
|
||||||
@ -1345,6 +1401,13 @@ listeners:
|
|||||||
00000000-0000-0000-0000-000000000001: PASSWORD_1
|
00000000-0000-0000-0000-000000000001: PASSWORD_1
|
||||||
# certificate: ./server.crt
|
# certificate: ./server.crt
|
||||||
# private-key: ./server.key
|
# private-key: ./server.key
|
||||||
|
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||||
|
# ech-key: |
|
||||||
|
# -----BEGIN ECH KEYS-----
|
||||||
|
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||||
|
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||||
|
# dC5jb20AAA==
|
||||||
|
# -----END ECH KEYS-----
|
||||||
## up 和 down 均不写或为 0 则使用 BBR 流控
|
## up 和 down 均不写或为 0 则使用 BBR 流控
|
||||||
# up: "30 Mbps" # 若不写单位,默认为 Mbps
|
# up: "30 Mbps" # 若不写单位,默认为 Mbps
|
||||||
# down: "200 Mbps" # 若不写单位,默认为 Mbps
|
# down: "200 Mbps" # 若不写单位,默认为 Mbps
|
||||||
|
@ -3,7 +3,6 @@ package anytls
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
@ -13,6 +12,8 @@ import (
|
|||||||
"github.com/metacubex/mihomo/common/atomic"
|
"github.com/metacubex/mihomo/common/atomic"
|
||||||
"github.com/metacubex/mihomo/common/buf"
|
"github.com/metacubex/mihomo/common/buf"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
"github.com/metacubex/mihomo/listener/sing"
|
"github.com/metacubex/mihomo/listener/sing"
|
||||||
@ -28,7 +29,7 @@ type Listener struct {
|
|||||||
closed bool
|
closed bool
|
||||||
config LC.AnyTLSServer
|
config LC.AnyTLSServer
|
||||||
listeners []net.Listener
|
listeners []net.Listener
|
||||||
tlsConfig *tls.Config
|
tlsConfig *tlsC.Config
|
||||||
userMap map[[32]byte]string
|
userMap map[[32]byte]string
|
||||||
padding atomic.TypedValue[*padding.PaddingFactory]
|
padding atomic.TypedValue[*padding.PaddingFactory]
|
||||||
}
|
}
|
||||||
@ -41,13 +42,20 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig := &tls.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
if config.Certificate != "" && config.PrivateKey != "" {
|
if config.Certificate != "" && config.PrivateKey != "" {
|
||||||
cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
|
cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||||
|
|
||||||
|
if config.EchKey != "" {
|
||||||
|
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sl = &Listener{
|
sl = &Listener{
|
||||||
@ -87,7 +95,7 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(tlsConfig.Certificates) > 0 {
|
if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tls.NewListener(l, tlsConfig)
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("disallow using AnyTLS without certificates config")
|
return nil, errors.New("disallow using AnyTLS without certificates config")
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ type AnyTLSServer struct {
|
|||||||
Users map[string]string `yaml:"users" json:"users,omitempty"`
|
Users map[string]string `yaml:"users" json:"users,omitempty"`
|
||||||
Certificate string `yaml:"certificate" json:"certificate"`
|
Certificate string `yaml:"certificate" json:"certificate"`
|
||||||
PrivateKey string `yaml:"private-key" json:"private-key"`
|
PrivateKey string `yaml:"private-key" json:"private-key"`
|
||||||
|
EchKey string `yaml:"ech-key" json:"ech-key"`
|
||||||
PaddingScheme string `yaml:"padding-scheme" json:"padding-scheme,omitempty"`
|
PaddingScheme string `yaml:"padding-scheme" json:"padding-scheme,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,5 +12,6 @@ type AuthServer struct {
|
|||||||
AuthStore auth.AuthStore
|
AuthStore auth.AuthStore
|
||||||
Certificate string
|
Certificate string
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
|
EchKey string
|
||||||
RealityConfig reality.Config
|
RealityConfig reality.Config
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ type Hysteria2Server struct {
|
|||||||
ObfsPassword string `yaml:"obfs-password" json:"obfs-password,omitempty"`
|
ObfsPassword string `yaml:"obfs-password" json:"obfs-password,omitempty"`
|
||||||
Certificate string `yaml:"certificate" json:"certificate"`
|
Certificate string `yaml:"certificate" json:"certificate"`
|
||||||
PrivateKey string `yaml:"private-key" json:"private-key"`
|
PrivateKey string `yaml:"private-key" json:"private-key"`
|
||||||
|
EchKey string `yaml:"ech-key" json:"ech-key,omitempty"`
|
||||||
MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"`
|
MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"`
|
||||||
ALPN []string `yaml:"alpn" json:"alpn,omitempty"`
|
ALPN []string `yaml:"alpn" json:"alpn,omitempty"`
|
||||||
Up string `yaml:"up" json:"up,omitempty"`
|
Up string `yaml:"up" json:"up,omitempty"`
|
||||||
|
@ -20,6 +20,7 @@ type TrojanServer struct {
|
|||||||
GrpcServiceName string
|
GrpcServiceName string
|
||||||
Certificate string
|
Certificate string
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
|
EchKey string
|
||||||
RealityConfig reality.Config
|
RealityConfig reality.Config
|
||||||
MuxOption sing.MuxOption
|
MuxOption sing.MuxOption
|
||||||
TrojanSSOption TrojanSSOption
|
TrojanSSOption TrojanSSOption
|
||||||
|
@ -13,6 +13,7 @@ type TuicServer struct {
|
|||||||
Users map[string]string `yaml:"users" json:"users,omitempty"`
|
Users map[string]string `yaml:"users" json:"users,omitempty"`
|
||||||
Certificate string `yaml:"certificate" json:"certificate"`
|
Certificate string `yaml:"certificate" json:"certificate"`
|
||||||
PrivateKey string `yaml:"private-key" json:"private-key"`
|
PrivateKey string `yaml:"private-key" json:"private-key"`
|
||||||
|
EchKey string `yaml:"ech-key" json:"ech-key"`
|
||||||
CongestionController string `yaml:"congestion-controller" json:"congestion-controller,omitempty"`
|
CongestionController string `yaml:"congestion-controller" json:"congestion-controller,omitempty"`
|
||||||
MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"`
|
MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"`
|
||||||
AuthenticationTimeout int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"`
|
AuthenticationTimeout int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"`
|
||||||
|
@ -21,6 +21,7 @@ type VlessServer struct {
|
|||||||
GrpcServiceName string
|
GrpcServiceName string
|
||||||
Certificate string
|
Certificate string
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
|
EchKey string
|
||||||
RealityConfig reality.Config
|
RealityConfig reality.Config
|
||||||
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
|
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ type VmessServer struct {
|
|||||||
GrpcServiceName string
|
GrpcServiceName string
|
||||||
Certificate string
|
Certificate string
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
|
EchKey string
|
||||||
RealityConfig reality.Config
|
RealityConfig reality.Config
|
||||||
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
|
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/adapter/inbound"
|
"github.com/metacubex/mihomo/adapter/inbound"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
authStore "github.com/metacubex/mihomo/listener/auth"
|
authStore "github.com/metacubex/mihomo/listener/auth"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
@ -64,7 +65,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig := &tls.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
var realityBuilder *reality.Builder
|
var realityBuilder *reality.Builder
|
||||||
|
|
||||||
if config.Certificate != "" && config.PrivateKey != "" {
|
if config.Certificate != "" && config.PrivateKey != "" {
|
||||||
@ -72,7 +73,14 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||||
|
|
||||||
|
if config.EchKey != "" {
|
||||||
|
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if config.RealityConfig.PrivateKey != "" {
|
if config.RealityConfig.PrivateKey != "" {
|
||||||
if tlsConfig.Certificates != nil {
|
if tlsConfig.Certificates != nil {
|
||||||
@ -87,7 +95,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
|||||||
if realityBuilder != nil {
|
if realityBuilder != nil {
|
||||||
l = realityBuilder.NewListener(l)
|
l = realityBuilder.NewListener(l)
|
||||||
} else if len(tlsConfig.Certificates) > 0 {
|
} else if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tls.NewListener(l, tlsConfig)
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
hl := &Listener{
|
hl := &Listener{
|
||||||
|
@ -14,6 +14,7 @@ type AnyTLSOption struct {
|
|||||||
Users map[string]string `inbound:"users,omitempty"`
|
Users map[string]string `inbound:"users,omitempty"`
|
||||||
Certificate string `inbound:"certificate"`
|
Certificate string `inbound:"certificate"`
|
||||||
PrivateKey string `inbound:"private-key"`
|
PrivateKey string `inbound:"private-key"`
|
||||||
|
EchKey string `inbound:"ech-key,omitempty"`
|
||||||
PaddingScheme string `inbound:"padding-scheme,omitempty"`
|
PaddingScheme string `inbound:"padding-scheme,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ func NewAnyTLS(options *AnyTLSOption) (*AnyTLS, error) {
|
|||||||
Users: options.Users,
|
Users: options.Users,
|
||||||
Certificate: options.Certificate,
|
Certificate: options.Certificate,
|
||||||
PrivateKey: options.PrivateKey,
|
PrivateKey: options.PrivateKey,
|
||||||
|
EchKey: options.EchKey,
|
||||||
PaddingScheme: options.PaddingScheme,
|
PaddingScheme: options.PaddingScheme,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -60,4 +60,14 @@ func TestInboundAnyTLS_TLS(t *testing.T) {
|
|||||||
Fingerprint: tlsFingerprint,
|
Fingerprint: tlsFingerprint,
|
||||||
}
|
}
|
||||||
testInboundAnyTLS(t, inboundOptions, outboundOptions)
|
testInboundAnyTLS(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundAnyTLS(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/metacubex/mihomo/common/utils"
|
"github.com/metacubex/mihomo/common/utils"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
"github.com/metacubex/mihomo/component/generater"
|
"github.com/metacubex/mihomo/component/generater"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
|
|
||||||
@ -38,6 +39,8 @@ var realityPrivateKey, realityPublickey string
|
|||||||
var realityDest = "itunes.apple.com"
|
var realityDest = "itunes.apple.com"
|
||||||
var realityShortid = "10f897e26c4b9478"
|
var realityShortid = "10f897e26c4b9478"
|
||||||
var realityRealDial = false
|
var realityRealDial = false
|
||||||
|
var echPublicSni = "public.sni"
|
||||||
|
var echConfigBase64, echKeyPem, _ = ech.GenECHConfig(echPublicSni)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rand.Read(httpData)
|
rand.Read(httpData)
|
||||||
|
@ -16,6 +16,7 @@ type HTTPOption struct {
|
|||||||
Users AuthUsers `inbound:"users,omitempty"`
|
Users AuthUsers `inbound:"users,omitempty"`
|
||||||
Certificate string `inbound:"certificate,omitempty"`
|
Certificate string `inbound:"certificate,omitempty"`
|
||||||
PrivateKey string `inbound:"private-key,omitempty"`
|
PrivateKey string `inbound:"private-key,omitempty"`
|
||||||
|
EchKey string `inbound:"ech-key,omitempty"`
|
||||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ func (h *HTTP) Listen(tunnel C.Tunnel) error {
|
|||||||
AuthStore: h.config.Users.GetAuthStore(),
|
AuthStore: h.config.Users.GetAuthStore(),
|
||||||
Certificate: h.config.Certificate,
|
Certificate: h.config.Certificate,
|
||||||
PrivateKey: h.config.PrivateKey,
|
PrivateKey: h.config.PrivateKey,
|
||||||
|
EchKey: h.config.EchKey,
|
||||||
RealityConfig: h.config.RealityConfig.Build(),
|
RealityConfig: h.config.RealityConfig.Build(),
|
||||||
},
|
},
|
||||||
tunnel,
|
tunnel,
|
||||||
|
@ -16,6 +16,7 @@ type Hysteria2Option struct {
|
|||||||
ObfsPassword string `inbound:"obfs-password,omitempty"`
|
ObfsPassword string `inbound:"obfs-password,omitempty"`
|
||||||
Certificate string `inbound:"certificate"`
|
Certificate string `inbound:"certificate"`
|
||||||
PrivateKey string `inbound:"private-key"`
|
PrivateKey string `inbound:"private-key"`
|
||||||
|
EchKey string `inbound:"ech-key,omitempty"`
|
||||||
MaxIdleTime int `inbound:"max-idle-time,omitempty"`
|
MaxIdleTime int `inbound:"max-idle-time,omitempty"`
|
||||||
ALPN []string `inbound:"alpn,omitempty"`
|
ALPN []string `inbound:"alpn,omitempty"`
|
||||||
Up string `inbound:"up,omitempty"`
|
Up string `inbound:"up,omitempty"`
|
||||||
@ -60,6 +61,7 @@ func NewHysteria2(options *Hysteria2Option) (*Hysteria2, error) {
|
|||||||
ObfsPassword: options.ObfsPassword,
|
ObfsPassword: options.ObfsPassword,
|
||||||
Certificate: options.Certificate,
|
Certificate: options.Certificate,
|
||||||
PrivateKey: options.PrivateKey,
|
PrivateKey: options.PrivateKey,
|
||||||
|
EchKey: options.EchKey,
|
||||||
MaxIdleTime: options.MaxIdleTime,
|
MaxIdleTime: options.MaxIdleTime,
|
||||||
ALPN: options.ALPN,
|
ALPN: options.ALPN,
|
||||||
Up: options.Up,
|
Up: options.Up,
|
||||||
|
@ -60,6 +60,16 @@ func TestInboundHysteria2_TLS(t *testing.T) {
|
|||||||
Fingerprint: tlsFingerprint,
|
Fingerprint: tlsFingerprint,
|
||||||
}
|
}
|
||||||
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundHysteria2_Salamander(t *testing.T) {
|
func TestInboundHysteria2_Salamander(t *testing.T) {
|
||||||
@ -75,6 +85,16 @@ func TestInboundHysteria2_Salamander(t *testing.T) {
|
|||||||
ObfsPassword: userUUID,
|
ObfsPassword: userUUID,
|
||||||
}
|
}
|
||||||
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundHysteria2_Brutal(t *testing.T) {
|
func TestInboundHysteria2_Brutal(t *testing.T) {
|
||||||
@ -90,4 +110,14 @@ func TestInboundHysteria2_Brutal(t *testing.T) {
|
|||||||
Down: "200 Mbps",
|
Down: "200 Mbps",
|
||||||
}
|
}
|
||||||
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ type MixedOption struct {
|
|||||||
UDP bool `inbound:"udp,omitempty"`
|
UDP bool `inbound:"udp,omitempty"`
|
||||||
Certificate string `inbound:"certificate,omitempty"`
|
Certificate string `inbound:"certificate,omitempty"`
|
||||||
PrivateKey string `inbound:"private-key,omitempty"`
|
PrivateKey string `inbound:"private-key,omitempty"`
|
||||||
|
EchKey string `inbound:"ech-key,omitempty"`
|
||||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +70,7 @@ func (m *Mixed) Listen(tunnel C.Tunnel) error {
|
|||||||
AuthStore: m.config.Users.GetAuthStore(),
|
AuthStore: m.config.Users.GetAuthStore(),
|
||||||
Certificate: m.config.Certificate,
|
Certificate: m.config.Certificate,
|
||||||
PrivateKey: m.config.PrivateKey,
|
PrivateKey: m.config.PrivateKey,
|
||||||
|
EchKey: m.config.EchKey,
|
||||||
RealityConfig: m.config.RealityConfig.Build(),
|
RealityConfig: m.config.RealityConfig.Build(),
|
||||||
},
|
},
|
||||||
tunnel,
|
tunnel,
|
||||||
|
@ -17,6 +17,7 @@ type SocksOption struct {
|
|||||||
UDP bool `inbound:"udp,omitempty"`
|
UDP bool `inbound:"udp,omitempty"`
|
||||||
Certificate string `inbound:"certificate,omitempty"`
|
Certificate string `inbound:"certificate,omitempty"`
|
||||||
PrivateKey string `inbound:"private-key,omitempty"`
|
PrivateKey string `inbound:"private-key,omitempty"`
|
||||||
|
EchKey string `inbound:"ech-key,omitempty"`
|
||||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +90,7 @@ func (s *Socks) Listen(tunnel C.Tunnel) error {
|
|||||||
AuthStore: s.config.Users.GetAuthStore(),
|
AuthStore: s.config.Users.GetAuthStore(),
|
||||||
Certificate: s.config.Certificate,
|
Certificate: s.config.Certificate,
|
||||||
PrivateKey: s.config.PrivateKey,
|
PrivateKey: s.config.PrivateKey,
|
||||||
|
EchKey: s.config.EchKey,
|
||||||
RealityConfig: s.config.RealityConfig.Build(),
|
RealityConfig: s.config.RealityConfig.Build(),
|
||||||
},
|
},
|
||||||
tunnel,
|
tunnel,
|
||||||
|
@ -16,6 +16,7 @@ type TrojanOption struct {
|
|||||||
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
|
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
|
||||||
Certificate string `inbound:"certificate,omitempty"`
|
Certificate string `inbound:"certificate,omitempty"`
|
||||||
PrivateKey string `inbound:"private-key,omitempty"`
|
PrivateKey string `inbound:"private-key,omitempty"`
|
||||||
|
EchKey string `inbound:"ech-key,omitempty"`
|
||||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||||
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
||||||
SSOption TrojanSSOption `inbound:"ss-option,omitempty"`
|
SSOption TrojanSSOption `inbound:"ss-option,omitempty"`
|
||||||
@ -67,6 +68,7 @@ func NewTrojan(options *TrojanOption) (*Trojan, error) {
|
|||||||
GrpcServiceName: options.GrpcServiceName,
|
GrpcServiceName: options.GrpcServiceName,
|
||||||
Certificate: options.Certificate,
|
Certificate: options.Certificate,
|
||||||
PrivateKey: options.PrivateKey,
|
PrivateKey: options.PrivateKey,
|
||||||
|
EchKey: options.EchKey,
|
||||||
RealityConfig: options.RealityConfig.Build(),
|
RealityConfig: options.RealityConfig.Build(),
|
||||||
MuxOption: options.MuxOption.Build(),
|
MuxOption: options.MuxOption.Build(),
|
||||||
TrojanSSOption: LC.TrojanSSOption{
|
TrojanSSOption: LC.TrojanSSOption{
|
||||||
|
@ -64,6 +64,16 @@ func TestInboundTrojan_TLS(t *testing.T) {
|
|||||||
Fingerprint: tlsFingerprint,
|
Fingerprint: tlsFingerprint,
|
||||||
}
|
}
|
||||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundTrojan_Wss1(t *testing.T) {
|
func TestInboundTrojan_Wss1(t *testing.T) {
|
||||||
@ -80,6 +90,16 @@ func TestInboundTrojan_Wss1(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundTrojan_Wss2(t *testing.T) {
|
func TestInboundTrojan_Wss2(t *testing.T) {
|
||||||
@ -97,6 +117,16 @@ func TestInboundTrojan_Wss2(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundTrojan_Grpc1(t *testing.T) {
|
func TestInboundTrojan_Grpc1(t *testing.T) {
|
||||||
@ -111,6 +141,16 @@ func TestInboundTrojan_Grpc1(t *testing.T) {
|
|||||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||||
}
|
}
|
||||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundTrojan_Grpc2(t *testing.T) {
|
func TestInboundTrojan_Grpc2(t *testing.T) {
|
||||||
@ -126,6 +166,16 @@ func TestInboundTrojan_Grpc2(t *testing.T) {
|
|||||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||||
}
|
}
|
||||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundTrojan_Reality(t *testing.T) {
|
func TestInboundTrojan_Reality(t *testing.T) {
|
||||||
@ -190,6 +240,16 @@ func TestInboundTrojan_TLS_TrojanSS(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundTrojan_Wss_TrojanSS(t *testing.T) {
|
func TestInboundTrojan_Wss_TrojanSS(t *testing.T) {
|
||||||
@ -216,4 +276,14 @@ func TestInboundTrojan_Wss_TrojanSS(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ type TuicOption struct {
|
|||||||
Users map[string]string `inbound:"users,omitempty"`
|
Users map[string]string `inbound:"users,omitempty"`
|
||||||
Certificate string `inbound:"certificate"`
|
Certificate string `inbound:"certificate"`
|
||||||
PrivateKey string `inbound:"private-key"`
|
PrivateKey string `inbound:"private-key"`
|
||||||
|
EchKey string `inbound:"ech-key,omitempty"`
|
||||||
CongestionController string `inbound:"congestion-controller,omitempty"`
|
CongestionController string `inbound:"congestion-controller,omitempty"`
|
||||||
MaxIdleTime int `inbound:"max-idle-time,omitempty"`
|
MaxIdleTime int `inbound:"max-idle-time,omitempty"`
|
||||||
AuthenticationTimeout int `inbound:"authentication-timeout,omitempty"`
|
AuthenticationTimeout int `inbound:"authentication-timeout,omitempty"`
|
||||||
@ -50,6 +51,7 @@ func NewTuic(options *TuicOption) (*Tuic, error) {
|
|||||||
Users: options.Users,
|
Users: options.Users,
|
||||||
Certificate: options.Certificate,
|
Certificate: options.Certificate,
|
||||||
PrivateKey: options.PrivateKey,
|
PrivateKey: options.PrivateKey,
|
||||||
|
EchKey: options.EchKey,
|
||||||
CongestionController: options.CongestionController,
|
CongestionController: options.CongestionController,
|
||||||
MaxIdleTime: options.MaxIdleTime,
|
MaxIdleTime: options.MaxIdleTime,
|
||||||
AuthenticationTimeout: options.AuthenticationTimeout,
|
AuthenticationTimeout: options.AuthenticationTimeout,
|
||||||
|
@ -89,4 +89,14 @@ func TestInboundTuic_TLS(t *testing.T) {
|
|||||||
Fingerprint: tlsFingerprint,
|
Fingerprint: tlsFingerprint,
|
||||||
}
|
}
|
||||||
testInboundTuic(t, inboundOptions, outboundOptions)
|
testInboundTuic(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundTuic(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ type VlessOption struct {
|
|||||||
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
|
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
|
||||||
Certificate string `inbound:"certificate,omitempty"`
|
Certificate string `inbound:"certificate,omitempty"`
|
||||||
PrivateKey string `inbound:"private-key,omitempty"`
|
PrivateKey string `inbound:"private-key,omitempty"`
|
||||||
|
EchKey string `inbound:"ech-key,omitempty"`
|
||||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||||
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
||||||
}
|
}
|
||||||
@ -61,6 +62,7 @@ func NewVless(options *VlessOption) (*Vless, error) {
|
|||||||
GrpcServiceName: options.GrpcServiceName,
|
GrpcServiceName: options.GrpcServiceName,
|
||||||
Certificate: options.Certificate,
|
Certificate: options.Certificate,
|
||||||
PrivateKey: options.PrivateKey,
|
PrivateKey: options.PrivateKey,
|
||||||
|
EchKey: options.EchKey,
|
||||||
RealityConfig: options.RealityConfig.Build(),
|
RealityConfig: options.RealityConfig.Build(),
|
||||||
MuxOption: options.MuxOption.Build(),
|
MuxOption: options.MuxOption.Build(),
|
||||||
},
|
},
|
||||||
|
@ -66,9 +66,25 @@ func TestInboundVless_TLS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||||
|
outboundOptions := outboundOptions
|
||||||
outboundOptions.Flow = "xtls-rprx-vision"
|
outboundOptions.Flow = "xtls-rprx-vision"
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
})
|
})
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
outboundOptions.Flow = "xtls-rprx-vision"
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVless_Wss1(t *testing.T) {
|
func TestInboundVless_Wss1(t *testing.T) {
|
||||||
@ -87,9 +103,25 @@ func TestInboundVless_Wss1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||||
|
outboundOptions := outboundOptions
|
||||||
outboundOptions.Flow = "xtls-rprx-vision"
|
outboundOptions.Flow = "xtls-rprx-vision"
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
})
|
})
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
outboundOptions.Flow = "xtls-rprx-vision"
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVless_Wss2(t *testing.T) {
|
func TestInboundVless_Wss2(t *testing.T) {
|
||||||
@ -109,9 +141,25 @@ func TestInboundVless_Wss2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||||
|
outboundOptions := outboundOptions
|
||||||
outboundOptions.Flow = "xtls-rprx-vision"
|
outboundOptions.Flow = "xtls-rprx-vision"
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
})
|
})
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
outboundOptions.Flow = "xtls-rprx-vision"
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVless_Grpc1(t *testing.T) {
|
func TestInboundVless_Grpc1(t *testing.T) {
|
||||||
@ -127,6 +175,16 @@ func TestInboundVless_Grpc1(t *testing.T) {
|
|||||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||||
}
|
}
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVless_Grpc2(t *testing.T) {
|
func TestInboundVless_Grpc2(t *testing.T) {
|
||||||
@ -143,6 +201,16 @@ func TestInboundVless_Grpc2(t *testing.T) {
|
|||||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||||
}
|
}
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVless_Reality(t *testing.T) {
|
func TestInboundVless_Reality(t *testing.T) {
|
||||||
@ -165,9 +233,25 @@ func TestInboundVless_Reality(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||||
|
outboundOptions := outboundOptions
|
||||||
outboundOptions.Flow = "xtls-rprx-vision"
|
outboundOptions.Flow = "xtls-rprx-vision"
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
})
|
})
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
outboundOptions.Flow = "xtls-rprx-vision"
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVless_Reality_Grpc(t *testing.T) {
|
func TestInboundVless_Reality_Grpc(t *testing.T) {
|
||||||
@ -192,4 +276,14 @@ func TestInboundVless_Reality_Grpc(t *testing.T) {
|
|||||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||||
}
|
}
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ type VmessOption struct {
|
|||||||
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
|
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
|
||||||
Certificate string `inbound:"certificate,omitempty"`
|
Certificate string `inbound:"certificate,omitempty"`
|
||||||
PrivateKey string `inbound:"private-key,omitempty"`
|
PrivateKey string `inbound:"private-key,omitempty"`
|
||||||
|
EchKey string `inbound:"ech-key,omitempty"`
|
||||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||||
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
||||||
}
|
}
|
||||||
@ -61,6 +62,7 @@ func NewVmess(options *VmessOption) (*Vmess, error) {
|
|||||||
GrpcServiceName: options.GrpcServiceName,
|
GrpcServiceName: options.GrpcServiceName,
|
||||||
Certificate: options.Certificate,
|
Certificate: options.Certificate,
|
||||||
PrivateKey: options.PrivateKey,
|
PrivateKey: options.PrivateKey,
|
||||||
|
EchKey: options.EchKey,
|
||||||
RealityConfig: options.RealityConfig.Build(),
|
RealityConfig: options.RealityConfig.Build(),
|
||||||
MuxOption: options.MuxOption.Build(),
|
MuxOption: options.MuxOption.Build(),
|
||||||
},
|
},
|
||||||
|
@ -73,6 +73,16 @@ func TestInboundVMess_TLS(t *testing.T) {
|
|||||||
Fingerprint: tlsFingerprint,
|
Fingerprint: tlsFingerprint,
|
||||||
}
|
}
|
||||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVMess_Ws(t *testing.T) {
|
func TestInboundVMess_Ws(t *testing.T) {
|
||||||
@ -160,6 +170,16 @@ func TestInboundVMess_Wss1(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVMess_Wss2(t *testing.T) {
|
func TestInboundVMess_Wss2(t *testing.T) {
|
||||||
@ -178,6 +198,16 @@ func TestInboundVMess_Wss2(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVMess_Grpc1(t *testing.T) {
|
func TestInboundVMess_Grpc1(t *testing.T) {
|
||||||
@ -193,6 +223,16 @@ func TestInboundVMess_Grpc1(t *testing.T) {
|
|||||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||||
}
|
}
|
||||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVMess_Grpc2(t *testing.T) {
|
func TestInboundVMess_Grpc2(t *testing.T) {
|
||||||
@ -209,6 +249,16 @@ func TestInboundVMess_Grpc2(t *testing.T) {
|
|||||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||||
}
|
}
|
||||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
t.Run("ECH", func(t *testing.T) {
|
||||||
|
inboundOptions := inboundOptions
|
||||||
|
outboundOptions := outboundOptions
|
||||||
|
inboundOptions.EchKey = echKeyPem
|
||||||
|
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||||
|
Enable: true,
|
||||||
|
Config: echConfigBase64,
|
||||||
|
}
|
||||||
|
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInboundVMess_Reality(t *testing.T) {
|
func TestInboundVMess_Reality(t *testing.T) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package mixed
|
package mixed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
@ -9,6 +8,8 @@ import (
|
|||||||
N "github.com/metacubex/mihomo/common/net"
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
"github.com/metacubex/mihomo/component/auth"
|
"github.com/metacubex/mihomo/component/auth"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
authStore "github.com/metacubex/mihomo/listener/auth"
|
authStore "github.com/metacubex/mihomo/listener/auth"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
@ -60,7 +61,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig := &tls.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
var realityBuilder *reality.Builder
|
var realityBuilder *reality.Builder
|
||||||
|
|
||||||
if config.Certificate != "" && config.PrivateKey != "" {
|
if config.Certificate != "" && config.PrivateKey != "" {
|
||||||
@ -68,7 +69,14 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||||
|
|
||||||
|
if config.EchKey != "" {
|
||||||
|
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if config.RealityConfig.PrivateKey != "" {
|
if config.RealityConfig.PrivateKey != "" {
|
||||||
if tlsConfig.Certificates != nil {
|
if tlsConfig.Certificates != nil {
|
||||||
@ -83,7 +91,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
|||||||
if realityBuilder != nil {
|
if realityBuilder != nil {
|
||||||
l = realityBuilder.NewListener(l)
|
l = realityBuilder.NewListener(l)
|
||||||
} else if len(tlsConfig.Certificates) > 0 {
|
} else if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tls.NewListener(l, tlsConfig)
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml := &Listener{
|
ml := &Listener{
|
||||||
|
@ -2,7 +2,6 @@ package sing_hysteria2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
@ -15,6 +14,7 @@ import (
|
|||||||
"github.com/metacubex/mihomo/adapter/outbound"
|
"github.com/metacubex/mihomo/adapter/outbound"
|
||||||
"github.com/metacubex/mihomo/common/sockopt"
|
"github.com/metacubex/mihomo/common/sockopt"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
@ -60,9 +60,16 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tlsC.Config{
|
||||||
MinVersion: tls.VersionTLS13,
|
MinVersion: tlsC.VersionTLS13,
|
||||||
Certificates: []tls.Certificate{cert},
|
}
|
||||||
|
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||||
|
|
||||||
|
if config.EchKey != "" {
|
||||||
|
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(config.ALPN) > 0 {
|
if len(config.ALPN) > 0 {
|
||||||
tlsConfig.NextProtos = config.ALPN
|
tlsConfig.NextProtos = config.ALPN
|
||||||
@ -125,7 +132,7 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi
|
|||||||
SendBPS: outbound.StringToBps(config.Up),
|
SendBPS: outbound.StringToBps(config.Up),
|
||||||
ReceiveBPS: outbound.StringToBps(config.Down),
|
ReceiveBPS: outbound.StringToBps(config.Down),
|
||||||
SalamanderPassword: salamanderPassword,
|
SalamanderPassword: salamanderPassword,
|
||||||
TLSConfig: tlsC.UConfig(tlsConfig),
|
TLSConfig: tlsConfig,
|
||||||
QUICConfig: quicConfig,
|
QUICConfig: quicConfig,
|
||||||
IgnoreClientBandwidth: config.IgnoreClientBandwidth,
|
IgnoreClientBandwidth: config.IgnoreClientBandwidth,
|
||||||
UDPTimeout: sing.UDPTimeout,
|
UDPTimeout: sing.UDPTimeout,
|
||||||
|
@ -2,7 +2,6 @@ package sing_vless
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -12,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/metacubex/mihomo/adapter/inbound"
|
"github.com/metacubex/mihomo/adapter/inbound"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
@ -82,7 +82,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
|
|
||||||
sl = &Listener{false, config, nil, service}
|
sl = &Listener{false, config, nil, service}
|
||||||
|
|
||||||
tlsConfig := &tls.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
var realityBuilder *reality.Builder
|
var realityBuilder *reality.Builder
|
||||||
var httpHandler http.Handler
|
var httpHandler http.Handler
|
||||||
|
|
||||||
@ -91,7 +91,14 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||||
|
|
||||||
|
if config.EchKey != "" {
|
||||||
|
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if config.RealityConfig.PrivateKey != "" {
|
if config.RealityConfig.PrivateKey != "" {
|
||||||
if tlsConfig.Certificates != nil {
|
if tlsConfig.Certificates != nil {
|
||||||
@ -137,7 +144,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
if realityBuilder != nil {
|
if realityBuilder != nil {
|
||||||
l = realityBuilder.NewListener(l)
|
l = realityBuilder.NewListener(l)
|
||||||
} else if len(tlsConfig.Certificates) > 0 {
|
} else if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tls.NewListener(l, tlsConfig)
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("disallow using Vless without both certificates/reality config")
|
return nil, errors.New("disallow using Vless without both certificates/reality config")
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package sing_vmess
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -11,6 +10,8 @@ import (
|
|||||||
|
|
||||||
"github.com/metacubex/mihomo/adapter/inbound"
|
"github.com/metacubex/mihomo/adapter/inbound"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
"github.com/metacubex/mihomo/listener/reality"
|
"github.com/metacubex/mihomo/listener/reality"
|
||||||
@ -75,7 +76,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
|
|
||||||
sl = &Listener{false, config, nil, service}
|
sl = &Listener{false, config, nil, service}
|
||||||
|
|
||||||
tlsConfig := &tls.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
var realityBuilder *reality.Builder
|
var realityBuilder *reality.Builder
|
||||||
var httpHandler http.Handler
|
var httpHandler http.Handler
|
||||||
|
|
||||||
@ -84,7 +85,14 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||||
|
|
||||||
|
if config.EchKey != "" {
|
||||||
|
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if config.RealityConfig.PrivateKey != "" {
|
if config.RealityConfig.PrivateKey != "" {
|
||||||
if tlsConfig.Certificates != nil {
|
if tlsConfig.Certificates != nil {
|
||||||
@ -130,7 +138,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
if realityBuilder != nil {
|
if realityBuilder != nil {
|
||||||
l = realityBuilder.NewListener(l)
|
l = realityBuilder.NewListener(l)
|
||||||
} else if len(tlsConfig.Certificates) > 0 {
|
} else if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tls.NewListener(l, tlsConfig)
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
}
|
}
|
||||||
sl.listeners = append(sl.listeners, l)
|
sl.listeners = append(sl.listeners, l)
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package socks
|
package socks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -10,6 +9,8 @@ import (
|
|||||||
N "github.com/metacubex/mihomo/common/net"
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
"github.com/metacubex/mihomo/component/auth"
|
"github.com/metacubex/mihomo/component/auth"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
authStore "github.com/metacubex/mihomo/listener/auth"
|
authStore "github.com/metacubex/mihomo/listener/auth"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
@ -59,7 +60,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig := &tls.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
var realityBuilder *reality.Builder
|
var realityBuilder *reality.Builder
|
||||||
|
|
||||||
if config.Certificate != "" && config.PrivateKey != "" {
|
if config.Certificate != "" && config.PrivateKey != "" {
|
||||||
@ -67,7 +68,14 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||||
|
|
||||||
|
if config.EchKey != "" {
|
||||||
|
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if config.RealityConfig.PrivateKey != "" {
|
if config.RealityConfig.PrivateKey != "" {
|
||||||
if tlsConfig.Certificates != nil {
|
if tlsConfig.Certificates != nil {
|
||||||
@ -82,7 +90,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
|||||||
if realityBuilder != nil {
|
if realityBuilder != nil {
|
||||||
l = realityBuilder.NewListener(l)
|
l = realityBuilder.NewListener(l)
|
||||||
} else if len(tlsConfig.Certificates) > 0 {
|
} else if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tls.NewListener(l, tlsConfig)
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
sl := &Listener{
|
sl := &Listener{
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package trojan
|
package trojan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -10,6 +9,8 @@ import (
|
|||||||
|
|
||||||
"github.com/metacubex/mihomo/adapter/inbound"
|
"github.com/metacubex/mihomo/adapter/inbound"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
"github.com/metacubex/mihomo/listener/reality"
|
"github.com/metacubex/mihomo/listener/reality"
|
||||||
@ -69,7 +70,7 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
}
|
}
|
||||||
sl = &Listener{false, config, nil, keys, pickCipher, h}
|
sl = &Listener{false, config, nil, keys, pickCipher, h}
|
||||||
|
|
||||||
tlsConfig := &tls.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
var realityBuilder *reality.Builder
|
var realityBuilder *reality.Builder
|
||||||
var httpHandler http.Handler
|
var httpHandler http.Handler
|
||||||
|
|
||||||
@ -78,7 +79,14 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||||
|
|
||||||
|
if config.EchKey != "" {
|
||||||
|
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if config.RealityConfig.PrivateKey != "" {
|
if config.RealityConfig.PrivateKey != "" {
|
||||||
if tlsConfig.Certificates != nil {
|
if tlsConfig.Certificates != nil {
|
||||||
@ -124,7 +132,7 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
if realityBuilder != nil {
|
if realityBuilder != nil {
|
||||||
l = realityBuilder.NewListener(l)
|
l = realityBuilder.NewListener(l)
|
||||||
} else if len(tlsConfig.Certificates) > 0 {
|
} else if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tls.NewListener(l, tlsConfig)
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
} else if !config.TrojanSSOption.Enabled {
|
} else if !config.TrojanSSOption.Enabled {
|
||||||
return nil, errors.New("disallow using Trojan without both certificates/reality/ss config")
|
return nil, errors.New("disallow using Trojan without both certificates/reality/ss config")
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package tuic
|
package tuic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -9,6 +8,7 @@ import (
|
|||||||
"github.com/metacubex/mihomo/adapter/inbound"
|
"github.com/metacubex/mihomo/adapter/inbound"
|
||||||
"github.com/metacubex/mihomo/common/sockopt"
|
"github.com/metacubex/mihomo/common/sockopt"
|
||||||
"github.com/metacubex/mihomo/component/ca"
|
"github.com/metacubex/mihomo/component/ca"
|
||||||
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
LC "github.com/metacubex/mihomo/listener/config"
|
LC "github.com/metacubex/mihomo/listener/config"
|
||||||
@ -52,9 +52,16 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tlsC.Config{
|
||||||
MinVersion: tls.VersionTLS13,
|
MinVersion: tlsC.VersionTLS13,
|
||||||
Certificates: []tls.Certificate{cert},
|
}
|
||||||
|
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||||
|
|
||||||
|
if config.EchKey != "" {
|
||||||
|
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(config.ALPN) > 0 {
|
if len(config.ALPN) > 0 {
|
||||||
tlsConfig.NextProtos = config.ALPN
|
tlsConfig.NextProtos = config.ALPN
|
||||||
@ -125,7 +132,7 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) (
|
|||||||
option := &tuic.ServerOption{
|
option := &tuic.ServerOption{
|
||||||
HandleTcpFn: handleTcpFn,
|
HandleTcpFn: handleTcpFn,
|
||||||
HandleUdpFn: handleUdpFn,
|
HandleUdpFn: handleUdpFn,
|
||||||
TlsConfig: tlsC.UConfig(tlsConfig),
|
TlsConfig: tlsConfig,
|
||||||
QuicConfig: quicConfig,
|
QuicConfig: quicConfig,
|
||||||
CongestionController: config.CongestionController,
|
CongestionController: config.CongestionController,
|
||||||
AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond,
|
AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond,
|
||||||
|
@ -239,7 +239,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok {
|
if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok {
|
||||||
tlsConfig := tlsC.UConfig(tlsConfig)
|
tlsConfig := tlsC.UConfig(cfg)
|
||||||
err := echConfig.ClientHandle(ctx, tlsConfig)
|
err := echConfig.ClientHandle(ctx, tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pconn.Close()
|
pconn.Close()
|
||||||
@ -277,7 +277,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
if echConfig != nil {
|
if echConfig != nil {
|
||||||
tlsConfig := tlsC.UConfig(tlsConfig)
|
tlsConfig := tlsC.UConfig(cfg)
|
||||||
err := echConfig.ClientHandle(ctx, tlsConfig)
|
err := echConfig.ClientHandle(ctx, tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pconn.Close()
|
pconn.Close()
|
||||||
|
@ -45,6 +45,12 @@ func NewConn(conn connWithUpstream, userUUID *uuid.UUID) (*Conn, error) {
|
|||||||
c.tlsConn = underlying
|
c.tlsConn = underlying
|
||||||
t = reflect.TypeOf(underlying).Elem()
|
t = reflect.TypeOf(underlying).Elem()
|
||||||
p = unsafe.Pointer(underlying)
|
p = unsafe.Pointer(underlying)
|
||||||
|
case *tlsC.Conn:
|
||||||
|
//log.Debugln("type *tlsC.Conn")
|
||||||
|
c.Conn = underlying.NetConn()
|
||||||
|
c.tlsConn = underlying
|
||||||
|
t = reflect.TypeOf(underlying).Elem()
|
||||||
|
p = unsafe.Pointer(underlying)
|
||||||
case *tlsC.UConn:
|
case *tlsC.UConn:
|
||||||
//log.Debugln("type *tlsC.UConn")
|
//log.Debugln("type *tlsC.UConn")
|
||||||
c.Conn = underlying.NetConn()
|
c.Conn = underlying.NetConn()
|
||||||
|
Loading…
Reference in New Issue
Block a user