From 92d9d03f992f152e337742131d66bded1a9cd023 Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Sun, 10 Apr 2022 00:05:59 +0800 Subject: [PATCH] Chore: move sniffing logic into a single file & code style --- adapter/adapter.go | 12 ++++---- config/initial.go | 35 ----------------------- tunnel/statistic/sniffing.go | 54 ++++++++++++++++++++++++++++++++++++ tunnel/statistic/tracker.go | 22 ++------------- 4 files changed, 63 insertions(+), 60 deletions(-) create mode 100644 tunnel/statistic/sniffing.go diff --git a/adapter/adapter.go b/adapter/adapter.go index f4087241..1548a5f6 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -3,12 +3,13 @@ package adapter import ( "context" "encoding/json" + "errors" "fmt" "net" "net/http" "net/url" - "strings" "time" + _ "unsafe" "github.com/Dreamacro/clash/common/queue" "github.com/Dreamacro/clash/component/dialer" @@ -17,6 +18,9 @@ import ( "go.uber.org/atomic" ) +//go:linkname errCanceled net.errCanceled +var errCanceled error + type Proxy struct { C.ProxyAdapter history *queue.Queue @@ -38,11 +42,7 @@ func (p *Proxy) Dial(metadata *C.Metadata) (C.Conn, error) { // DialContext implements C.ProxyAdapter func (p *Proxy) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { conn, err := p.ProxyAdapter.DialContext(ctx, metadata, opts...) - wasCancel := false - if err != nil { - wasCancel = strings.Contains(err.Error(), "operation was canceled") - } - p.alive.Store(err == nil || wasCancel) + p.alive.Store(err == nil || errors.Is(err, errCanceled)) return conn, err } diff --git a/config/initial.go b/config/initial.go index 9d8288ba..a365153b 100644 --- a/config/initial.go +++ b/config/initial.go @@ -50,23 +50,6 @@ func initMMDB() error { return nil } -//func downloadGeoIP(path string) (err error) { -// resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat") -// if err != nil { -// return -// } -// defer resp.Body.Close() -// -// f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644) -// if err != nil { -// return err -// } -// defer f.Close() -// _, err = io.Copy(f, resp.Body) -// -// return err -//} - func downloadGeoSite(path string) (err error) { resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat") if err != nil { @@ -84,19 +67,6 @@ func downloadGeoSite(path string) (err error) { return err } -// -//func initGeoIP() error { -// if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) { -// log.Infoln("Can't find GeoIP.dat, start download") -// if err := downloadGeoIP(C.Path.GeoIP()); err != nil { -// return fmt.Errorf("can't download GeoIP.dat: %s", err.Error()) -// } -// log.Infoln("Download GeoIP.dat finish") -// } -// -// return nil -//} - func initGeoSite() error { if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) { log.Infoln("Can't find GeoSite.dat, start download") @@ -129,11 +99,6 @@ func Init(dir string) error { f.Close() } - //// initial GeoIP - //if err := initGeoIP(); err != nil { - // return fmt.Errorf("can't initial GeoIP: %w", err) - //} - // initial mmdb if err := initMMDB(); err != nil { return fmt.Errorf("can't initial MMDB: %w", err) diff --git a/tunnel/statistic/sniffing.go b/tunnel/statistic/sniffing.go new file mode 100644 index 00000000..2d1f1bfd --- /dev/null +++ b/tunnel/statistic/sniffing.go @@ -0,0 +1,54 @@ +package statistic + +import ( + "errors" + + "github.com/Dreamacro/clash/common/snifer/tls" + "github.com/Dreamacro/clash/component/resolver" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" + + "go.uber.org/atomic" +) + +type sniffing struct { + C.Conn + + metadata *C.Metadata + totalWrite *atomic.Uint64 +} + +func (r *sniffing) Read(b []byte) (int, error) { + return r.Conn.Read(b) +} + +func (r *sniffing) Write(b []byte) (int, error) { + if r.totalWrite.Load() < 128 && r.metadata.Host == "" && (r.metadata.DstPort == "443" || r.metadata.DstPort == "8443" || r.metadata.DstPort == "993" || r.metadata.DstPort == "465" || r.metadata.DstPort == "995") { + header, err := tls.SniffTLS(b) + if err != nil { + // log.Errorln("Expect no error but actually %s %s:%s:%s", err.Error(), tt.Metadata.Host, tt.Metadata.DstIP.String(), tt.Metadata.DstPort) + } else { + resolver.InsertHostByIP(r.metadata.DstIP, header.Domain()) + log.Warnln("use sni update host: %s ip: %s", header.Domain(), r.metadata.DstIP.String()) + r.Conn.Close() + return 0, errors.New("sni update, break current link to avoid leaks") + } + } + + n, err := r.Conn.Write(b) + r.totalWrite.Add(uint64(n)) + + return n, err +} + +func (r *sniffing) Close() error { + return r.Conn.Close() +} + +func NewSniffing(conn C.Conn, metadata *C.Metadata) C.Conn { + return &sniffing{ + Conn: conn, + metadata: metadata, + totalWrite: atomic.NewUint64(0), + } +} diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index db018c05..6fd8b3e7 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -1,14 +1,10 @@ package statistic import ( - "errors" "net" "time" - "github.com/Dreamacro/clash/common/snifer/tls" - "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" "github.com/gofrs/uuid" "go.uber.org/atomic" @@ -52,20 +48,7 @@ func (tt *tcpTracker) Write(b []byte) (int, error) { n, err := tt.Conn.Write(b) upload := int64(n) tt.manager.PushUploaded(upload) - if tt.UploadTotal.Load() < 128 && tt.Metadata.Host == "" && (tt.Metadata.DstPort == "443" || tt.Metadata.DstPort == "8443" || tt.Metadata.DstPort == "993" || tt.Metadata.DstPort == "465" || tt.Metadata.DstPort == "995") { - header, err := tls.SniffTLS(b) - if err != nil { - // log.Errorln("Expect no error but actually %s %s:%s:%s", err.Error(), tt.Metadata.Host, tt.Metadata.DstIP.String(), tt.Metadata.DstPort) - } else { - resolver.InsertHostByIP(tt.Metadata.DstIP, header.Domain()) - log.Warnln("use sni update host: %s ip: %s", header.Domain(), tt.Metadata.DstIP.String()) - tt.manager.Leave(tt) - tt.Conn.Close() - return n, errors.New("sni update, break current link to avoid leaks") - } - } tt.UploadTotal.Add(upload) - return n, err } @@ -74,7 +57,7 @@ func (tt *tcpTracker) Close() error { return tt.Conn.Close() } -func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule) *tcpTracker { +func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule) C.Conn { uuid, _ := uuid.NewV4() t := &tcpTracker{ @@ -97,7 +80,8 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R } manager.Join(t) - return t + conn = NewSniffing(t, metadata) + return conn } type udpTracker struct {