From d9cfdc3242ae677dcfd2bec005e57a0ce56a3e42 Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Fri, 17 Nov 2023 13:19:24 +0800 Subject: [PATCH] chore: add android feature and patch --- component/dialer/dialer.go | 10 +++++++++ component/dialer/patch_common.go | 17 ++++++++++++++ component/resource/fetcher.go | 38 ++++++++++++++++++-------------- constant/features/cmfa.go | 6 +++++ hub/executor/executor.go | 6 ++++- listener/http/server.go | 7 ++++++ 6 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 component/dialer/patch_common.go create mode 100644 constant/features/cmfa.go diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 0e0e3cef..37a2bcba 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -12,6 +12,8 @@ import ( "time" "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/constant/features" + "golang.org/x/exp/slices" ) type dialFunc func(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) @@ -70,6 +72,10 @@ func DialContext(ctx context.Context, network, address string, options ...Option } func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) { + if slices.Contains(features.TAGS, "cmfa") { + return listenPacketHooked(ctx, network, address) + } + cfg := applyOptions(options...) lc := &net.ListenConfig{} @@ -114,6 +120,10 @@ func GetTcpConcurrent() bool { } func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) { + if slices.Contains(features.TAGS, "cmfa") { + return dialContextHooked(ctx, network, destination, port) + } + address := net.JoinHostPort(destination.String(), port) netDialer := opt.netDialer diff --git a/component/dialer/patch_common.go b/component/dialer/patch_common.go new file mode 100644 index 00000000..9253d6b7 --- /dev/null +++ b/component/dialer/patch_common.go @@ -0,0 +1,17 @@ +// +build !cmfa + +package dialer + +import ( + "context" + "net" + "net/netip" +) + +func dialContextHooked(ctx context.Context, network string, destination netip.Addr, port string) (net.Conn, error) { + return nil, nil +} + +func listenPacketHooked(ctx context.Context, network, address string) (net.PacketConn, error) { + return nil, nil +} diff --git a/component/resource/fetcher.go b/component/resource/fetcher.go index 3d749645..44ca45c2 100644 --- a/component/resource/fetcher.go +++ b/component/resource/fetcher.go @@ -13,6 +13,10 @@ import ( "github.com/samber/lo" ) +const ( + minInterval = time.Minute * 5 +) + var ( fileMode os.FileMode = 0o666 dirMode os.FileMode = 0o755 @@ -24,8 +28,7 @@ type Fetcher[V any] struct { resourceType string name string vehicle types.Vehicle - UpdatedAt *time.Time - ticker *time.Ticker + UpdatedAt time.Time done chan struct{} hash [16]byte parser Parser[V] @@ -56,14 +59,15 @@ func (f *Fetcher[V]) Initial() (V, error) { if stat, fErr := os.Stat(f.vehicle.Path()); fErr == nil { buf, err = os.ReadFile(f.vehicle.Path()) modTime := stat.ModTime() - f.UpdatedAt = &modTime + f.UpdatedAt = modTime isLocal = true if f.interval != 0 && modTime.Add(f.interval).Before(time.Now()) { - log.Warnln("[Provider] %s not updated for %s, force update", f.Name(), time.Now().Sub(modTime)) + log.Warnln("[Provider] %s not updated for a long time, force refresh", f.Name()) forceUpdate = true } } else { buf, err = f.vehicle.Read() + f.UpdatedAt = time.Now() } if err != nil { @@ -113,7 +117,7 @@ func (f *Fetcher[V]) Initial() (V, error) { f.hash = md5.Sum(buf) // pull contents automatically - if f.ticker != nil { + if f.interval > 0 { go f.pullLoop() } @@ -129,7 +133,7 @@ func (f *Fetcher[V]) Update() (V, bool, error) { now := time.Now() hash := md5.Sum(buf) if bytes.Equal(f.hash[:], hash[:]) { - f.UpdatedAt = &now + f.UpdatedAt = now _ = os.Chtimes(f.vehicle.Path(), now, now) return lo.Empty[V](), true, nil } @@ -145,23 +149,31 @@ func (f *Fetcher[V]) Update() (V, bool, error) { } } - f.UpdatedAt = &now + f.UpdatedAt = now f.hash = hash return contents, false, nil } func (f *Fetcher[V]) Destroy() error { - if f.ticker != nil { + if f.interval > 0 { f.done <- struct{}{} } return nil } func (f *Fetcher[V]) pullLoop() { + initialInterval := f.interval - time.Since(f.UpdatedAt) + if initialInterval < minInterval { + initialInterval = minInterval + } + + timer := time.NewTimer(initialInterval) + defer timer.Stop() for { select { - case <-f.ticker.C: + case <-timer.C: + timer.Reset(f.interval) elm, same, err := f.Update() if err != nil { log.Errorln("[Provider] %s pull error: %s", f.Name(), err.Error()) @@ -178,7 +190,6 @@ func (f *Fetcher[V]) pullLoop() { f.OnUpdate(elm) } case <-f.done: - f.ticker.Stop() return } } @@ -197,17 +208,12 @@ func safeWrite(path string, buf []byte) error { } func NewFetcher[V any](name string, interval time.Duration, vehicle types.Vehicle, parser Parser[V], onUpdate func(V)) *Fetcher[V] { - var ticker *time.Ticker - if interval != 0 { - ticker = time.NewTicker(interval) - } return &Fetcher[V]{ name: name, - ticker: ticker, vehicle: vehicle, parser: parser, - done: make(chan struct{}, 1), + done: make(chan struct{}, 8), OnUpdate: onUpdate, interval: interval, } diff --git a/constant/features/cmfa.go b/constant/features/cmfa.go new file mode 100644 index 00000000..ab76b06d --- /dev/null +++ b/constant/features/cmfa.go @@ -0,0 +1,6 @@ +//go:build cmfa +package features + +func init() { + TAGS = append(TAGS, "cmfa") +} diff --git a/hub/executor/executor.go b/hub/executor/executor.go index efd9a076..216754cc 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -35,6 +35,8 @@ import ( "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/ntp" "github.com/metacubex/mihomo/tunnel" + "github.com/metacubex/mihomo/constant/features" + "golang.org/x/exp/slices" ) var mux sync.Mutex @@ -170,7 +172,9 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList listener.ReCreateHTTP(general.Port, tunnel.Tunnel) listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel) listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel) - listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) + if !slices.Contains(features.TAGS, "cmfa") { + listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) + } listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel) listener.ReCreateMixed(general.MixedPort, tunnel.Tunnel) listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel) diff --git a/listener/http/server.go b/listener/http/server.go index a75e2092..06389185 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -6,6 +6,8 @@ import ( "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/common/cache" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/features" + "golang.org/x/exp/slices" ) type Listener struct { @@ -65,6 +67,11 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi } continue } + if slices.Contains(features.TAGS, "cmfa") { + if t, ok := conn.(*net.TCPConn); ok { + t.SetKeepAlive(false) + } + } go HandleConn(conn, tunnel, c, additions...) } }()