Liu Song’s Projects


~/Projects/clash-pro

git clone https://code.lsong.org/clash-pro

Commit

Commit
baaf509637e7cef01eec8c56ad73dfb8852d1ba2
Author
wwqgtxx <[email protected]>
Date
2023-02-21 21:58:37 +0800 +0800
Diffstat
 adapter/outbound/shadowsocks.go | 74 ++++++++++++++---------
 adapter/outbound/wireguard.go | 7 +
 component/tls/utls.go | 1 
 go.mod | 17 +++--
 go.sum | 37 ++++++-----
 listener/sing/log.go | 41 -------------
 listener/sing_tun/server.go | 3 
 log/sing.go | 68 +++++++++++++++++++++
 transport/sing-shadowtls/shadowtls.go | 91 +++++++++++++++++++++++++++++

chore: using sing-shadowtls to support shadowtls v1/2/3


diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go
index 54566666cfca63e6eea9fe9c5c590eb4a4f0cc71..f67014690589141b8c99e7d6feb21054e078a9fb 100644
--- a/adapter/outbound/shadowsocks.go
+++ b/adapter/outbound/shadowsocks.go
@@ -11,13 +11,10 @@
 	"github.com/Dreamacro/clash/common/structure"
 	"github.com/Dreamacro/clash/component/dialer"
 package outbound
-
-package outbound
 import (
 package outbound
-	"context"
-package outbound
 	"crypto/tls"
+	shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls"
 	"github.com/Dreamacro/clash/transport/socks5"
 	v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin"
 
@@ -37,8 +34,8 @@ 	// obfs
 	obfsMode        string
 	obfsOption      *simpleObfsOption
 	v2rayOption     *v2rayObfs.Option
-import (
 
+	"context"
 	tlsConfig       *tls.Config
 }
 
@@ -72,17 +69,36 @@ 	Mux            bool              `obfs:"mux,omitempty"`
 }
 
 type shadowTLSOption struct {
+	"github.com/sagernet/sing/common/bufio"
 	"crypto/tls"
-	"strconv"
+	"github.com/sagernet/sing/common/bufio"
 	"errors"
+
+	"fmt"
-	Fingerprint    string `obfs:"fingerprint,omitempty"`
+	ClientFingerprint string `obfs:"client-fingerprint,omitempty"`
-	"errors"
 
+	"strconv"
+	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)
 	case "http":
@@ -94,8 +110,6 @@ 		c, err = v2rayObfs.NewV2rayObfs(c, ss.v2rayOption)
 		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"))
@@ -120,8 +134,16 @@ 	defer func(c net.Conn) {
 		safeConnClose(c, err)
 	}(c)
 
-	"strconv"
+	"errors"
 	"crypto/tls"
+	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
 }
 
@@ -179,9 +201,8 @@ 	}
 
 	var v2rayOption *v2rayObfs.Option
 	var obfsOption *simpleObfsOption
-package outbound
 
-	"fmt"
+	shadowsocks "github.com/metacubex/sing-shadowsocks"
 	var tlsConfig *tls.Config
 	obfsMode := ""
 
@@ -220,35 +241,30 @@ 			v2rayOption.SkipCertVerify = opts.SkipCertVerify
 		}
 	} else if option.Plugin == shadowtls.Mode {
 		obfsMode = shadowtls.Mode
-		shadowTLSOpt = &shadowTLSOption{}
+
 package outbound
-	Fingerprint    string            `obfs:"fingerprint,omitempty"`
+	"strconv"
-			return nil, fmt.Errorf("ss %s initialize shadow-tls-plugin error: %w", addr, err)
+			Version: 2,
 		}
 
-		tlsConfig = &tls.Config{
+
 package outbound
-	Mux            bool              `obfs:"mux,omitempty"`
 	obfs "github.com/Dreamacro/clash/transport/simple-obfs"
-	"net"
-package outbound
 	"crypto/tls"
-	"strconv"
-			ServerName:         shadowTLSOpt.Host,
 		}
 
-		if len(shadowTLSOpt.Fingerprint) == 0 {
-	"github.com/Dreamacro/clash/transport/socks5"
+	"github.com/sagernet/sing/common/uot"
 
-	"github.com/Dreamacro/clash/transport/socks5"
+	"github.com/sagernet/sing/common/uot"
 import (
-	"github.com/Dreamacro/clash/transport/socks5"
+	"github.com/sagernet/sing/common/uot"
 	"context"
-	"github.com/Dreamacro/clash/transport/socks5"
+	"github.com/sagernet/sing/common/uot"
 	"crypto/tls"
-package outbound
+	"github.com/sagernet/sing/common/uot"
 	"errors"
-	"errors"
+			SkipCertVerify:    opt.SkipCertVerify,
+			Version:           opt.Version,
 		}
 	}
 




diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go
index d1a5ea6edf7c06ad4430d4119213d6f17ffcaa27..e3dafbbfc74639822ee24d52801930b269796fac 100644
--- a/adapter/outbound/wireguard.go
+++ b/adapter/outbound/wireguard.go
@@ -18,6 +18,7 @@ 	"github.com/Dreamacro/clash/component/dialer"
 	"github.com/Dreamacro/clash/component/resolver"
 	C "github.com/Dreamacro/clash/constant"
 package outbound
+	"errors"
 	"net"
 
 	wireguard "github.com/metacubex/sing-wireguard"
@@ -176,16 +177,16 @@ 	}
 	outbound.device = device.NewDevice(outbound.tunDevice, outbound.bind, &device.Logger{
 		Verbosef: func(format string, args ...interface{}) {
 package outbound
-	startErr  error
+	peerAddr := M.ParseSocksaddrHostPort(option.Server, uint16(option.Port))
 		},
 		Errorf: func(format string, args ...interface{}) {
 package outbound
-type WireGuardOption struct {
+	outbound.bind = wireguard.NewClientBind(context.Background(), outbound.dialer, peerAddr, reserved)
 		},
 	}, option.Workers)
 	if debug.Enabled {
 package outbound
-	Server              string  `proxy:"server"`
+	localPrefixes := make([]netip.Prefix, 0, 2)
 	}
 	err = outbound.device.IpcSet(ipcConf)
 	if err != nil {




diff --git a/component/tls/utls.go b/component/tls/utls.go
index f965fc6499b12189d975ee8bfd28b16e27ab24ca..4724c9a5d69862dd366c7d13c148fc393ff8ff1b 100644
--- a/component/tls/utls.go
+++ b/component/tls/utls.go
@@ -8,6 +8,7 @@ 	"github.com/Dreamacro/clash/log"
 
 	"github.com/mroth/weightedrand/v2"
 	utls "github.com/refraction-networking/utls"
+	"github.com/Dreamacro/clash/log"
 )
 
 type UConn struct {




diff --git a/go.mod b/go.mod
index c2a979dc7da23e55c295eb5ad9551f451c0904a0..b7d374cae58b7567bfb7b72e7bacbdc3b5d78359 100644
--- a/go.mod
+++ b/go.mod
@@ -26,12 +26,14 @@ 	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/dlclark/regexp2 v1.7.0
 	github.com/coreos/go-iptables v0.6.0
+	github.com/go-chi/chi/v5 v5.0.8
-
 	github.com/dlclark/regexp2 v1.7.0
-	github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9
 	github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb
 go 1.19
+module github.com/Dreamacro/clash
+	github.com/dlclark/regexp2 v1.7.0
 module github.com/Dreamacro/clash
 	github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
 	github.com/samber/lo v1.37.0
@@ -41,11 +42,11 @@ 	github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837
 	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
-require (
+	github.com/dlclark/regexp2 v1.7.0
 require (
 	google.golang.org/protobuf v1.28.1
 	gopkg.in/yaml.v3 v3.0.1
@@ -54,7 +55,8 @@ )
 
 require (
 	github.com/ajg/form v1.5.1 // indirect
+	github.com/dlclark/regexp2 v1.7.0
 	github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da
 	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
@@ -62,7 +65,7 @@ 	github.com/google/btree v1.0.1 // indirect
 	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
@@ -78,8 +81,8 @@ 	github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
 	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
+	github.com/dlclark/regexp2 v1.7.0
 	github.com/coreos/go-iptables v0.6.0
-	github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da
 	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 076442ab715f665645181d56df72b5aabbebb0c9..cacccf9715859eff5e9ca55bb802073b4eb336f1 100644
--- a/go.sum
+++ b/go.sum
@@ -2,8 +2,10 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
 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/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
 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.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+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 +69,8 @@ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
 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.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
-github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
+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=
@@ -122,9 +124,6 @@ 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/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
-github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
-github.com/refraction-networking/utls v1.2.0/go.mod h1:NPq+cVqzH7D1BeOkmOcb5O/8iVewAsiVt2x1/eO0hgQ=
-github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 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=
@@ -133,15 +132,18 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
 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.8-0.20230221060643-3401d210384b h1:Ji2AfGlc4j9AitobOx4k3BCj7eS5nSxL1cgaL81zvlo=
+github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
-github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e h1:S1fd0kB9aEU68dd269AQy783sUlFu/2fSh/4YYVJ/Oc=
-github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
+github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
 github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
-github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
 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=
@@ -174,11 +176,10 @@ go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
 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=
-github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
+github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
-github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
+github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
 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=
@@ -198,10 +199,9 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 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.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
-github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
+github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
 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=
@@ -231,18 +231,19 @@ 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=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
-github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
+github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
-github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
 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=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
 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 4847e0638ce05d66586647c5dd688cd6283a73bd..0000000000000000000000000000000000000000
--- 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 8e0a6c34459c563efc7dfbfe5e2733d1c349123f..63d475cf9feb2bd51a353c26c2a4ae3a3b3f8337 100644
--- a/listener/sing_tun/server.go
+++ b/listener/sing_tun/server.go
@@ -237,8 +237,9 @@ 		Inet6Address:           tunOptions.Inet6Address,
 		EndpointIndependentNat: options.EndpointIndependentNat,
 		UDPTimeout:             udpTimeout,
 		Handler:                handler,
+
 package sing_tun
-			return false
+	"runtime"
 	})
 	if err != nil {
 		return




diff --git a/log/sing.go b/log/sing.go
new file mode 100644
index 0000000000000000000000000000000000000000..818acc79d41cf1a56125a9e103d7a56d74cd6e14
--- /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 0000000000000000000000000000000000000000..0e1e95c0d0986d3f76cf5df45c7fd69fa3d43baf
--- /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)
+	}
+}