mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-03-13 04:19:57 +00:00
feat: add ech-opts for anytls/shadowsocks/trojan/vmess/vless outbound
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/metacubex/mihomo/component/ca"
|
||||
"github.com/metacubex/mihomo/component/ech"
|
||||
"github.com/metacubex/mihomo/transport/vmess"
|
||||
smux "github.com/metacubex/smux"
|
||||
)
|
||||
@@ -18,6 +19,7 @@ type Option struct {
|
||||
Path string
|
||||
Headers map[string]string
|
||||
TLS bool
|
||||
ECHConfig *ech.Config
|
||||
SkipCertVerify bool
|
||||
Fingerprint string
|
||||
Mux bool
|
||||
@@ -48,10 +50,11 @@ func NewGostWebsocket(ctx context.Context, conn net.Conn, option *Option) (net.C
|
||||
}
|
||||
|
||||
config := &vmess.WebsocketConfig{
|
||||
Host: option.Host,
|
||||
Port: option.Port,
|
||||
Path: option.Path,
|
||||
Headers: header,
|
||||
Host: option.Host,
|
||||
Port: option.Port,
|
||||
Path: option.Path,
|
||||
ECHConfig: option.ECHConfig,
|
||||
Headers: header,
|
||||
}
|
||||
|
||||
if option.TLS {
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/metacubex/mihomo/common/atomic"
|
||||
"github.com/metacubex/mihomo/common/buf"
|
||||
"github.com/metacubex/mihomo/common/pool"
|
||||
"github.com/metacubex/mihomo/component/ech"
|
||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
|
||||
@@ -224,7 +225,7 @@ func (g *Conn) SetDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap {
|
||||
func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint string, echConfig *ech.Config, realityConfig *tlsC.RealityConfig) *TransportWrap {
|
||||
dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
@@ -238,8 +239,15 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri
|
||||
}
|
||||
|
||||
if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok {
|
||||
tlsConfig := tlsC.UConfig(tlsConfig)
|
||||
err := echConfig.ClientHandle(ctx, tlsConfig)
|
||||
if err != nil {
|
||||
pconn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if realityConfig == nil {
|
||||
tlsConn := tlsC.UClient(pconn, tlsC.UConfig(cfg), clientFingerprint)
|
||||
tlsConn := tlsC.UClient(pconn, tlsConfig, clientFingerprint)
|
||||
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
||||
pconn.Close()
|
||||
return nil, err
|
||||
@@ -251,7 +259,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri
|
||||
}
|
||||
return tlsConn, nil
|
||||
} else {
|
||||
realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, cfg, realityConfig)
|
||||
realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, tlsConfig, realityConfig)
|
||||
if err != nil {
|
||||
pconn.Close()
|
||||
return nil, err
|
||||
@@ -268,6 +276,27 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri
|
||||
return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint")
|
||||
}
|
||||
|
||||
if echConfig != nil {
|
||||
tlsConfig := tlsC.UConfig(tlsConfig)
|
||||
err := echConfig.ClientHandle(ctx, tlsConfig)
|
||||
if err != nil {
|
||||
pconn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn := tlsC.Client(pconn, tlsConfig)
|
||||
if err := conn.HandshakeContext(ctx); err != nil {
|
||||
pconn.Close()
|
||||
return nil, err
|
||||
}
|
||||
state := conn.ConnectionState()
|
||||
if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
conn := tls.Client(pconn, cfg)
|
||||
if err := conn.HandshakeContext(ctx); err != nil {
|
||||
pconn.Close()
|
||||
@@ -345,12 +374,12 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config, realityConfig *tlsC.RealityConfig) (net.Conn, error) {
|
||||
func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config, echConfig *ech.Config, realityConfig *tlsC.RealityConfig) (net.Conn, error) {
|
||||
dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, realityConfig)
|
||||
transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, echConfig, realityConfig)
|
||||
c, err := StreamGunWithTransport(transport, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/metacubex/mihomo/component/ca"
|
||||
"github.com/metacubex/mihomo/component/ech"
|
||||
"github.com/metacubex/mihomo/transport/vmess"
|
||||
)
|
||||
|
||||
@@ -17,6 +18,7 @@ type Option struct {
|
||||
Path string
|
||||
Headers map[string]string
|
||||
TLS bool
|
||||
ECHConfig *ech.Config
|
||||
SkipCertVerify bool
|
||||
Fingerprint string
|
||||
Mux bool
|
||||
@@ -37,6 +39,7 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn,
|
||||
Path: option.Path,
|
||||
V2rayHttpUpgrade: option.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: option.V2rayHttpUpgradeFastOpen,
|
||||
ECHConfig: option.ECHConfig,
|
||||
Headers: header,
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/metacubex/mihomo/component/ca"
|
||||
"github.com/metacubex/mihomo/component/ech"
|
||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||
)
|
||||
|
||||
@@ -16,9 +17,14 @@ type TLSConfig struct {
|
||||
FingerPrint string
|
||||
ClientFingerprint string
|
||||
NextProtos []string
|
||||
ECH *ech.Config
|
||||
Reality *tlsC.RealityConfig
|
||||
}
|
||||
|
||||
type ECHConfig struct {
|
||||
Enable bool
|
||||
}
|
||||
|
||||
func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
|
||||
tlsConfig := &tls.Config{
|
||||
ServerName: cfg.Host,
|
||||
@@ -33,8 +39,14 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn
|
||||
}
|
||||
|
||||
if clientFingerprint, ok := tlsC.GetFingerprint(cfg.ClientFingerprint); ok {
|
||||
tlsConfig := tlsC.UConfig(tlsConfig)
|
||||
err = cfg.ECH.ClientHandle(ctx, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cfg.Reality == nil {
|
||||
tlsConn := tlsC.UClient(conn, tlsC.UConfig(tlsConfig), clientFingerprint)
|
||||
tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint)
|
||||
err = tlsConn.HandshakeContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -48,6 +60,19 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn
|
||||
return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint")
|
||||
}
|
||||
|
||||
if cfg.ECH != nil {
|
||||
tlsConfig := tlsC.UConfig(tlsConfig)
|
||||
err = cfg.ECH.ClientHandle(ctx, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConn := tlsC.Client(conn, tlsConfig)
|
||||
|
||||
err = tlsConn.HandshakeContext(ctx)
|
||||
return tlsConn, err
|
||||
}
|
||||
|
||||
tlsConn := tls.Client(conn, tlsConfig)
|
||||
|
||||
err = tlsConn.HandshakeContext(ctx)
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/metacubex/mihomo/common/buf"
|
||||
N "github.com/metacubex/mihomo/common/net"
|
||||
"github.com/metacubex/mihomo/component/ech"
|
||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
@@ -56,6 +57,7 @@ type WebsocketConfig struct {
|
||||
Headers http.Header
|
||||
TLS bool
|
||||
TLSConfig *tls.Config
|
||||
ECHConfig *ech.Config
|
||||
MaxEarlyData int
|
||||
EarlyDataHeaderName string
|
||||
ClientFingerprint string
|
||||
@@ -355,6 +357,11 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig,
|
||||
}
|
||||
|
||||
if clientFingerprint, ok := tlsC.GetFingerprint(c.ClientFingerprint); ok {
|
||||
tlsConfig := tlsC.UConfig(config)
|
||||
err = c.ECHConfig.ClientHandle(ctx, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConn := tlsC.UClient(conn, tlsC.UConfig(config), clientFingerprint)
|
||||
if err = tlsC.BuildWebsocketHandshakeState(tlsConn); err != nil {
|
||||
return nil, fmt.Errorf("parse url %s error: %w", c.Path, err)
|
||||
@@ -364,6 +371,16 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig,
|
||||
return nil, err
|
||||
}
|
||||
conn = tlsConn
|
||||
} else if c.ECHConfig != nil {
|
||||
tlsConfig := tlsC.UConfig(config)
|
||||
err = c.ECHConfig.ClientHandle(ctx, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConn := tlsC.Client(conn, tlsConfig)
|
||||
|
||||
err = tlsConn.HandshakeContext(ctx)
|
||||
conn = tlsConn
|
||||
} else {
|
||||
tlsConn := tls.Client(conn, config)
|
||||
err = tlsConn.HandshakeContext(ctx)
|
||||
|
||||
Reference in New Issue
Block a user