mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-24 02:48:02 +08:00
Compare commits
4 Commits
303f5e33bf
...
d036d98128
Author | SHA1 | Date | |
---|---|---|---|
|
d036d98128 | ||
|
d900c71214 | ||
|
1672750c47 | ||
|
41b57afb3f |
68
component/tls/httpserver.go
Normal file
68
component/tls/httpserver.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
|
"github.com/metacubex/mihomo/log"
|
||||||
|
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func extractTlsHandshakeTimeoutFromServer(s *http.Server) time.Duration {
|
||||||
|
var ret time.Duration
|
||||||
|
for _, v := range [...]time.Duration{
|
||||||
|
s.ReadHeaderTimeout,
|
||||||
|
s.ReadTimeout,
|
||||||
|
s.WriteTimeout,
|
||||||
|
} {
|
||||||
|
if v <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ret == 0 || v < ret {
|
||||||
|
ret = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewListenerForHttps returns a net.Listener for (*http.Server).Serve()
|
||||||
|
// the "func (c *conn) serve(ctx context.Context)" in http\server.go
|
||||||
|
// only do tls handshake and check NegotiatedProtocol with std's *tls.Conn
|
||||||
|
// so we do the same logic to let http2 (not h2c) work fine
|
||||||
|
func NewListenerForHttps(l net.Listener, httpServer *http.Server, tlsConfig *Config) net.Listener {
|
||||||
|
http2Server := &http2.Server{}
|
||||||
|
_ = http2.ConfigureServer(httpServer, http2Server)
|
||||||
|
return N.NewHandleContextListener(context.Background(), l, func(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
||||||
|
c := Server(conn, tlsConfig)
|
||||||
|
|
||||||
|
tlsTO := extractTlsHandshakeTimeoutFromServer(httpServer)
|
||||||
|
if tlsTO > 0 {
|
||||||
|
dl := time.Now().Add(tlsTO)
|
||||||
|
_ = conn.SetReadDeadline(dl)
|
||||||
|
_ = conn.SetWriteDeadline(dl)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.HandshakeContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore Conn-level deadlines.
|
||||||
|
if tlsTO > 0 {
|
||||||
|
_ = conn.SetReadDeadline(time.Time{})
|
||||||
|
_ = conn.SetWriteDeadline(time.Time{})
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ConnectionState().NegotiatedProtocol == http2.NextProtoTLS {
|
||||||
|
http2Server.ServeConn(c, &http2.ServeConnOpts{BaseConfig: httpServer})
|
||||||
|
return nil, net.ErrClosed
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}, func(a any) {
|
||||||
|
log.Errorln("https server panic: %s", a)
|
||||||
|
})
|
||||||
|
}
|
@ -26,7 +26,6 @@ import (
|
|||||||
utls "github.com/metacubex/utls"
|
utls "github.com/metacubex/utls"
|
||||||
"golang.org/x/crypto/chacha20poly1305"
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
"golang.org/x/crypto/hkdf"
|
"golang.org/x/crypto/hkdf"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,6 +50,10 @@ func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHello
|
|||||||
VerifyPeerCertificate: verifier.VerifyPeerCertificate,
|
VerifyPeerCertificate: verifier.VerifyPeerCertificate,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !realityConfig.SupportX25519MLKEM768 && fingerprint == HelloChrome_Auto {
|
||||||
|
fingerprint = HelloChrome_120 // old reality server doesn't work with X25519MLKEM768
|
||||||
|
}
|
||||||
|
|
||||||
uConn := utls.UClient(conn, uConfig, fingerprint)
|
uConn := utls.UClient(conn, uConfig, fingerprint)
|
||||||
verifier.UConn = uConn
|
verifier.UConn = uConn
|
||||||
err := uConn.BuildHandshakeState()
|
err := uConn.BuildHandshakeState()
|
||||||
@ -58,29 +61,6 @@ func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHello
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !realityConfig.SupportX25519MLKEM768 {
|
|
||||||
// ------for X25519MLKEM768 does not work properly with the old reality server-------
|
|
||||||
// Iterate over extensions and check
|
|
||||||
for _, extension := range uConn.Extensions {
|
|
||||||
if ce, ok := extension.(*utls.SupportedCurvesExtension); ok {
|
|
||||||
ce.Curves = slices.DeleteFunc(ce.Curves, func(curveID utls.CurveID) bool {
|
|
||||||
return curveID == utls.X25519MLKEM768
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if ks, ok := extension.(*utls.KeyShareExtension); ok {
|
|
||||||
ks.KeyShares = slices.DeleteFunc(ks.KeyShares, func(share utls.KeyShare) bool {
|
|
||||||
return share.Group == utls.X25519MLKEM768
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Rebuild the client hello
|
|
||||||
err = uConn.BuildHandshakeState()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// --------------------------------------------------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
hello := uConn.HandshakeState.Hello
|
hello := uConn.HandshakeState.Hello
|
||||||
rawSessionID := hello.Raw[39 : 39+32] // the location of session ID
|
rawSessionID := hello.Raw[39 : 39+32] // the location of session ID
|
||||||
for i := range rawSessionID { // https://github.com/golang/go/issues/5373
|
for i := range rawSessionID { // https://github.com/golang/go/issues/5373
|
||||||
|
@ -16,6 +16,7 @@ type Conn = utls.Conn
|
|||||||
type UConn = utls.UConn
|
type UConn = utls.UConn
|
||||||
type UClientHelloID = utls.ClientHelloID
|
type UClientHelloID = utls.ClientHelloID
|
||||||
|
|
||||||
|
const VersionTLS12 = utls.VersionTLS12
|
||||||
const VersionTLS13 = utls.VersionTLS13
|
const VersionTLS13 = utls.VersionTLS13
|
||||||
|
|
||||||
func Client(c net.Conn, config *utls.Config) *Conn {
|
func Client(c net.Conn, config *utls.Config) *Conn {
|
||||||
@ -26,6 +27,10 @@ func UClient(c net.Conn, config *utls.Config, fingerprint UClientHelloID) *UConn
|
|||||||
return utls.UClient(c, config, fingerprint)
|
return utls.UClient(c, config, fingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Server(c net.Conn, config *utls.Config) *Conn {
|
||||||
|
return utls.Server(c, config)
|
||||||
|
}
|
||||||
|
|
||||||
func NewListener(inner net.Listener, config *Config) net.Listener {
|
func NewListener(inner net.Listener, config *Config) net.Listener {
|
||||||
return utls.NewListener(inner, config)
|
return utls.NewListener(inner, config)
|
||||||
}
|
}
|
||||||
@ -69,21 +74,26 @@ var randomFingerprint = once.OnceValue(func() UClientHelloID {
|
|||||||
return fingerprint
|
return fingerprint
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var HelloChrome_Auto = utls.HelloChrome_Auto
|
||||||
|
var HelloChrome_120 = utls.HelloChrome_120 // special fingerprint for some old protocols doesn't work with HelloChrome_Auto
|
||||||
|
|
||||||
var fingerprints = map[string]UClientHelloID{
|
var fingerprints = map[string]UClientHelloID{
|
||||||
"chrome": utls.HelloChrome_Auto,
|
"chrome": utls.HelloChrome_Auto,
|
||||||
|
"firefox": utls.HelloFirefox_Auto,
|
||||||
|
"safari": utls.HelloSafari_Auto,
|
||||||
|
"ios": utls.HelloIOS_Auto,
|
||||||
|
"android": utls.HelloAndroid_11_OkHttp,
|
||||||
|
"edge": utls.HelloEdge_Auto,
|
||||||
|
"360": utls.Hello360_Auto,
|
||||||
|
"qq": utls.HelloQQ_Auto,
|
||||||
|
"random": {},
|
||||||
|
|
||||||
|
// deprecated fingerprints should not be used
|
||||||
"chrome_psk": utls.HelloChrome_100_PSK,
|
"chrome_psk": utls.HelloChrome_100_PSK,
|
||||||
"chrome_psk_shuffle": utls.HelloChrome_106_Shuffle,
|
"chrome_psk_shuffle": utls.HelloChrome_106_Shuffle,
|
||||||
"chrome_padding_psk_shuffle": utls.HelloChrome_114_Padding_PSK_Shuf,
|
"chrome_padding_psk_shuffle": utls.HelloChrome_114_Padding_PSK_Shuf,
|
||||||
"chrome_pq": utls.HelloChrome_115_PQ,
|
"chrome_pq": utls.HelloChrome_115_PQ,
|
||||||
"chrome_pq_psk": utls.HelloChrome_115_PQ_PSK,
|
"chrome_pq_psk": utls.HelloChrome_115_PQ_PSK,
|
||||||
"firefox": utls.HelloFirefox_Auto,
|
|
||||||
"safari": utls.HelloSafari_Auto,
|
|
||||||
"ios": utls.HelloIOS_Auto,
|
|
||||||
"android": utls.HelloAndroid_11_OkHttp,
|
|
||||||
"edge": utls.HelloEdge_Auto,
|
|
||||||
"360": utls.Hello360_Auto,
|
|
||||||
"qq": utls.HelloQQ_Auto,
|
|
||||||
"random": {},
|
|
||||||
"randomized": utls.HelloRandomized,
|
"randomized": utls.HelloRandomized,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,6 @@ import (
|
|||||||
"github.com/gobwas/ws"
|
"github.com/gobwas/ws"
|
||||||
"github.com/gobwas/ws/wsutil"
|
"github.com/gobwas/ws/wsutil"
|
||||||
"github.com/sagernet/cors"
|
"github.com/sagernet/cors"
|
||||||
"golang.org/x/net/http2"
|
|
||||||
"golang.org/x/net/http2/h2c"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -215,11 +213,10 @@ func startTLS(cfg *Config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
// using h2c.NewHandler to ensure we can work in plain http2 and some tls conn is not *tls.Conn
|
Handler: router(cfg.IsDebug, cfg.Secret, cfg.DohServer, cfg.Cors),
|
||||||
Handler: h2c.NewHandler(router(cfg.IsDebug, cfg.Secret, cfg.DohServer, cfg.Cors), &http2.Server{}),
|
|
||||||
}
|
}
|
||||||
tlsServer = server
|
tlsServer = server
|
||||||
if err = server.Serve(tlsC.NewListener(l, tlsConfig)); err != nil {
|
if err = server.Serve(tlsC.NewListenerForHttps(l, server, tlsConfig)); err != nil {
|
||||||
log.Errorln("External controller tls serve error: %s", err)
|
log.Errorln("External controller tls serve error: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,13 @@ import (
|
|||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
"github.com/metacubex/mihomo/component/ech"
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
"github.com/metacubex/mihomo/component/generater"
|
"github.com/metacubex/mihomo/component/generater"
|
||||||
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/render"
|
"github.com/go-chi/render"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var httpPath = "/inbound_test"
|
var httpPath = "/inbound_test"
|
||||||
@ -134,7 +136,10 @@ func NewHttpTestTunnel() *TestTunnel {
|
|||||||
r.Get(httpPath, func(w http.ResponseWriter, r *http.Request) {
|
r.Get(httpPath, func(w http.ResponseWriter, r *http.Request) {
|
||||||
render.Data(w, r, httpData)
|
render.Data(w, r, httpData)
|
||||||
})
|
})
|
||||||
go http.Serve(ln, r)
|
h2Server := &http2.Server{}
|
||||||
|
server := http.Server{Handler: r}
|
||||||
|
_ = http2.ConfigureServer(&server, h2Server)
|
||||||
|
go server.Serve(ln)
|
||||||
testFn := func(t *testing.T, proxy C.ProxyAdapter, proto string) {
|
testFn := func(t *testing.T, proxy C.ProxyAdapter, proto string) {
|
||||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s://%s%s", proto, remoteAddr, httpPath), nil)
|
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s://%s%s", proto, remoteAddr, httpPath), nil)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
@ -208,23 +213,27 @@ func NewHttpTestTunnel() *TestTunnel {
|
|||||||
ch: make(chan struct{}),
|
ch: make(chan struct{}),
|
||||||
}
|
}
|
||||||
if metadata.DstPort == 443 {
|
if metadata.DstPort == 443 {
|
||||||
tlsConn := tls.Server(c, tlsConfig.Clone())
|
tlsConn := tlsC.Server(c, tlsC.UConfig(tlsConfig))
|
||||||
if metadata.Host == realityDest { // ignore the tls handshake error for realityDest
|
if metadata.Host == realityDest { // ignore the tls handshake error for realityDest
|
||||||
if realityRealDial {
|
if realityRealDial {
|
||||||
rconn, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress())
|
rconn, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
N.Relay(rconn, tlsConn)
|
N.Relay(rconn, conn)
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, C.DefaultTLSTimeout)
|
|
||||||
defer cancel()
|
|
||||||
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ln.ch <- tlsConn
|
ctx, cancel := context.WithTimeout(ctx, C.DefaultTLSTimeout)
|
||||||
|
defer cancel()
|
||||||
|
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if tlsConn.ConnectionState().NegotiatedProtocol == http2.NextProtoTLS {
|
||||||
|
h2Server.ServeConn(tlsConn, &http2.ServeConnOpts{BaseConfig: &server})
|
||||||
|
} else {
|
||||||
|
ln.ch <- tlsConn
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ln.ch <- c
|
ln.ch <- c
|
||||||
}
|
}
|
||||||
|
@ -237,14 +237,9 @@ func TestInboundVless_Reality(t *testing.T) {
|
|||||||
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("X25519MLKEM768", func(t *testing.T) {
|
||||||
inboundOptions := inboundOptions
|
|
||||||
outboundOptions := outboundOptions
|
outboundOptions := outboundOptions
|
||||||
inboundOptions.EchKey = echKeyPem
|
outboundOptions.RealityOpts.SupportX25519MLKEM768 = true
|
||||||
outboundOptions.ECHOpts = outbound.ECHOptions{
|
|
||||||
Enable: true,
|
|
||||||
Config: echConfigBase64,
|
|
||||||
}
|
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||||
outboundOptions := outboundOptions
|
outboundOptions := outboundOptions
|
||||||
@ -276,14 +271,9 @@ func TestInboundVless_Reality_Grpc(t *testing.T) {
|
|||||||
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
GrpcOpts: outbound.GrpcOptions{GrpcServiceName: "GunService"},
|
||||||
}
|
}
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
t.Run("ECH", func(t *testing.T) {
|
t.Run("X25519MLKEM768", func(t *testing.T) {
|
||||||
inboundOptions := inboundOptions
|
|
||||||
outboundOptions := outboundOptions
|
outboundOptions := outboundOptions
|
||||||
inboundOptions.EchKey = echKeyPem
|
outboundOptions.RealityOpts.SupportX25519MLKEM768 = true
|
||||||
outboundOptions.ECHOpts = outbound.ECHOptions{
|
|
||||||
Enable: true,
|
|
||||||
Config: echConfigBase64,
|
|
||||||
}
|
|
||||||
testInboundVless(t, inboundOptions, outboundOptions)
|
testInboundVless(t, inboundOptions, outboundOptions)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
|
|
||||||
tlsConfig := &tlsC.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
var realityBuilder *reality.Builder
|
var realityBuilder *reality.Builder
|
||||||
var httpHandler http.Handler
|
var httpServer http.Server
|
||||||
|
|
||||||
if config.Certificate != "" && config.PrivateKey != "" {
|
if config.Certificate != "" && config.PrivateKey != "" {
|
||||||
cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
|
cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
|
||||||
@ -119,16 +119,16 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
}
|
}
|
||||||
sl.HandleConn(conn, tunnel, additions...)
|
sl.HandleConn(conn, tunnel, additions...)
|
||||||
})
|
})
|
||||||
httpHandler = httpMux
|
httpServer.Handler = httpMux
|
||||||
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1")
|
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1")
|
||||||
}
|
}
|
||||||
if config.GrpcServiceName != "" {
|
if config.GrpcServiceName != "" {
|
||||||
httpHandler = gun.NewServerHandler(gun.ServerOption{
|
httpServer.Handler = gun.NewServerHandler(gun.ServerOption{
|
||||||
ServiceName: config.GrpcServiceName,
|
ServiceName: config.GrpcServiceName,
|
||||||
ConnHandler: func(conn net.Conn) {
|
ConnHandler: func(conn net.Conn) {
|
||||||
sl.HandleConn(conn, tunnel, additions...)
|
sl.HandleConn(conn, tunnel, additions...)
|
||||||
},
|
},
|
||||||
HttpHandler: httpHandler,
|
HttpHandler: httpServer.Handler,
|
||||||
})
|
})
|
||||||
tlsConfig.NextProtos = append([]string{"h2"}, tlsConfig.NextProtos...) // h2 must before http/1.1
|
tlsConfig.NextProtos = append([]string{"h2"}, tlsConfig.NextProtos...) // h2 must before http/1.1
|
||||||
}
|
}
|
||||||
@ -144,15 +144,19 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
if realityBuilder != nil {
|
if realityBuilder != nil {
|
||||||
l = realityBuilder.NewListener(l)
|
l = realityBuilder.NewListener(l)
|
||||||
} else if len(tlsConfig.Certificates) > 0 {
|
} else if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tlsC.NewListener(l, tlsConfig)
|
if httpServer.Handler != nil {
|
||||||
|
l = tlsC.NewListenerForHttps(l, &httpServer, tlsConfig)
|
||||||
|
} else {
|
||||||
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("disallow using Vless without both certificates/reality config")
|
return nil, errors.New("disallow using Vless without both certificates/reality config")
|
||||||
}
|
}
|
||||||
sl.listeners = append(sl.listeners, l)
|
sl.listeners = append(sl.listeners, l)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if httpHandler != nil {
|
if httpServer.Handler != nil {
|
||||||
_ = http.Serve(l, httpHandler)
|
_ = httpServer.Serve(l)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
|
@ -78,7 +78,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
|
|
||||||
tlsConfig := &tlsC.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
var realityBuilder *reality.Builder
|
var realityBuilder *reality.Builder
|
||||||
var httpHandler http.Handler
|
var httpServer http.Server
|
||||||
|
|
||||||
if config.Certificate != "" && config.PrivateKey != "" {
|
if config.Certificate != "" && config.PrivateKey != "" {
|
||||||
cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
|
cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
|
||||||
@ -113,16 +113,16 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
}
|
}
|
||||||
sl.HandleConn(conn, tunnel, additions...)
|
sl.HandleConn(conn, tunnel, additions...)
|
||||||
})
|
})
|
||||||
httpHandler = httpMux
|
httpServer.Handler = httpMux
|
||||||
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1")
|
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1")
|
||||||
}
|
}
|
||||||
if config.GrpcServiceName != "" {
|
if config.GrpcServiceName != "" {
|
||||||
httpHandler = gun.NewServerHandler(gun.ServerOption{
|
httpServer.Handler = gun.NewServerHandler(gun.ServerOption{
|
||||||
ServiceName: config.GrpcServiceName,
|
ServiceName: config.GrpcServiceName,
|
||||||
ConnHandler: func(conn net.Conn) {
|
ConnHandler: func(conn net.Conn) {
|
||||||
sl.HandleConn(conn, tunnel, additions...)
|
sl.HandleConn(conn, tunnel, additions...)
|
||||||
},
|
},
|
||||||
HttpHandler: httpHandler,
|
HttpHandler: httpServer.Handler,
|
||||||
})
|
})
|
||||||
tlsConfig.NextProtos = append([]string{"h2"}, tlsConfig.NextProtos...) // h2 must before http/1.1
|
tlsConfig.NextProtos = append([]string{"h2"}, tlsConfig.NextProtos...) // h2 must before http/1.1
|
||||||
}
|
}
|
||||||
@ -138,13 +138,17 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
if realityBuilder != nil {
|
if realityBuilder != nil {
|
||||||
l = realityBuilder.NewListener(l)
|
l = realityBuilder.NewListener(l)
|
||||||
} else if len(tlsConfig.Certificates) > 0 {
|
} else if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tlsC.NewListener(l, tlsConfig)
|
if httpServer.Handler != nil {
|
||||||
|
l = tlsC.NewListenerForHttps(l, &httpServer, tlsConfig)
|
||||||
|
} else {
|
||||||
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sl.listeners = append(sl.listeners, l)
|
sl.listeners = append(sl.listeners, l)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if httpHandler != nil {
|
if httpServer.Handler != nil {
|
||||||
_ = http.Serve(l, httpHandler)
|
_ = httpServer.Serve(l)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
|
@ -72,7 +72,7 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
|
|
||||||
tlsConfig := &tlsC.Config{}
|
tlsConfig := &tlsC.Config{}
|
||||||
var realityBuilder *reality.Builder
|
var realityBuilder *reality.Builder
|
||||||
var httpHandler http.Handler
|
var httpServer http.Server
|
||||||
|
|
||||||
if config.Certificate != "" && config.PrivateKey != "" {
|
if config.Certificate != "" && config.PrivateKey != "" {
|
||||||
cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
|
cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
|
||||||
@ -107,16 +107,16 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
}
|
}
|
||||||
sl.HandleConn(conn, tunnel, additions...)
|
sl.HandleConn(conn, tunnel, additions...)
|
||||||
})
|
})
|
||||||
httpHandler = httpMux
|
httpServer.Handler = httpMux
|
||||||
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1")
|
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1")
|
||||||
}
|
}
|
||||||
if config.GrpcServiceName != "" {
|
if config.GrpcServiceName != "" {
|
||||||
httpHandler = gun.NewServerHandler(gun.ServerOption{
|
httpServer.Handler = gun.NewServerHandler(gun.ServerOption{
|
||||||
ServiceName: config.GrpcServiceName,
|
ServiceName: config.GrpcServiceName,
|
||||||
ConnHandler: func(conn net.Conn) {
|
ConnHandler: func(conn net.Conn) {
|
||||||
sl.HandleConn(conn, tunnel, additions...)
|
sl.HandleConn(conn, tunnel, additions...)
|
||||||
},
|
},
|
||||||
HttpHandler: httpHandler,
|
HttpHandler: httpServer.Handler,
|
||||||
})
|
})
|
||||||
tlsConfig.NextProtos = append([]string{"h2"}, tlsConfig.NextProtos...) // h2 must before http/1.1
|
tlsConfig.NextProtos = append([]string{"h2"}, tlsConfig.NextProtos...) // h2 must before http/1.1
|
||||||
}
|
}
|
||||||
@ -132,15 +132,19 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
|||||||
if realityBuilder != nil {
|
if realityBuilder != nil {
|
||||||
l = realityBuilder.NewListener(l)
|
l = realityBuilder.NewListener(l)
|
||||||
} else if len(tlsConfig.Certificates) > 0 {
|
} else if len(tlsConfig.Certificates) > 0 {
|
||||||
l = tlsC.NewListener(l, tlsConfig)
|
if httpServer.Handler != nil {
|
||||||
|
l = tlsC.NewListenerForHttps(l, &httpServer, tlsConfig)
|
||||||
|
} else {
|
||||||
|
l = tlsC.NewListener(l, tlsConfig)
|
||||||
|
}
|
||||||
} else if !config.TrojanSSOption.Enabled {
|
} else if !config.TrojanSSOption.Enabled {
|
||||||
return nil, errors.New("disallow using Trojan without both certificates/reality/ss config")
|
return nil, errors.New("disallow using Trojan without both certificates/reality/ss config")
|
||||||
}
|
}
|
||||||
sl.listeners = append(sl.listeners, l)
|
sl.listeners = append(sl.listeners, l)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if httpHandler != nil {
|
if httpServer.Handler != nil {
|
||||||
_ = http.Serve(l, httpHandler)
|
_ = httpServer.Serve(l)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
|
@ -214,6 +214,13 @@ func (g *Conn) SetReadDeadline(t time.Time) error { return g.SetDeadline(t) }
|
|||||||
func (g *Conn) SetWriteDeadline(t time.Time) error { return g.SetDeadline(t) }
|
func (g *Conn) SetWriteDeadline(t time.Time) error { return g.SetDeadline(t) }
|
||||||
|
|
||||||
func (g *Conn) SetDeadline(t time.Time) error {
|
func (g *Conn) SetDeadline(t time.Time) error {
|
||||||
|
if t.IsZero() {
|
||||||
|
if g.deadline != nil {
|
||||||
|
g.deadline.Stop()
|
||||||
|
g.deadline = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
d := time.Until(t)
|
d := time.Until(t)
|
||||||
if g.deadline != nil {
|
if g.deadline != nil {
|
||||||
g.deadline.Reset(d)
|
g.deadline.Reset(d)
|
||||||
|
@ -49,7 +49,7 @@ func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsHandshake := uTLSHandshakeFunc(tlsConfig, option.ClientFingerprint)
|
tlsHandshake := uTLSHandshakeFunc(tlsConfig, option.ClientFingerprint, option.Version)
|
||||||
client, err := shadowtls.NewClient(shadowtls.ClientConfig{
|
client, err := shadowtls.NewClient(shadowtls.ClientConfig{
|
||||||
Version: option.Version,
|
Version: option.Version,
|
||||||
Password: option.Password,
|
Password: option.Password,
|
||||||
@ -62,15 +62,19 @@ func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (
|
|||||||
return client.DialContextConn(ctx, conn)
|
return client.DialContextConn(ctx, conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func uTLSHandshakeFunc(config *tls.Config, clientFingerprint string) shadowtls.TLSHandshakeFunc {
|
func uTLSHandshakeFunc(config *tls.Config, clientFingerprint string, version int) shadowtls.TLSHandshakeFunc {
|
||||||
return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error {
|
return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error {
|
||||||
tlsConfig := tlsC.UConfig(config)
|
tlsConfig := tlsC.UConfig(config)
|
||||||
tlsConfig.SessionIDGenerator = sessionIDGenerator
|
tlsConfig.SessionIDGenerator = sessionIDGenerator
|
||||||
if config.MaxVersion == tls.VersionTLS12 { // for ShadowTLS v1
|
if version == 1 {
|
||||||
|
tlsConfig.MaxVersion = tlsC.VersionTLS12 // ShadowTLS v1 only support TLS 1.2
|
||||||
tlsConn := tlsC.Client(conn, tlsConfig)
|
tlsConn := tlsC.Client(conn, tlsConfig)
|
||||||
return tlsConn.HandshakeContext(ctx)
|
return tlsConn.HandshakeContext(ctx)
|
||||||
}
|
}
|
||||||
if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok {
|
if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok {
|
||||||
|
if version == 2 && clientFingerprint == tlsC.HelloChrome_Auto {
|
||||||
|
clientFingerprint = tlsC.HelloChrome_120 // ShadowTLS v2 not work with X25519MLKEM768
|
||||||
|
}
|
||||||
tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint)
|
tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint)
|
||||||
if slices.Equal(tlsConfig.NextProtos, WsALPN) {
|
if slices.Equal(tlsConfig.NextProtos, WsALPN) {
|
||||||
err := tlsC.BuildWebsocketHandshakeState(tlsConn)
|
err := tlsC.BuildWebsocketHandshakeState(tlsConn)
|
||||||
|
Loading…
Reference in New Issue
Block a user