From 9e96d7084006b25b13369119d8cf650ccefd2002 Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Fri, 17 Nov 2023 01:19:20 +0800 Subject: [PATCH] feat: share more code from android branch --- adapter/inbound/http.go | 2 + adapter/inbound/packet.go | 2 + adapter/outboundgroup/patch_android.go | 64 ++++++++++++++++++++ adapter/provider/healthcheck.go | 6 ++ adapter/provider/patch_android.go | 36 ++++++++++++ component/dialer/patch_android.go | 39 +++++++++++++ component/mmdb/patch_android.go | 18 ++++++ component/process/patch_android.go | 16 +++++ config/config.go | 17 ++++-- constant/metadata.go | 3 + dns/dhcp.go | 2 + dns/patch_!android.go | 7 +++ dns/patch_android.go | 81 ++++++++++++++++++++++++++ dns/server.go | 2 + listener/http/patch_android.go | 9 +++ rules/provider/patch_android.go | 27 +++++++++ tunnel/statistic/patch_android.go | 7 +++ 17 files changed, 333 insertions(+), 5 deletions(-) create mode 100644 adapter/outboundgroup/patch_android.go create mode 100644 adapter/provider/patch_android.go create mode 100644 component/dialer/patch_android.go create mode 100644 component/mmdb/patch_android.go create mode 100644 component/process/patch_android.go create mode 100644 dns/patch_!android.go create mode 100644 dns/patch_android.go create mode 100644 listener/http/patch_android.go create mode 100644 rules/provider/patch_android.go create mode 100644 tunnel/statistic/patch_android.go diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 137e17d3..8f912fbe 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -12,6 +12,8 @@ func NewHTTP(target socks5.Addr, srcConn net.Conn, conn net.Conn, additions ...A metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP + metadata.RawSrcAddr = srcConn.RemoteAddr() + metadata.RawDstAddr = srcConn.LocalAddr() ApplyAdditions(metadata, WithSrcAddr(srcConn.RemoteAddr()), WithInAddr(conn.LocalAddr())) ApplyAdditions(metadata, additions...) return conn, metadata diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index 7e245f98..a10d402e 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -10,6 +10,8 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions metadata := parseSocksAddr(target) metadata.NetWork = C.UDP metadata.Type = source + metadata.RawSrcAddr = packet.LocalAddr() + metadata.RawDstAddr = metadata.UDPAddr() ApplyAdditions(metadata, WithSrcAddr(packet.LocalAddr())) if p, ok := packet.(C.UDPPacketInAddr); ok { ApplyAdditions(metadata, WithInAddr(p.InAddr())) diff --git a/adapter/outboundgroup/patch_android.go b/adapter/outboundgroup/patch_android.go new file mode 100644 index 00000000..e219ca9f --- /dev/null +++ b/adapter/outboundgroup/patch_android.go @@ -0,0 +1,64 @@ +// +build android + +package outboundgroup + +import ( + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" +) + +type ProxyGroup interface { + C.ProxyAdapter + + Providers() []provider.ProxyProvider + Proxies() []C.Proxy + Now() string +} + +func (f *Fallback) Providers() []provider.ProxyProvider { + return f.providers +} + +func (lb *LoadBalance) Providers() []provider.ProxyProvider { + return lb.providers +} + +func (f *Fallback) Proxies() []C.Proxy { + return f.GetProxies(false) +} + +func (lb *LoadBalance) Proxies() []C.Proxy { + return lb.GetProxies(false) +} + +func (lb *LoadBalance) Now() string { + return "" +} + +func (r *Relay) Providers() []provider.ProxyProvider { + return r.providers +} + +func (r *Relay) Proxies() []C.Proxy { + return r.GetProxies(false) +} + +func (r *Relay) Now() string { + return "" +} + +func (s *Selector) Providers() []provider.ProxyProvider { + return s.providers +} + +func (s *Selector) Proxies() []C.Proxy { + return s.GetProxies(false) +} + +func (u *URLTest) Providers() []provider.ProxyProvider { + return u.providers +} + +func (u *URLTest) Proxies() []C.Proxy { + return u.GetProxies(false) +} diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index e7f021e1..6a7cd3ef 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -18,6 +18,7 @@ import ( const ( defaultURLTestTimeout = time.Second * 5 + defaultURLTestURL = "https://www.gstatic.com/generate_204" ) type HealthCheckOption struct { @@ -148,6 +149,10 @@ func (hc *HealthCheck) stop() { } func (hc *HealthCheck) check() { + if len(hc.proxies) == 0 { + return + } + _, _, _ = hc.singleDo.Do(func() (struct{}, error) { id := utils.NewUUIDV4().String() log.Debugln("Start New Health Checking {%s}", id) @@ -223,6 +228,7 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, exp if len(url) == 0 { interval = 0 expectedStatus = nil + url = defaultURLTestURL } return &HealthCheck{ diff --git a/adapter/provider/patch_android.go b/adapter/provider/patch_android.go new file mode 100644 index 00000000..eb0ca1f9 --- /dev/null +++ b/adapter/provider/patch_android.go @@ -0,0 +1,36 @@ +// +build android + +package provider + +import ( + "time" +) + +var ( + suspended bool +) + +type UpdatableProvider interface { + UpdatedAt() time.Time +} + +func (pp *proxySetProvider) UpdatedAt() time.Time { + return pp.Fetcher.UpdatedAt +} + +func (pp *proxySetProvider) Close() error { + pp.healthCheck.close() + pp.Fetcher.Destroy() + + return nil +} + +func (cp *compatibleProvider) Close() error { + cp.healthCheck.close() + + return nil +} + +func Suspend(s bool) { + suspended = s +} diff --git a/component/dialer/patch_android.go b/component/dialer/patch_android.go new file mode 100644 index 00000000..2fe39924 --- /dev/null +++ b/component/dialer/patch_android.go @@ -0,0 +1,39 @@ +// +build android + +package dialer + +import ( + "context" + "net" + "net/netip" + "syscall" +) + +type SocketControl func(network, address string, conn syscall.RawConn) error + +var DefaultSocketHook SocketControl + +func dialContextHooked(ctx context.Context, network string, destination netip.Addr, port string) (net.Conn, error) { + dialer := &net.Dialer{ + Control: DefaultSocketHook, + } + + conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port)) + if err != nil { + return nil, err + } + + if t, ok := conn.(*net.TCPConn); ok { + t.SetKeepAlive(false) + } + + return conn, nil +} + +func listenPacketHooked(ctx context.Context, network, address string) (net.PacketConn, error) { + lc := &net.ListenConfig{ + Control: DefaultSocketHook, + } + + return lc.ListenPacket(ctx, network, address) +} diff --git a/component/mmdb/patch_android.go b/component/mmdb/patch_android.go new file mode 100644 index 00000000..23afbb90 --- /dev/null +++ b/component/mmdb/patch_android.go @@ -0,0 +1,18 @@ +// +build android + +package mmdb + +import "github.com/oschwald/maxminddb-golang" + +func InstallOverride(override *maxminddb.Reader) { + newReader := Reader{Reader: override} + switch override.Metadata.DatabaseType { + case "sing-geoip": + reader.databaseType = typeSing + case "Meta-geoip0": + reader.databaseType = typeMetaV0 + default: + reader.databaseType = typeMaxmind + } + reader = newReader +} diff --git a/component/process/patch_android.go b/component/process/patch_android.go new file mode 100644 index 00000000..ae68d7b2 --- /dev/null +++ b/component/process/patch_android.go @@ -0,0 +1,16 @@ +// +build android + +package process + +import "github.com/metacubex/mihomo/constant" + +type PackageNameResolver func(metadata *constant.Metadata) (string, error) + +var DefaultPackageNameResolver PackageNameResolver + +func FindPackageName(metadata *constant.Metadata) (string, error) { + if resolver := DefaultPackageNameResolver; resolver != nil { + return resolver(metadata) + } + return "", ErrPlatformNotSupport +} diff --git a/config/config.go b/config/config.go index 11db26c8..d808f702 100644 --- a/config/config.go +++ b/config/config.go @@ -212,11 +212,16 @@ type RawDNS struct { } type RawFallbackFilter struct { - GeoIP bool `yaml:"geoip"` - GeoIPCode string `yaml:"geoip-code"` - IPCIDR []string `yaml:"ipcidr"` - Domain []string `yaml:"domain"` - GeoSite []string `yaml:"geosite"` + GeoIP bool `yaml:"geoip" json:"geoip"` + GeoIPCode string `yaml:"geoip-code" json:"geoip-code"` + IPCIDR []string `yaml:"ipcidr" json:"ipcidr"` + Domain []string `yaml:"domain" json:"domain"` + GeoSite []string `yaml:"geosite" json:"geosite"` +} + +type RawClashForAndroid struct { + AppendSystemDNS bool `yaml:"append-system-dns" json:"append-system-dns"` + UiSubtitlePattern string `yaml:"ui-subtitle-pattern" json:"ui-subtitle-pattern"` } type RawTun struct { @@ -317,6 +322,8 @@ type RawConfig struct { SubRules map[string][]string `yaml:"sub-rules"` RawTLS TLS `yaml:"tls"` Listeners []map[string]any `yaml:"listeners"` + + ClashForAndroid RawClashForAndroid `yaml:"clash-for-android"` } type GeoXUrl struct { diff --git a/constant/metadata.go b/constant/metadata.go index 4b547a81..09a2f152 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -147,6 +147,9 @@ type Metadata struct { SpecialProxy string `json:"specialProxy"` SpecialRules string `json:"specialRules"` RemoteDst string `json:"remoteDestination"` + + RawSrcAddr net.Addr `json:"-"` + RawDstAddr net.Addr `json:"-"` // Only domain rule SniffHost string `json:"sniffHost"` } diff --git a/dns/dhcp.go b/dns/dhcp.go index dc1344f5..bd3143c6 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -1,3 +1,5 @@ +// +build !android + package dns import ( diff --git a/dns/patch_!android.go b/dns/patch_!android.go new file mode 100644 index 00000000..566d8fd5 --- /dev/null +++ b/dns/patch_!android.go @@ -0,0 +1,7 @@ +// +build !android + +package dns + +func UpdateIsolateHandler(resolver *Resolver, mapper *ResolverEnhancer) { + return +} \ No newline at end of file diff --git a/dns/patch_android.go b/dns/patch_android.go new file mode 100644 index 00000000..56f5ef54 --- /dev/null +++ b/dns/patch_android.go @@ -0,0 +1,81 @@ +// +build android + +package dns + +import ( + "context" + + D "github.com/miekg/dns" + + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/component/dhcp" + "github.com/metacubex/mihomo/component/resolver" +) + +const SystemDNSPlaceholder = "system" + +var systemResolver *Resolver +var isolateHandler handler + +var _ dnsClient = (*dhcpClient)(nil) + +type dhcpClient struct { + enable bool +} + +func (d *dhcpClient) Address() string { + return SystemDNSPlaceholder +} + +func (d *dhcpClient) Exchange(m *D.Msg) (msg *D.Msg, err error) { + return d.ExchangeContext(context.Background(), m) +} + +func (d *dhcpClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { + if s := systemResolver; s != nil { + return s.ExchangeContext(ctx, m) + } + + return nil, dhcp.ErrNotFound +} + +func ServeDNSWithDefaultServer(msg *D.Msg) (*D.Msg, error) { + if h := isolateHandler; h != nil { + return handlerWithContext(context.Background(), h, msg) + } + + return nil, D.ErrTime +} + +func FlushCacheWithDefaultResolver() { + if r := resolver.DefaultResolver; r != nil { + r.(*Resolver).lruCache = cache.New[string, *D.Msg](cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)) + } +} + +func UpdateSystemDNS(addr []string) { + if len(addr) == 0 { + systemResolver = nil + } + + ns := make([]NameServer, 0, len(addr)) + for _, d := range addr { + ns = append(ns, NameServer{Addr: d}) + } + + systemResolver = NewResolver(Config{Main: ns}) +} + +func UpdateIsolateHandler(resolver *Resolver, mapper *ResolverEnhancer) { + if resolver == nil { + isolateHandler = nil + + return + } + + isolateHandler = NewHandler(resolver, mapper) +} + +func newDHCPClient(ifaceName string) *dhcpClient { + return &dhcpClient{enable: ifaceName == SystemDNSPlaceholder} +} diff --git a/dns/server.go b/dns/server.go index 1cf58d4d..2eac173e 100644 --- a/dns/server.go +++ b/dns/server.go @@ -49,6 +49,8 @@ func (s *Server) SetHandler(handler handler) { } func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) { + UpdateIsolateHandler(resolver, mapper) + if addr == address && resolver != nil { handler := NewHandler(resolver, mapper) server.SetHandler(handler) diff --git a/listener/http/patch_android.go b/listener/http/patch_android.go new file mode 100644 index 00000000..33dc0874 --- /dev/null +++ b/listener/http/patch_android.go @@ -0,0 +1,9 @@ +// +build android + +package http + +import "net" + +func (l *Listener) Listener() net.Listener { + return l.listener +} diff --git a/rules/provider/patch_android.go b/rules/provider/patch_android.go new file mode 100644 index 00000000..2bea2fa3 --- /dev/null +++ b/rules/provider/patch_android.go @@ -0,0 +1,27 @@ +// +build android + +package provider + +import "time" + +var ( + suspended bool +) + +type UpdatableProvider interface { + UpdatedAt() time.Time +} + +func (f *ruleSetProvider) UpdatedAt() time.Time { + return f.Fetcher.UpdatedAt +} + +func (rp *ruleSetProvider) Close() error { + rp.Fetcher.Destroy() + + return nil +} + +func Suspend(s bool) { + suspended = s +} diff --git a/tunnel/statistic/patch_android.go b/tunnel/statistic/patch_android.go new file mode 100644 index 00000000..c000567f --- /dev/null +++ b/tunnel/statistic/patch_android.go @@ -0,0 +1,7 @@ +// +build android + +package statistic + +func (m *Manager) Total() (up, down int64) { + return m.uploadTotal.Load(), m.downloadTotal.Load() +}