mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-11-16 11:42:43 +08:00
Android: patch
This commit is contained in:
parent
8c3557e96b
commit
807d41f57b
|
@ -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
|
||||||
|
|
|
@ -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()))
|
||||||
|
|
62
adapter/outboundgroup/patch.go
Normal file
62
adapter/outboundgroup/patch.go
Normal 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)
|
||||||
|
}
|
|
@ -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{
|
||||||
|
|
|
@ -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
34
adapter/provider/patch.go
Normal 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
|
||||||
|
}
|
|
@ -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
37
component/dialer/patch.go
Normal 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
16
component/mmdb/patch.go
Normal 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
|
||||||
|
}
|
14
component/process/patch.go
Normal file
14
component/process/patch.go
Normal 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
|
||||||
|
}
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
//go:build disabled
|
||||||
|
// +build disabled
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
79
dns/patch.go
Normal file
79
dns/patch.go
Normal 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}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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
7
listener/http/patch.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
func (l *Listener) Listener() net.Listener {
|
||||||
|
return l.listener
|
||||||
|
}
|
|
@ -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...)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
25
rules/provider/patch.go
Normal 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
|
||||||
|
}
|
5
tunnel/statistic/patch.go
Normal file
5
tunnel/statistic/patch.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package statistic
|
||||||
|
|
||||||
|
func (m *Manager) Total() (up, down int64) {
|
||||||
|
return m.uploadTotal.Load(), m.downloadTotal.Load()
|
||||||
|
}
|
|
@ -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{}
|
||||||
|
@ -593,8 +594,8 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
||||||
configMux.RLock()
|
configMux.RLock()
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user