mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-20 00:50:06 +08:00
feat: add mTLS support for client & server
`certificate` and `private-key` for proxies `client-auth-type` and `client-auth-cert` for listeners
This commit is contained in:
parent
40b2cde2b2
commit
0dc5e3051d
@ -36,6 +36,8 @@ type AnyTLSOption struct {
|
||||
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
Certificate string `proxy:"certificate,omitempty"`
|
||||
PrivateKey string `proxy:"private-key,omitempty"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
IdleSessionCheckInterval int `proxy:"idle-session-check-interval,omitempty"`
|
||||
IdleSessionTimeout int `proxy:"idle-session-timeout,omitempty"`
|
||||
@ -120,6 +122,8 @@ func NewAnyTLS(option AnyTLSOption) (*AnyTLS, error) {
|
||||
SkipCertVerify: option.SkipCertVerify,
|
||||
NextProtos: option.ALPN,
|
||||
FingerPrint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
ClientFingerprint: option.ClientFingerprint,
|
||||
ECH: echConfig,
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ type HttpOption struct {
|
||||
SNI string `proxy:"sni,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
Certificate string `proxy:"certificate,omitempty"`
|
||||
PrivateKey string `proxy:"private-key,omitempty"`
|
||||
Headers map[string]string `proxy:"headers,omitempty"`
|
||||
}
|
||||
|
||||
@ -173,6 +175,8 @@ func NewHttp(option HttpOption) (*Http, error) {
|
||||
ServerName: sni,
|
||||
},
|
||||
Fingerprint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -125,6 +125,8 @@ type HysteriaOption struct {
|
||||
ECHOpts ECHOptions `proxy:"ech-opts,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
Certificate string `proxy:"certificate,omitempty"`
|
||||
PrivateKey string `proxy:"private-key,omitempty"`
|
||||
ALPN []string `proxy:"alpn,omitempty"`
|
||||
ReceiveWindowConn int `proxy:"recv-window-conn,omitempty"`
|
||||
ReceiveWindow int `proxy:"recv-window,omitempty"`
|
||||
@ -165,6 +167,8 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
|
||||
MinVersion: tls.VersionTLS13,
|
||||
},
|
||||
Fingerprint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -55,6 +55,8 @@ type Hysteria2Option struct {
|
||||
ECHOpts ECHOptions `proxy:"ech-opts,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
Certificate string `proxy:"certificate,omitempty"`
|
||||
PrivateKey string `proxy:"private-key,omitempty"`
|
||||
ALPN []string `proxy:"alpn,omitempty"`
|
||||
CWND int `proxy:"cwnd,omitempty"`
|
||||
UdpMTU int `proxy:"udp-mtu,omitempty"`
|
||||
@ -146,6 +148,8 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) {
|
||||
MinVersion: tls.VersionTLS13,
|
||||
},
|
||||
Fingerprint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -65,6 +65,8 @@ type v2rayObfsOption struct {
|
||||
TLS bool `obfs:"tls,omitempty"`
|
||||
ECHOpts ECHOptions `obfs:"ech-opts,omitempty"`
|
||||
Fingerprint string `obfs:"fingerprint,omitempty"`
|
||||
Certificate string `obfs:"certificate,omitempty"`
|
||||
PrivateKey string `obfs:"private-key,omitempty"`
|
||||
Headers map[string]string `obfs:"headers,omitempty"`
|
||||
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
|
||||
Mux bool `obfs:"mux,omitempty"`
|
||||
@ -79,6 +81,8 @@ type gostObfsOption struct {
|
||||
TLS bool `obfs:"tls,omitempty"`
|
||||
ECHOpts ECHOptions `obfs:"ech-opts,omitempty"`
|
||||
Fingerprint string `obfs:"fingerprint,omitempty"`
|
||||
Certificate string `obfs:"certificate,omitempty"`
|
||||
PrivateKey string `obfs:"private-key,omitempty"`
|
||||
Headers map[string]string `obfs:"headers,omitempty"`
|
||||
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
|
||||
Mux bool `obfs:"mux,omitempty"`
|
||||
@ -88,6 +92,8 @@ type shadowTLSOption struct {
|
||||
Password string `obfs:"password,omitempty"`
|
||||
Host string `obfs:"host"`
|
||||
Fingerprint string `obfs:"fingerprint,omitempty"`
|
||||
Certificate string `obfs:"certificate,omitempty"`
|
||||
PrivateKey string `obfs:"private-key,omitempty"`
|
||||
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
|
||||
Version int `obfs:"version,omitempty"`
|
||||
ALPN []string `obfs:"alpn,omitempty"`
|
||||
@ -302,6 +308,8 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
v2rayOption.TLS = true
|
||||
v2rayOption.SkipCertVerify = opts.SkipCertVerify
|
||||
v2rayOption.Fingerprint = opts.Fingerprint
|
||||
v2rayOption.Certificate = opts.Certificate
|
||||
v2rayOption.PrivateKey = opts.PrivateKey
|
||||
|
||||
echConfig, err := opts.ECHOpts.Parse()
|
||||
if err != nil {
|
||||
@ -330,6 +338,8 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
gostOption.TLS = true
|
||||
gostOption.SkipCertVerify = opts.SkipCertVerify
|
||||
gostOption.Fingerprint = opts.Fingerprint
|
||||
gostOption.Certificate = opts.Certificate
|
||||
gostOption.PrivateKey = opts.PrivateKey
|
||||
|
||||
echConfig, err := opts.ECHOpts.Parse()
|
||||
if err != nil {
|
||||
@ -350,6 +360,8 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
Password: opt.Password,
|
||||
Host: opt.Host,
|
||||
Fingerprint: opt.Fingerprint,
|
||||
Certificate: opt.Certificate,
|
||||
PrivateKey: opt.PrivateKey,
|
||||
ClientFingerprint: option.ClientFingerprint,
|
||||
SkipCertVerify: opt.SkipCertVerify,
|
||||
Version: opt.Version,
|
||||
|
||||
@ -39,6 +39,8 @@ type Socks5Option struct {
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
Certificate string `proxy:"certificate,omitempty"`
|
||||
PrivateKey string `proxy:"private-key,omitempty"`
|
||||
}
|
||||
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
@ -200,6 +202,8 @@ func NewSocks5(option Socks5Option) (*Socks5, error) {
|
||||
ServerName: option.Server,
|
||||
},
|
||||
Fingerprint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -48,6 +48,8 @@ type TrojanOption struct {
|
||||
SNI string `proxy:"sni,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
Certificate string `proxy:"certificate,omitempty"`
|
||||
PrivateKey string `proxy:"private-key,omitempty"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
Network string `proxy:"network,omitempty"`
|
||||
ECHOpts ECHOptions `proxy:"ech-opts,omitempty"`
|
||||
@ -108,6 +110,8 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.
|
||||
ServerName: t.option.SNI,
|
||||
},
|
||||
Fingerprint: t.option.Fingerprint,
|
||||
Certificate: t.option.Certificate,
|
||||
PrivateKey: t.option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -127,6 +131,8 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.
|
||||
Host: t.option.SNI,
|
||||
SkipCertVerify: t.option.SkipCertVerify,
|
||||
FingerPrint: t.option.Fingerprint,
|
||||
Certificate: t.option.Certificate,
|
||||
PrivateKey: t.option.PrivateKey,
|
||||
ClientFingerprint: t.option.ClientFingerprint,
|
||||
NextProtos: alpn,
|
||||
ECH: t.echConfig,
|
||||
@ -372,6 +378,8 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
||||
ServerName: option.SNI,
|
||||
},
|
||||
Fingerprint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -55,6 +55,8 @@ type TuicOption struct {
|
||||
CWND int `proxy:"cwnd,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
Certificate string `proxy:"certificate,omitempty"`
|
||||
PrivateKey string `proxy:"private-key,omitempty"`
|
||||
ReceiveWindowConn int `proxy:"recv-window-conn,omitempty"`
|
||||
ReceiveWindow int `proxy:"recv-window,omitempty"`
|
||||
DisableMTUDiscovery bool `proxy:"disable-mtu-discovery,omitempty"`
|
||||
@ -170,6 +172,8 @@ func NewTuic(option TuicOption) (*Tuic, error) {
|
||||
MinVersion: tls.VersionTLS13,
|
||||
},
|
||||
Fingerprint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -67,6 +67,8 @@ type VlessOption struct {
|
||||
WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
Certificate string `proxy:"certificate,omitempty"`
|
||||
PrivateKey string `proxy:"private-key,omitempty"`
|
||||
ServerName string `proxy:"servername,omitempty"`
|
||||
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
|
||||
}
|
||||
@ -103,6 +105,8 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
|
||||
NextProtos: []string{"http/1.1"},
|
||||
},
|
||||
Fingerprint: v.option.Fingerprint,
|
||||
Certificate: v.option.Certificate,
|
||||
PrivateKey: v.option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -206,6 +210,8 @@ func (v *Vless) streamTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (ne
|
||||
Host: host,
|
||||
SkipCertVerify: v.option.SkipCertVerify,
|
||||
FingerPrint: v.option.Fingerprint,
|
||||
Certificate: v.option.Certificate,
|
||||
PrivateKey: v.option.PrivateKey,
|
||||
ClientFingerprint: v.option.ClientFingerprint,
|
||||
ECH: v.echConfig,
|
||||
Reality: v.realityConfig,
|
||||
@ -505,6 +511,8 @@ func NewVless(option VlessOption) (*Vless, error) {
|
||||
ServerName: v.option.ServerName,
|
||||
},
|
||||
Fingerprint: v.option.Fingerprint,
|
||||
Certificate: v.option.Certificate,
|
||||
PrivateKey: v.option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -58,6 +58,8 @@ type VmessOption struct {
|
||||
ALPN []string `proxy:"alpn,omitempty"`
|
||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
Certificate string `proxy:"certificate,omitempty"`
|
||||
PrivateKey string `proxy:"private-key,omitempty"`
|
||||
ServerName string `proxy:"servername,omitempty"`
|
||||
ECHOpts ECHOptions `proxy:"ech-opts,omitempty"`
|
||||
RealityOpts RealityOptions `proxy:"reality-opts,omitempty"`
|
||||
@ -130,6 +132,8 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
|
||||
NextProtos: []string{"http/1.1"},
|
||||
},
|
||||
Fingerprint: v.option.Fingerprint,
|
||||
Certificate: v.option.Certificate,
|
||||
PrivateKey: v.option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -179,6 +183,8 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
|
||||
Host: host,
|
||||
SkipCertVerify: v.option.SkipCertVerify,
|
||||
FingerPrint: v.option.Fingerprint,
|
||||
Certificate: v.option.Certificate,
|
||||
PrivateKey: v.option.PrivateKey,
|
||||
NextProtos: []string{"h2"},
|
||||
ClientFingerprint: v.option.ClientFingerprint,
|
||||
Reality: v.realityConfig,
|
||||
@ -209,6 +215,8 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M
|
||||
Host: host,
|
||||
SkipCertVerify: v.option.SkipCertVerify,
|
||||
FingerPrint: v.option.Fingerprint,
|
||||
Certificate: v.option.Certificate,
|
||||
PrivateKey: v.option.PrivateKey,
|
||||
ClientFingerprint: v.option.ClientFingerprint,
|
||||
ECH: v.echConfig,
|
||||
Reality: v.realityConfig,
|
||||
@ -508,6 +516,8 @@ func NewVmess(option VmessOption) (*Vmess, error) {
|
||||
ServerName: v.option.ServerName,
|
||||
},
|
||||
Fingerprint: v.option.Fingerprint,
|
||||
Certificate: v.option.Certificate,
|
||||
PrivateKey: v.option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/metacubex/mihomo/common/once"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/ntp"
|
||||
)
|
||||
|
||||
@ -79,6 +80,8 @@ type Option struct {
|
||||
TLSConfig *tls.Config
|
||||
Fingerprint string
|
||||
ZeroTrust bool
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
}
|
||||
|
||||
func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) {
|
||||
@ -101,6 +104,15 @@ func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) {
|
||||
}
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
|
||||
if len(opt.Certificate) > 0 || len(opt.PrivateKey) > 0 {
|
||||
var cert tls.Certificate
|
||||
cert, err = LoadTLSKeyPair(opt.Certificate, opt.PrivateKey, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,8 @@ import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Path interface {
|
||||
@ -56,6 +58,33 @@ func LoadTLSKeyPair(certificate, privateKey string, path Path) (tls.Certificate,
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
func LoadCertificates(certificate string, path Path) (*x509.CertPool, error) {
|
||||
pool := x509.NewCertPool()
|
||||
if pool.AppendCertsFromPEM([]byte(certificate)) {
|
||||
return pool, nil
|
||||
}
|
||||
painTextErr := fmt.Errorf("invalid certificate: %s", certificate)
|
||||
if path == nil {
|
||||
return nil, painTextErr
|
||||
}
|
||||
|
||||
certificate = path.Resolve(certificate)
|
||||
var loadErr error
|
||||
if !path.IsSafePath(certificate) {
|
||||
loadErr = path.ErrNotSafePath(certificate)
|
||||
} else {
|
||||
certPEMBlock, err := os.ReadFile(certificate)
|
||||
if pool.AppendCertsFromPEM(certPEMBlock) {
|
||||
return pool, nil
|
||||
}
|
||||
loadErr = err
|
||||
}
|
||||
if loadErr != nil {
|
||||
return nil, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
type KeyPairType string
|
||||
|
||||
const (
|
||||
@ -85,7 +114,11 @@ func NewRandomTLSKeyPair(keyPairType KeyPairType) (certificate string, privateKe
|
||||
return
|
||||
}
|
||||
|
||||
template := x509.Certificate{SerialNumber: big.NewInt(1)}
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
NotBefore: time.Now().Add(-time.Hour * 24 * 365),
|
||||
NotAfter: time.Now().Add(time.Hour * 24 * 365),
|
||||
}
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, key.Public(), key)
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
45
component/tls/auth.go
Normal file
45
component/tls/auth.go
Normal file
@ -0,0 +1,45 @@
|
||||
package tls
|
||||
|
||||
import (
|
||||
utls "github.com/metacubex/utls"
|
||||
)
|
||||
|
||||
type ClientAuthType = utls.ClientAuthType
|
||||
|
||||
const (
|
||||
NoClientCert = utls.NoClientCert
|
||||
RequestClientCert = utls.RequestClientCert
|
||||
RequireAnyClientCert = utls.RequireAnyClientCert
|
||||
VerifyClientCertIfGiven = utls.VerifyClientCertIfGiven
|
||||
RequireAndVerifyClientCert = utls.RequireAndVerifyClientCert
|
||||
)
|
||||
|
||||
func ClientAuthTypeFromString(s string) ClientAuthType {
|
||||
switch s {
|
||||
case "request":
|
||||
return RequestClientCert
|
||||
case "require-any":
|
||||
return RequireAnyClientCert
|
||||
case "verify-if-given":
|
||||
return VerifyClientCertIfGiven
|
||||
case "require-and-verify":
|
||||
return RequireAndVerifyClientCert
|
||||
default:
|
||||
return NoClientCert
|
||||
}
|
||||
}
|
||||
|
||||
func ClientAuthTypeToString(t ClientAuthType) string {
|
||||
switch t {
|
||||
case RequestClientCert:
|
||||
return "request"
|
||||
case RequireAnyClientCert:
|
||||
return "require-any"
|
||||
case VerifyClientCertIfGiven:
|
||||
return "verify-if-given"
|
||||
case RequireAndVerifyClientCert:
|
||||
return "require-and-verify"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@ -135,6 +135,8 @@ func UConfig(config *tls.Config) *utls.Config {
|
||||
RootCAs: config.RootCAs,
|
||||
NextProtos: config.NextProtos,
|
||||
ServerName: config.ServerName,
|
||||
ClientAuth: utls.ClientAuthType(config.ClientAuth),
|
||||
ClientCAs: config.ClientCAs,
|
||||
InsecureSkipVerify: config.InsecureSkipVerify,
|
||||
CipherSuites: config.CipherSuites,
|
||||
MinVersion: config.MinVersion,
|
||||
|
||||
@ -174,6 +174,8 @@ type Profile struct {
|
||||
type TLS struct {
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
ClientAuthType string
|
||||
ClientAuthCert string
|
||||
EchKey string
|
||||
CustomTrustCert []string
|
||||
}
|
||||
@ -368,6 +370,8 @@ type RawSniffingConfig struct {
|
||||
type RawTLS struct {
|
||||
Certificate string `yaml:"certificate" json:"certificate"`
|
||||
PrivateKey string `yaml:"private-key" json:"private-key"`
|
||||
ClientAuthType string `yaml:"client-auth-type" json:"client-auth-type"`
|
||||
ClientAuthCert string `yaml:"client-auth-cert" json:"client-auth-cert"`
|
||||
EchKey string `yaml:"ech-key" json:"ech-key"`
|
||||
CustomTrustCert []string `yaml:"custom-certifactes" json:"custom-certifactes"`
|
||||
}
|
||||
@ -827,6 +831,8 @@ func parseTLS(cfg *RawConfig) (*TLS, error) {
|
||||
return &TLS{
|
||||
Certificate: cfg.TLS.Certificate,
|
||||
PrivateKey: cfg.TLS.PrivateKey,
|
||||
ClientAuthType: cfg.TLS.ClientAuthType,
|
||||
ClientAuthCert: cfg.TLS.ClientAuthCert,
|
||||
EchKey: cfg.TLS.EchKey,
|
||||
CustomTrustCert: cfg.TLS.CustomTrustCert,
|
||||
}, nil
|
||||
|
||||
112
docs/config.yaml
112
docs/config.yaml
@ -48,6 +48,9 @@ ipv6: true # 开启 IPv6 总开关,关闭阻断所有 IPv6 链接和屏蔽 DNS
|
||||
tls:
|
||||
certificate: string # 证书 PEM 格式,或者 证书的路径
|
||||
private-key: string # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
@ -350,6 +353,9 @@ proxies: # socks5
|
||||
# password: password
|
||||
# tls: true
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# skip-cert-verify: true
|
||||
# udp: true
|
||||
# ip-version: ipv6
|
||||
@ -365,6 +371,9 @@ proxies: # socks5
|
||||
# skip-cert-verify: true
|
||||
# sni: custom.com
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# ip-version: dual
|
||||
|
||||
# Snell
|
||||
@ -433,6 +442,9 @@ proxies: # socks5
|
||||
mode: websocket # no QUIC now
|
||||
# tls: true # wss
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# ech-opts:
|
||||
# enable: true # 必须手动开启
|
||||
# # 如果config为空则通过dns解析,不为空则通过该值指定,格式为经过base64编码的ech参数(dig +short TYPE65 tls-ech.dev)
|
||||
@ -471,6 +483,9 @@ proxies: # socks5
|
||||
mode: websocket
|
||||
# tls: true # wss
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# skip-cert-verify: true
|
||||
# host: bing.com
|
||||
# path: "/"
|
||||
@ -531,6 +546,9 @@ proxies: # socks5
|
||||
# udp: true
|
||||
# tls: true
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# client-fingerprint: chrome # Available: "chrome","firefox","safari","ios","random", currently only support TLS transport in TCP/GRPC/WS/HTTP for VLESS/Vmess and trojan.
|
||||
# skip-cert-verify: true
|
||||
# servername: example.com # priority over wss host
|
||||
@ -558,6 +576,9 @@ proxies: # socks5
|
||||
network: h2
|
||||
tls: true
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
h2-opts:
|
||||
host:
|
||||
- http.example.com
|
||||
@ -593,6 +614,9 @@ proxies: # socks5
|
||||
network: grpc
|
||||
tls: true
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
servername: example.com
|
||||
# skip-cert-verify: true
|
||||
grpc-opts:
|
||||
@ -608,6 +632,9 @@ proxies: # socks5
|
||||
network: tcp
|
||||
servername: example.com # AKA SNI
|
||||
# skip-cert-verify: true
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# client-fingerprint: random # Available: "chrome","firefox","safari","random","none"
|
||||
# ech-opts:
|
||||
@ -625,6 +652,9 @@ proxies: # socks5
|
||||
udp: true
|
||||
flow: xtls-rprx-vision
|
||||
client-fingerprint: chrome
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# skip-cert-verify: true
|
||||
|
||||
@ -696,6 +726,9 @@ proxies: # socks5
|
||||
servername: example.com # priority over wss host
|
||||
# skip-cert-verify: true
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
ws-opts:
|
||||
path: "/"
|
||||
headers:
|
||||
@ -711,6 +744,9 @@ proxies: # socks5
|
||||
password: yourpsk
|
||||
# client-fingerprint: random # Available: "chrome","firefox","safari","random","none"
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# udp: true
|
||||
# sni: example.com # aka server name
|
||||
# alpn:
|
||||
@ -735,6 +771,9 @@ proxies: # socks5
|
||||
sni: example.com
|
||||
# skip-cert-verify: true
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
udp: true
|
||||
grpc-opts:
|
||||
grpc-service-name: "example"
|
||||
@ -748,6 +787,9 @@ proxies: # socks5
|
||||
sni: example.com
|
||||
# skip-cert-verify: true
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
udp: true
|
||||
# ws-opts:
|
||||
# path: /path
|
||||
@ -767,6 +809,9 @@ proxies: # socks5
|
||||
# sni: example.com # aka server name
|
||||
# skip-cert-verify: true
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
|
||||
#hysteria
|
||||
- name: "hysteria"
|
||||
@ -791,6 +836,9 @@ proxies: # socks5
|
||||
# recv-window: 52428800
|
||||
# disable-mtu-discovery: false
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# fast-open: true # 支持 TCP 快速打开,默认为 false
|
||||
|
||||
#hysteria2
|
||||
@ -813,6 +861,9 @@ proxies: # socks5
|
||||
# config: AEn+DQBFKwAgACABWIHUGj4u+PIggYXcR5JF0gYk3dCRioBW8uJq9H4mKAAIAAEAAQABAANAEnB1YmxpYy50bHMtZWNoLmRldgAA
|
||||
# skip-cert-verify: false
|
||||
# fingerprint: xxxx # 配置指纹将实现 SSL Pining 效果, 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取
|
||||
# 下面两项如果填写则开启 mTLS(需要同时填写)
|
||||
# certificate: ./client.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./client.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# alpn:
|
||||
# - h3
|
||||
###quic-go特殊配置项,不要随意修改除非你知道你在干什么###
|
||||
@ -1193,8 +1244,11 @@ listeners:
|
||||
# - username: aaa
|
||||
# password: aaa
|
||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
# certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
@ -1213,8 +1267,11 @@ listeners:
|
||||
# - username: aaa
|
||||
# password: aaa
|
||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
# certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
@ -1234,8 +1291,11 @@ listeners:
|
||||
# - username: aaa
|
||||
# password: aaa
|
||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
# certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
@ -1290,8 +1350,11 @@ listeners:
|
||||
# ws-path: "/" # 如果不为空则开启 websocket 传输层
|
||||
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
|
||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
# certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
@ -1329,8 +1392,11 @@ listeners:
|
||||
# users: # tuicV5 填写(可以同时填写 token)
|
||||
# 00000000-0000-0000-0000-000000000000: PASSWORD_0
|
||||
# 00000000-0000-0000-0000-000000000001: PASSWORD_1
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
# certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
@ -1380,8 +1446,11 @@ listeners:
|
||||
# -------------------------
|
||||
# decryption: "mlkem768x25519plus.native/xorpub/random.600s(300-600s)/0s.(padding len).(padding gap).(X25519 PrivateKey).(ML-KEM-768 Seed)..."
|
||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
# certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
@ -1417,8 +1486,11 @@ listeners:
|
||||
username1: password1
|
||||
username2: password2
|
||||
# "certificate" and "private-key" are required
|
||||
certificate: ./server.crt
|
||||
certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
private-key: ./server.key
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
@ -1440,8 +1512,11 @@ listeners:
|
||||
# ws-path: "/" # 如果不为空则开启 websocket 传输层
|
||||
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
|
||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||
certificate: ./server.crt
|
||||
private-key: ./server.key
|
||||
certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
@ -1482,8 +1557,11 @@ listeners:
|
||||
users:
|
||||
00000000-0000-0000-0000-000000000000: PASSWORD_0
|
||||
00000000-0000-0000-0000-000000000001: PASSWORD_1
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
# certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
# private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
|
||||
@ -57,6 +57,8 @@ func applyRoute(cfg *config.Config) {
|
||||
Secret: cfg.Controller.Secret,
|
||||
Certificate: cfg.TLS.Certificate,
|
||||
PrivateKey: cfg.TLS.PrivateKey,
|
||||
ClientAuthType: cfg.TLS.ClientAuthType,
|
||||
ClientAuthCert: cfg.TLS.ClientAuthCert,
|
||||
EchKey: cfg.TLS.EchKey,
|
||||
DohServer: cfg.Controller.ExternalDohServer,
|
||||
IsDebug: cfg.General.LogLevel == log.DEBUG,
|
||||
|
||||
@ -64,6 +64,8 @@ type Config struct {
|
||||
Secret string
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
ClientAuthType string
|
||||
ClientAuthCert string
|
||||
EchKey string
|
||||
DohServer string
|
||||
IsDebug bool
|
||||
@ -205,6 +207,20 @@ func startTLS(cfg *Config) {
|
||||
tlsConfig := &tlsC.Config{Time: ntp.Now}
|
||||
tlsConfig.NextProtos = []string{"h2", "http/1.1"}
|
||||
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(cfg.ClientAuthType)
|
||||
if len(cfg.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(cfg.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
log.Errorln("External controller tls listen error: %s", err)
|
||||
return
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
|
||||
if cfg.EchKey != "" {
|
||||
err = ech.LoadECHKey(cfg.EchKey, tlsConfig, C.Path)
|
||||
|
||||
@ -58,6 +58,19 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
||||
}
|
||||
}
|
||||
}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType)
|
||||
if len(config.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
|
||||
sl = &Listener{
|
||||
config: config,
|
||||
|
||||
@ -10,6 +10,8 @@ type AnyTLSServer struct {
|
||||
Users map[string]string `yaml:"users" json:"users,omitempty"`
|
||||
Certificate string `yaml:"certificate" json:"certificate"`
|
||||
PrivateKey string `yaml:"private-key" json:"private-key"`
|
||||
ClientAuthType string `yaml:"client-auth-type" json:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `yaml:"client-auth-cert" json:"client-auth-cert,omitempty"`
|
||||
EchKey string `yaml:"ech-key" json:"ech-key"`
|
||||
PaddingScheme string `yaml:"padding-scheme" json:"padding-scheme,omitempty"`
|
||||
}
|
||||
|
||||
@ -12,6 +12,8 @@ type AuthServer struct {
|
||||
AuthStore auth.AuthStore
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
ClientAuthType string
|
||||
ClientAuthCert string
|
||||
EchKey string
|
||||
RealityConfig reality.Config
|
||||
}
|
||||
|
||||
@ -14,6 +14,8 @@ type Hysteria2Server struct {
|
||||
ObfsPassword string `yaml:"obfs-password" json:"obfs-password,omitempty"`
|
||||
Certificate string `yaml:"certificate" json:"certificate"`
|
||||
PrivateKey string `yaml:"private-key" json:"private-key"`
|
||||
ClientAuthType string `yaml:"client-auth-type" json:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `yaml:"client-auth-cert" json:"client-auth-cert,omitempty"`
|
||||
EchKey string `yaml:"ech-key" json:"ech-key,omitempty"`
|
||||
MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"`
|
||||
ALPN []string `yaml:"alpn" json:"alpn,omitempty"`
|
||||
|
||||
@ -20,6 +20,8 @@ type TrojanServer struct {
|
||||
GrpcServiceName string
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
ClientAuthType string
|
||||
ClientAuthCert string
|
||||
EchKey string
|
||||
RealityConfig reality.Config
|
||||
MuxOption sing.MuxOption
|
||||
|
||||
@ -13,6 +13,8 @@ type TuicServer struct {
|
||||
Users map[string]string `yaml:"users" json:"users,omitempty"`
|
||||
Certificate string `yaml:"certificate" json:"certificate"`
|
||||
PrivateKey string `yaml:"private-key" json:"private-key"`
|
||||
ClientAuthType string `yaml:"client-auth-type" json:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `yaml:"client-auth-cert" json:"client-auth-cert,omitempty"`
|
||||
EchKey string `yaml:"ech-key" json:"ech-key"`
|
||||
CongestionController string `yaml:"congestion-controller" json:"congestion-controller,omitempty"`
|
||||
MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"`
|
||||
|
||||
@ -22,6 +22,8 @@ type VlessServer struct {
|
||||
GrpcServiceName string
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
ClientAuthType string
|
||||
ClientAuthCert string
|
||||
EchKey string
|
||||
RealityConfig reality.Config
|
||||
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
|
||||
|
||||
@ -21,6 +21,8 @@ type VmessServer struct {
|
||||
GrpcServiceName string
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
ClientAuthType string
|
||||
ClientAuthCert string
|
||||
EchKey string
|
||||
RealityConfig reality.Config
|
||||
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
|
||||
|
||||
@ -83,6 +83,19 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
||||
}
|
||||
}
|
||||
}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType)
|
||||
if len(config.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
if config.RealityConfig.PrivateKey != "" {
|
||||
if tlsConfig.Certificates != nil {
|
||||
return nil, errors.New("certificate is unavailable in reality")
|
||||
|
||||
@ -14,6 +14,8 @@ type AnyTLSOption struct {
|
||||
Users map[string]string `inbound:"users,omitempty"`
|
||||
Certificate string `inbound:"certificate"`
|
||||
PrivateKey string `inbound:"private-key"`
|
||||
ClientAuthType string `inbound:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `inbound:"client-auth-cert,omitempty"`
|
||||
EchKey string `inbound:"ech-key,omitempty"`
|
||||
PaddingScheme string `inbound:"padding-scheme,omitempty"`
|
||||
}
|
||||
@ -43,6 +45,8 @@ func NewAnyTLS(options *AnyTLSOption) (*AnyTLS, error) {
|
||||
Users: options.Users,
|
||||
Certificate: options.Certificate,
|
||||
PrivateKey: options.PrivateKey,
|
||||
ClientAuthType: options.ClientAuthType,
|
||||
ClientAuthCert: options.ClientAuthCert,
|
||||
EchKey: options.EchKey,
|
||||
PaddingScheme: options.PaddingScheme,
|
||||
},
|
||||
|
||||
@ -70,4 +70,25 @@ func TestInboundAnyTLS_TLS(t *testing.T) {
|
||||
}
|
||||
testInboundAnyTLS(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
testInboundAnyTLS(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS+ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
inboundOptions.EchKey = echKeyPem
|
||||
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||
Enable: true,
|
||||
Config: echConfigBase64,
|
||||
}
|
||||
testInboundAnyTLS(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ var httpData = make([]byte, 2*pool.RelayBufferSize)
|
||||
var remoteAddr = netip.MustParseAddr("1.2.3.4")
|
||||
var userUUID = utils.NewUUIDV4().String()
|
||||
var tlsCertificate, tlsPrivateKey, tlsFingerprint, _ = ca.NewRandomTLSKeyPair(ca.KeyPairTypeP256)
|
||||
var tlsAuthCertificate, tlsAuthPrivateKey, _, _ = ca.NewRandomTLSKeyPair(ca.KeyPairTypeP256)
|
||||
var tlsConfigCert, _ = tls.X509KeyPair([]byte(tlsCertificate), []byte(tlsPrivateKey))
|
||||
var tlsConfig = &tls.Config{Certificates: []tls.Certificate{tlsConfigCert}, NextProtos: []string{"h2", "http/1.1"}}
|
||||
var tlsClientConfig, _ = ca.GetTLSConfig(ca.Option{Fingerprint: tlsFingerprint})
|
||||
|
||||
@ -16,6 +16,8 @@ type HTTPOption struct {
|
||||
Users AuthUsers `inbound:"users,omitempty"`
|
||||
Certificate string `inbound:"certificate,omitempty"`
|
||||
PrivateKey string `inbound:"private-key,omitempty"`
|
||||
ClientAuthType string `inbound:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `inbound:"client-auth-cert,omitempty"`
|
||||
EchKey string `inbound:"ech-key,omitempty"`
|
||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||
}
|
||||
@ -65,6 +67,8 @@ func (h *HTTP) Listen(tunnel C.Tunnel) error {
|
||||
AuthStore: h.config.Users.GetAuthStore(),
|
||||
Certificate: h.config.Certificate,
|
||||
PrivateKey: h.config.PrivateKey,
|
||||
ClientAuthType: h.config.ClientAuthType,
|
||||
ClientAuthCert: h.config.ClientAuthCert,
|
||||
EchKey: h.config.EchKey,
|
||||
RealityConfig: h.config.RealityConfig.Build(),
|
||||
},
|
||||
|
||||
@ -16,6 +16,8 @@ type Hysteria2Option struct {
|
||||
ObfsPassword string `inbound:"obfs-password,omitempty"`
|
||||
Certificate string `inbound:"certificate"`
|
||||
PrivateKey string `inbound:"private-key"`
|
||||
ClientAuthType string `inbound:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `inbound:"client-auth-cert,omitempty"`
|
||||
EchKey string `inbound:"ech-key,omitempty"`
|
||||
MaxIdleTime int `inbound:"max-idle-time,omitempty"`
|
||||
ALPN []string `inbound:"alpn,omitempty"`
|
||||
@ -61,6 +63,8 @@ func NewHysteria2(options *Hysteria2Option) (*Hysteria2, error) {
|
||||
ObfsPassword: options.ObfsPassword,
|
||||
Certificate: options.Certificate,
|
||||
PrivateKey: options.PrivateKey,
|
||||
ClientAuthType: options.ClientAuthType,
|
||||
ClientAuthCert: options.ClientAuthCert,
|
||||
EchKey: options.EchKey,
|
||||
MaxIdleTime: options.MaxIdleTime,
|
||||
ALPN: options.ALPN,
|
||||
|
||||
@ -51,14 +51,7 @@ func testInboundHysteria2(t *testing.T, inboundOptions inbound.Hysteria2Option,
|
||||
tunnel.DoTest(t, out)
|
||||
}
|
||||
|
||||
func TestInboundHysteria2_TLS(t *testing.T) {
|
||||
inboundOptions := inbound.Hysteria2Option{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
}
|
||||
outboundOptions := outbound.Hysteria2Option{
|
||||
Fingerprint: tlsFingerprint,
|
||||
}
|
||||
func testInboundHysteria2TLS(t *testing.T, inboundOptions inbound.Hysteria2Option, outboundOptions outbound.Hysteria2Option) {
|
||||
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||
t.Run("ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
@ -70,6 +63,38 @@ func TestInboundHysteria2_TLS(t *testing.T) {
|
||||
}
|
||||
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS+ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
inboundOptions.EchKey = echKeyPem
|
||||
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||
Enable: true,
|
||||
Config: echConfigBase64,
|
||||
}
|
||||
testInboundHysteria2(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboundHysteria2_TLS(t *testing.T) {
|
||||
inboundOptions := inbound.Hysteria2Option{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
}
|
||||
outboundOptions := outbound.Hysteria2Option{
|
||||
Fingerprint: tlsFingerprint,
|
||||
}
|
||||
testInboundHysteria2TLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundHysteria2_Salamander(t *testing.T) {
|
||||
@ -84,17 +109,7 @@ func TestInboundHysteria2_Salamander(t *testing.T) {
|
||||
Obfs: "salamander",
|
||||
ObfsPassword: userUUID,
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundHysteria2TLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundHysteria2_Brutal(t *testing.T) {
|
||||
@ -109,15 +124,5 @@ func TestInboundHysteria2_Brutal(t *testing.T) {
|
||||
Up: "30 Mbps",
|
||||
Down: "200 Mbps",
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundHysteria2TLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ type MixedOption struct {
|
||||
UDP bool `inbound:"udp,omitempty"`
|
||||
Certificate string `inbound:"certificate,omitempty"`
|
||||
PrivateKey string `inbound:"private-key,omitempty"`
|
||||
ClientAuthType string `inbound:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `inbound:"client-auth-cert,omitempty"`
|
||||
EchKey string `inbound:"ech-key,omitempty"`
|
||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||
}
|
||||
@ -70,6 +72,8 @@ func (m *Mixed) Listen(tunnel C.Tunnel) error {
|
||||
AuthStore: m.config.Users.GetAuthStore(),
|
||||
Certificate: m.config.Certificate,
|
||||
PrivateKey: m.config.PrivateKey,
|
||||
ClientAuthType: m.config.ClientAuthType,
|
||||
ClientAuthCert: m.config.ClientAuthCert,
|
||||
EchKey: m.config.EchKey,
|
||||
RealityConfig: m.config.RealityConfig.Build(),
|
||||
},
|
||||
|
||||
@ -17,6 +17,8 @@ type SocksOption struct {
|
||||
UDP bool `inbound:"udp,omitempty"`
|
||||
Certificate string `inbound:"certificate,omitempty"`
|
||||
PrivateKey string `inbound:"private-key,omitempty"`
|
||||
ClientAuthType string `inbound:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `inbound:"client-auth-cert,omitempty"`
|
||||
EchKey string `inbound:"ech-key,omitempty"`
|
||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||
}
|
||||
@ -90,6 +92,8 @@ func (s *Socks) Listen(tunnel C.Tunnel) error {
|
||||
AuthStore: s.config.Users.GetAuthStore(),
|
||||
Certificate: s.config.Certificate,
|
||||
PrivateKey: s.config.PrivateKey,
|
||||
ClientAuthType: s.config.ClientAuthType,
|
||||
ClientAuthCert: s.config.ClientAuthCert,
|
||||
EchKey: s.config.EchKey,
|
||||
RealityConfig: s.config.RealityConfig.Build(),
|
||||
},
|
||||
|
||||
@ -16,6 +16,8 @@ type TrojanOption struct {
|
||||
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
|
||||
Certificate string `inbound:"certificate,omitempty"`
|
||||
PrivateKey string `inbound:"private-key,omitempty"`
|
||||
ClientAuthType string `inbound:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `inbound:"client-auth-cert,omitempty"`
|
||||
EchKey string `inbound:"ech-key,omitempty"`
|
||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
||||
@ -68,6 +70,8 @@ func NewTrojan(options *TrojanOption) (*Trojan, error) {
|
||||
GrpcServiceName: options.GrpcServiceName,
|
||||
Certificate: options.Certificate,
|
||||
PrivateKey: options.PrivateKey,
|
||||
ClientAuthType: options.ClientAuthType,
|
||||
ClientAuthCert: options.ClientAuthCert,
|
||||
EchKey: options.EchKey,
|
||||
RealityConfig: options.RealityConfig.Build(),
|
||||
MuxOption: options.MuxOption.Build(),
|
||||
|
||||
@ -58,14 +58,7 @@ func testInboundTrojan(t *testing.T, inboundOptions inbound.TrojanOption, outbou
|
||||
testSingMux(t, tunnel, out)
|
||||
}
|
||||
|
||||
func TestInboundTrojan_TLS(t *testing.T) {
|
||||
inboundOptions := inbound.TrojanOption{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
}
|
||||
outboundOptions := outbound.TrojanOption{
|
||||
Fingerprint: tlsFingerprint,
|
||||
}
|
||||
func testInboundTrojanTLS(t *testing.T, inboundOptions inbound.TrojanOption, outboundOptions outbound.TrojanOption) {
|
||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||
t.Run("ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
@ -77,6 +70,38 @@ func TestInboundTrojan_TLS(t *testing.T) {
|
||||
}
|
||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS+ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
inboundOptions.EchKey = echKeyPem
|
||||
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||
Enable: true,
|
||||
Config: echConfigBase64,
|
||||
}
|
||||
testInboundTrojan(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboundTrojan_TLS(t *testing.T) {
|
||||
inboundOptions := inbound.TrojanOption{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
}
|
||||
outboundOptions := outbound.TrojanOption{
|
||||
Fingerprint: tlsFingerprint,
|
||||
}
|
||||
testInboundTrojanTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundTrojan_Wss1(t *testing.T) {
|
||||
@ -92,17 +117,7 @@ func TestInboundTrojan_Wss1(t *testing.T) {
|
||||
Path: "/ws",
|
||||
},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundTrojanTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundTrojan_Wss2(t *testing.T) {
|
||||
@ -119,17 +134,7 @@ func TestInboundTrojan_Wss2(t *testing.T) {
|
||||
Path: "/ws",
|
||||
},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundTrojanTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundTrojan_Grpc1(t *testing.T) {
|
||||
@ -143,17 +148,7 @@ func TestInboundTrojan_Grpc1(t *testing.T) {
|
||||
Network: "grpc",
|
||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundTrojanTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundTrojan_Grpc2(t *testing.T) {
|
||||
@ -168,17 +163,7 @@ func TestInboundTrojan_Grpc2(t *testing.T) {
|
||||
Network: "grpc",
|
||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundTrojanTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundTrojan_Reality(t *testing.T) {
|
||||
@ -242,17 +227,7 @@ func TestInboundTrojan_TLS_TrojanSS(t *testing.T) {
|
||||
Password: "password",
|
||||
},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundTrojanTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundTrojan_Wss_TrojanSS(t *testing.T) {
|
||||
@ -278,15 +253,5 @@ func TestInboundTrojan_Wss_TrojanSS(t *testing.T) {
|
||||
Path: "/ws",
|
||||
},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundTrojanTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
@ -15,6 +15,8 @@ type TuicOption struct {
|
||||
Users map[string]string `inbound:"users,omitempty"`
|
||||
Certificate string `inbound:"certificate"`
|
||||
PrivateKey string `inbound:"private-key"`
|
||||
ClientAuthType string `inbound:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `inbound:"client-auth-cert,omitempty"`
|
||||
EchKey string `inbound:"ech-key,omitempty"`
|
||||
CongestionController string `inbound:"congestion-controller,omitempty"`
|
||||
MaxIdleTime int `inbound:"max-idle-time,omitempty"`
|
||||
@ -51,6 +53,8 @@ func NewTuic(options *TuicOption) (*Tuic, error) {
|
||||
Users: options.Users,
|
||||
Certificate: options.Certificate,
|
||||
PrivateKey: options.PrivateKey,
|
||||
ClientAuthType: options.ClientAuthType,
|
||||
ClientAuthCert: options.ClientAuthCert,
|
||||
EchKey: options.EchKey,
|
||||
CongestionController: options.CongestionController,
|
||||
MaxIdleTime: options.MaxIdleTime,
|
||||
|
||||
@ -99,4 +99,25 @@ func TestInboundTuic_TLS(t *testing.T) {
|
||||
}
|
||||
testInboundTuic(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
testInboundTuic(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS+ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
inboundOptions.EchKey = echKeyPem
|
||||
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||
Enable: true,
|
||||
Config: echConfigBase64,
|
||||
}
|
||||
testInboundTuic(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
}
|
||||
|
||||
@ -17,6 +17,8 @@ type VlessOption struct {
|
||||
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
|
||||
Certificate string `inbound:"certificate,omitempty"`
|
||||
PrivateKey string `inbound:"private-key,omitempty"`
|
||||
ClientAuthType string `inbound:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `inbound:"client-auth-cert,omitempty"`
|
||||
EchKey string `inbound:"ech-key,omitempty"`
|
||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
||||
@ -64,6 +66,8 @@ func NewVless(options *VlessOption) (*Vless, error) {
|
||||
GrpcServiceName: options.GrpcServiceName,
|
||||
Certificate: options.Certificate,
|
||||
PrivateKey: options.PrivateKey,
|
||||
ClientAuthType: options.ClientAuthType,
|
||||
ClientAuthCert: options.ClientAuthCert,
|
||||
EchKey: options.EchKey,
|
||||
RealityConfig: options.RealityConfig.Build(),
|
||||
MuxOption: options.MuxOption.Build(),
|
||||
|
||||
@ -59,21 +59,15 @@ func testInboundVless(t *testing.T, inboundOptions inbound.VlessOption, outbound
|
||||
testSingMux(t, tunnel, out)
|
||||
}
|
||||
|
||||
func TestInboundVless_TLS(t *testing.T) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
TLS: true,
|
||||
Fingerprint: tlsFingerprint,
|
||||
}
|
||||
func testInboundVlessTLS(t *testing.T, inboundOptions inbound.VlessOption, outboundOptions outbound.VlessOption, testVision bool) {
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
if testVision {
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
outboundOptions := outboundOptions
|
||||
outboundOptions.Flow = "xtls-rprx-vision"
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
}
|
||||
t.Run("ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
@ -83,12 +77,61 @@ func TestInboundVless_TLS(t *testing.T) {
|
||||
Config: echConfigBase64,
|
||||
}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
if testVision {
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
outboundOptions := outboundOptions
|
||||
outboundOptions.Flow = "xtls-rprx-vision"
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
}
|
||||
})
|
||||
t.Run("mTLS", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
if testVision {
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
outboundOptions := outboundOptions
|
||||
outboundOptions.Flow = "xtls-rprx-vision"
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
}
|
||||
})
|
||||
t.Run("mTLS+ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
inboundOptions.EchKey = echKeyPem
|
||||
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||
Enable: true,
|
||||
Config: echConfigBase64,
|
||||
}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
if testVision {
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
outboundOptions := outboundOptions
|
||||
outboundOptions.Flow = "xtls-rprx-vision"
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboundVless_TLS(t *testing.T) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
TLS: true,
|
||||
Fingerprint: tlsFingerprint,
|
||||
}
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, true)
|
||||
}
|
||||
|
||||
func TestInboundVless_Encryption(t *testing.T) {
|
||||
@ -183,17 +226,7 @@ func TestInboundVless_Wss1(t *testing.T) {
|
||||
Network: "ws",
|
||||
WSOpts: outbound.WSOptions{Path: "/ws"},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, false)
|
||||
}
|
||||
|
||||
func TestInboundVless_Wss2(t *testing.T) {
|
||||
@ -209,17 +242,7 @@ func TestInboundVless_Wss2(t *testing.T) {
|
||||
Network: "ws",
|
||||
WSOpts: outbound.WSOptions{Path: "/ws"},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, false)
|
||||
}
|
||||
|
||||
func TestInboundVless_Grpc1(t *testing.T) {
|
||||
@ -234,17 +257,7 @@ func TestInboundVless_Grpc1(t *testing.T) {
|
||||
Network: "grpc",
|
||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, false)
|
||||
}
|
||||
|
||||
func TestInboundVless_Grpc2(t *testing.T) {
|
||||
@ -260,17 +273,7 @@ func TestInboundVless_Grpc2(t *testing.T) {
|
||||
Network: "grpc",
|
||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, false)
|
||||
}
|
||||
|
||||
func TestInboundVless_Reality(t *testing.T) {
|
||||
|
||||
@ -16,6 +16,8 @@ type VmessOption struct {
|
||||
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
|
||||
Certificate string `inbound:"certificate,omitempty"`
|
||||
PrivateKey string `inbound:"private-key,omitempty"`
|
||||
ClientAuthType string `inbound:"client-auth-type,omitempty"`
|
||||
ClientAuthCert string `inbound:"client-auth-cert,omitempty"`
|
||||
EchKey string `inbound:"ech-key,omitempty"`
|
||||
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
|
||||
MuxOption MuxOption `inbound:"mux-option,omitempty"`
|
||||
@ -62,6 +64,8 @@ func NewVmess(options *VmessOption) (*Vmess, error) {
|
||||
GrpcServiceName: options.GrpcServiceName,
|
||||
Certificate: options.Certificate,
|
||||
PrivateKey: options.PrivateKey,
|
||||
ClientAuthType: options.ClientAuthType,
|
||||
ClientAuthCert: options.ClientAuthCert,
|
||||
EchKey: options.EchKey,
|
||||
RealityConfig: options.RealityConfig.Build(),
|
||||
MuxOption: options.MuxOption.Build(),
|
||||
|
||||
@ -66,15 +66,7 @@ func TestInboundVMess_Basic(t *testing.T) {
|
||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundVMess_TLS(t *testing.T) {
|
||||
inboundOptions := inbound.VmessOption{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
}
|
||||
outboundOptions := outbound.VmessOption{
|
||||
TLS: true,
|
||||
Fingerprint: tlsFingerprint,
|
||||
}
|
||||
func testInboundVMessTLS(t *testing.T, inboundOptions inbound.VmessOption, outboundOptions outbound.VmessOption) {
|
||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||
t.Run("ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
@ -86,6 +78,39 @@ func TestInboundVMess_TLS(t *testing.T) {
|
||||
}
|
||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
t.Run("mTLS+ECH", func(t *testing.T) {
|
||||
inboundOptions := inboundOptions
|
||||
outboundOptions := outboundOptions
|
||||
inboundOptions.ClientAuthCert = tlsAuthCertificate
|
||||
outboundOptions.Certificate = tlsAuthCertificate
|
||||
outboundOptions.PrivateKey = tlsAuthPrivateKey
|
||||
inboundOptions.EchKey = echKeyPem
|
||||
outboundOptions.ECHOpts = outbound.ECHOptions{
|
||||
Enable: true,
|
||||
Config: echConfigBase64,
|
||||
}
|
||||
testInboundVMess(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboundVMess_TLS(t *testing.T) {
|
||||
inboundOptions := inbound.VmessOption{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
}
|
||||
outboundOptions := outbound.VmessOption{
|
||||
TLS: true,
|
||||
Fingerprint: tlsFingerprint,
|
||||
}
|
||||
testInboundVMessTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundVMess_Ws(t *testing.T) {
|
||||
@ -172,17 +197,7 @@ func TestInboundVMess_Wss1(t *testing.T) {
|
||||
Path: "/ws",
|
||||
},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundVMessTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundVMess_Wss2(t *testing.T) {
|
||||
@ -200,17 +215,7 @@ func TestInboundVMess_Wss2(t *testing.T) {
|
||||
Path: "/ws",
|
||||
},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundVMessTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundVMess_Grpc1(t *testing.T) {
|
||||
@ -225,17 +230,7 @@ func TestInboundVMess_Grpc1(t *testing.T) {
|
||||
Network: "grpc",
|
||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundVMessTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundVMess_Grpc2(t *testing.T) {
|
||||
@ -251,17 +246,7 @@ func TestInboundVMess_Grpc2(t *testing.T) {
|
||||
Network: "grpc",
|
||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||
}
|
||||
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)
|
||||
})
|
||||
testInboundVMessTLS(t, inboundOptions, outboundOptions)
|
||||
}
|
||||
|
||||
func TestInboundVMess_Reality(t *testing.T) {
|
||||
|
||||
@ -79,6 +79,19 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
||||
}
|
||||
}
|
||||
}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType)
|
||||
if len(config.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
if config.RealityConfig.PrivateKey != "" {
|
||||
if tlsConfig.Certificates != nil {
|
||||
return nil, errors.New("certificate is unavailable in reality")
|
||||
|
||||
@ -66,6 +66,19 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi
|
||||
MinVersion: tlsC.VersionTLS13,
|
||||
}
|
||||
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType)
|
||||
if len(config.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
|
||||
if config.EchKey != "" {
|
||||
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||
|
||||
@ -94,6 +94,19 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
||||
}
|
||||
}
|
||||
}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType)
|
||||
if len(config.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
if config.RealityConfig.PrivateKey != "" {
|
||||
if tlsConfig.Certificates != nil {
|
||||
return nil, errors.New("certificate is unavailable in reality")
|
||||
|
||||
@ -94,6 +94,19 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
||||
}
|
||||
}
|
||||
}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType)
|
||||
if len(config.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
if config.RealityConfig.PrivateKey != "" {
|
||||
if tlsConfig.Certificates != nil {
|
||||
return nil, errors.New("certificate is unavailable in reality")
|
||||
|
||||
@ -78,6 +78,19 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
|
||||
}
|
||||
}
|
||||
}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType)
|
||||
if len(config.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
if config.RealityConfig.PrivateKey != "" {
|
||||
if tlsConfig.Certificates != nil {
|
||||
return nil, errors.New("certificate is unavailable in reality")
|
||||
|
||||
@ -89,6 +89,19 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
||||
}
|
||||
}
|
||||
}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType)
|
||||
if len(config.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
if config.RealityConfig.PrivateKey != "" {
|
||||
if tlsConfig.Certificates != nil {
|
||||
return nil, errors.New("certificate is unavailable in reality")
|
||||
|
||||
@ -58,6 +58,19 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) (
|
||||
MinVersion: tlsC.VersionTLS13,
|
||||
}
|
||||
tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)}
|
||||
tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType)
|
||||
if len(config.ClientAuthCert) > 0 {
|
||||
if tlsConfig.ClientAuth == tlsC.NoClientCert {
|
||||
tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert {
|
||||
pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.ClientCAs = pool
|
||||
}
|
||||
|
||||
if config.EchKey != "" {
|
||||
err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
|
||||
|
||||
@ -22,6 +22,8 @@ type Option struct {
|
||||
ECHConfig *ech.Config
|
||||
SkipCertVerify bool
|
||||
Fingerprint string
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
Mux bool
|
||||
}
|
||||
|
||||
@ -67,6 +69,8 @@ func NewGostWebsocket(ctx context.Context, conn net.Conn, option *Option) (net.C
|
||||
NextProtos: []string{"http/1.1"},
|
||||
},
|
||||
Fingerprint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -26,6 +26,8 @@ type ShadowTLSOption struct {
|
||||
Password string
|
||||
Host string
|
||||
Fingerprint string
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
ClientFingerprint string
|
||||
SkipCertVerify bool
|
||||
Version int
|
||||
@ -41,6 +43,8 @@ func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (
|
||||
ServerName: option.Host,
|
||||
},
|
||||
Fingerprint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -21,6 +21,8 @@ type Option struct {
|
||||
ECHConfig *ech.Config
|
||||
SkipCertVerify bool
|
||||
Fingerprint string
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
Mux bool
|
||||
V2rayHttpUpgrade bool
|
||||
V2rayHttpUpgradeFastOpen bool
|
||||
@ -53,6 +55,8 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
},
|
||||
Fingerprint: option.Fingerprint,
|
||||
Certificate: option.Certificate,
|
||||
PrivateKey: option.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -15,6 +15,8 @@ type TLSConfig struct {
|
||||
Host string
|
||||
SkipCertVerify bool
|
||||
FingerPrint string
|
||||
Certificate string
|
||||
PrivateKey string
|
||||
ClientFingerprint string
|
||||
NextProtos []string
|
||||
ECH *ech.Config
|
||||
@ -33,6 +35,8 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn
|
||||
NextProtos: cfg.NextProtos,
|
||||
},
|
||||
Fingerprint: cfg.FingerPrint,
|
||||
Certificate: cfg.Certificate,
|
||||
PrivateKey: cfg.PrivateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Loading…
Reference in New Issue
Block a user