From baaf509637e7cef01eec8c56ad73dfb8852d1ba2 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 21 Feb 2023 21:58:37 +0800 Subject: [PATCH] chore: using sing-shadowtls to support shadowtls v1/2/3 --- adapter/outbound/shadowsocks.go | 70 +++++++++++++-------- adapter/outbound/wireguard.go | 8 +-- component/tls/utls.go | 2 +- go.mod | 17 ++--- go.sum | 34 +++++----- listener/sing/log.go | 41 ------------ listener/sing_tun/server.go | 2 +- log/sing.go | 68 ++++++++++++++++++++ transport/sing-shadowtls/shadowtls.go | 91 +++++++++++++++++++++++++++ 9 files changed, 236 insertions(+), 97 deletions(-) delete mode 100644 listener/sing/log.go create mode 100644 log/sing.go create mode 100644 transport/sing-shadowtls/shadowtls.go diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 54566666..f6701469 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -10,10 +10,9 @@ import ( "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/dialer" - tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/shadowtls" obfs "github.com/Dreamacro/clash/transport/simple-obfs" + shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls" "github.com/Dreamacro/clash/transport/socks5" v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" @@ -33,7 +32,7 @@ type ShadowSocks struct { obfsMode string obfsOption *simpleObfsOption v2rayOption *v2rayObfs.Option - shadowTLSOption *shadowTLSOption + shadowTLSOption *shadowtls.ShadowTLSOption tlsConfig *tls.Config } @@ -67,14 +66,31 @@ type v2rayObfsOption struct { } type shadowTLSOption struct { - Password string `obfs:"password"` - Host string `obfs:"host"` - Fingerprint string `obfs:"fingerprint,omitempty"` - SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` + Password string `obfs:"password"` + Host string `obfs:"host"` + Fingerprint string `obfs:"fingerprint,omitempty"` + ClientFingerprint string `obfs:"client-fingerprint,omitempty"` + SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` + Version int `obfs:"version,omitempty"` } // StreamConn implements C.ProxyAdapter func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { + switch ss.obfsMode { + case shadowtls.Mode: + // fix tls handshake not timeout + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) + defer cancel() + var err error + c, err = shadowtls.NewShadowTLS(ctx, c, ss.shadowTLSOption) + if err != nil { + return nil, err + } + } + return ss.streamConn(c, metadata) +} + +func (ss *ShadowSocks) streamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { switch ss.obfsMode { case "tls": c = obfs.NewTLSObfs(c, ss.obfsOption.Host) @@ -87,8 +103,6 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } - case shadowtls.Mode: - c = shadowtls.NewShadowTLS(c, ss.shadowTLSOption.Password, ss.tlsConfig) } if metadata.NetWork == C.UDP && ss.option.UDPOverTCP { return ss.method.DialConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")) @@ -113,7 +127,15 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale safeConnClose(c, err) }(c) - c, err = ss.StreamConn(c, metadata) + switch ss.obfsMode { + case shadowtls.Mode: + c, err = shadowtls.NewShadowTLS(ctx, c, ss.shadowTLSOption) + if err != nil { + return nil, err + } + } + + c, err = ss.streamConn(c, metadata) return NewConn(c, ss), err } @@ -171,7 +193,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { var v2rayOption *v2rayObfs.Option var obfsOption *simpleObfsOption - var shadowTLSOpt *shadowTLSOption + var shadowTLSOpt *shadowtls.ShadowTLSOption var tlsConfig *tls.Config obfsMode := "" @@ -210,24 +232,20 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } } else if option.Plugin == shadowtls.Mode { obfsMode = shadowtls.Mode - shadowTLSOpt = &shadowTLSOption{} - if err := decoder.Decode(option.PluginOpts, shadowTLSOpt); err != nil { + opt := &shadowTLSOption{ + Version: 2, + } + if err := decoder.Decode(option.PluginOpts, opt); err != nil { return nil, fmt.Errorf("ss %s initialize shadow-tls-plugin error: %w", addr, err) } - tlsConfig = &tls.Config{ - NextProtos: shadowtls.DefaultALPN, - MinVersion: tls.VersionTLS12, - InsecureSkipVerify: shadowTLSOpt.SkipCertVerify, - ServerName: shadowTLSOpt.Host, - } - - if len(shadowTLSOpt.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, shadowTLSOpt.Fingerprint); err != nil { - return nil, err - } + shadowTLSOpt = &shadowtls.ShadowTLSOption{ + Password: opt.Password, + Host: opt.Host, + Fingerprint: opt.Fingerprint, + ClientFingerprint: opt.ClientFingerprint, + SkipCertVerify: opt.SkipCertVerify, + Version: opt.Version, } } diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index d1a5ea6e..e3dafbbf 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -17,7 +17,7 @@ import ( "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/sing" + "github.com/Dreamacro/clash/log" wireguard "github.com/metacubex/sing-wireguard" @@ -174,14 +174,14 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { } outbound.device = device.NewDevice(outbound.tunDevice, outbound.bind, &device.Logger{ Verbosef: func(format string, args ...interface{}) { - sing.Logger.Debug(fmt.Sprintf(strings.ToLower(format), args...)) + log.SingLogger.Debug(fmt.Sprintf(strings.ToLower(format), args...)) }, Errorf: func(format string, args ...interface{}) { - sing.Logger.Error(fmt.Sprintf(strings.ToLower(format), args...)) + log.SingLogger.Error(fmt.Sprintf(strings.ToLower(format), args...)) }, }, option.Workers) if debug.Enabled { - sing.Logger.Trace("created wireguard ipc conf: \n", ipcConf) + log.SingLogger.Trace("created wireguard ipc conf: \n", ipcConf) } err = outbound.device.IpcSet(ipcConf) if err != nil { diff --git a/component/tls/utls.go b/component/tls/utls.go index f965fc64..4724c9a5 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -7,7 +7,7 @@ import ( "github.com/Dreamacro/clash/log" "github.com/mroth/weightedrand/v2" - utls "github.com/refraction-networking/utls" + utls "github.com/sagernet/utls" ) type UConn struct { diff --git a/go.mod b/go.mod index c2a979dc..b7d374ca 100644 --- a/go.mod +++ b/go.mod @@ -25,11 +25,12 @@ require ( github.com/miekg/dns v1.1.50 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 - github.com/refraction-networking/utls v1.2.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 + github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b + github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d + github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 github.com/sirupsen/logrus v1.9.0 @@ -38,11 +39,11 @@ require ( go.etcd.io/bbolt v1.3.6 go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 - golang.org/x/crypto v0.5.0 + golang.org/x/crypto v0.6.0 golang.org/x/exp v0.0.0-20221205204356-47842c84f3db - golang.org/x/net v0.5.0 + golang.org/x/net v0.6.0 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.4.0 + golang.org/x/sys v0.5.0 google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.1.7 @@ -50,7 +51,7 @@ require ( require ( github.com/ajg/form v1.5.1 // indirect - github.com/andybalholm/brotli v1.0.4 // indirect + github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect @@ -59,7 +60,7 @@ require ( github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/josharian/native v1.1.0 // indirect - github.com/klauspost/compress v1.15.12 // indirect + github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/mdlayher/socket v0.4.0 // indirect github.com/metacubex/gvisor v0.0.0-20230213124051-7a16c835d80e // indirect @@ -75,7 +76,7 @@ require ( github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect golang.org/x/mod v0.6.0 // indirect - golang.org/x/text v0.6.0 // indirect + golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/tools v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index 076442ab..cacccf97 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -67,8 +67,8 @@ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGu github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= -github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= +github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= @@ -121,8 +121,6 @@ github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4 github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI= github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/refraction-networking/utls v1.2.0 h1:U5f8wkij2NVinfLuJdFP3gCMwIHs+EzvhxmYdXgiapo= -github.com/refraction-networking/utls v1.2.0/go.mod h1:NPq+cVqzH7D1BeOkmOcb5O/8iVewAsiVt2x1/eO0hgQ= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g= @@ -131,12 +129,16 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 h1:qnXh4RjHsNjdZXkfbqwVqAzYUfc160gfkS5gepmsA+A= -github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= +github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b h1:Ji2AfGlc4j9AitobOx4k3BCj7eS5nSxL1cgaL81zvlo= +github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e h1:S1fd0kB9aEU68dd269AQy783sUlFu/2fSh/4YYVJ/Oc= +github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb h1:oyd3w17fXNmWVYFUe17YVHJW5CLW9X2mxJFDP/IWrAM= github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb/go.mod h1:9KkmnQzTL4Gvv8U2TRAH2BOITCGsGPpHtUPP5sxn5sY= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= +github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 h1:gDXi/0uYe8dA48UyUI1LM2la5QYN0IvsDvR2H2+kFnA= +github.com/sagernet/utls v0.0.0-20230220130002-c08891932056/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= @@ -169,8 +171,8 @@ go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -190,8 +192,8 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= @@ -220,14 +222,14 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/listener/sing/log.go b/listener/sing/log.go deleted file mode 100644 index 4847e063..00000000 --- a/listener/sing/log.go +++ /dev/null @@ -1,41 +0,0 @@ -package sing - -import ( - "fmt" - - "github.com/Dreamacro/clash/log" - - L "github.com/sagernet/sing/common/logger" -) - -type logger struct{} - -func (l logger) Trace(args ...any) { - log.Debugln(fmt.Sprint(args...)) -} - -func (l logger) Debug(args ...any) { - log.Debugln(fmt.Sprint(args...)) -} - -func (l logger) Info(args ...any) { - log.Infoln(fmt.Sprint(args...)) -} - -func (l logger) Warn(args ...any) { - log.Warnln(fmt.Sprint(args...)) -} - -func (l logger) Error(args ...any) { - log.Errorln(fmt.Sprint(args...)) -} - -func (l logger) Fatal(args ...any) { - log.Fatalln(fmt.Sprint(args...)) -} - -func (l logger) Panic(args ...any) { - log.Fatalln(fmt.Sprint(args...)) -} - -var Logger L.Logger = logger{} diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 8e0a6c34..63d475cf 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -237,7 +237,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte EndpointIndependentNat: options.EndpointIndependentNat, UDPTimeout: udpTimeout, Handler: handler, - Logger: sing.Logger, + Logger: log.SingLogger, }) if err != nil { return diff --git a/log/sing.go b/log/sing.go new file mode 100644 index 00000000..818acc79 --- /dev/null +++ b/log/sing.go @@ -0,0 +1,68 @@ +package log + +import ( + "context" + "fmt" + + L "github.com/sagernet/sing/common/logger" +) + +type singLogger struct{} + +func (l singLogger) TraceContext(ctx context.Context, args ...any) { + Debugln(fmt.Sprint(args...)) +} + +func (l singLogger) DebugContext(ctx context.Context, args ...any) { + Debugln(fmt.Sprint(args...)) +} + +func (l singLogger) InfoContext(ctx context.Context, args ...any) { + Infoln(fmt.Sprint(args...)) +} + +func (l singLogger) WarnContext(ctx context.Context, args ...any) { + Warnln(fmt.Sprint(args...)) +} + +func (l singLogger) ErrorContext(ctx context.Context, args ...any) { + Errorln(fmt.Sprint(args...)) +} + +func (l singLogger) FatalContext(ctx context.Context, args ...any) { + Fatalln(fmt.Sprint(args...)) +} + +func (l singLogger) PanicContext(ctx context.Context, args ...any) { + Fatalln(fmt.Sprint(args...)) +} + +func (l singLogger) Trace(args ...any) { + Debugln(fmt.Sprint(args...)) +} + +func (l singLogger) Debug(args ...any) { + Debugln(fmt.Sprint(args...)) +} + +func (l singLogger) Info(args ...any) { + Infoln(fmt.Sprint(args...)) +} + +func (l singLogger) Warn(args ...any) { + Warnln(fmt.Sprint(args...)) +} + +func (l singLogger) Error(args ...any) { + Errorln(fmt.Sprint(args...)) +} + +func (l singLogger) Fatal(args ...any) { + Fatalln(fmt.Sprint(args...)) +} + +func (l singLogger) Panic(args ...any) { + Fatalln(fmt.Sprint(args...)) +} + +var SingLogger L.ContextLogger = singLogger{} diff --git a/transport/sing-shadowtls/shadowtls.go b/transport/sing-shadowtls/shadowtls.go new file mode 100644 index 00000000..0e1e95c0 --- /dev/null +++ b/transport/sing-shadowtls/shadowtls.go @@ -0,0 +1,91 @@ +package sing_shadowtls + +import ( + "context" + "crypto/tls" + "net" + + tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/log" + + "github.com/sagernet/sing-shadowtls" + sing_common "github.com/sagernet/sing/common" + utls "github.com/sagernet/utls" +) + +const ( + Mode string = "shadow-tls" +) + +var ( + DefaultALPN = []string{"h2", "http/1.1"} +) + +type ShadowTLSOption struct { + Password string + Host string + Fingerprint string + ClientFingerprint string + SkipCertVerify bool + Version int +} + +func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (net.Conn, error) { + tlsConfig := &tls.Config{ + NextProtos: DefaultALPN, + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: option.SkipCertVerify, + ServerName: option.Host, + } + + var err error + if len(option.Fingerprint) == 0 { + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) + } else { + if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { + return nil, err + } + } + + tlsHandshake := shadowtls.DefaultTLSHandshakeFunc(option.Password, tlsConfig) + if len(option.ClientFingerprint) != 0 { + if fingerprint, exists := tlsC.GetFingerprint(option.ClientFingerprint); exists { + tlsHandshake = uTLSHandshakeFunc(tlsConfig, *fingerprint.ClientHelloID) + } + } + client, err := shadowtls.NewClient(shadowtls.ClientConfig{ + Version: option.Version, + Password: option.Password, + TLSHandshake: tlsHandshake, + Logger: log.SingLogger, + }) + if err != nil { + return nil, err + } + return client.DialContextConn(ctx, conn) +} + +func uTLSHandshakeFunc(config *tls.Config, clientHelloID utls.ClientHelloID) shadowtls.TLSHandshakeFunc { + return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error { + tlsConfig := &utls.Config{ + Rand: config.Rand, + Time: config.Time, + VerifyPeerCertificate: config.VerifyPeerCertificate, + RootCAs: config.RootCAs, + NextProtos: config.NextProtos, + ServerName: config.ServerName, + InsecureSkipVerify: config.InsecureSkipVerify, + CipherSuites: config.CipherSuites, + MinVersion: config.MinVersion, + MaxVersion: config.MaxVersion, + CurvePreferences: sing_common.Map(config.CurvePreferences, func(it tls.CurveID) utls.CurveID { + return utls.CurveID(it) + }), + SessionTicketsDisabled: config.SessionTicketsDisabled, + Renegotiation: utls.RenegotiationSupport(config.Renegotiation), + SessionIDGenerator: sessionIDGenerator, + } + tlsConn := utls.UClient(conn, tlsConfig, clientHelloID) + return tlsConn.HandshakeContext(ctx) + } +}