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