Android: patch

This commit is contained in:
GitHub Action 2023-11-03 05:59:14 +00:00
parent 8c3557e96b
commit 807d41f57b
25 changed files with 390 additions and 81 deletions

View File

@ -12,6 +12,8 @@ func NewHTTP(target socks5.Addr, srcConn net.Conn, conn net.Conn, additions ...A
metadata := parseSocksAddr(target) metadata := parseSocksAddr(target)
metadata.NetWork = C.TCP metadata.NetWork = C.TCP
metadata.Type = C.HTTP metadata.Type = C.HTTP
metadata.RawSrcAddr = srcConn.RemoteAddr()
metadata.RawDstAddr = srcConn.LocalAddr()
ApplyAdditions(metadata, WithSrcAddr(srcConn.RemoteAddr()), WithInAddr(conn.LocalAddr())) ApplyAdditions(metadata, WithSrcAddr(srcConn.RemoteAddr()), WithInAddr(conn.LocalAddr()))
ApplyAdditions(metadata, additions...) ApplyAdditions(metadata, additions...)
return conn, metadata return conn, metadata

View File

@ -10,6 +10,8 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions
metadata := parseSocksAddr(target) metadata := parseSocksAddr(target)
metadata.NetWork = C.UDP metadata.NetWork = C.UDP
metadata.Type = source metadata.Type = source
metadata.RawSrcAddr = packet.LocalAddr()
metadata.RawDstAddr = metadata.UDPAddr()
ApplyAdditions(metadata, WithSrcAddr(packet.LocalAddr())) ApplyAdditions(metadata, WithSrcAddr(packet.LocalAddr()))
if p, ok := packet.(C.UDPPacketInAddr); ok { if p, ok := packet.(C.UDPPacketInAddr); ok {
ApplyAdditions(metadata, WithInAddr(p.InAddr())) ApplyAdditions(metadata, WithInAddr(p.InAddr()))

View File

@ -0,0 +1,62 @@
package outboundgroup
import (
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/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)
}

View File

@ -18,6 +18,7 @@ import (
const ( const (
defaultURLTestTimeout = time.Second * 5 defaultURLTestTimeout = time.Second * 5
defaultURLTestURL = "https://www.gstatic.com/generate_204"
) )
type HealthCheckOption struct { type HealthCheckOption struct {
@ -148,6 +149,11 @@ func (hc *HealthCheck) stop() {
} }
func (hc *HealthCheck) check() { func (hc *HealthCheck) check() {
if len(hc.proxies) == 0 {
return
}
_, _, _ = hc.singleDo.Do(func() (struct{}, error) { _, _, _ = hc.singleDo.Do(func() (struct{}, error) {
id := utils.NewUUIDV4().String() id := utils.NewUUIDV4().String()
log.Debugln("Start New Health Checking {%s}", id) log.Debugln("Start New Health Checking {%s}", id)
@ -223,6 +229,7 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, exp
if len(url) == 0 { if len(url) == 0 {
interval = 0 interval = 0
expectedStatus = nil expectedStatus = nil
url = defaultURLTestURL
} }
return &HealthCheck{ return &HealthCheck{

View File

@ -68,9 +68,6 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide
case "http": case "http":
if schema.Path != "" { if schema.Path != "" {
path := C.Path.Resolve(schema.Path) path := C.Path.Resolve(schema.Path)
if !C.Path.IsSafePath(path) {
return nil, fmt.Errorf("%w: %s", errSubPath, path)
}
vehicle = resource.NewHTTPVehicle(schema.URL, path) vehicle = resource.NewHTTPVehicle(schema.URL, path)
} else { } else {
path := C.Path.GetPathByHash("proxies", schema.URL) path := C.Path.GetPathByHash("proxies", schema.URL)

34
adapter/provider/patch.go Normal file
View File

@ -0,0 +1,34 @@
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
}

View File

@ -70,6 +70,9 @@ func DialContext(ctx context.Context, network, address string, options ...Option
} }
func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) { func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) {
if DefaultSocketHook != nil {
return listenPacketHooked(ctx, network, address)
}
cfg := applyOptions(options...) cfg := applyOptions(options...)
lc := &net.ListenConfig{} lc := &net.ListenConfig{}
@ -114,6 +117,9 @@ func GetTcpConcurrent() bool {
} }
func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) { func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) {
if DefaultSocketHook != nil {
return dialContextHooked(ctx, network, destination, port)
}
address := net.JoinHostPort(destination.String(), port) address := net.JoinHostPort(destination.String(), port)
netDialer := opt.netDialer netDialer := opt.netDialer

37
component/dialer/patch.go Normal file
View File

@ -0,0 +1,37 @@
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)
}

16
component/mmdb/patch.go Normal file
View File

@ -0,0 +1,16 @@
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
}

View File

@ -0,0 +1,14 @@
package process
import "github.com/Dreamacro/clash/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
}

View File

@ -13,6 +13,10 @@ import (
"github.com/samber/lo" "github.com/samber/lo"
) )
const (
minInterval = time.Minute * 5
)
var ( var (
fileMode os.FileMode = 0o666 fileMode os.FileMode = 0o666
dirMode os.FileMode = 0o755 dirMode os.FileMode = 0o755
@ -24,8 +28,7 @@ type Fetcher[V any] struct {
resourceType string resourceType string
name string name string
vehicle types.Vehicle vehicle types.Vehicle
UpdatedAt *time.Time UpdatedAt time.Time
ticker *time.Ticker
done chan struct{} done chan struct{}
hash [16]byte hash [16]byte
parser Parser[V] parser Parser[V]
@ -56,7 +59,7 @@ func (f *Fetcher[V]) Initial() (V, error) {
if stat, fErr := os.Stat(f.vehicle.Path()); fErr == nil { if stat, fErr := os.Stat(f.vehicle.Path()); fErr == nil {
buf, err = os.ReadFile(f.vehicle.Path()) buf, err = os.ReadFile(f.vehicle.Path())
modTime := stat.ModTime() modTime := stat.ModTime()
f.UpdatedAt = &modTime f.UpdatedAt = modTime
isLocal = true isLocal = true
if f.interval != 0 && modTime.Add(f.interval).Before(time.Now()) { if f.interval != 0 && modTime.Add(f.interval).Before(time.Now()) {
log.Warnln("[Provider] %s not updated for a long time, force refresh", f.Name()) log.Warnln("[Provider] %s not updated for a long time, force refresh", f.Name())
@ -64,6 +67,7 @@ func (f *Fetcher[V]) Initial() (V, error) {
} }
} else { } else {
buf, err = f.vehicle.Read() buf, err = f.vehicle.Read()
f.UpdatedAt = time.Now()
} }
if err != nil { if err != nil {
@ -113,7 +117,7 @@ func (f *Fetcher[V]) Initial() (V, error) {
f.hash = md5.Sum(buf) f.hash = md5.Sum(buf)
// pull contents automatically // pull contents automatically
if f.ticker != nil { if f.interval > 0 {
go f.pullLoop() go f.pullLoop()
} }
@ -129,7 +133,7 @@ func (f *Fetcher[V]) Update() (V, bool, error) {
now := time.Now() now := time.Now()
hash := md5.Sum(buf) hash := md5.Sum(buf)
if bytes.Equal(f.hash[:], hash[:]) { if bytes.Equal(f.hash[:], hash[:]) {
f.UpdatedAt = &now f.UpdatedAt = now
_ = os.Chtimes(f.vehicle.Path(), now, now) _ = os.Chtimes(f.vehicle.Path(), now, now)
return lo.Empty[V](), true, nil 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 f.hash = hash
return contents, false, nil return contents, false, nil
} }
func (f *Fetcher[V]) Destroy() error { func (f *Fetcher[V]) Destroy() error {
if f.ticker != nil { if f.interval > 0 {
f.done <- struct{}{} f.done <- struct{}{}
} }
return nil return nil
} }
func (f *Fetcher[V]) pullLoop() { 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 { for {
select { select {
case <-f.ticker.C: case <-timer.C:
timer.Reset(f.interval)
elm, same, err := f.Update() elm, same, err := f.Update()
if err != nil { if err != nil {
log.Errorln("[Provider] %s pull error: %s", f.Name(), err.Error()) log.Errorln("[Provider] %s pull error: %s", f.Name(), err.Error())
@ -178,7 +190,6 @@ func (f *Fetcher[V]) pullLoop() {
f.OnUpdate(elm) f.OnUpdate(elm)
} }
case <-f.done: case <-f.done:
f.ticker.Stop()
return 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] { 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]{ return &Fetcher[V]{
name: name, name: name,
ticker: ticker,
vehicle: vehicle, vehicle: vehicle,
parser: parser, parser: parser,
done: make(chan struct{}, 1), done: make(chan struct{}, 8),
OnUpdate: onUpdate, OnUpdate: onUpdate,
interval: interval, interval: interval,
} }

View File

@ -58,7 +58,6 @@ type General struct {
TCPConcurrent bool `json:"tcp-concurrent"` TCPConcurrent bool `json:"tcp-concurrent"`
FindProcessMode P.FindProcessMode `json:"find-process-mode"` FindProcessMode P.FindProcessMode `json:"find-process-mode"`
Sniffing bool `json:"sniffing"` Sniffing bool `json:"sniffing"`
EBpf EBpf `json:"-"`
GlobalClientFingerprint string `json:"global-client-fingerprint"` GlobalClientFingerprint string `json:"global-client-fingerprint"`
GlobalUA string `json:"global-ua"` GlobalUA string `json:"global-ua"`
} }
@ -193,29 +192,34 @@ type RawNTP struct {
} }
type RawDNS struct { type RawDNS struct {
Enable bool `yaml:"enable"` Enable bool `yaml:"enable" json:"enable"`
PreferH3 bool `yaml:"prefer-h3"` PreferH3 bool `yaml:"prefer-h3" json:"prefer-h3"`
IPv6 bool `yaml:"ipv6"` IPv6 bool `yaml:"ipv6" json:"ipv6"`
IPv6Timeout uint `yaml:"ipv6-timeout"` IPv6Timeout uint `yaml:"ipv6-timeout" json:"ipv6-timeout"`
UseHosts bool `yaml:"use-hosts"` UseHosts bool `yaml:"use-hosts" json:"use-hosts"`
NameServer []string `yaml:"nameserver"` NameServer []string `yaml:"nameserver" json:"nameserver"`
Fallback []string `yaml:"fallback"` Fallback []string `yaml:"fallback" json:"fallback"`
FallbackFilter RawFallbackFilter `yaml:"fallback-filter"` FallbackFilter RawFallbackFilter `yaml:"fallback-filter" json:"fallback-filter"`
Listen string `yaml:"listen"` Listen string `yaml:"listen" json:"listen"`
EnhancedMode C.DNSMode `yaml:"enhanced-mode"` EnhancedMode C.DNSMode `yaml:"enhanced-mode" json:"enhanced-mode"`
FakeIPRange string `yaml:"fake-ip-range"` FakeIPRange string `yaml:"fake-ip-range" json:"fake-ip-range"`
FakeIPFilter []string `yaml:"fake-ip-filter"` FakeIPFilter []string `yaml:"fake-ip-filter" json:"fake-ip-filter"`
DefaultNameserver []string `yaml:"default-nameserver"` DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"`
NameServerPolicy map[string]any `yaml:"nameserver-policy"` NameServerPolicy map[string]any `yaml:"nameserver-policy" json:"nameserver-policy"`
ProxyServerNameserver []string `yaml:"proxy-server-nameserver"` ProxyServerNameserver []string `yaml:"proxy-server-nameserver" json:"proxy-server-nameserver"`
} }
type RawFallbackFilter struct { type RawFallbackFilter struct {
GeoIP bool `yaml:"geoip"` GeoIP bool `yaml:"geoip" json:"geoip"`
GeoIPCode string `yaml:"geoip-code"` GeoIPCode string `yaml:"geoip-code" json:"geoip-code"`
IPCIDR []string `yaml:"ipcidr"` IPCIDR []string `yaml:"ipcidr" json:"ipcidr"`
Domain []string `yaml:"domain"` Domain []string `yaml:"domain" json:"domain"`
GeoSite []string `yaml:"geosite"` 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 { type RawTun struct {
@ -263,23 +267,23 @@ type RawTuicServer struct {
} }
type RawConfig struct { type RawConfig struct {
Port int `yaml:"port"` Port int `yaml:"port" json:"port"`
SocksPort int `yaml:"socks-port"` SocksPort int `yaml:"socks-port" json:"socks-port"`
RedirPort int `yaml:"redir-port"` RedirPort int `yaml:"redir-port" json:"redir-port"`
TProxyPort int `yaml:"tproxy-port"` TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"`
MixedPort int `yaml:"mixed-port"` MixedPort int `yaml:"mixed-port" json:"mixed-port"`
ShadowSocksConfig string `yaml:"ss-config"` ShadowSocksConfig string `yaml:"ss-config"`
VmessConfig string `yaml:"vmess-config"` VmessConfig string `yaml:"vmess-config"`
InboundTfo bool `yaml:"inbound-tfo"` InboundTfo bool `yaml:"inbound-tfo"`
InboundMPTCP bool `yaml:"inbound-mptcp"` InboundMPTCP bool `yaml:"inbound-mptcp"`
Authentication []string `yaml:"authentication"` Authentication []string `yaml:"authentication" json:"authentication"`
SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"` SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"`
AllowLan bool `yaml:"allow-lan"` AllowLan bool `yaml:"allow-lan" json:"allow-lan"`
BindAddress string `yaml:"bind-address"` BindAddress string `yaml:"bind-address" json:"bind-address"`
Mode T.TunnelMode `yaml:"mode"` Mode T.TunnelMode `yaml:"mode" json:"mode"`
UnifiedDelay bool `yaml:"unified-delay"` UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"`
LogLevel log.LogLevel `yaml:"log-level"` LogLevel log.LogLevel `yaml:"log-level" json:"log-level"`
IPv6 bool `yaml:"ipv6"` IPv6 bool `yaml:"ipv6" json:"ipv6"`
ExternalController string `yaml:"external-controller"` ExternalController string `yaml:"external-controller"`
ExternalControllerTLS string `yaml:"external-controller-tls"` ExternalControllerTLS string `yaml:"external-controller-tls"`
ExternalUI string `yaml:"external-ui"` ExternalUI string `yaml:"external-ui"`
@ -289,20 +293,20 @@ type RawConfig struct {
Interface string `yaml:"interface-name"` Interface string `yaml:"interface-name"`
RoutingMark int `yaml:"routing-mark"` RoutingMark int `yaml:"routing-mark"`
Tunnels []LC.Tunnel `yaml:"tunnels"` Tunnels []LC.Tunnel `yaml:"tunnels"`
GeodataMode bool `yaml:"geodata-mode"` GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"`
GeodataLoader string `yaml:"geodata-loader"` GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"`
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"`
GlobalClientFingerprint string `yaml:"global-client-fingerprint"` GlobalClientFingerprint string `yaml:"global-client-fingerprint"`
GlobalUA string `yaml:"global-ua"` GlobalUA string `yaml:"global-ua"`
KeepAliveInterval int `yaml:"keep-alive-interval"` KeepAliveInterval int `yaml:"keep-alive-interval"`
Sniffer RawSniffer `yaml:"sniffer"` Sniffer RawSniffer `yaml:"sniffer" json:"sniffer"`
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
RuleProvider map[string]map[string]any `yaml:"rule-providers"` RuleProvider map[string]map[string]any `yaml:"rule-providers"`
Hosts map[string]any `yaml:"hosts"` Hosts map[string]any `yaml:"hosts" json:"hosts"`
NTP RawNTP `yaml:"ntp"` NTP RawNTP `yaml:"ntp" json:"ntp"`
DNS RawDNS `yaml:"dns"` DNS RawDNS `yaml:"dns" json:"dns"`
Tun RawTun `yaml:"tun"` Tun RawTun `yaml:"tun"`
TuicServer RawTuicServer `yaml:"tuic-server"` TuicServer RawTuicServer `yaml:"tuic-server"`
EBpf EBpf `yaml:"ebpf"` EBpf EBpf `yaml:"ebpf"`
@ -316,6 +320,8 @@ type RawConfig struct {
SubRules map[string][]string `yaml:"sub-rules"` SubRules map[string][]string `yaml:"sub-rules"`
RawTLS TLS `yaml:"tls"` RawTLS TLS `yaml:"tls"`
Listeners []map[string]any `yaml:"listeners"` Listeners []map[string]any `yaml:"listeners"`
ClashForAndroid RawClashForAndroid `yaml:"clash-for-android" json:"clash-for-android"`
} }
type GeoXUrl struct { type GeoXUrl struct {
@ -483,7 +489,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
startTime := time.Now() startTime := time.Now()
config.Experimental = &rawCfg.Experimental config.Experimental = &rawCfg.Experimental
config.Profile = &rawCfg.Profile config.Profile = &rawCfg.Profile
config.IPTables = &rawCfg.IPTables
config.TLS = &rawCfg.RawTLS config.TLS = &rawCfg.RawTLS
general, err := parseGeneral(rawCfg) general, err := parseGeneral(rawCfg)
@ -544,11 +549,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
} }
config.DNS = dnsCfg config.DNS = dnsCfg
err = parseTun(rawCfg.Tun, config.General)
if err != nil {
return nil, err
}
err = parseTuicServer(rawCfg.TuicServer, config.General) err = parseTuicServer(rawCfg.TuicServer, config.General)
if err != nil { if err != nil {
return nil, err return nil, err
@ -645,7 +645,6 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
GeodataLoader: cfg.GeodataLoader, GeodataLoader: cfg.GeodataLoader,
TCPConcurrent: cfg.TCPConcurrent, TCPConcurrent: cfg.TCPConcurrent,
FindProcessMode: cfg.FindProcessMode, FindProcessMode: cfg.FindProcessMode,
EBpf: cfg.EBpf,
GlobalClientFingerprint: cfg.GlobalClientFingerprint, GlobalClientFingerprint: cfg.GlobalClientFingerprint,
GlobalUA: cfg.GlobalUA, GlobalUA: cfg.GlobalUA,
}, nil }, nil

View File

@ -2,7 +2,7 @@ package constant
var ( var (
GeodataMode bool GeodataMode bool
GeoIpUrl string GeoIpUrl = "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat"
MmdbUrl string MmdbUrl = "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb"
GeoSiteUrl string GeoSiteUrl = "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat"
) )

View File

@ -147,6 +147,9 @@ type Metadata struct {
SpecialProxy string `json:"specialProxy"` SpecialProxy string `json:"specialProxy"`
SpecialRules string `json:"specialRules"` SpecialRules string `json:"specialRules"`
RemoteDst string `json:"remoteDestination"` RemoteDst string `json:"remoteDestination"`
RawSrcAddr net.Addr `json:"-"`
RawDstAddr net.Addr `json:"-"`
// Only domain rule // Only domain rule
SniffHost string `json:"sniffHost"` SniffHost string `json:"sniffHost"`
} }

View File

@ -1,3 +1,6 @@
//go:build disabled
// +build disabled
package dns package dns
import ( import (

79
dns/patch.go Normal file
View File

@ -0,0 +1,79 @@
package dns
import (
"context"
D "github.com/miekg/dns"
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/component/dhcp"
"github.com/Dreamacro/clash/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}
}

View File

@ -49,6 +49,7 @@ func (s *Server) SetHandler(handler handler) {
} }
func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) { func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) {
UpdateIsolateHandler(resolver, mapper)
if addr == address && resolver != nil { if addr == address && resolver != nil {
handler := NewHandler(resolver, mapper) handler := NewHandler(resolver, mapper)
server.SetHandler(handler) server.SetHandler(handler)

View File

@ -172,7 +172,7 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList
listener.ReCreateHTTP(general.Port, tunnel.Tunnel) listener.ReCreateHTTP(general.Port, tunnel.Tunnel)
listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel) listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel)
listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel) listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel)
listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) // listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel)
listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel) listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel)
listener.ReCreateMixed(general.MixedPort, tunnel.Tunnel) listener.ReCreateMixed(general.MixedPort, tunnel.Tunnel)
listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel) listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel)

7
listener/http/patch.go Normal file
View File

@ -0,0 +1,7 @@
package http
import "net"
func (l *Listener) Listener() net.Listener {
return l.listener
}

View File

@ -65,6 +65,9 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi
} }
continue continue
} }
if t, ok := conn.(*net.TCPConn); ok {
t.SetKeepAlive(false)
}
go HandleConn(conn, tunnel, c, additions...) go HandleConn(conn, tunnel, c, additions...)
} }
}() }()

View File

@ -27,6 +27,8 @@ func HandleTcp(address string) (conn net.Conn, err error) {
metadata.Type = C.INNER metadata.Type = C.INNER
metadata.DNSMode = C.DNSNormal metadata.DNSMode = C.DNSNormal
metadata.Process = C.ClashName metadata.Process = C.ClashName
metadata.RawSrcAddr = conn1.RemoteAddr()
metadata.RawDstAddr = conn1.LocalAddr()
if h, port, err := net.SplitHostPort(address); err == nil { if h, port, err := net.SplitHostPort(address); err == nil {
if port, err := strconv.ParseUint(port, 10, 16); err == nil { if port, err := strconv.ParseUint(port, 10, 16); err == nil {
metadata.DstPort = uint16(port) metadata.DstPort = uint16(port)

View File

@ -62,15 +62,11 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t
case "http": case "http":
if schema.Path != "" { if schema.Path != "" {
path := C.Path.Resolve(schema.Path) path := C.Path.Resolve(schema.Path)
if !C.Path.IsSafePath(path) {
return nil, fmt.Errorf("%w: %s", errSubPath, path)
}
vehicle = resource.NewHTTPVehicle(schema.URL, path) vehicle = resource.NewHTTPVehicle(schema.URL, path)
} else { } else {
path := C.Path.GetPathByHash("rules", schema.URL) path := C.Path.GetPathByHash("rules", schema.URL)
vehicle = resource.NewHTTPVehicle(schema.URL, path) vehicle = resource.NewHTTPVehicle(schema.URL, path)
} }
default: default:
return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type) return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
} }

25
rules/provider/patch.go Normal file
View File

@ -0,0 +1,25 @@
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
}

View File

@ -0,0 +1,5 @@
package statistic
func (m *Manager) Total() (up, down int64) {
return m.uploadTotal.Load(), m.downloadTotal.Load()
}

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"net" "net"
"net/netip" "net/netip"
"path/filepath"
"runtime" "runtime"
"sync" "sync"
"time" "time"
@ -47,6 +46,8 @@ var (
findProcessMode P.FindProcessMode findProcessMode P.FindProcessMode
fakeIPRange netip.Prefix fakeIPRange netip.Prefix
procesCache string
) )
type tunnel struct{} type tunnel struct{}
@ -594,7 +595,7 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
defer configMux.RUnlock() defer configMux.RUnlock()
var ( var (
resolved bool resolved bool
attemptProcessLookup = true processFound bool
) )
if node, ok := resolver.DefaultHosts.Search(metadata.Host, false); ok { if node, ok := resolver.DefaultHosts.Search(metadata.Host, false); ok {
@ -618,15 +619,17 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
}() }()
} }
if attemptProcessLookup && !findProcessMode.Off() && (findProcessMode.Always() || rule.ShouldFindProcess()) { if !findProcessMode.Off() && !processFound && (findProcessMode.Always() || rule.ShouldFindProcess()) {
attemptProcessLookup = false pkg, err := P.FindPackageName(metadata)
uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort))
if err != nil { if err != nil {
log.Debugln("[Process] find process %s: %v", metadata.String(), err) log.Debugln("[Process] find process %s: %v", metadata.String(), err)
} else { } else {
metadata.Process = filepath.Base(path) metadata.Process = pkg
metadata.ProcessPath = path processFound = true
metadata.Uid = uid if procesCache != metadata.Process {
log.Debugln("[Process] %s from process %s", metadata.String(), metadata.Process)
}
procesCache = metadata.Process
} }
} }